3
0
Fork 0
mirror of https://github.com/Z3Prover/z3 synced 2025-04-22 16:45:31 +00:00

working on tab-context

Signed-off-by: Nikolaj Bjorner <nbjorner@microsoft.com>
This commit is contained in:
Nikolaj Bjorner 2013-01-23 21:44:42 -08:00
parent 0e02fcad60
commit c89531bcf8
2 changed files with 204 additions and 144 deletions

View file

@ -618,7 +618,6 @@ namespace datalog {
expr_ref_vector const& s1, expr_ref_vector const& s2, rule const& res) {
if (!pc) return;
ast_manager& m = s1.get_manager();
dl_decl_util util(m);
expr_ref fml1(m), fml2(m), fml3(m);
r1.to_formula(fml1);
r2.to_formula(fml2);

View file

@ -148,8 +148,7 @@ namespace tb {
}
};
class goal {
datalog::rule_ref m_goal; // goal as rule
class clause {
app_ref m_head; // head predicate
app_ref_vector m_predicates; // predicates used in goal
expr_ref m_constraint; // side constraint
@ -164,8 +163,7 @@ namespace tb {
public:
goal(datalog::rule_manager& rm):
m_goal(rm),
clause(datalog::rule_manager& rm):
m_head(rm.get_manager()),
m_predicates(rm.get_manager()),
m_constraint(rm.get_manager()),
@ -188,14 +186,13 @@ namespace tb {
unsigned get_num_predicates() const { return m_predicates.size(); }
app* get_predicate(unsigned i) const { return m_predicates[i]; }
expr* get_constraint() const { return m_constraint; }
datalog::rule const& get_rule() const { return *m_goal; }
unsigned get_num_vars() const { return m_num_vars; }
unsigned get_index() const { return m_index; }
void set_index(unsigned index) { m_index = index; }
app* get_head() const { return m_head; }
unsigned get_parent_index() const { return m_parent_index; }
unsigned get_parent_rule() const { return m_parent_rule; }
void set_parent(ref<tb::goal>& parent) {
void set_parent(ref<tb::clause>& parent) {
m_parent_index = parent->get_index();
m_parent_rule = parent->get_next_rule();
}
@ -219,8 +216,28 @@ namespace tb {
::get_free_vars(m_constraint, vars);
}
expr_ref to_formula() const {
ast_manager& m = get_manager();
expr_ref body = get_body();
body = m.mk_implies(body, m_head);
ptr_vector<sort> vars;
svector<symbol> names;
get_free_vars(vars);
mk_fresh_name fresh;
fresh.add(body);
vars.reverse();
for (unsigned i = 0; i < vars.size(); ++i) {
names.push_back(fresh.next());
if (!vars[i]) vars[i] = m.mk_bool_sort();
}
vars.reverse();
if (!vars.empty()) {
body = m.mk_forall(vars.size(), vars.c_ptr(), names.c_ptr(), body);
}
return body;
}
void init(app* head, app_ref_vector const& predicates, expr* constraint) {
m_goal = 0;
m_index = 0;
m_predicate_index = 0;
m_next_rule = static_cast<unsigned>(-1);
@ -235,7 +252,6 @@ namespace tb {
}
void init(datalog::rule_ref& g) {
m_goal = g;
m_index = 0;
m_predicate_index = 0;
m_next_rule = static_cast<unsigned>(-1);
@ -294,7 +310,7 @@ namespace tb {
bool_rewriter(m).mk_and(fmls.size(), fmls.c_ptr(), m_constraint);
}
// Simplify a goal by applying equalities as substitutions on predicates.
// Simplify a clause by applying equalities as substitutions on predicates.
// x = t[y], if x does not occur in t[y], then add t[y] to subst.
void reduce_equalities() {
ast_manager& m = get_manager();
@ -388,11 +404,11 @@ namespace tb {
// rules
class rules {
typedef obj_map<func_decl, unsigned_vector> map;
vector<ref<goal> > m_rules;
vector<ref<clause> > m_rules;
map m_index;
public:
typedef vector<ref<goal> >::const_iterator iterator;
typedef vector<ref<clause> >::const_iterator iterator;
iterator begin() const { return m_rules.begin(); }
iterator end() const { return m_rules.end(); }
@ -406,13 +422,13 @@ namespace tb {
datalog::rule_set::iterator end = rules.end();
for (; it != end; ++it) {
r = *it;
ref<goal> g = alloc(goal, rm);
ref<clause> g = alloc(clause, rm);
g->init(r);
insert(g);
}
}
void insert(ref<goal>& g) {
void insert(ref<clause>& g) {
unsigned idx = m_rules.size();
m_rules.push_back(g);
func_decl* f = g->get_head()->get_decl();
@ -431,7 +447,7 @@ namespace tb {
}
}
ref<goal> get_rule(func_decl* p, unsigned idx) const {
ref<clause> get_rule(func_decl* p, unsigned idx) const {
map::obj_map_entry* e = m_index.find_core(p);
SASSERT(p);
unsigned rule_id = e->get_data().get_value()[idx];
@ -448,8 +464,8 @@ namespace tb {
app_ref_vector m_preds;
expr_ref m_precond;
expr_ref_vector m_sideconds;
ref<goal> m_goal;
vector<ref<goal> > m_index;
ref<clause> m_clause;
vector<ref<clause> > m_index;
matcher m_matcher;
substitution m_subst;
qe_lite m_qe;
@ -474,13 +490,13 @@ namespace tb {
m_solver(m, m_fparams),
m_cancel(false) {}
void insert(ref<goal>& g) {
void insert(ref<clause>& g) {
m_index.push_back(g);
}
bool is_subsumed(ref<tb::goal>& g, unsigned& subsumer) {
bool is_subsumed(ref<tb::clause>& g, unsigned& subsumer) {
setup(*g);
m_goal = g;
m_clause = g;
m_solver.push();
m_solver.assert_expr(m_precond);
bool found = find_match(subsumer);
@ -506,7 +522,7 @@ namespace tb {
private:
void setup(goal const& g) {
void setup(clause const& g) {
m_preds.reset();
expr_ref_vector fmls(m);
expr_ref_vector vars(m);
@ -551,7 +567,7 @@ namespace tb {
// for now: skip multiple matches within the same rule (incomplete).
//
bool match_rule(unsigned rule_index) {
goal const& g = *m_index[rule_index];
clause const& g = *m_index[rule_index];
m_sideconds.reset();
m_subst.reset();
m_subst.reserve(2, g.get_num_vars());
@ -562,7 +578,7 @@ namespace tb {
}
bool match_predicates(unsigned predicate_index, goal const& g) {
bool match_predicates(unsigned predicate_index, clause const& g) {
if (predicate_index == g.get_num_predicates()) {
return check_substitution(g);
}
@ -592,14 +608,12 @@ namespace tb {
return false;
}
bool check_substitution(goal const& g) {
bool check_substitution(clause const& g) {
unsigned deltas[2] = {0, 0};
expr_ref q(m), postcond(m);
expr_ref_vector fmls(m_sideconds);
m_subst.reset_cache();
for (unsigned i = 0; !m_cancel && i < fmls.size(); ++i) {
m_subst.apply(2, deltas, expr_offset(fmls[i].get(), 0), q);
fmls[i] = q;
@ -628,7 +642,7 @@ namespace tb {
if (!is_ground(postcond)) {
IF_VERBOSE(1, verbose_stream() << "TBD: non-ground\n"
<< mk_pp(postcond, m) << "\n";
m_goal->display(verbose_stream());
m_clause->display(verbose_stream());
verbose_stream() << "\n=>\n";
g.display(verbose_stream());
verbose_stream() << "\n";);
@ -662,7 +676,7 @@ namespace tb {
m_scores.reset();
rules::iterator it = rs.begin(), end = rs.end();
for (; it != end; ++it) {
ref<goal> g = *it;
ref<clause> g = *it;
app* p = g->get_head();
unsigned_vector scores;
score_predicate(p, scores);
@ -670,7 +684,7 @@ namespace tb {
}
}
unsigned select(goal const& g) {
unsigned select(clause const& g) {
return 0;
#if 0
unsigned max_score = 0;
@ -748,87 +762,89 @@ namespace tb {
class unifier {
ast_manager& m;
datalog::context& m_ctx;
datalog::rule_unifier m_unif;
::unifier m_unifier;
substitution m_subst;
ref<goal> m_tgt;
ref<goal> m_src;
substitution m_S1;
substitution m_S2;
expr_ref_vector m_sub1;
expr_ref_vector m_sub2;
public:
unifier(ast_manager& m, datalog::context& ctx):
m(m),
m_ctx(ctx),
m_unif(ctx),
m_unifier(m),
m_subst(m) {}
m_S1(m),
m_S2(m),
m_sub1(m),
m_sub2(m) {}
bool operator()(ref<goal>& tgt, ref<goal>& src, bool compute_subst, ref<goal>& result) {
bool operator()(ref<clause>& tgt, ref<clause>& src, bool compute_subst, ref<clause>& result) {
unsigned idx = tgt->get_predicate_index();
datalog::rule_ref res(m_ctx.get_rule_manager());
datalog::rule const& t = tgt->get_rule();
datalog::rule const& s = src->get_rule();
SASSERT(t.get_decl(idx) == s.get_decl());
m_src = src;
m_tgt = tgt;
(void) compute_subst;
if (m_unif.unify_rules(t, idx, s) &&
m_unif.apply(t, idx, s, res)) {
result = alloc(goal, m_ctx.get_rule_manager());
result->init(res);
{
ref<goal> result2;
new_unify(*tgt, *src, compute_subst, result2);
}
return true;
}
else {
return false;
}
return new_unify(*tgt, *src, compute_subst, result);
}
expr_ref_vector get_rule_subst(bool is_tgt) {
return m_unif.get_rule_subst(is_tgt?m_tgt->get_rule():m_src->get_rule(), is_tgt);
if (is_tgt) {
return m_sub1;
}
else {
return m_sub2;
}
}
bool new_unify(goal const& tgt, goal const& src, bool compute_subst, ref<goal>& result) {
bool new_unify(clause const& tgt, clause const& src, bool compute_subst, ref<clause>& result) {
qe_lite qe(m);
reset();
unsigned idx = tgt.get_predicate_index();
SASSERT(tgt.get_predicate(idx)->get_decl() == src.get_head()->get_decl());
unsigned var_cnt = std::max(tgt.get_num_vars(), src.get_num_vars());
m_subst.reserve(2, var_cnt);
if (!m_unifier(tgt.get_predicate(idx), src.get_head(), m_subst)) {
m_S1.reserve(2, var_cnt);
if (!m_unifier(tgt.get_predicate(idx), src.get_head(), m_S1)) {
return false;
}
app_ref_vector predicates(m);
expr_ref tmp(m), tmp2(m), constraint(m);
app_ref head(m);
result = alloc(goal, m_ctx.get_rule_manager());
result = alloc(clause, m_ctx.get_rule_manager());
unsigned delta[2] = { 0, var_cnt };
m_subst.apply(2, delta, expr_offset(tgt.get_head(), 0), tmp);
m_S1.apply(2, delta, expr_offset(tgt.get_head(), 0), tmp);
head = to_app(tmp);
for (unsigned i = 0; i < tgt.get_num_predicates(); ++i) {
if (i != idx) {
m_subst.apply(2, delta, expr_offset(tgt.get_predicate(i), 0), tmp);
m_S1.apply(2, delta, expr_offset(tgt.get_predicate(i), 0), tmp);
predicates.push_back(to_app(tmp));
}
}
for (unsigned i = 0; i < src.get_num_predicates(); ++i) {
m_subst.apply(2, delta, expr_offset(src.get_predicate(i), 1), tmp);
m_S1.apply(2, delta, expr_offset(src.get_predicate(i), 1), tmp);
predicates.push_back(to_app(tmp));
}
m_subst.apply(2, delta, expr_offset(tgt.get_constraint(), 0), tmp);
m_subst.apply(2, delta, expr_offset(src.get_constraint(), 1), tmp2);
constraint = m.mk_and(tmp, tmp2);
m_S1.apply(2, delta, expr_offset(tgt.get_constraint(), 0), tmp);
m_S1.apply(2, delta, expr_offset(src.get_constraint(), 1), tmp2);
constraint = m.mk_and(tmp, tmp2);
ptr_vector<sort> vars;
// perform trival quantifier-elimination:
uint_set index_set;
get_free_vars(head, vars);
for (unsigned i = 0; i < predicates.size(); ++i) {
get_free_vars(predicates[i].get(), vars);
}
for (unsigned i = 0; i < vars.size(); ++i) {
if (vars[i]) {
index_set.insert(i);
}
}
qe(index_set, false, constraint);
if (m.is_false(constraint)) {
return false;
}
// initialize rule.
result->init(head, predicates, constraint);
vars.reset();
result->get_free_vars(vars);
substitution S2(m);
S2.reserve(1, vars.size());
m_S2.reserve(1, vars.size());
bool change = false;
for (unsigned i = 0, j = 0; i < vars.size(); ++i) {
if (vars[i]) {
@ -836,29 +852,25 @@ namespace tb {
var_ref v(m), w(m);
v = m.mk_var(i, vars[i]);
w = m.mk_var(j, vars[i]);
S2.insert(v, 0, expr_offset(w, 0));
m_S2.insert(v, 0, expr_offset(w, 0));
change = true;
}
++j;
}
}
if (change) {
S2.apply(1, delta, expr_offset(result->get_constraint(), 0), constraint);
m_S2.apply(1, delta, expr_offset(result->get_constraint(), 0), constraint);
for (unsigned i = 0; i < result->get_num_predicates(); ++i) {
S2.apply(1, delta, expr_offset(result->get_predicate(i), 0), tmp);
m_S2.apply(1, delta, expr_offset(result->get_predicate(i), 0), tmp);
predicates[i] = to_app(tmp);
}
S2.apply(1, delta, expr_offset(result->get_head(), 0), tmp);
m_S2.apply(1, delta, expr_offset(result->get_head(), 0), tmp);
head = to_app(tmp);
result->init(head, predicates, constraint);
}
if (compute_subst) {
ptr_vector<sort> vars1;
tgt.get_free_vars(vars1);
for (unsigned i = 0; i < vars1.size(); ++i) {
// TBD:
// apply the two substitutions after each-other.
}
extract_subst(delta, tgt, 0);
extract_subst(delta, src, 1);
}
IF_VERBOSE(1,
@ -872,7 +884,37 @@ namespace tb {
private:
void reset() {
m_subst.reset();
m_S1.reset();
m_S2.reset();
m_sub1.reset();
m_sub2.reset();
}
void extract_subst(unsigned const* delta, clause const& g, unsigned offset) {
ptr_vector<sort> vars;
var_ref v(m);
expr_ref tmp(m);
g.get_free_vars(vars);
for (unsigned i = 0; i < vars.size(); ++i) {
if (vars[i]) {
v = m.mk_var(i, vars[i]);
m_S1.apply(2, delta, expr_offset(v, offset), tmp);
m_S2.apply(1, delta, expr_offset(tmp, 0), tmp);
insert_subst(offset, tmp);
}
else {
insert_subst(offset, m.mk_true());
}
}
}
void insert_subst(unsigned offset, expr* e) {
if (offset == 0) {
m_sub1.push_back(e);
}
else {
m_sub2.push_back(e);
}
}
};
@ -918,7 +960,7 @@ namespace datalog {
smt::kernel m_solver;
mutable tb::unifier m_unifier;
tb::rules m_rules;
vector<ref<tb::goal> > m_goals;
vector<ref<tb::clause> > m_clauses;
unsigned m_seqno;
tb::instruction m_instruction;
lbool m_status;
@ -955,25 +997,25 @@ namespace datalog {
m_rules.init(m_ctx.get_rules());
m_selection.init(m_rules);
rule_ref_vector query_rules(rm);
rule_ref goal(rm);
rule_ref clause(rm);
func_decl_ref query_pred(m);
rm.mk_query(query, query_pred, query_rules, goal);
rm.mk_query(query, query_pred, query_rules, clause);
// ensure goal predicate does not take free variables.
// ensure clause predicate does not take free variables.
ptr_vector<app> tail;
svector<bool> is_neg;
for (unsigned i = 0; i < goal->get_tail_size(); ++i) {
tail.push_back(goal->get_tail(i));
is_neg.push_back(goal->is_neg_tail(i));
for (unsigned i = 0; i < clause->get_tail_size(); ++i) {
tail.push_back(clause->get_tail(i));
is_neg.push_back(clause->is_neg_tail(i));
}
app_ref query_app(m);
query_app = m.mk_const(symbol("query"), m.mk_bool_sort());
m_ctx.register_predicate(query_app->get_decl());
goal = rm.mk(query_app, tail.size(), tail.c_ptr(), is_neg.c_ptr());
ref<tb::goal> g = alloc(tb::goal, rm);
g->init(goal);
init_goal(g);
IF_VERBOSE(1, display_goal(*get_goal(), verbose_stream() << "g" << get_goal()->get_seqno() << " "););
clause = rm.mk(query_app, tail.size(), tail.c_ptr(), is_neg.c_ptr());
ref<tb::clause> g = alloc(tb::clause, rm);
g->init(clause);
init_clause(g);
IF_VERBOSE(1, display_clause(*get_clause(), verbose_stream() << "g" << get_clause()->get_seqno() << " "););
return run();
}
@ -985,7 +1027,7 @@ namespace datalog {
void cleanup() {
m_cancel = false;
m_goals.reset();
m_clauses.reset();
m_index.cleanup();
m_solver.reset_cancel();
}
@ -1024,7 +1066,7 @@ namespace datalog {
private:
void select_predicate() {
tb::goal & g = *get_goal();
tb::clause & g = *get_clause();
unsigned num_predicates = g.get_num_predicates();
if (num_predicates == 0) {
m_instruction = tb::UNSATISFIABLE;
@ -1038,29 +1080,29 @@ namespace datalog {
}
}
void apply_rule(ref<tb::goal>& r) {
ref<tb::goal> goal = get_goal();
ref<tb::goal> next_goal;
if (m_unifier(goal, r, false, next_goal) &&
l_false != query_is_sat(*next_goal)) {
init_goal(next_goal);
void apply_rule(ref<tb::clause>& r) {
ref<tb::clause> clause = get_clause();
ref<tb::clause> next_clause;
if (m_unifier(clause, r, false, next_clause) &&
l_false != query_is_sat(*next_clause)) {
init_clause(next_clause);
unsigned subsumer = 0;
IF_VERBOSE(1,
display_rule(*goal, verbose_stream());
display_premise(*goal,
verbose_stream() << "g" << next_goal->get_seqno() << " ");
display_goal(*next_goal, verbose_stream());
display_rule(*clause, verbose_stream());
display_premise(*clause,
verbose_stream() << "g" << next_clause->get_seqno() << " ");
display_clause(*next_clause, verbose_stream());
);
if (m_index.is_subsumed(next_goal, subsumer)) {
if (m_index.is_subsumed(next_clause, subsumer)) {
IF_VERBOSE(1, verbose_stream() << "subsumed by g" << subsumer << "\n";);
m_stats.m_num_subsumed++;
m_goals.pop_back();
m_clauses.pop_back();
m_instruction = tb::SELECT_RULE;
}
else {
m_stats.m_num_unfold++;
next_goal->set_parent(goal);
m_index.insert(next_goal);
next_clause->set_parent(clause);
m_index.insert(next_clause);
m_instruction = tb::SELECT_PREDICATE;
}
}
@ -1071,7 +1113,7 @@ namespace datalog {
}
void select_rule() {
tb::goal& g = *get_goal();
tb::clause& g = *get_clause();
g.inc_next_rule();
unsigned pi = g.get_predicate_index();
func_decl* p = g.get_predicate(pi)->get_decl();
@ -1081,15 +1123,15 @@ namespace datalog {
m_instruction = tb::BACKTRACK;
}
else {
ref<tb::goal> rl = m_rules.get_rule(p, index);
ref<tb::clause> rl = m_rules.get_rule(p, index);
apply_rule(rl);
}
}
void backtrack() {
SASSERT(!m_goals.empty());
m_goals.pop_back();
if (m_goals.empty()) {
SASSERT(!m_clauses.empty());
m_clauses.pop_back();
if (m_clauses.empty()) {
m_instruction = tb::SATISFIABLE;
}
else {
@ -1131,7 +1173,7 @@ namespace datalog {
}
}
lbool query_is_sat(tb::goal const& g) {
lbool query_is_sat(tb::clause const& g) {
ptr_vector<sort> sorts;
svector<symbol> names;
expr_ref fml = g.get_body();
@ -1157,18 +1199,18 @@ namespace datalog {
}
void init_goal(ref<tb::goal>& goal) {
goal->set_index(m_goals.size());
goal->set_seqno(m_seqno++);
m_goals.push_back(goal);
void init_clause(ref<tb::clause>& clause) {
clause->set_index(m_clauses.size());
clause->set_seqno(m_seqno++);
m_clauses.push_back(clause);
}
ref<tb::goal> get_goal() const { return m_goals.back(); }
ref<tb::clause> get_clause() const { return m_clauses.back(); }
void display_rule(tb::goal const& p, std::ostream& out) {
void display_rule(tb::clause const& p, std::ostream& out) {
func_decl* f = p.get_predicate(p.get_predicate_index())->get_decl();
ref<tb::goal> rl = m_rules.get_rule(f, p.get_next_rule());
ref<tb::clause> rl = m_rules.get_rule(f, p.get_next_rule());
unsigned idx = rl->get_index();
if (!m_displayed_rules.contains(idx)) {
m_displayed_rules.insert(idx);
@ -1176,44 +1218,43 @@ namespace datalog {
}
}
void display_premise(tb::goal& p, std::ostream& out) {
void display_premise(tb::clause& p, std::ostream& out) {
func_decl* f = p.get_predicate(p.get_predicate_index())->get_decl();
out << "{g" << p.get_seqno() << " " << f->get_name() << " pos: " << p.get_predicate_index() << " rule: " << p.get_next_rule() << "}\n";
}
void display_goal(tb::goal& g, std::ostream& out) {
void display_clause(tb::clause& g, std::ostream& out) {
g.display(out);
}
proof_ref get_proof() const {
scoped_proof sp(m);
expr_ref root(m);
proof_ref pr(m);
proof_ref_vector prs(m);
expr_ref_vector subst(m);
ref<tb::goal> goal = get_goal();
ref<tb::goal> replayed_goal;
ref<tb::clause> clause = get_clause();
ref<tb::clause> replayed_clause;
replace_proof_converter pc(m);
// goal is a empty clause.
// clause is a empty clause.
// Pretend it is asserted.
// It gets replaced by premises.
SASSERT(goal->get_num_predicates() == 0);
goal->get_rule().to_formula(root);
SASSERT(clause->get_num_predicates() == 0);
expr_ref root = clause->to_formula();
while (0 != goal->get_index()) {
SASSERT(goal->get_parent_index() < goal->get_index());
unsigned p_index = goal->get_parent_index();
unsigned p_rule = goal->get_parent_rule();
ref<tb::goal> parent = m_goals[p_index];
while (0 != clause->get_index()) {
SASSERT(clause->get_parent_index() < clause->get_index());
unsigned p_index = clause->get_parent_index();
unsigned p_rule = clause->get_parent_rule();
ref<tb::clause> parent = m_clauses[p_index];
unsigned pi = parent->get_predicate_index();
func_decl* pred = parent->get_predicate(pi)->get_decl();
ref<tb::goal> rl = m_rules.get_rule(pred, p_rule);
VERIFY(m_unifier(parent, rl, true, replayed_goal));
ref<tb::clause> rl = m_rules.get_rule(pred, p_rule);
VERIFY(m_unifier(parent, rl, true, replayed_clause));
expr_ref_vector s1(m_unifier.get_rule_subst(true));
expr_ref_vector s2(m_unifier.get_rule_subst(false));
resolve_rule(&pc, parent->get_rule(), rl->get_rule(), pi, s1, s2, goal->get_rule());
goal = parent;
resolve_rule(pc, *parent, *rl, s1, s2, *clause);
clause = parent;
IF_VERBOSE(1000,
verbose_stream() << "substitution\n";
for (unsigned i = 0; i < s1.size(); ++i) {
@ -1231,6 +1272,26 @@ namespace datalog {
});
return pr;
}
void resolve_rule(replace_proof_converter& pc, tb::clause const& r1, tb::clause const& r2,
expr_ref_vector const& s1, expr_ref_vector const& s2, tb::clause const& res) const {
unsigned idx = r1.get_predicate_index();
expr_ref fml1 = r1.to_formula();
expr_ref fml2 = r2.to_formula();
expr_ref fml3 = res.to_formula();
vector<expr_ref_vector> substs;
svector<std::pair<unsigned, unsigned> > positions;
substs.push_back(s1);
substs.push_back(s2);
scoped_proof _sc(m);
proof_ref pr(m);
proof_ref_vector premises(m);
premises.push_back(m.mk_asserted(fml1));
premises.push_back(m.mk_asserted(fml2));
positions.push_back(std::make_pair(idx+1, 0));
pr = m.mk_hyper_resolve(2, premises.c_ptr(), fml3, positions, substs);
pc.insert(pr);
}
};