mirror of
https://github.com/Z3Prover/z3
synced 2026-02-17 22:24:20 +00:00
Merge with branch lws (#8498)
* t0 Signed-off-by: Lev Nachmanson <levnach@hotmail.com> * t1 Signed-off-by: Lev Nachmanson <levnach@hotmail.com> * t2 * scaffoldin * scaffolding Signed-off-by: Lev Nachmanson <levnach@hotmail.com> * closer to the paper Signed-off-by: Lev Nachmanson <levnach@hotmail.com> * more scaffolding Signed-off-by: Lev Nachmanson <levnach@hotmail.com> * define symbolic_interval Signed-off-by: Lev Nachmanson <levnach@hotmail.com> * t Signed-off-by: Lev Nachmanson <levnach@hotmail.com> * use std::map instead of std::unordered_map Signed-off-by: Lev Nachmanson <levnach@hotmail.com> * more accurate init of the relation between polynomial properties Signed-off-by: Lev Nachmanson <levnach@hotmail.com> * t Signed-off-by: Lev Nachmanson <levnach@hotmail.com> * pass anum_manager to levelwise, crash on sign Signed-off-by: Lev Nachmanson <levnach@hotmail.com> * pass pmanager Signed-off-by: Lev Nachmanson <levnach@hotmail.com> * create free function display functions * use new display functions * pass nlsat::solver to levelwise Signed-off-by: Lev Nachmanson <levnach@hotmail.com> * add trace tag for levelwise Signed-off-by: Lev Nachmanson <levnach@hotmail.com> * refactor Signed-off-by: Lev Nachmanson <levnach@hotmail.com> * refactor Signed-off-by: Lev Nachmanson <levnach@hotmail.com> * define indexed root expression Signed-off-by: Lev Nachmanson <levnach@hotmail.com> * refact lws Signed-off-by: Lev Nachmanson <levnach@hotmail.com> * refact lws Signed-off-by: Lev Nachmanson <levnach@hotmail.com> * refactor lws Signed-off-by: Lev Nachmanson <levnach@hotmail.com> * trying to figure out right indices Signed-off-by: Lev Nachmanson <levnach@hotmail.com> * rename explain::main_operator to compute_conflict_explanation * preprocess the input of levelwise to drop a level Signed-off-by: Lev Nachmanson <levnach@hotmail.com> * ttt Signed-off-by: Lev Nachmanson <levnach@hotmail.com> * renaming Signed-off-by: Lev Nachmanson <levnach@hotmail.com> * rename Signed-off-by: Lev Nachmanson <levnach@hotmail.com> * work on seed_properties Signed-off-by: Lev Nachmanson <levnach@hotmail.com> * work on seed_properties Signed-off-by: Lev Nachmanson <levnach@hotmail.com> * work on seed_properties Signed-off-by: Lev Nachmanson <levnach@hotmail.com> * move a comment Signed-off-by: Lev Nachmanson <levnach@hotmail.com> * t Signed-off-by: Lev Nachmanson <levnach@hotmail.com> * t Signed-off-by: Lev Nachmanson <levnach@hotmail.com> * t Signed-off-by: Lev Nachmanson <levnach@hotmail.com> * t Signed-off-by: Lev Nachmanson <levnach@hotmail.com> * t Signed-off-by: Lev Nachmanson <levnach@hotmail.com> * t Signed-off-by: Lev Nachmanson <levnach@hotmail.com> * t Signed-off-by: Lev Nachmanson <levnach@hotmail.com> * t Signed-off-by: Lev Nachmanson <levnach@hotmail.com> * t Signed-off-by: Lev Nachmanson <levnach@hotmail.com> * t Signed-off-by: Lev Nachmanson <levnach@hotmail.com> * simplify Signed-off-by: Lev Nachmanson <levnach@hotmail.com> * simplify Signed-off-by: Lev Nachmanson <levnach@hotmail.com> * debug Signed-off-by: Lev Nachmanson <levnach@hotmail.com> * refactor and assert _irreducible Signed-off-by: Lev Nachmanson <levnach@hotmail.com> * add a display method Signed-off-by: Lev Nachmanson <levnach@hotmail.com> * t Signed-off-by: Lev Nachmanson <levnach@hotmail.com> * t Signed-off-by: Lev Nachmanson <levnach@hotmail.com> * t Signed-off-by: Lev Nachmanson <levnach@hotmail.com> * t Signed-off-by: Lev Nachmanson <levnach@hotmail.com> * t Signed-off-by: Lev Nachmanson <levnach@hotmail.com> * t Signed-off-by: Lev Nachmanson <levnach@hotmail.com> * simplify Signed-off-by: Lev Nachmanson <levnach@hotmail.com> * simplify Signed-off-by: Lev Nachmanson <levnach@hotmail.com> * remove erase_from_Q Signed-off-by: Lev Nachmanson <levnach@hotmail.com> * ignore holds properties Signed-off-by: Lev Nachmanson <levnach@hotmail.com> * t Signed-off-by: Lev Nachmanson <levnach@hotmail.com> * t Signed-off-by: Lev Nachmanson <levnach@hotmail.com> * t Signed-off-by: Lev Nachmanson <levnach@hotmail.com> * t Signed-off-by: Lev Nachmanson <levnach@hotmail.com> * t Signed-off-by: Lev Nachmanson <levnach@hotmail.com> * t Signed-off-by: Lev Nachmanson <levnach@hotmail.com> * t Signed-off-by: Lev Nachmanson <levnach@hotmail.com> * t Signed-off-by: Lev Nachmanson <levnach@hotmail.com> * got a section Signed-off-by: Lev Nachmanson <levnach@hotmail.com> * t Signed-off-by: Lev Nachmanson <levnach@hotmail.com> * introdure mk_prop Signed-off-by: Lev Nachmanson <levnach@hotmail.com> * t Signed-off-by: Lev Nachmanson <levnach@hotmail.com> * t Signed-off-by: Lev Nachmanson <levnach@hotmail.com> * remove a parameter Signed-off-by: Lev Nachmanson <levnach@hotmail.com> * t Signed-off-by: Lev Nachmanson <levnach@hotmail.com> * t Signed-off-by: Lev Nachmanson <levnach@hotmail.com> * t Signed-off-by: Lev Nachmanson <levnach@hotmail.com> * t Signed-off-by: Lev Nachmanson <levnach@hotmail.com> * add parameter to suppress/enable levelwise Signed-off-by: Lev Nachmanson <levnach@hotmail.com> * t Signed-off-by: Lev Nachmanson <levnach@hotmail.com> * comment * t Signed-off-by: Lev Nachmanson <levnach@hotmail.com> * fixing factoring and hitting NOT_IMPLEMENTED on ir_ord Signed-off-by: Lev Nachmanson <levnach@hotmail.com> * adding ir_ord Signed-off-by: Lev Nachmanson <levnach@hotmail.com> * produce more literals but creating sat lemmas Signed-off-by: Lev Nachmanson <levnach@hotmail.com> * t Signed-off-by: Lev Nachmanson <levnach@hotmail.com> * try iterative factoring Signed-off-by: Lev Nachmanson <levnach@hotmail.com> * new file Signed-off-by: Lev Nachmanson <levnach@hotmail.com> * create irreducible polynomials on init Signed-off-by: Lev Nachmanson <levnach@hotmail.com> * add a guard on m_fail Signed-off-by: Lev Nachmanson <levnach@hotmail.com> * t Signed-off-by: Lev Nachmanson <levnach@hotmail.com> * process level 0 as well Signed-off-by: Lev Nachmanson <levnach@hotmail.com> * remove a warning Signed-off-by: Lev Nachmanson <levnach@hotmail.com> * debug Signed-off-by: Lev Nachmanson <levnach@hotmail.com> * t Signed-off-by: Lev Nachmanson <levnach@hotmail.com> * prepare to fill the relation Signed-off-by: Lev Nachmanson <levnach@hotmail.com> * filling the relation Signed-off-by: Lev Nachmanson <levnach@hotmail.com> * separate the lower and upper bound root functions Signed-off-by: Lev Nachmanson <levnach@hotmail.com> * fix an assert statement Signed-off-by: Lev Nachmanson <levnach@hotmail.com> * create a better queue on properties Signed-off-by: Lev Nachmanson <levnach@hotmail.com> * normalize before pushing Signed-off-by: Lev Nachmanson <levnach@hotmail.com> * relax an assert Signed-off-by: Lev Nachmanson <levnach@hotmail.com> * rebase with master Signed-off-by: Lev Nachmanson <levnach@hotmail.com> * add stats to track levelwise calls Signed-off-by: Lev Nachmanson <levnach@hotmail.com> * catch and fail on an exception Signed-off-by: Lev Nachmanson <levnach@hotmail.com> * fix a bug in Rule 4.2 Signed-off-by: Lev Nachmanson <levnach@hotmail.com> * remove debug instruction Signed-off-by: Lev Nachmanson <levnach@hotmail.com> * call levelwise on a correct set of polynomials Signed-off-by: Lev Nachmanson <levnach@hotmail.com> * cosmetics Signed-off-by: Lev Nachmanson <levnach@hotmail.com> * use polynomial_ref instead of poly* Signed-off-by: Lev Nachmanson <levnach@hotmail.com> * do not refactor again multivariate polynomials Signed-off-by: Lev Nachmanson <levnach@hotmail.com> * canonicalize polinomals in todo_set Signed-off-by: Lev Nachmanson <levnach@hotmail.com> * t Signed-off-by: Lev Nachmanson <levnach@hotmail.com> * t Signed-off-by: Lev Nachmanson <levnach@hotmail.com> * canonicalize polynomials in nlsat Signed-off-by: Lev Nachmanson <levnach@hotmail.com> * t * normalize polynomials Signed-off-by: Lev Nachmanson <levnach@hotmail.com> * try not to fail in add_sgn_inv_leading_coeff_for Signed-off-by: Lev Nachmanson <levnach@hotmail.com> * use the cache consistently Signed-off-by: Lev Nachmanson <levnach@hotmail.com> * unsound state Signed-off-by: Lev Nachmanson <levnach@hotmail.com> * unsound state Signed-off-by: Lev Nachmanson <levnach@hotmail.com> * handle the zero case in add_ord_inv_resultant Signed-off-by: Lev Nachmanson <levnach@hotmail.com> * optimizations by using cached psc Signed-off-by: Lev Nachmanson <levnach@hotmail.com> * t Signed-off-by: Lev Nachmanson <levnach@hotmail.com> * make normalize optional Signed-off-by: Lev Nachmanson <levnach@hotmail.com> * Revert "make normalize optional" This reverts commitc80cfb0b8e. * t Signed-off-by: Lev Nachmanson <levnach@hotmail.com> * cleanup and more caching Signed-off-by: Lev Nachmanson <levnach@hotmail.com> * t Signed-off-by: Lev Nachmanson <levnach@hotmail.com> * better sort of root functions Signed-off-by: Lev Nachmanson <levnach@hotmail.com> * index bug Signed-off-by: Lev Nachmanson <levnach@hotmail.com> * with resultant calculation ignore one of p and q with a common root Signed-off-by: Lev Nachmanson <levnach@hotmail.com> * fix the duplicate bug Signed-off-by: Lev Nachmanson <levnach@hotmail.com> * t * simplify by removing back propagation Signed-off-by: Lev Nachmanson <levnach@hotmail.com> * t * t Signed-off-by: Lev Nachmanson <levnach@hotmail.com> * t Signed-off-by: Lev Nachmanson <levnach@hotmail.com> * hook up different relation build strategies for lws Signed-off-by: Lev Nachmanson <levnach@hotmail.com> * introduce isolate_root_closest Signed-off-by: Lev Nachmanson <levnach@hotmail.com> * fix a bug with non-adding ldcf Signed-off-by: Lev Nachmanson <levnach@hotmail.com> * simple choice of non-vanishing Signed-off-by: Lev Nachmanson <levnach@hotmail.com> * restore choose_non_zero_coeff Signed-off-by: Lev Nachmanson <levnach@hotmail.com> * efficient sort of root functions Signed-off-by: Lev Nachmanson <levnach@hotmail.com> * avoid ldcf with the projective theorem Signed-off-by: Lev Nachmanson <levnach@hotmail.com> * omit some disc Signed-off-by: Lev Nachmanson <levnach@hotmail.com> * use std_vector more Signed-off-by: Lev Nachmanson <levnach@hotmail.com> * avoid a compare call Signed-off-by: Lev Nachmanson <levnach@hotmail.com> * try optimizing build_interval_and_relation Signed-off-by: Lev Nachmanson <levnach@hotmail.com> * discard a discriminant only in the section case Signed-off-by: Lev Nachmanson <levnach@hotmail.com> * refactor Signed-off-by: Lev Nachmanson <levnach@hotmail.com> * refactor * refactor Signed-off-by: Lev Nachmanson <levnach@hotmail.com> * cache the polynomial roots Signed-off-by: Lev Nachmanson <levnach@hotmail.com> * Revert "cache the polynomial roots" This reverts commitaefcd16aaa. * ignore const non-null witnesses Signed-off-by: Lev Nachmanson <levnach@hotmail.com> * toward more like SMT-RAT split Signed-off-by: Lev Nachmanson <levnach@hotmail.com> * align with SMT-RAT Signed-off-by: Lev Nachmanson <levnach@hotmail.com> * t Signed-off-by: Lev Nachmanson <levnach@hotmail.com> * disables some heuristics in section Signed-off-by: Lev Nachmanson <levnach@hotmail.com> * Implement chain noLdcf optimization matching SMT-RAT Add find_partition_boundary() helper to locate the boundary between lower and upper root partitions in m_rfunc. Implement compute_omit_lc_sector_chain() and compute_omit_lc_section_chain() following SMT-RAT's OneCellCAD.h logic: - Omit ldcf for extreme of lower chain (index 0) if it appears on upper side - Omit ldcf for extreme of upper chain (last index) if it appears on lower side Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com> * Restrict noDisc optimization to section_lowest_degree only Match SMT-RAT behavior: noDisc (discriminant omission for leaves connected only to section polynomial) is only applied for sectionHeuristic == 3 (lowest_degree), not for biggest_cell or chain. Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com> * Cache partition boundary to avoid repeated algebraic number comparisons Store the partition boundary (index of first root > sample) in relation_E after sorting root functions. Use this cached value in compute_omit_lc_sector_chain() and compute_omit_lc_section_chain() instead of recomputing via algebraic number comparisons. Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com> * Refactor levelwise: consolidate partition indices into m_l_rf/m_u_rf Replace scattered local l_index/u_index parameters and m_partition_boundary with two impl members: - m_l_rf: position of lower bound in m_rel.m_rfunc - m_u_rf: position of upper bound in m_rel.m_rfunc (UINT_MAX in section case) This simplifies the code by: - Removing parameter passing through multiple function calls - Removing redundant m_partition_boundary from relation_E - Making the partition state explicit in impl Also clean up nlsat_explain.cpp to trust root_function_interval invariants: - Section case: assert l and l_index are valid instead of defensive check - Sector bounds: !l_inf()/!u_inf() implies valid polynomial and index Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com> * Refactor levelwise: use member variables for per-level state Replace local variables and function parameters with member variables: - m_level_ps: polynomials at current level (owned) - m_level_tags: tags for each polynomial (owned) - m_witnesses: non-zero coefficient witnesses - m_poly_has_roots: which polynomials have roots - m_todo: pointer to todo_set Functions now use these member variables directly: - extract_max_tagged() fills m_level_ps/m_level_tags and sets m_level - process_level() and process_top_level() are now parameterless - All helper functions use member variables instead of parameters Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com> * Refactor levelwise: change m_todo from pointer to member - Change m_todo from todo_set* to todo_set - Initialize m_todo in constructor initializer list - Use m_todo.reset() in single_cell_work instead of creating local todo_set - Replace pointer access (m_todo->) with member access (m_todo.) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com> * Add dynamic heuristic selection for levelwise projection Implement weight-based dynamic selection of projection heuristics in levelwise CAD. The weight function w(p, level) = deg(p, level) estimates projection complexity, with w(res(a,b)) ≈ w(a) + w(b). At each level, all three heuristics (biggest_cell, chain, lowest_degree) are evaluated and the one with minimum estimated resultant weight is selected. When fewer than 2 root functions exist, the default heuristic is used since all produce equivalent results. Add parameter nlsat.lws_dynamic_heuristic (default: true) to enable or disable dynamic selection. When disabled, the static heuristic from lws_sector_rel_mode/lws_section_rel_mode is used. Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com> * local optimization Signed-off-by: Lev Nachmanson <levnach@hotmail.com> * call omit_lc only when both bounds are present Signed-off-by: Lev Nachmanson <levnach@hotmail.com> * use std_vector Signed-off-by: Lev Nachmanson <levnach@hotmail.com> * remove m_level_tags Signed-off-by: Lev Nachmanson <levnach@hotmail.com> * count added lcs in the heuriistic estimates Signed-off-by: Lev Nachmanson <levnach@hotmail.com> * add both side spanning tree heuristic Signed-off-by: Lev Nachmanson <levnach@hotmail.com> * Fix nlsat projection bug: ensure polynomials with assumptions are also projected When polynomials are added as assumptions (via add_assumption or ensure_sign), they must also be added to the projection set (m_todo) to ensure proper cell construction. Previously, assumptions were added without corresponding projection, leading to unsound lemmas. Fixes: 1. In normalize(): collect lower-stage polynomials in m_lower_stage_polys and add them to m_ps in main() before projection. 2. In ensure_sign(): call insert_fresh_factors_in_todo(p) after adding assumption. 3. In project_cdcac(): when levelwise fails, use flet to set m_add_all_coeffs=true for the fallback projection. * Remove deprecated project_original and cell_sample parameter - Remove project_original() function from nlsat_explain.cpp - Remove m_sample_cell_project member variable - Simplify project() to just call project_cdcac() - Remove cell_sample parameter from nlsat_params.pyg - Update nlsat_solver.cpp to remove cell_sample() references - Update nlsat_explain.h constructor signature * Enforce bound polynomial LC protection in compute_omit_lc functions Move the invariant that bound-defining polynomials must never have their LC omitted from add_level_projections_sector() into the source functions: - compute_omit_lc_both_sides() - compute_omit_lc_chain_extremes() This centralizes the protection and removes the redundant override check. * fix the build Signed-off-by: Lev Nachmanson <levnach@hotmail.com> * bug fixes Signed-off-by: Lev Nachmanson <levnach@hotmail.com> * restore a deleted function Signed-off-by: Lev Nachmanson <levnach@hotmail.com> * remove sector/section stats Signed-off-by: Lev Nachmanson <levnach@hotmail.com> * Simplify levelwise: remove chain/lowest_degree heuristics, unify relation mode - Remove chain and lowest_degree heuristics, keep only biggest_cell and spanning_tree - Unify m_sector_relation_mode and m_section_relation_mode into single m_rel_mode - Remove lws_rel_mode, lws_sector_rel_mode, lws_section_rel_mode, lws_dynamic_heuristic params - lws_spt_threshold < 2 now disables spanning tree (single tuning parameter) - Restore noDisc optimization for spanning_tree leaves connected to boundary - Add noDisc for sector with same_boundary_poly (treat like section case) - Significant code reduction (~390 lines removed) Signed-off-by: Lev Nachmanson <levnach@hotmail.com> * fix bug with skipping too many discriminants Signed-off-by: Lev Nachmanson <levnach@hotmail.com> * t Signed-off-by: Lev Nachmanson <levnach@hotmail.com> * simplifications and bug fixes in lws, use static_tree only with sector + different bound polynomials, otherwise us biggest cell Signed-off-by: Lev Nachmanson <levnach@hotmail.com> * bug fixes and cleanup Signed-off-by: Lev Nachmanson <levnach@hotmail.com> * add the discriminant in degenerated case Signed-off-by: Lev Nachmanson <levnach@hotmail.com> * fix a bug with skipping a vanishing discriminant Signed-off-by: Lev Nachmanson <levnach@hotmail.com> * remove the unsound optimization Signed-off-by: Lev Nachmanson <levnach@hotmail.com> * fiddle with heuristics Signed-off-by: Lev Nachmanson <levnach@hotmail.com> * preserve random seed in nlsat_solver::check_lemma Signed-off-by: Lev Nachmanson <levnach@hotmail.com> * fix a typo in poly_has_roots Signed-off-by: Lev Nachmanson <levnach@hotmail.com> * add lc(p) and disc(p) for a rootless p in section case Signed-off-by: Lev Nachmanson <levnach@hotmail.com> * remove warnings Signed-off-by: Lev Nachmanson <levnach@hotmail.com> * untracking .beads Signed-off-by: Lev Nachmanson <levnach@hotmail.com> * fix the explosion in m_todo with lws.false Signed-off-by: Lev Nachmanson <levnach@hotmail.com> * fix issue 8397 Signed-off-by: Lev Nachmanson <levnach@hotmail.com> * set default to nlsat.lws=false for the merge with master Signed-off-by: Lev Nachmanson <levnach@hotmail.com> * set nlsat.lws=true by default, enable levelwise Signed-off-by: Lev Nachmanson <levnach@hotmail.com> --------- Signed-off-by: Lev Nachmanson <levnach@hotmail.com> Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
parent
1f855efa09
commit
63f05ff6e6
22 changed files with 4002 additions and 267 deletions
|
|
@ -17,9 +17,11 @@ Revision History:
|
|||
|
||||
--*/
|
||||
#include "nlsat/nlsat_explain.h"
|
||||
#include "nlsat/levelwise.h"
|
||||
#include "nlsat/nlsat_assignment.h"
|
||||
#include "nlsat/nlsat_evaluator.h"
|
||||
#include "math/polynomial/algebraic_numbers.h"
|
||||
#include "nlsat/nlsat_common.h"
|
||||
#include "util/ref_buffer.h"
|
||||
#include "util/mpq.h"
|
||||
|
||||
|
|
@ -32,7 +34,6 @@ namespace nlsat {
|
|||
|
||||
struct explain::imp {
|
||||
solver & m_solver;
|
||||
assignment const & m_assignment;
|
||||
atom_vector const & m_atoms;
|
||||
atom_vector const & m_x2eq;
|
||||
anum_manager & m_am;
|
||||
|
|
@ -49,85 +50,25 @@ namespace nlsat {
|
|||
bool m_factor;
|
||||
bool m_add_all_coeffs;
|
||||
bool m_add_zero_disc;
|
||||
bool m_cell_sample;
|
||||
|
||||
assignment const & sample() const { return m_solver.sample(); }
|
||||
assignment & sample() { return m_solver.sample(); }
|
||||
|
||||
struct todo_set {
|
||||
polynomial::cache & m_cache;
|
||||
polynomial_ref_vector m_set;
|
||||
svector<char> m_in_set;
|
||||
|
||||
todo_set(polynomial::cache & u):m_cache(u), m_set(u.pm()) {}
|
||||
|
||||
void reset() {
|
||||
pmanager & pm = m_set.m();
|
||||
unsigned sz = m_set.size();
|
||||
for (unsigned i = 0; i < sz; ++i) {
|
||||
m_in_set[pm.id(m_set.get(i))] = false;
|
||||
}
|
||||
m_set.reset();
|
||||
}
|
||||
|
||||
void insert(poly * p) {
|
||||
pmanager & pm = m_set.m();
|
||||
p = m_cache.mk_unique(p);
|
||||
unsigned pid = pm.id(p);
|
||||
if (m_in_set.get(pid, false))
|
||||
return;
|
||||
m_in_set.setx(pid, true, false);
|
||||
m_set.push_back(p);
|
||||
}
|
||||
|
||||
bool empty() const { return m_set.empty(); }
|
||||
|
||||
// Return max variable in todo_set
|
||||
var max_var() const {
|
||||
pmanager & pm = m_set.m();
|
||||
var max = null_var;
|
||||
unsigned sz = m_set.size();
|
||||
for (unsigned i = 0; i < sz; ++i) {
|
||||
var x = pm.max_var(m_set.get(i));
|
||||
SASSERT(x != null_var);
|
||||
if (max == null_var || x > max)
|
||||
max = x;
|
||||
}
|
||||
return max;
|
||||
}
|
||||
|
||||
/**
|
||||
\brief Remove the maximal polynomials from the set and store
|
||||
them in max_polys. Return the maximal variable
|
||||
*/
|
||||
var extract_max_polys(polynomial_ref_vector & max_polys) {
|
||||
max_polys.reset();
|
||||
var x = max_var();
|
||||
pmanager & pm = m_set.m();
|
||||
unsigned sz = m_set.size();
|
||||
unsigned j = 0;
|
||||
for (unsigned i = 0; i < sz; ++i) {
|
||||
poly * p = m_set.get(i);
|
||||
var y = pm.max_var(p);
|
||||
SASSERT(y <= x);
|
||||
if (y == x) {
|
||||
max_polys.push_back(p);
|
||||
m_in_set[pm.id(p)] = false;
|
||||
}
|
||||
else {
|
||||
m_set.set(j, p);
|
||||
j++;
|
||||
}
|
||||
}
|
||||
m_set.shrink(j);
|
||||
return x;
|
||||
}
|
||||
};
|
||||
|
||||
// temporary field for store todo set of polynomials
|
||||
todo_set m_todo;
|
||||
|
||||
// Track polynomials already processed in current projection to avoid cycles
|
||||
todo_set m_processed;
|
||||
|
||||
// temporary fields for preprocessing core
|
||||
scoped_literal_vector m_core1;
|
||||
scoped_literal_vector m_core2;
|
||||
|
||||
// Lower-stage polynomials encountered during normalization that need to be projected
|
||||
polynomial_ref_vector m_lower_stage_polys;
|
||||
|
||||
// Store last levelwise input for debugging unsound lemmas
|
||||
polynomial_ref_vector m_last_lws_input_polys;
|
||||
|
||||
// temporary fields for storing the result
|
||||
scoped_literal_vector * m_result = nullptr;
|
||||
|
|
@ -136,9 +77,8 @@ namespace nlsat {
|
|||
evaluator & m_evaluator;
|
||||
|
||||
imp(solver & s, assignment const & x2v, polynomial::cache & u, atom_vector const & atoms, atom_vector const & x2eq,
|
||||
evaluator & ev, bool is_sample):
|
||||
evaluator & ev, bool canonicalize):
|
||||
m_solver(s),
|
||||
m_assignment(x2v),
|
||||
m_atoms(atoms),
|
||||
m_x2eq(x2eq),
|
||||
m_am(x2v.am()),
|
||||
|
|
@ -150,10 +90,12 @@ namespace nlsat {
|
|||
m_factors(m_pm),
|
||||
m_factors_save(m_pm),
|
||||
m_roots_tmp(m_am),
|
||||
m_cell_sample(is_sample),
|
||||
m_todo(u),
|
||||
m_todo(u, canonicalize),
|
||||
m_processed(u, canonicalize),
|
||||
m_core1(s),
|
||||
m_core2(s),
|
||||
m_lower_stage_polys(m_pm),
|
||||
m_last_lws_input_polys(m_pm),
|
||||
m_evaluator(ev) {
|
||||
m_simplify_cores = false;
|
||||
m_full_dimensional = false;
|
||||
|
|
@ -162,25 +104,8 @@ namespace nlsat {
|
|||
m_add_zero_disc = true;
|
||||
}
|
||||
|
||||
std::ostream& display(std::ostream & out, polynomial_ref const & p) const {
|
||||
m_pm.display(out, p, m_solver.display_proc());
|
||||
return out;
|
||||
}
|
||||
|
||||
std::ostream& display(std::ostream & out, polynomial_ref_vector const & ps, char const * delim = "\n") const {
|
||||
for (unsigned i = 0; i < ps.size(); ++i) {
|
||||
if (i > 0)
|
||||
out << delim;
|
||||
m_pm.display(out, ps.get(i), m_solver.display_proc());
|
||||
}
|
||||
return out;
|
||||
}
|
||||
|
||||
std::ostream& display(std::ostream & out, literal l) const { return m_solver.display(out, l); }
|
||||
std::ostream& display_var(std::ostream & out, var x) const { return m_solver.display(out, x); }
|
||||
std::ostream& display(std::ostream & out, unsigned sz, literal const * ls) const { return m_solver.display(out, sz, ls); }
|
||||
std::ostream& display(std::ostream & out, literal_vector const & ls) const { return display(out, ls.size(), ls.data()); }
|
||||
std::ostream& display(std::ostream & out, scoped_literal_vector const & ls) const { return display(out, ls.size(), ls.data()); }
|
||||
// display helpers moved to free functions in nlsat_common.h
|
||||
|
||||
|
||||
/**
|
||||
\brief Add literal to the result vector.
|
||||
|
|
@ -208,28 +133,7 @@ namespace nlsat {
|
|||
SASSERT(check_already_added());
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
\brief evaluate the given polynomial in the current interpretation.
|
||||
max_var(p) must be assigned in the current interpretation.
|
||||
*/
|
||||
::sign sign(polynomial_ref const & p) {
|
||||
SASSERT(max_var(p) == null_var || m_assignment.is_assigned(max_var(p)));
|
||||
auto s = m_am.eval_sign_at(p, m_assignment);
|
||||
TRACE(nlsat_explain, tout << "p: " << p << " var: " << max_var(p) << " sign: " << s << "\n";);
|
||||
return s;
|
||||
}
|
||||
|
||||
/**
|
||||
\brief Wrapper for factorization
|
||||
*/
|
||||
void factor(polynomial_ref & p, polynomial_ref_vector & fs) {
|
||||
// TODO: add params, caching
|
||||
TRACE(nlsat_factor, tout << "factor\n" << p << "\n";);
|
||||
fs.reset();
|
||||
m_cache.factor(p.get(), fs);
|
||||
}
|
||||
|
||||
/**
|
||||
\brief Wrapper for psc chain computation
|
||||
*/
|
||||
|
|
@ -306,14 +210,14 @@ namespace nlsat {
|
|||
|
||||
void find_cell_roots(polynomial_ref_vector & ps, var y, cell_root_info & info) {
|
||||
info.reset();
|
||||
SASSERT(m_assignment.is_assigned(y));
|
||||
SASSERT(m_solver.sample().is_assigned(y));
|
||||
bool lower_inf = true;
|
||||
bool upper_inf = true;
|
||||
scoped_anum_vector & roots = m_roots_tmp;
|
||||
scoped_anum lower(m_am);
|
||||
scoped_anum upper(m_am);
|
||||
anum const & y_val = m_assignment.value(y);
|
||||
TRACE(nlsat_explain, tout << "adding literals for "; display_var(tout, y); tout << " -> ";
|
||||
anum const & y_val = m_solver.sample().value(y);
|
||||
TRACE(nlsat_explain, tout << "adding literals for "; m_solver.display_var(tout, y); tout << " -> ";
|
||||
m_am.display_decimal(tout, y_val); tout << "\n";);
|
||||
polynomial_ref p(m_pm);
|
||||
unsigned sz = ps.size();
|
||||
|
|
@ -322,12 +226,12 @@ namespace nlsat {
|
|||
if (max_var(p) != y)
|
||||
continue;
|
||||
roots.reset();
|
||||
// Variable y is assigned in m_assignment. We must temporarily unassign it.
|
||||
// Variable y is assigned in m_solver.sample(). We must temporarily unassign it.
|
||||
// Otherwise, the isolate_roots procedure will assume p is a constant polynomial.
|
||||
m_am.isolate_roots(p, undef_var_assignment(m_assignment, y), roots);
|
||||
m_am.isolate_roots(p, undef_var_assignment(m_solver.sample(), y), roots);
|
||||
unsigned num_roots = roots.size();
|
||||
TRACE(nlsat_explain,
|
||||
tout << "isolated roots for "; display_var(tout, y);
|
||||
tout << "isolated roots for "; m_solver.display_var(tout, y);
|
||||
tout << " with polynomial: " << p << "\n";
|
||||
for (unsigned ri = 0; ri < num_roots; ++ri) {
|
||||
m_am.display_decimal(tout << " root[" << (ri+1) << "] = ", roots[ri]);
|
||||
|
|
@ -386,6 +290,11 @@ namespace nlsat {
|
|||
}
|
||||
}
|
||||
|
||||
::sign sign(polynomial_ref const & p) {
|
||||
return ::nlsat::sign(p, m_solver.sample(), m_am);
|
||||
}
|
||||
|
||||
|
||||
void add_zero_assumption(polynomial_ref& p) {
|
||||
// Build a square-free representative of p so that we can speak about
|
||||
// a specific root that coincides with the current assignment.
|
||||
|
|
@ -400,7 +309,7 @@ namespace nlsat {
|
|||
SASSERT(maxx != null_var);
|
||||
if (maxx == null_var)
|
||||
return;
|
||||
SASSERT(m_assignment.is_assigned(maxx));
|
||||
SASSERT(m_solver.sample().is_assigned(maxx));
|
||||
|
||||
polynomial_ref_vector singleton(m_pm);
|
||||
singleton.push_back(q);
|
||||
|
|
@ -411,7 +320,7 @@ namespace nlsat {
|
|||
|
||||
TRACE(nlsat_explain,
|
||||
tout << "adding zero-assumption root literal for ";
|
||||
display_var(tout, maxx); tout << " using root[" << info.m_eq_idx << "] of " << q << "\n";);
|
||||
m_solver.display_var(tout, maxx); tout << " using root[" << info.m_eq_idx << "] of " << q << "\n";);
|
||||
add_root_literal(atom::ROOT_EQ, maxx, info.m_eq_idx, info.m_eq);
|
||||
}
|
||||
|
||||
|
|
@ -456,23 +365,23 @@ namespace nlsat {
|
|||
TRACE(nlsat_explain, tout << "lc: " << lc << " reduct: " << reduct << "\n";);
|
||||
insert_fresh_factors_in_todo(lc);
|
||||
if (!is_zero(lc) && sign(lc)) {
|
||||
insert_fresh_factors_in_todo(lc);
|
||||
TRACE(nlsat_explain, tout << "lc does no vaninsh\n";);
|
||||
return;
|
||||
}
|
||||
add_zero_assumption(lc);
|
||||
if (k == 0) {
|
||||
// all coefficients of p vanished in the current interpretation,
|
||||
// and were added as assumptions.
|
||||
p = m_pm.mk_zero();
|
||||
TRACE(nlsat_explain, tout << "all coefficients of p vanished\n";);
|
||||
if (m_add_all_coeffs) {
|
||||
add_zero_assumption(lc);
|
||||
return;
|
||||
}
|
||||
TRACE(nlsat_explain, tout << "falling back to add-all-coeffs projection\n";);
|
||||
m_add_all_coeffs = true;
|
||||
throw add_all_coeffs_restart();
|
||||
}
|
||||
add_zero_assumption(lc);
|
||||
k--;
|
||||
p = reduct;
|
||||
}
|
||||
|
|
@ -524,6 +433,7 @@ namespace nlsat {
|
|||
Remark: root atoms are not normalized
|
||||
*/
|
||||
literal normalize(literal l, var max) {
|
||||
TRACE(nlsat_explain, display(tout << "l:", m_solver, l) << '\n';);
|
||||
bool_var b = l.var();
|
||||
if (b == true_bool_var)
|
||||
return l;
|
||||
|
|
@ -546,6 +456,8 @@ namespace nlsat {
|
|||
SASSERT(max_var(p) != null_var);
|
||||
SASSERT(max_var(p) < max);
|
||||
// factor p is a lower stage polynomial, so we should add assumption to justify p being eliminated
|
||||
// Also collect it for projection to ensure proper cell construction
|
||||
m_lower_stage_polys.push_back(p);
|
||||
if (s == 0)
|
||||
add_assumption(atom::EQ, p); // add assumption p = 0
|
||||
else if (a->is_even(i))
|
||||
|
|
@ -613,6 +525,7 @@ namespace nlsat {
|
|||
stages) from (arithmetic) literals,
|
||||
*/
|
||||
void normalize(scoped_literal_vector & C, var max) {
|
||||
TRACE(nlsat_explain, display(tout << "C:\n", m_solver, C) << '\n';);
|
||||
unsigned sz = C.size();
|
||||
unsigned j = 0;
|
||||
for (unsigned i = 0; i < sz; ++i) {
|
||||
|
|
@ -699,6 +612,10 @@ namespace nlsat {
|
|||
\brief Add factors of p to todo
|
||||
*/
|
||||
void insert_fresh_factors_in_todo(polynomial_ref & p) {
|
||||
// Skip if already processed in this projection (prevents cycles)
|
||||
if (m_processed.contains(p))
|
||||
return;
|
||||
|
||||
if (is_const(p))
|
||||
return;
|
||||
elim_vanishing(p);
|
||||
|
|
@ -706,14 +623,14 @@ namespace nlsat {
|
|||
return;
|
||||
if (m_factor) {
|
||||
restore_factors _restore(m_factors, m_factors_save);
|
||||
factor(p, m_factors);
|
||||
TRACE(nlsat_explain, display(tout << "adding factors of\n", p); tout << "\n" << m_factors << "\n";);
|
||||
factor(p, m_cache, m_factors);
|
||||
TRACE(nlsat_explain, display(tout << "adding factors of\n", m_solver, p); tout << "\n" << m_factors << "\n";);
|
||||
polynomial_ref f(m_pm);
|
||||
for (unsigned i = 0; i < m_factors.size(); ++i) {
|
||||
f = m_factors.get(i);
|
||||
elim_vanishing(f);
|
||||
if (!is_const(f)) {
|
||||
TRACE(nlsat_explain, tout << "adding factor:\n"; display(tout, f); tout << "\n";);
|
||||
if (!is_const(f) && !m_processed.contains(f)) {
|
||||
TRACE(nlsat_explain, tout << "adding factor:\n"; display(tout, m_solver, f); tout << "\n";);
|
||||
m_todo.insert(f);
|
||||
}
|
||||
}
|
||||
|
|
@ -736,10 +653,10 @@ namespace nlsat {
|
|||
unsigned k_deg = m_pm.degree(p, x);
|
||||
if (k_deg == 0) continue;
|
||||
// p depends on x
|
||||
TRACE(nlsat_explain, tout << "processing poly of degree " << k_deg << " w.r.t x" << x << ": "; display(tout, p) << "\n";);
|
||||
TRACE(nlsat_explain, tout << "processing poly of degree " << k_deg << " w.r.t x" << x << ": "; m_solver.display(tout, p) << "\n";);
|
||||
for (int j_coeff_deg = k_deg; j_coeff_deg >= 0; j_coeff_deg--) {
|
||||
coeff = m_pm.coeff(p, x, j_coeff_deg);
|
||||
TRACE(nlsat_explain, tout << " coeff deg " << j_coeff_deg << ": "; display(tout, coeff) << "\n";);
|
||||
TRACE(nlsat_explain, tout << " coeff deg " << j_coeff_deg << ": "; display(tout, m_solver, coeff) << "\n";);
|
||||
insert_fresh_factors_in_todo(coeff);
|
||||
if (!m_add_all_coeffs)
|
||||
break;
|
||||
|
|
@ -766,7 +683,7 @@ namespace nlsat {
|
|||
// this function also explains the value 0, if met
|
||||
bool coeffs_are_zeroes(polynomial_ref &s) {
|
||||
restore_factors _restore(m_factors, m_factors_save);
|
||||
factor(s, m_factors);
|
||||
factor(s, m_cache, m_factors);
|
||||
unsigned num_factors = m_factors.size();
|
||||
m_zero_fs.reset();
|
||||
m_is_even.reset();
|
||||
|
|
@ -774,7 +691,7 @@ namespace nlsat {
|
|||
bool have_zero = false;
|
||||
for (unsigned i = 0; i < num_factors; ++i) {
|
||||
f = m_factors.get(i);
|
||||
if (coeffs_are_zeroes_in_factor(f)) {
|
||||
if (coeffs_are_zeroes_on_sample(f, m_pm, sample(), m_am)) {
|
||||
have_zero = true;
|
||||
break;
|
||||
}
|
||||
|
|
@ -799,7 +716,7 @@ namespace nlsat {
|
|||
auto c = polynomial_ref(this->m_pm);
|
||||
for (unsigned j = 0; j <= n; ++j) {
|
||||
c = m_pm.coeff(s, x, j);
|
||||
if (sign(c) != 0)
|
||||
if (nlsat::sign(c, sample(), m_am) != 0)
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
|
|
@ -814,7 +731,7 @@ namespace nlsat {
|
|||
|
||||
psc_chain(p, q, x, S);
|
||||
unsigned sz = S.size();
|
||||
TRACE(nlsat_explain, tout << "computing psc of\n"; display(tout, p); tout << "\n"; display(tout, q); tout << "\n";
|
||||
TRACE(nlsat_explain, tout << "computing psc of\n"; display(tout, m_solver, p); tout << "\n"; display(tout, m_solver, q); tout << "\n";
|
||||
for (unsigned i = 0; i < sz; ++i) {
|
||||
s = S.get(i);
|
||||
tout << "psc: " << s << "\n";
|
||||
|
|
@ -822,10 +739,16 @@ namespace nlsat {
|
|||
|
||||
for (unsigned i = 0; i < sz; ++i) {
|
||||
s = S.get(i);
|
||||
TRACE(nlsat_explain, display(tout << "processing psc(" << i << ")\n", s) << "\n";);
|
||||
TRACE(nlsat_explain, display(tout << "processing psc(" << i << ")\n", m_solver, s) << "\n";);
|
||||
if (is_zero(s)) {
|
||||
TRACE(nlsat_explain, tout << "skipping psc is the zero polynomial\n";);
|
||||
continue;
|
||||
// PSC is identically zero - polynomials share a common factor.
|
||||
// This can cause unsound lemmas. Fall back to add-all-coeffs projection.
|
||||
TRACE(nlsat_explain, tout << "psc is zero polynomial - polynomials share common factor\n";);
|
||||
if (m_add_all_coeffs)
|
||||
continue;
|
||||
TRACE(nlsat_explain, tout << "falling back to add-all-coeffs projection\n";);
|
||||
m_add_all_coeffs = true;
|
||||
throw add_all_coeffs_restart();
|
||||
}
|
||||
if (is_const(s)) {
|
||||
TRACE(nlsat_explain, tout << "done, psc is a constant\n";);
|
||||
|
|
@ -836,11 +759,11 @@ namespace nlsat {
|
|||
}
|
||||
TRACE(nlsat_explain,
|
||||
tout << "adding v-psc of\n";
|
||||
display(tout, p);
|
||||
display(tout, m_solver, p);
|
||||
tout << "\n";
|
||||
display(tout, q);
|
||||
display(tout, m_solver, q);
|
||||
tout << "\n---->\n";
|
||||
display(tout, s);
|
||||
display(tout, m_solver, s);
|
||||
tout << "\n";);
|
||||
// s did not vanish completely, but its leading coefficient may have vanished
|
||||
insert_fresh_factors_in_todo(s);
|
||||
|
|
@ -900,14 +823,14 @@ namespace nlsat {
|
|||
|
||||
void add_root_literal(atom::kind k, var y, unsigned i, poly * p) {
|
||||
polynomial_ref pr(p, m_pm);
|
||||
TRACE(nlsat_explain,
|
||||
display(tout << "x" << y << " " << k << "[" << i << "](", pr); tout << ")\n";);
|
||||
TRACE(nlsat_explain,
|
||||
display(tout << "x" << y << " " << k << "[" << i << "](", m_solver, pr); tout << ")\n";);
|
||||
|
||||
if (!mk_linear_root(k, y, i, p) &&
|
||||
!mk_quadratic_root(k, y, i, p)) {
|
||||
bool_var b = m_solver.mk_root_atom(k, y, i, p);
|
||||
literal l(b, true);
|
||||
TRACE(nlsat_explain, tout << "adding literal\n"; display(tout, l); tout << "\n";);
|
||||
TRACE(nlsat_explain, tout << "adding literal\n"; display(tout, m_solver, l); tout << "\n";);
|
||||
add_literal(l);
|
||||
}
|
||||
}
|
||||
|
|
@ -968,7 +891,7 @@ namespace nlsat {
|
|||
return false;
|
||||
}
|
||||
|
||||
SASSERT(m_assignment.is_assigned(y));
|
||||
SASSERT(sample().is_assigned(y));
|
||||
polynomial_ref A(m_pm), B(m_pm), C(m_pm), q(m_pm), p_diff(m_pm), yy(m_pm);
|
||||
A = m_pm.coeff(p, y, 2);
|
||||
B = m_pm.coeff(p, y, 1);
|
||||
|
|
@ -1000,6 +923,8 @@ namespace nlsat {
|
|||
if (!is_const(p)) {
|
||||
TRACE(nlsat_explain, tout << p << "\n";);
|
||||
add_assumption(s == 0 ? atom::EQ : (s < 0 ? atom::LT : atom::GT), p);
|
||||
// Also add p to the projection to ensure proper cell construction
|
||||
insert_fresh_factors_in_todo(p);
|
||||
}
|
||||
return s;
|
||||
}
|
||||
|
|
@ -1013,7 +938,7 @@ namespace nlsat {
|
|||
|
||||
*/
|
||||
void mk_linear_root(atom::kind k, var y, unsigned i, poly * p, bool mk_neg) {
|
||||
TRACE(nlsat_explain, display_var(tout, y); m_pm.display(tout << ": ", p, m_solver.display_proc()); tout << "\n");
|
||||
TRACE(nlsat_explain, m_solver.display_var(tout, y); m_pm.display(tout << ": ", p, m_solver.display_proc()); tout << "\n");
|
||||
polynomial_ref p_prime(m_pm);
|
||||
p_prime = p;
|
||||
bool lsign = false;
|
||||
|
|
@ -1104,33 +1029,37 @@ namespace nlsat {
|
|||
\brief Apply model-based projection operation defined in our paper.
|
||||
*/
|
||||
|
||||
void project_original(polynomial_ref_vector & ps, var max_x) {
|
||||
if (ps.empty())
|
||||
return;
|
||||
m_todo.reset();
|
||||
for (poly* p : ps) {
|
||||
m_todo.insert(p);
|
||||
}
|
||||
var x = m_todo.extract_max_polys(ps);
|
||||
// Remark: after vanishing coefficients are eliminated, ps may not contain max_x anymore
|
||||
if (x < max_x)
|
||||
add_cell_lits(ps, x);
|
||||
while (true) {
|
||||
if (all_univ(ps, x) && m_todo.empty()) {
|
||||
m_todo.reset();
|
||||
break;
|
||||
bool levelwise_single_cell(polynomial_ref_vector & ps, var max_x, polynomial::cache & cache) {
|
||||
// Store polynomials for debugging unsound lemmas
|
||||
m_last_lws_input_polys.reset();
|
||||
for (unsigned i = 0; i < ps.size(); i++)
|
||||
m_last_lws_input_polys.push_back(ps.get(i));
|
||||
|
||||
levelwise lws(m_solver, ps, max_x, sample(), m_pm, m_am, cache);
|
||||
auto cell = lws.single_cell();
|
||||
if (lws.failed())
|
||||
return false;
|
||||
|
||||
TRACE(lws, for (unsigned i = 0; i < cell.size(); i++)
|
||||
display(tout << "I[" << i << "]:", m_solver, cell[i]) << "\n";);
|
||||
// Enumerate all intervals in the computed cell and add literals for each non-trivial interval.
|
||||
// Non-trivial = section, or sector with at least one finite bound (ignore (-oo,+oo)).
|
||||
for (auto const & I : cell) {
|
||||
if (I.is_section()) {
|
||||
SASSERT(I.l && I.l_index);
|
||||
add_root_literal(atom::ROOT_EQ, max_var(I.l.get()), I.l_index, I.l.get());
|
||||
continue;
|
||||
}
|
||||
TRACE(nlsat_explain, tout << "project loop, processing var "; display_var(tout, x);
|
||||
tout << "\npolynomials\n";
|
||||
display(tout, ps); tout << "\n";);
|
||||
add_lcs(ps, x);
|
||||
psc_discriminant(ps, x);
|
||||
psc_resultant(ps, x);
|
||||
if (m_todo.empty())
|
||||
break;
|
||||
x = m_todo.extract_max_polys(ps);
|
||||
add_cell_lits(ps, x);
|
||||
if (I.l_inf() && I.u_inf())
|
||||
continue; // skip whole-line sector
|
||||
if (!I.l_inf())
|
||||
add_root_literal(m_full_dimensional ? atom::ROOT_GE :
|
||||
atom::ROOT_GT, max_var(I.l.get()), I.l_index, I.l.get());
|
||||
if (!I.u_inf())
|
||||
add_root_literal(m_full_dimensional ? atom::ROOT_LE :
|
||||
atom::ROOT_LT, max_var(I.u.get()), I.u_index, I.u.get());
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -1140,12 +1069,17 @@ namespace nlsat {
|
|||
* "Solving Satisfiability of Polynomial Formulas By Sample - Cell Projection"
|
||||
* https://arxiv.org/abs/2003.00409
|
||||
*/
|
||||
void collect_to_processed(polynomial_ref_vector & ps) {
|
||||
for (unsigned i = 0; i < ps.size(); ++i)
|
||||
m_processed.insert(ps.get(i));
|
||||
}
|
||||
|
||||
void project_cdcac(polynomial_ref_vector & ps, var max_x) {
|
||||
bool first = true;
|
||||
if (ps.empty())
|
||||
return;
|
||||
|
||||
m_todo.reset();
|
||||
m_processed.reset();
|
||||
for (unsigned i = 0; i < ps.size(); ++i) {
|
||||
polynomial_ref p(m_pm);
|
||||
p = ps.get(i);
|
||||
|
|
@ -1155,10 +1089,22 @@ namespace nlsat {
|
|||
ps.reset();
|
||||
for (auto p: m_todo.m_set)
|
||||
ps.push_back(p);
|
||||
|
||||
bool use_all_coeffs = false;
|
||||
|
||||
if (m_solver.apply_levelwise()) {
|
||||
bool levelwise_ok = levelwise_single_cell(ps, max_x, m_cache);
|
||||
m_solver.record_levelwise_result(levelwise_ok);
|
||||
if (levelwise_ok)
|
||||
return;
|
||||
// Levelwise failed, use add_all_coeffs mode for fallback projection
|
||||
use_all_coeffs = true;
|
||||
}
|
||||
// Set m_add_all_coeffs for the rest of the projection, restore on function exit
|
||||
flet<bool> _set_all_coeffs(m_add_all_coeffs, use_all_coeffs || m_add_all_coeffs);
|
||||
|
||||
var x = m_todo.extract_max_polys(ps);
|
||||
// Remark: after vanishing coefficients are eliminated, ps may not contain max_x anymore
|
||||
|
||||
collect_to_processed(ps);
|
||||
polynomial_ref_vector samples(m_pm);
|
||||
if (x < max_x)
|
||||
cac_add_cell_lits(ps, x, samples);
|
||||
|
|
@ -1168,8 +1114,8 @@ namespace nlsat {
|
|||
m_todo.reset();
|
||||
break;
|
||||
}
|
||||
TRACE(nlsat_explain, tout << "project loop, processing var "; display_var(tout, x); tout << "\npolynomials\n";
|
||||
display(tout, ps); tout << "\n";);
|
||||
TRACE(nlsat_explain, tout << "project loop, processing var "; m_solver.display_var(tout, x); tout << "\npolynomials\n";
|
||||
display(tout, m_solver, ps); tout << "\n";);
|
||||
if (first) { // The first run is special because x is not constrained by the sample, we cannot surround it by the root functions.
|
||||
// we make the polynomials in ps delinable
|
||||
add_lcs(ps, x);
|
||||
|
|
@ -1186,17 +1132,14 @@ namespace nlsat {
|
|||
if (m_todo.empty())
|
||||
break;
|
||||
x = m_todo.extract_max_polys(ps);
|
||||
collect_to_processed(ps);
|
||||
cac_add_cell_lits(ps, x, samples);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void project(polynomial_ref_vector & ps, var max_x) {
|
||||
if (m_cell_sample) {
|
||||
project_cdcac(ps, max_x);
|
||||
}
|
||||
else {
|
||||
project_original(ps, max_x);
|
||||
}
|
||||
project_cdcac(ps, max_x);
|
||||
}
|
||||
|
||||
bool check_already_added() const {
|
||||
|
|
@ -1291,7 +1234,7 @@ namespace nlsat {
|
|||
new_lit = l;
|
||||
return;
|
||||
}
|
||||
TRACE(nlsat_simplify_core, display(tout << "trying to simplify literal\n", l) << "\nusing equation\n";
|
||||
TRACE(nlsat_simplify_core, display(tout << "trying to simplify literal\n", m_solver, l) << "\nusing equation\n";
|
||||
m_pm.display(tout, info.m_eq, m_solver.display_proc()); tout << "\n";);
|
||||
int atom_sign = 1;
|
||||
bool modified_lit = false;
|
||||
|
|
@ -1374,14 +1317,14 @@ namespace nlsat {
|
|||
new_lit = m_solver.mk_ineq_literal(new_k, new_factors.size(), new_factors.data(), new_factors_even.data());
|
||||
if (l.sign())
|
||||
new_lit.neg();
|
||||
TRACE(nlsat_simplify_core, tout << "simplified literal:\n"; display(tout, new_lit) << " " << m_solver.value(new_lit) << "\n";);
|
||||
TRACE(nlsat_simplify_core, tout << "simplified literal:\n"; display(tout, m_solver, new_lit) << " " << m_solver.value(new_lit) << "\n";);
|
||||
|
||||
if (max_var(new_lit) < max) {
|
||||
if (m_solver.value(new_lit) == l_true) {
|
||||
TRACE(nlsat_simplify_bug,
|
||||
tout << "literal normalized away because it is already true after rewriting:\n";
|
||||
display(tout << " original: ", l) << "\n";
|
||||
display(tout << " rewritten: ", new_lit) << "\n";
|
||||
m_solver.display(tout << " original: ", l) << "\n";
|
||||
m_solver.display(tout << " rewritten: ", new_lit) << "\n";
|
||||
if (info.m_eq) {
|
||||
polynomial_ref eq_ref(const_cast<poly*>(info.m_eq), m_pm);
|
||||
m_pm.display(tout << " equation used: ", eq_ref, m_solver.display_proc());
|
||||
|
|
@ -1393,8 +1336,8 @@ namespace nlsat {
|
|||
literal assumption = new_lit;
|
||||
TRACE(nlsat_simplify_bug,
|
||||
tout << "literal replaced by lower-stage assumption due to rewriting:\n";
|
||||
display(tout << " original: ", l) << "\n";
|
||||
display(tout << " assumption: ", assumption) << "\n";
|
||||
m_solver.display(tout << " original: ", l) << "\n";
|
||||
m_solver.display(tout << " assumption: ", assumption) << "\n";
|
||||
if (info.m_eq) {
|
||||
polynomial_ref eq_ref(const_cast<poly*>(info.m_eq), m_pm);
|
||||
m_pm.display(tout << " equation used: ", eq_ref, m_solver.display_proc());
|
||||
|
|
@ -1408,12 +1351,12 @@ namespace nlsat {
|
|||
literal before = new_lit;
|
||||
(void)before;
|
||||
new_lit = normalize(new_lit, max);
|
||||
TRACE(nlsat_simplify_core, tout << "simplified literal after normalization:\n"; display(tout, new_lit); tout << " " << m_solver.value(new_lit) << "\n";);
|
||||
TRACE(nlsat_simplify_core, tout << "simplified literal after normalization:\n"; m_solver.display(tout, new_lit); tout << " " << m_solver.value(new_lit) << "\n";);
|
||||
if (new_lit == true_literal || new_lit == false_literal) {
|
||||
TRACE(nlsat_simplify_bug,
|
||||
tout << "normalize() turned rewritten literal into constant value:\n";
|
||||
display(tout << " original: ", l) << "\n";
|
||||
display(tout << " rewritten: ", before) << "\n";
|
||||
m_solver.display(tout << " original: ", l) << "\n";
|
||||
m_solver.display(tout << " rewritten: ", before) << "\n";
|
||||
tout << " result: " << (new_lit == true_literal ? "true" : "false") << "\n";
|
||||
if (info.m_eq) {
|
||||
polynomial_ref eq_ref(const_cast<poly*>(info.m_eq), m_pm);
|
||||
|
|
@ -1577,7 +1520,7 @@ namespace nlsat {
|
|||
poly * eq_p = eq->p(0);
|
||||
VERIFY(simplify(C, eq_p, max));
|
||||
// add equation as an assumption
|
||||
TRACE(nlsat_simpilfy_core, display(tout << "adding equality as assumption ", literal(eq->bvar(), true)); tout << "\n";);
|
||||
TRACE(nlsat_simpilfy_core, display(tout << "adding equality as assumption ", m_solver, literal(eq->bvar(), true)); tout << "\n";);
|
||||
add_literal(literal(eq->bvar(), true));
|
||||
}
|
||||
}
|
||||
|
|
@ -1586,33 +1529,52 @@ namespace nlsat {
|
|||
\brief Main procedure. The explain the given unsat core, and store the result in m_result
|
||||
*/
|
||||
void main(unsigned num, literal const * ls) {
|
||||
if (num == 0)
|
||||
if (num == 0) {
|
||||
TRACE(nlsat_explain, tout << "num:" << num << "\n";);
|
||||
return;
|
||||
}
|
||||
collect_polys(num, ls, m_ps);
|
||||
|
||||
// Add lower-stage polynomials collected during normalization
|
||||
// These polynomials had assumptions added but need to be projected as well
|
||||
for (unsigned i = 0; i < m_lower_stage_polys.size(); i++) {
|
||||
m_ps.push_back(m_lower_stage_polys.get(i));
|
||||
}
|
||||
|
||||
var max_x = max_var(m_ps);
|
||||
TRACE(nlsat_explain, tout << "polynomials in the conflict:\n"; display(tout, m_ps); tout << "\n";);
|
||||
TRACE(nlsat_explain, tout << "polynomials in the conflict:\n"; display(tout, m_solver, m_ps); tout << "\n";);
|
||||
|
||||
// Note: levelwise is now called in process2() before normalize()
|
||||
// to ensure it receives the original polynomials
|
||||
|
||||
elim_vanishing(m_ps);
|
||||
TRACE(nlsat_explain, tout << "after elim_vanishing m_ps:\n"; display(tout, m_ps); tout << "\n";);
|
||||
TRACE(nlsat_explain, tout << "after elim_vanishing m_ps:\n"; display(tout, m_solver, m_ps); tout << "\n";);
|
||||
project(m_ps, max_x);
|
||||
TRACE(nlsat_explain, tout << "after projection\n"; display(tout, m_ps); tout << "\n";);
|
||||
TRACE(nlsat_explain, tout << "after projection\n"; display(tout, m_solver, m_ps); tout << "\n";);
|
||||
}
|
||||
|
||||
void process2(unsigned num, literal const * ls) {
|
||||
// Reset lower-stage polynomials collection
|
||||
m_lower_stage_polys.reset();
|
||||
|
||||
// Try levelwise with ORIGINAL polynomials BEFORE any normalization
|
||||
|
||||
if (m_simplify_cores) {
|
||||
TRACE(nlsat_explain, tout << "m_simplify_cores is true\n";);
|
||||
m_core2.reset();
|
||||
m_core2.append(num, ls);
|
||||
var max = max_var(num, ls);
|
||||
SASSERT(max != null_var);
|
||||
TRACE(nlsat_explain, display(tout << "core before normalization\n", m_core2) << "\n";);
|
||||
TRACE(nlsat_explain, display(tout << "core before normalization\n", m_solver, m_core2) << "\n";);
|
||||
normalize(m_core2, max);
|
||||
TRACE(nlsat_explain, display(tout << "core after normalization\n", m_core2) << "\n";);
|
||||
TRACE(nlsat_explain, display(tout << "core after normalization\n", m_solver, m_core2) << "\n";);
|
||||
simplify(m_core2, max);
|
||||
TRACE(nlsat_explain, display(tout << "core after simplify\n", m_core2) << "\n";);
|
||||
TRACE(nlsat_explain, display(tout << "core after simplify\n", m_solver, m_core2) << "\n";);
|
||||
main(m_core2.size(), m_core2.data());
|
||||
m_core2.reset();
|
||||
}
|
||||
else {
|
||||
TRACE(nlsat_explain, display(tout << "core befor normalization\n", m_core2) << "\n";);
|
||||
TRACE(nlsat_explain, display(tout << "core befor normalization\n", m_solver, m_core2) << "\n";);
|
||||
main(num, ls);
|
||||
}
|
||||
}
|
||||
|
|
@ -1674,39 +1636,42 @@ namespace nlsat {
|
|||
todo.reset(); core.reset();
|
||||
todo.append(num, ls);
|
||||
while (true) {
|
||||
TRACE(nlsat_minimize, tout << "core minimization:\n"; display(tout, todo); tout << "\nCORE:\n"; display(tout, core) << "\n";);
|
||||
TRACE(nlsat_minimize, tout << "core minimization:\n"; display(tout, m_solver, todo); tout << "\nCORE:\n"; display(tout, m_solver, core) << "\n";);
|
||||
if (!minimize_core(todo, core))
|
||||
break;
|
||||
std::reverse(todo.begin(), todo.end());
|
||||
TRACE(nlsat_minimize, tout << "core minimization:\n"; display(tout, todo); tout << "\nCORE:\n"; display(tout, core) << "\n";);
|
||||
TRACE(nlsat_minimize, tout << "core minimization:\n"; display(tout, m_solver, todo); tout << "\nCORE:\n"; display(tout, m_solver, core) << "\n";);
|
||||
if (!minimize_core(todo, core))
|
||||
break;
|
||||
}
|
||||
TRACE(nlsat_minimize, tout << "core:\n"; display(tout, core););
|
||||
TRACE(nlsat_minimize, tout << "core:\n"; display(tout, m_solver, core););
|
||||
r.append(core.size(), core.data());
|
||||
}
|
||||
|
||||
void process(unsigned num, literal const * ls) {
|
||||
if (m_minimize_cores && num > 1) {
|
||||
TRACE(nlsat_explain, tout << "m_minimize_cores:" << m_minimize_cores << ", num:" << num;);
|
||||
m_core1.reset();
|
||||
minimize(num, ls, m_core1);
|
||||
process2(m_core1.size(), m_core1.data());
|
||||
m_core1.reset();
|
||||
}
|
||||
else {
|
||||
TRACE(nlsat_explain, tout << "directly to process2\n";);
|
||||
process2(num, ls);
|
||||
}
|
||||
}
|
||||
|
||||
void operator()(unsigned num, literal const * ls, scoped_literal_vector & result) {
|
||||
void compute_conflict_explanation(unsigned num, literal const * ls, scoped_literal_vector & result) {
|
||||
SASSERT(check_already_added());
|
||||
SASSERT(num > 0);
|
||||
TRACE(nlsat_explain,
|
||||
tout << "[explain] set of literals is infeasible in the current interpretation\n";
|
||||
display(tout, num, ls) << "\n";
|
||||
m_solver.display_assignment(tout);
|
||||
tout << "the infeasible clause:\n";
|
||||
display(tout, m_solver, num, ls) << "\n";
|
||||
|
||||
m_solver.display_assignment(tout << "assignment:\n");
|
||||
);
|
||||
if (max_var(num, ls) == 0 && !m_assignment.is_assigned(0)) {
|
||||
if (max_var(num, ls) == 0 && !m_solver.sample().is_assigned(0)) {
|
||||
TRACE(nlsat_explain, tout << "all literals use unassigned max var; returning justification\n";);
|
||||
result.reset();
|
||||
return;
|
||||
|
|
@ -1718,7 +1683,7 @@ namespace nlsat {
|
|||
process(num, ls);
|
||||
reset_already_added();
|
||||
m_result = nullptr;
|
||||
TRACE(nlsat_explain, display(tout << "[explain] result\n", result) << "\n";);
|
||||
TRACE(nlsat_explain, display(tout << "[explain] result\n", m_solver, result) << "\n";);
|
||||
CASSERT("nlsat", check_already_added());
|
||||
break;
|
||||
}
|
||||
|
|
@ -1848,12 +1813,12 @@ namespace nlsat {
|
|||
collect_polys(lits.size(), lits.data(), m_ps);
|
||||
unbounded = true;
|
||||
scoped_anum x_val(m_am);
|
||||
x_val = m_assignment.value(x);
|
||||
x_val = sample().value(x);
|
||||
for (unsigned i = 0; i < m_ps.size(); ++i) {
|
||||
p = m_ps.get(i);
|
||||
scoped_anum_vector & roots = m_roots_tmp;
|
||||
roots.reset();
|
||||
m_am.isolate_roots(p, undef_var_assignment(m_assignment, x), roots);
|
||||
m_am.isolate_roots(p, undef_var_assignment(sample(), x), roots);
|
||||
for (unsigned j = 0; j < roots.size(); ++j) {
|
||||
int s = m_am.compare(x_val, roots[j]);
|
||||
if (s <= 0 && (unbounded || m_am.compare(roots[j], val) <= 0)) {
|
||||
|
|
@ -1867,8 +1832,8 @@ namespace nlsat {
|
|||
};
|
||||
|
||||
explain::explain(solver & s, assignment const & x2v, polynomial::cache & u,
|
||||
atom_vector const& atoms, atom_vector const& x2eq, evaluator & ev, bool use_cell_sample) {
|
||||
m_imp = alloc(imp, s, x2v, u, atoms, x2eq, ev, use_cell_sample);
|
||||
atom_vector const& atoms, atom_vector const& x2eq, evaluator & ev, bool canonicalize) {
|
||||
m_imp = alloc(imp, s, x2v, u, atoms, x2eq, ev, canonicalize);
|
||||
}
|
||||
|
||||
explain::~explain() {
|
||||
|
|
@ -1904,8 +1869,8 @@ namespace nlsat {
|
|||
m_imp->m_add_zero_disc = f;
|
||||
}
|
||||
|
||||
void explain::main_operator(unsigned n, literal const * ls, scoped_literal_vector & result) {
|
||||
(*m_imp)(n, ls, result);
|
||||
void explain::compute_conflict_explanation(unsigned n, literal const * ls, scoped_literal_vector & result) {
|
||||
m_imp->compute_conflict_explanation(n, ls, result);
|
||||
}
|
||||
|
||||
void explain::project(var x, unsigned n, literal const * ls, scoped_literal_vector & result) {
|
||||
|
|
@ -1916,6 +1881,16 @@ namespace nlsat {
|
|||
m_imp->maximize(x, n, ls, val, unbounded);
|
||||
}
|
||||
|
||||
void explain::display_last_lws_input(std::ostream& out) {
|
||||
out << "=== POLYNOMIALS PASSED TO LEVELWISE ===\n";
|
||||
for (unsigned i = 0; i < m_imp->m_last_lws_input_polys.size(); i++) {
|
||||
out << " p[" << i << "]: ";
|
||||
m_imp->m_pm.display(out, m_imp->m_last_lws_input_polys.get(i));
|
||||
out << "\n";
|
||||
}
|
||||
out << "=== END LEVELWISE INPUT (" << m_imp->m_last_lws_input_polys.size() << " polynomials) ===\n";
|
||||
}
|
||||
|
||||
void explain::test_root_literal(atom::kind k, var y, unsigned i, poly* p, scoped_literal_vector & result) {
|
||||
m_imp->test_root_literal(k, y, i, p, result);
|
||||
}
|
||||
|
|
@ -1924,29 +1899,29 @@ namespace nlsat {
|
|||
#ifdef Z3DEBUG
|
||||
#include <iostream>
|
||||
void pp(nlsat::explain::imp & ex, unsigned num, nlsat::literal const * ls) {
|
||||
ex.display(std::cout, num, ls);
|
||||
display(std::cout, ex.m_solver, num, ls);
|
||||
}
|
||||
void pp(nlsat::explain::imp & ex, nlsat::scoped_literal_vector & ls) {
|
||||
ex.display(std::cout, ls);
|
||||
display(std::cout, ex.m_solver, ls);
|
||||
}
|
||||
void pp(nlsat::explain::imp & ex, polynomial_ref const & p) {
|
||||
ex.display(std::cout, p);
|
||||
display(std::cout, ex.m_solver, p);
|
||||
std::cout << std::endl;
|
||||
}
|
||||
void pp(nlsat::explain::imp & ex, polynomial::polynomial * p) {
|
||||
polynomial_ref _p(p, ex.m_pm);
|
||||
ex.display(std::cout, _p);
|
||||
display(std::cout, ex.m_solver, _p);
|
||||
std::cout << std::endl;
|
||||
}
|
||||
void pp(nlsat::explain::imp & ex, polynomial_ref_vector const & ps) {
|
||||
ex.display(std::cout, ps);
|
||||
display(std::cout, ex.m_solver, ps);
|
||||
}
|
||||
void pp_var(nlsat::explain::imp & ex, nlsat::var x) {
|
||||
ex.display(std::cout, x);
|
||||
display_var(std::cout, ex.m_solver, x);
|
||||
std::cout << std::endl;
|
||||
}
|
||||
void pp_lit(nlsat::explain::imp & ex, nlsat::literal l) {
|
||||
ex.display(std::cout, l);
|
||||
display(std::cout, ex.m_solver, l);
|
||||
std::cout << std::endl;
|
||||
}
|
||||
#endif
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue