mirror of
https://github.com/Z3Prover/z3
synced 2025-07-19 10:52:02 +00:00
stab at forbidden intervals
Signed-off-by: Nikolaj Bjorner <nbjorner@microsoft.com>
This commit is contained in:
parent
9450ac0d18
commit
e6c4ae19c6
5 changed files with 37 additions and 53 deletions
|
@ -77,7 +77,7 @@ namespace polysat {
|
||||||
|
|
||||||
void insert(signed_constraint c);
|
void insert(signed_constraint c);
|
||||||
void insert(signed_constraint c, vector<signed_constraint> premises);
|
void insert(signed_constraint c, vector<signed_constraint> premises);
|
||||||
void remove(signed_constraint c);
|
void remove(signed_constraint c) { NOT_IMPLEMENTED_YET(); }
|
||||||
|
|
||||||
/** Perform boolean resolution with the clause upon variable 'var'.
|
/** Perform boolean resolution with the clause upon variable 'var'.
|
||||||
* Precondition: core/clause contain complementary 'var'-literals.
|
* Precondition: core/clause contain complementary 'var'-literals.
|
||||||
|
|
|
@ -12,6 +12,10 @@ Author:
|
||||||
Nikolaj Bjorner (nbjorner) 2021-03-19
|
Nikolaj Bjorner (nbjorner) 2021-03-19
|
||||||
Jakob Rath 2021-04-6
|
Jakob Rath 2021-04-6
|
||||||
|
|
||||||
|
|
||||||
|
TODO:
|
||||||
|
move "forbidden interval method from constraints
|
||||||
|
|
||||||
--*/
|
--*/
|
||||||
#include "math/polysat/forbidden_intervals.h"
|
#include "math/polysat/forbidden_intervals.h"
|
||||||
#include "math/polysat/clause_builder.h"
|
#include "math/polysat/clause_builder.h"
|
||||||
|
@ -64,17 +68,24 @@ namespace polysat {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool forbidden_intervals::explain(solver& s, vector<signed_constraint> const& conflict, pvar v, clause_ref& out_lemma) {
|
/**
|
||||||
|
* A single constraint implies an empty interval.
|
||||||
|
* We assume that neg_cond is a consequence of src that
|
||||||
|
* does not mention the variable v to be eliminated.
|
||||||
|
*/
|
||||||
|
void forbidden_intervals::full_interval_conflict(signed_constraint src, signed_constraint neg_cond, conflict_core& core) {
|
||||||
|
SASSERT(neg_cond);
|
||||||
|
core.insert(~neg_cond);
|
||||||
|
core.remove(src); // or add a lemma?
|
||||||
|
}
|
||||||
|
|
||||||
return false;
|
bool forbidden_intervals::perform(solver& s, pvar v, conflict_core& core) {
|
||||||
|
|
||||||
#if 0
|
|
||||||
// Extract forbidden intervals from conflicting constraints
|
// Extract forbidden intervals from conflicting constraints
|
||||||
vector<fi_record> records;
|
vector<fi_record> records;
|
||||||
bool has_full = false;
|
|
||||||
rational longest_len;
|
rational longest_len;
|
||||||
unsigned longest_i = UINT_MAX;
|
unsigned longest_i = UINT_MAX;
|
||||||
for (signed_constraint c : conflict) {
|
for (signed_constraint c : core) {
|
||||||
LOG_H3("Computing forbidden interval for: " << c);
|
LOG_H3("Computing forbidden interval for: " << c);
|
||||||
eval_interval interval = eval_interval::full();
|
eval_interval interval = eval_interval::full();
|
||||||
signed_constraint neg_cond;
|
signed_constraint neg_cond;
|
||||||
|
@ -83,8 +94,12 @@ namespace polysat {
|
||||||
LOG("neg_cond: " << neg_cond);
|
LOG("neg_cond: " << neg_cond);
|
||||||
if (interval.is_currently_empty())
|
if (interval.is_currently_empty())
|
||||||
continue;
|
continue;
|
||||||
if (interval.is_full())
|
if (interval.is_full()) {
|
||||||
has_full = true;
|
// We have a single interval covering the whole domain
|
||||||
|
// => the side conditions of that interval are enough to produce a conflict
|
||||||
|
full_interval_conflict(c, neg_cond, core);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
else {
|
else {
|
||||||
auto const len = interval.current_len();
|
auto const len = interval.current_len();
|
||||||
if (len > longest_len) {
|
if (len > longest_len) {
|
||||||
|
@ -93,31 +108,15 @@ namespace polysat {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
records.push_back({ std::move(interval), std::move(neg_cond), c });
|
records.push_back({ std::move(interval), std::move(neg_cond), c });
|
||||||
if (has_full)
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
LOG("has_full: " << std::boolalpha << has_full);
|
|
||||||
if (has_full) {
|
|
||||||
// We have a single interval covering the whole domain
|
|
||||||
// => the side conditions of that interval are enough to produce a conflict
|
|
||||||
auto& full_record = records.back();
|
|
||||||
SASSERT(full_record.interval.is_full());
|
|
||||||
clause_builder clause(s);
|
|
||||||
sat::literal src_lit = full_record.src.blit();
|
|
||||||
clause.push_literal(~src_lit);
|
|
||||||
if (full_record.neg_cond)
|
|
||||||
clause.push_new_constraint(std::move(full_record.neg_cond));
|
|
||||||
out_lemma = clause.build();
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (records.empty()) {
|
if (records.empty()) {
|
||||||
LOG("aborted (no intervals)");
|
LOG("aborted (no intervals)");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
SASSERT(longest_i != UINT_MAX);
|
SASSERT(longest_i != UINT_MAX);
|
||||||
LOG("longest: i=" << longest_i << "; " << records[longest_i].interval);
|
LOG("longest: i=" << longest_i << "; " << records[longest_i].interval);
|
||||||
|
|
||||||
|
@ -138,20 +137,14 @@ namespace polysat {
|
||||||
lemma_lvl = std::max(lemma_lvl, c->level());
|
lemma_lvl = std::max(lemma_lvl, c->level());
|
||||||
}
|
}
|
||||||
|
|
||||||
// Create lemma
|
// Update the conflict state
|
||||||
// Idea:
|
// Idea:
|
||||||
// - If the src constraints hold, and
|
// - If the src constraints hold, and
|
||||||
// - if the side conditions hold, and
|
// - if the side conditions hold, and
|
||||||
// - the upper bound of each interval is contained in the next interval,
|
// - the upper bound of each interval is contained in the next interval,
|
||||||
// then the forbidden intervals cover the whole domain and we have a conflict.
|
// then the forbidden intervals cover the whole domain and we have a conflict.
|
||||||
// We learn the negation of this conjunction.
|
//
|
||||||
|
|
||||||
clause_builder clause(s);
|
|
||||||
// Add negation of src constraints as antecedents (may be resolved during backtracking)
|
|
||||||
for (unsigned const i : seq) {
|
|
||||||
sat::literal src_lit = records[i].src.blit();
|
|
||||||
clause.push_literal(~src_lit);
|
|
||||||
}
|
|
||||||
// Add side conditions and interval constraints
|
// Add side conditions and interval constraints
|
||||||
for (unsigned seq_i = seq.size(); seq_i-- > 0; ) {
|
for (unsigned seq_i = seq.size(); seq_i-- > 0; ) {
|
||||||
unsigned const i = seq[seq_i];
|
unsigned const i = seq[seq_i];
|
||||||
|
@ -166,18 +159,18 @@ namespace polysat {
|
||||||
// NB: do we really have to pass in the level to this new literal?
|
// NB: do we really have to pass in the level to this new literal?
|
||||||
// seems separating the level from the constraint is what we want
|
// seems separating the level from the constraint is what we want
|
||||||
// the level of a literal is when it was assigned. Lemmas could have unassigned literals.
|
// the level of a literal is when it was assigned. Lemmas could have unassigned literals.
|
||||||
signed_constraint c = ~s.m_constraints.ult(lemma_lvl, lhs, rhs);
|
signed_constraint c = s.m_constraints.ult(lemma_lvl, lhs, rhs);
|
||||||
LOG("constraint: " << c);
|
LOG("constraint: " << c);
|
||||||
clause.push_new_constraint(std::move(c));
|
core.insert(c);
|
||||||
// Side conditions
|
// Side conditions
|
||||||
// TODO: check whether the condition is subsumed by c? maybe at the end do a "lemma reduction" step, to try and reduce branching?
|
// TODO: check whether the condition is subsumed by c? maybe at the end do a "lemma reduction" step, to try and reduce branching?
|
||||||
signed_constraint& neg_cond = records[i].neg_cond;
|
signed_constraint& neg_cond = records[i].neg_cond;
|
||||||
if (neg_cond)
|
if (neg_cond)
|
||||||
clause.push_new_constraint(std::move(neg_cond));
|
core.insert(std::move(~neg_cond));
|
||||||
|
|
||||||
|
core.remove(records[i].src);
|
||||||
}
|
}
|
||||||
out_lemma = clause.build();
|
|
||||||
return true;
|
return true;
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -16,13 +16,13 @@ Author:
|
||||||
#pragma once
|
#pragma once
|
||||||
#include "math/polysat/constraint.h"
|
#include "math/polysat/constraint.h"
|
||||||
#include "math/polysat/solver.h"
|
#include "math/polysat/solver.h"
|
||||||
|
#include "math/polysat/variable_elimination.h"
|
||||||
|
|
||||||
namespace polysat {
|
namespace polysat {
|
||||||
|
|
||||||
class forbidden_intervals {
|
class forbidden_intervals : public variable_elimination_engine {
|
||||||
|
void full_interval_conflict(signed_constraint c, signed_constraint neg_cond, conflict_core& core);
|
||||||
public:
|
public:
|
||||||
static bool explain(solver& s, vector<signed_constraint> const& conflict, pvar v, clause_ref& out_lemma);
|
bool perform(solver& s, pvar v, conflict_core& core) override;
|
||||||
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
|
@ -35,9 +35,4 @@ namespace polysat {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool ve_forbidden_intervals::perform(solver& s, pvar v, conflict_core& core) {
|
|
||||||
NOT_IMPLEMENTED_YET();
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -29,8 +29,4 @@ namespace polysat {
|
||||||
bool perform(solver& s, pvar v, conflict_core& core) override;
|
bool perform(solver& s, pvar v, conflict_core& core) override;
|
||||||
};
|
};
|
||||||
|
|
||||||
class ve_forbidden_intervals : public variable_elimination_engine {
|
|
||||||
public:
|
|
||||||
bool perform(solver& s, pvar v, conflict_core& core) override;
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue