Skip to content

Commit cccf7b0

Browse files
committed
create known debug values on the fly
Signed-off-by: Lev Nachmanson <levnach@hotmail.com>
1 parent 0f52d1e commit cccf7b0

File tree

2 files changed

+121
-118
lines changed

2 files changed

+121
-118
lines changed

src/nlsat/nlsat_explain.cpp

Lines changed: 55 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -618,27 +618,57 @@ namespace nlsat {
618618
}
619619
}
620620

621-
// for each p in ps add first non-const coefficients to the projection
622-
void add_lcs(polynomial_ref_vector &ps, var x, bool include_all = true){
623-
polynomial_ref p(m_pm);
624-
polynomial_ref lc(m_pm);
625-
unsigned sz = ps.size();
626-
bool first = true;
627-
for (unsigned i = 0; i < sz; i++){
628-
p = ps.get(i);
629-
unsigned k = degree(p, x);
630-
SASSERT(k > 0);
631-
TRACE("nlsat_explain", tout << "process p of degree " << k << ":" ; display(tout, p); tout << "\n";);
632-
for(; k > 0; k--){
633-
lc = m_pm.coeff(p, x, k);
634-
TRACE("nlsat_explain", tout << "add coeff: "; display(tout, lc) << "\n";);
635-
add_factors(lc);
636-
if (!include_all)
637-
break;
638-
first = false;
639-
if (m_pm.nonzero_const_coeff(p, x, k)){
640-
TRACE("nlsat_explain", tout << "skipping the rest of coeffs\n";);
641-
break;
621+
// for each p in ps add first or all coefficients to the projection
622+
void add_lcs(polynomial_ref_vector &ps, var x) {
623+
polynomial_ref p_poly(m_pm);
624+
polynomial_ref lc_poly(m_pm);
625+
polynomial_ref disc_poly(m_pm);
626+
polynomial_ref current_coeff_poly(m_pm);
627+
628+
bool is_globally_well_oriented = true;
629+
630+
// First pass: Determine global well-orientedness
631+
for (unsigned i = 0; i < ps.size(); i++) {
632+
p_poly = ps.get(i);
633+
unsigned k_deg = m_pm.degree(p_poly, x);
634+
635+
if (k_deg > 0) { // p_poly depends on x
636+
lc_poly = m_pm.coeff(p_poly, x, k_deg);
637+
if (this->sign(lc_poly) == 0) { // LC is zero
638+
is_globally_well_oriented = false;
639+
TRACE("nlsat_explain", tout << "Global !WO: LC of poly is zero. Poly: "; display(tout, p_poly); tout << " LC: "; display(tout, lc_poly) << "\\n";);
640+
break;
641+
}
642+
643+
if (k_deg > 1) { // Degree > 1, check discriminant
644+
disc_poly = discriminant(p_poly, x); // Use global helper
645+
if (this->sign(disc_poly) == 0) { // Discriminant is zero
646+
is_globally_well_oriented = false;
647+
TRACE("nlsat_explain", tout << "Global !WO: Discriminant of poly is zero. Poly: "; display(tout, p_poly); tout << " Disc: "; display(tout, disc_poly) << "\\n";);
648+
break;
649+
}
650+
}
651+
}
652+
}
653+
654+
// Second pass: Add factors based on global well-orientedness
655+
for (unsigned i = 0; i < ps.size(); i++) {
656+
p_poly = ps.get(i);
657+
unsigned k_deg = m_pm.degree(p_poly, x);
658+
659+
if (k_deg > 0) { // p_poly depends on x
660+
TRACE("nlsat_explain", tout << "add_lcs: processing poly of degree " << k_deg << " w.r.t x" << x << ": "; display(tout, p_poly); tout << (is_globally_well_oriented ? " (WO)" : " (!WO)") << "\\n";);
661+
if (is_globally_well_oriented) {
662+
lc_poly = m_pm.coeff(p_poly, x, k_deg);
663+
TRACE("nlsat_explain", tout << " WO: adding LC: "; display(tout, lc_poly) << "\\n";);
664+
add_factors(lc_poly);
665+
} else {
666+
TRACE("nlsat_explain", tout << " !WO: adding all coeffs (deg " << k_deg << " down to 1) for poly: "; display(tout, p_poly) << "\\n";);
667+
for (unsigned j_coeff_deg = k_deg; j_coeff_deg >= 1; j_coeff_deg--) {
668+
current_coeff_poly = m_pm.coeff(p_poly, x, j_coeff_deg);
669+
TRACE("nlsat_explain", tout << " coeff deg " << j_coeff_deg << ": "; display(tout, current_coeff_poly) << "\\n";);
670+
add_factors(current_coeff_poly);
671+
}
642672
}
643673
}
644674
}
@@ -1389,12 +1419,10 @@ namespace nlsat {
13891419
// If the leading coefficient is not a constant, we must store this information as an extra assumption.
13901420
if (d % 2 == 0 || // d is even
13911421
is_even || // rewriting a factor of even degree, sign flip doesn't matter
1392-
_a->get_kind() == atom::EQ) { // rewriting an equation, sign flip doesn't matter
1422+
_a->get_kind() == atom::EQ) // rewriting an equation, sign flip doesn't matter
13931423
info.add_lc_diseq();
1394-
}
1395-
else {
1424+
else
13961425
info.add_lc_ineq();
1397-
}
13981426
}
13991427
if (s < 0 && !is_even) {
14001428
atom_sign = -atom_sign;
@@ -1407,12 +1435,10 @@ namespace nlsat {
14071435
if (!info.m_lc_const) {
14081436
if (d % 2 == 0 || // d is even
14091437
is_even || // rewriting a factor of even degree, sign flip doesn't matter
1410-
_a->get_kind() == atom::EQ) { // rewriting an equation, sign flip doesn't matter
1438+
_a->get_kind() == atom::EQ) // rewriting an equation, sign flip doesn't matter
14111439
info.add_lc_diseq();
1412-
}
1413-
else {
1440+
else
14141441
info.add_lc_ineq();
1415-
}
14161442
}
14171443
}
14181444
}
@@ -2120,7 +2146,6 @@ namespace nlsat {
21202146
}
21212147

21222148
};
2123-
21242149
#ifdef Z3DEBUG
21252150
#include <iostream>
21262151
void pp(nlsat::explain::imp & ex, unsigned num, nlsat::literal const * ls) {

src/nlsat/nlsat_solver.cpp

Lines changed: 66 additions & 88 deletions
Original file line numberDiff line numberDiff line change
@@ -106,9 +106,7 @@ namespace nlsat {
106106
anum_manager& m_am;
107107
mutable assumption_manager m_asm;
108108
assignment m_assignment, m_lo, m_hi; // partial interpretation
109-
assignment m_debug_assignment;
110109
mutable evaluator m_evaluator;
111-
mutable evaluator m_debug_evaluator;
112110
interval_set_manager & m_ism;
113111
ineq_atom_table m_ineq_atoms;
114112
root_atom_table m_root_atoms;
@@ -242,50 +240,7 @@ namespace nlsat {
242240
};
243241
// statistics
244242
stats m_stats;
245-
std::unordered_map<std::string, anum> m_debug_known_sat_anum_map;
246-
std::unordered_map<std::string, lbool> m_debug_known_sat_bool_non_pure_atom_vals;
247-
std::unordered_map<unsigned, lbool> m_debug_pure_bool_vals;
248-
std::string m_debug_known_sol_file_name;
249-
const anum & debug_get_known_sat_anum_value(unsigned j) {
250-
std::string name = debug_get_var_name(j);
251-
252-
auto it = m_debug_known_sat_anum_map.find(name);
253-
if (it != m_debug_known_sat_anum_map.end())
254-
return it->second;
255-
else
256-
UNREACHABLE();
257-
return it->second;
258-
}
259-
260-
lbool debug_get_known_literal_value(literal l) {
261-
std::string atom_string = debug_atom_string(l.var());
262-
auto it = m_debug_known_sat_bool_non_pure_atom_vals.find(atom_string);
263-
if (it == m_debug_known_sat_bool_non_pure_atom_vals.end())
264-
return l_undef;
265-
if (it->second == l_false) {
266-
if (l.sign())
267-
return l_true;
268-
return l_false;
269-
} else if (it->second == l_true) {
270-
if (l.sign())
271-
return l_false;
272-
return l_true;
273-
} else
274-
UNREACHABLE();
275-
276-
return l_undef;
277-
}
278-
279-
void debug_set_known_sat_values() {
280-
std::vector<std::pair<std::string, anum>> var_sat_values = debug_parse_var_anum_file();
281-
282-
for (auto const & kv : var_sat_values) {
283-
anum val;
284-
// Convert kv.second to an anum using m_am
285-
m_am.set(val, kv.second);
286-
m_debug_known_sat_anum_map[kv.first] = val;
287-
}
288-
}
243+
std::string m_debug_known_solution_file_name;
289244

290245
imp(solver& s, ctx& c):
291246
m_ctx(c),
@@ -299,9 +254,7 @@ namespace nlsat {
299254
m_am(c.m_am),
300255
m_asm(*this, m_allocator),
301256
m_assignment(m_am), m_lo(m_am), m_hi(m_am),
302-
m_debug_assignment(m_am),
303257
m_evaluator(s, m_assignment, m_pm, m_allocator),
304-
m_debug_evaluator(s, m_debug_assignment, m_pm, m_allocator),
305258
m_ism(m_evaluator.ism()),
306259
m_num_bool_vars(0),
307260
m_simplify(s, m_atoms, m_clauses, m_learned, m_pm),
@@ -316,8 +269,6 @@ namespace nlsat {
316269
reset_statistics();
317270
mk_true_bvar();
318271
m_lemma_count = 0;
319-
if (!m_debug_known_sol_file_name.empty())
320-
debug_set_known_sat_values();
321272
}
322273

323274
~imp() {
@@ -357,7 +308,7 @@ namespace nlsat {
357308
m_explain.set_minimize_cores(min_cores);
358309
m_explain.set_factor(p.factor());
359310
m_am.updt_params(p.p);
360-
m_debug_known_sol_file_name = p.debug_known_sol_file();
311+
m_debug_known_solution_file_name = p.debug_known_sol_file();
361312
}
362313

363314
void reset() {
@@ -925,14 +876,6 @@ namespace nlsat {
925876
bool_var operator[](bool_var v) const { return vec[v]; }
926877
};
927878

928-
void debug_set_debug_assignment_to_known_vals() {
929-
m_debug_assignment.reset();
930-
for (var x = 0; x < num_vars(); ++x) {
931-
const anum& dval = debug_get_known_sat_anum_value(x);
932-
m_debug_assignment.set(x, dval);
933-
}
934-
}
935-
936879
std::vector<unsigned> collect_vars(literal l) {
937880
var_vector vars;
938881
this->vars(l, vars);
@@ -975,21 +918,75 @@ namespace nlsat {
975918
// At least one literal has to be evaluate to true.
976919
// The method might ignore a lemma with pure boolean varibles.
977920
void debug_check_lemma_on_known_sat_values(unsigned n_of_literals, literal const *cls, assumption_set a) {
978-
debug_set_debug_assignment_to_known_vals();
979921
SASSERT(a == nullptr);
922+
923+
// If no debug file is specified, just return
924+
if (m_debug_known_solution_file_name.empty())
925+
return;
926+
927+
// Create local debug objects
928+
assignment debug_assignment(m_am);
929+
evaluator debug_evaluator(m_solver, debug_assignment, m_pm, m_allocator);
930+
931+
// Parse the debug file to get known variable values
932+
std::vector<std::pair<std::string, anum>> var_sat_values;
933+
std::ifstream in(m_debug_known_solution_file_name);
934+
std::string line;
935+
while (std::getline(in, line)) {
936+
std::istringstream iss(line);
937+
std::string name, value_str;
938+
if (!(iss >> name >> value_str)) {
939+
std::cout << line << std::endl;
940+
std::cout << "is not recognized\n";
941+
exit(1);
942+
}
943+
// Parse rational value
944+
rational r;
945+
size_t slash = value_str.find('/');
946+
if (slash == std::string::npos) {
947+
r = rational(value_str.c_str());
948+
} else {
949+
std::string num = value_str.substr(0, slash);
950+
std::string den = value_str.substr(slash + 1);
951+
r = rational(num.c_str()) / rational(den.c_str());
952+
}
953+
anum a;
954+
const auto& q = r.to_mpq();
955+
m_am.set(a, q);
956+
var_sat_values.emplace_back(name, a);
957+
}
958+
959+
// Build a map from variable names to their known values
960+
std::unordered_map<std::string, anum> debug_known_sat_anum_map;
961+
for (auto const & kv : var_sat_values) {
962+
anum val;
963+
m_am.set(val, kv.second);
964+
debug_known_sat_anum_map[kv.first] = val;
965+
}
966+
967+
// Set up the debug assignment with known values
968+
debug_assignment.reset();
969+
for (var x = 0; x < num_vars(); ++x) {
970+
std::string name = debug_get_var_name(x);
971+
auto it = debug_known_sat_anum_map.find(name);
972+
if (it != debug_known_sat_anum_map.end()) {
973+
debug_assignment.set(x, it->second);
974+
}
975+
}
976+
980977
bool satisfied = false;
981978
for (unsigned i = 0; i < n_of_literals && !satisfied; ++i) {
982979
literal l = cls[i];
983980
bool_var b = l.var();
984981
atom* a = m_atoms[b];
985982
if (a == nullptr)
986-
return; // ignore lemmas with pure booleal variables
983+
return; // ignore lemmas with pure boolean variables
987984

988985
lbool val = l_undef;
989986
// Arithmetic atom: evaluate directly
990987
var max = a->max_var();
991-
SASSERT (m_debug_assignment.is_assigned(max));
992-
val = to_lbool(m_debug_evaluator.eval(a, l.sign()));
988+
SASSERT(debug_assignment.is_assigned(max));
989+
val = to_lbool(debug_evaluator.eval(a, l.sign()));
993990
SASSERT(val != l_undef);
994991
if (val == l_true)
995992
satisfied = true;
@@ -998,7 +995,7 @@ namespace nlsat {
998995
m_display_var.m_proc = nullptr;
999996
std::cout << "Known sat assignment does not satisfy valid lemma!\n";
1000997
display(std::cout, n_of_literals, cls) << "\n";
1001-
display_assignment_on_clause(std::cout, m_debug_assignment, n_of_literals, cls);
998+
display_assignment_on_clause(std::cout, debug_assignment, n_of_literals, cls);
1002999
exit(1);
10031000
}
10041001
}
@@ -1357,16 +1354,10 @@ namespace nlsat {
13571354
\brief Assign literal to true using the given justification
13581355
*/
13591356
void set_literal_to_true(literal l, justification j) {
1360-
if (!m_debug_known_sol_file_name.empty())
1361-
debug_set_debug_assignment_to_known_vals();
13621357
TRACE("nlsat_assign",
13631358
tout << "literal" << l << "\n";
13641359
display(tout << "assigning literal to true: ", l) << "\n";
1365-
display(tout << " <- ", j);
1366-
auto known_val = debug_get_known_literal_value(l);
1367-
if (known_val != l_undef) {
1368-
tout << "known val of literal is " << known_val << "\n";
1369-
});
1360+
display(tout << " <- ", j););
13701361

13711362
SASSERT(assigned_value(l) == l_undef);
13721363
SASSERT(j != null_justification);
@@ -1578,12 +1569,11 @@ namespace nlsat {
15781569
atom * a = m_atoms[b];
15791570
SASSERT(a != nullptr);
15801571
interval_set_ref curr_set(m_ism);
1581-
curr_set = m_evaluator.infeasible_intervals(a, l.sign(), &cls);
1582-
TRACE("nlsat_inf_set",
1572+
curr_set = m_evaluator.infeasible_intervals(a, l.sign(), &cls);
1573+
TRACE("nlsat_inf_set",
15831574
tout << "infeasible set for literal: "; display(tout, l); tout << "\n"; m_ism.display(tout, curr_set); tout << "\n";
15841575
display(tout << "cls: " , cls) << "\n";
1585-
tout << "m_xk:" << m_xk << "(" << debug_get_var_name(m_xk) << ")"<< "\n";
1586-
tout << "known deb value of the literal is: " << debug_get_known_literal_value(l) << "\n";);
1576+
tout << "m_xk:" << m_xk << "(" << debug_get_var_name(m_xk) << ")"<< "\n";);
15871577
if (m_ism.is_empty(curr_set)) {
15881578
TRACE("nlsat_inf_set", tout << "infeasible set is empty, found literal\n";);
15891579
R_propagate(l, nullptr);
@@ -1700,18 +1690,6 @@ namespace nlsat {
17001690
}
17011691
}
17021692

1703-
bool debug_set_known_sat_value_to_xk_() {
1704-
const anum& dw = debug_get_known_sat_anum_value(m_xk);
1705-
bool can_use = m_ism.contains_in_complement(m_infeasible[m_xk], false, dw);
1706-
if (!can_use){
1707-
return false;
1708-
}
1709-
anum val;
1710-
m_am.set(val, dw);
1711-
m_assignment.set_core(m_xk, val);
1712-
return true;
1713-
}
1714-
17151693
/**
17161694
\brief Assign m_xk
17171695
*/
@@ -4077,7 +4055,7 @@ namespace nlsat {
40774055

40784056
std::vector<std::pair<std::string, anum>> debug_parse_var_anum_file() {
40794057
std::vector<std::pair<std::string, anum>> result;
4080-
std::ifstream in(m_debug_known_sol_file_name);
4058+
std::ifstream in(m_debug_known_solution_file_name);
40814059
std::string line;
40824060
while (std::getline(in, line)) {
40834061
std::istringstream iss(line);

0 commit comments

Comments
 (0)