mirror of
https://github.com/Z3Prover/z3
synced 2026-02-22 16:27:37 +00:00
159 lines
5.7 KiB
C++
159 lines
5.7 KiB
C++
/*++
|
|
Copyright (c) 2025
|
|
|
|
Module Name:
|
|
|
|
nlsat_common.h
|
|
|
|
Abstract:
|
|
|
|
Pretty-print helpers for NLSAT components as free functions.
|
|
These forward to existing solver/pmanager display facilities.
|
|
|
|
--*/
|
|
#pragma once
|
|
|
|
#include "nlsat/nlsat_assignment.h"
|
|
#include "nlsat/nlsat_solver.h"
|
|
#include "nlsat/nlsat_scoped_literal_vector.h"
|
|
#include "math/polynomial/polynomial_cache.h"
|
|
|
|
namespace nlsat {
|
|
|
|
// Lightweight set of polynomials that keeps elements unique (by cache id) and
|
|
// supports extracting all polynomials whose maximal variable is maximal.
|
|
// Optional canonicalization (primitive + sign) can be enabled per instance.
|
|
struct todo_set {
|
|
polynomial::cache& m_cache;
|
|
polynomial_ref_vector m_set;
|
|
svector<char> m_in_set;
|
|
bool m_canonicalize;
|
|
|
|
todo_set(polynomial::cache& u, bool canonicalize);
|
|
|
|
void reset();
|
|
// Insert polynomial (canonicalizing if requested) and return the cached representative.
|
|
poly* insert(poly* p);
|
|
bool contains(poly* p) const;
|
|
bool contains(polynomial_ref const& p) const { return contains(p.get()); }
|
|
bool empty() const;
|
|
// Return max variable in todo_set
|
|
var max_var() const;
|
|
/**
|
|
\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);
|
|
// Extract polynomials whose max_var equals \c x, appending them to \c out.
|
|
// Returns the number of polynomials extracted.
|
|
unsigned extract_polys_at_level(var x, polynomial_ref_vector& out);
|
|
};
|
|
|
|
inline std::ostream& display(std::ostream& out, pmanager& pm, polynomial_ref const& p, display_var_proc const& proc) {
|
|
pm.display(out, p, proc);
|
|
return out;
|
|
}
|
|
|
|
inline std::ostream& display(std::ostream& out, pmanager& pm, polynomial_ref_vector const& ps, display_var_proc const& proc, char const* delim = "\n") {
|
|
for (unsigned i = 0; i < ps.size(); ++i) {
|
|
if (i > 0) out << delim;
|
|
pm.display(out, ps.get(i), proc);
|
|
}
|
|
return out;
|
|
}
|
|
|
|
inline std::ostream& display(std::ostream& out, solver& s, polynomial_ref const& p) {
|
|
return display(out, s.pm(), p, s.display_proc());
|
|
}
|
|
|
|
inline std::ostream& display(std::ostream& out, solver& s, poly* p) {
|
|
return display(out, s.pm(), polynomial_ref(p, s.pm()), s.display_proc());
|
|
}
|
|
|
|
inline std::ostream& display(std::ostream& out, solver& s, polynomial_ref_vector const& ps, char const* delim = "\n") {
|
|
return display(out, s.pm(), ps, s.display_proc(), delim);
|
|
}
|
|
|
|
inline std::ostream& display(std::ostream& out, solver& s, literal l) {
|
|
return s.display(out, l);
|
|
}
|
|
|
|
inline std::ostream& display(std::ostream& out, solver& s, unsigned n, literal const* ls) {
|
|
return s.display(out, n, ls);
|
|
}
|
|
|
|
inline std::ostream& display(std::ostream& out, solver& s, literal_vector const& ls) {
|
|
return s.display(out, ls);
|
|
}
|
|
|
|
inline std::ostream& display(std::ostream& out, solver& s, scoped_literal_vector const& ls) {
|
|
return s.display(out, ls.size(), ls.data());
|
|
}
|
|
|
|
inline std::ostream& display_var(std::ostream& out, solver& s, var x) {
|
|
return s.display(out, x);
|
|
}
|
|
/**
|
|
\brief evaluate the given polynomial in the current interpretation.
|
|
max_var(p) must be assigned in the current interpretation.
|
|
*/
|
|
inline ::sign sign(polynomial_ref const & p, assignment & x2v, anum_manager& am) {
|
|
SASSERT(max_var(p) == null_var || x2v.is_assigned(max_var(p)));
|
|
auto s = am.eval_sign_at(p, x2v);
|
|
return s;
|
|
}
|
|
|
|
/**
|
|
* Check whether all coefficients of the polynomial `s` (viewed as a polynomial
|
|
* in its main variable) evaluate to zero under the given assignment `x2v`.
|
|
* This is exactly the logic used in several places in the nlsat codebase
|
|
* (e.g. coeffs_are_zeroes_in_factor in nlsat_explain.cpp).
|
|
*/
|
|
inline bool coeffs_are_zeroes_on_sample(polynomial_ref const & s, pmanager & pm, assignment & x2v, anum_manager & am) {
|
|
polynomial_ref c(pm);
|
|
var x = pm.max_var(s);
|
|
unsigned n = pm.degree(s, x);
|
|
for (unsigned j = 0; j <= n; ++j) {
|
|
c = pm.coeff(s, x, j);
|
|
if (sign(c, x2v, am) != 0)
|
|
return false;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
/**
|
|
* \brief Display a vector of algebraic numbers in several commonly useful formats.
|
|
*
|
|
* This mirrors the ad-hoc helper that existed in `src/test/algebraic.cpp` so that
|
|
* solver / explanation code can conveniently dump root sets while debugging.
|
|
*
|
|
* For each algebraic number it prints (in order):
|
|
* - a decimal approximation (10 digits)
|
|
* - the root object representation (defining polynomial & isolating interval)
|
|
* - the isolating interval alone
|
|
*
|
|
*/
|
|
inline void display(std::ostream & out, scoped_anum_vector const & rs) {
|
|
algebraic_numbers::manager & m = rs.m();
|
|
out << "numbers in decimal:\n";
|
|
for (const auto & r : rs) {
|
|
m.display_decimal(out, r, 10);
|
|
out << '\n';
|
|
}
|
|
out << "numbers as root objects\n";
|
|
for (const auto & r : rs) {
|
|
m.display_root(out, r);
|
|
out << '\n';
|
|
}
|
|
out << "numbers as intervals\n";
|
|
for (const auto & r : rs) {
|
|
m.display_interval(out, r);
|
|
out << '\n';
|
|
}
|
|
}
|
|
/**
|
|
\brief Wrapper for factorization
|
|
*/
|
|
void factor(polynomial_ref & p, polynomial::cache& cache, polynomial_ref_vector & fs);
|
|
|
|
} // namespace nlsat
|