mirror of
https://github.com/Z3Prover/z3
synced 2025-04-29 20:05:51 +00:00
adding ack/model
Signed-off-by: Nikolaj Bjorner <nbjorner@microsoft.com>
This commit is contained in:
parent
7f0b5bc129
commit
4244ce4aad
31 changed files with 831 additions and 914 deletions
211
src/sat/smt/euf_ackerman.cpp
Normal file
211
src/sat/smt/euf_ackerman.cpp
Normal file
|
@ -0,0 +1,211 @@
|
|||
/*++
|
||||
Copyright (c) 2020 Microsoft Corporation
|
||||
|
||||
Module Name:
|
||||
|
||||
euf_ackerman.cpp
|
||||
|
||||
Abstract:
|
||||
|
||||
Ackerman reduction plugin for EUF
|
||||
|
||||
Author:
|
||||
|
||||
Nikolaj Bjorner (nbjorner) 2020-08-28
|
||||
|
||||
--*/
|
||||
#pragma once
|
||||
|
||||
#include "sat/smt/euf_solver.h"
|
||||
#include "sat/smt/euf_ackerman.h"
|
||||
|
||||
namespace euf {
|
||||
|
||||
ackerman::ackerman(solver& s, ast_manager& m): s(s), m(m) {
|
||||
new_tmp();
|
||||
}
|
||||
|
||||
ackerman::~ackerman() {
|
||||
reset();
|
||||
dealloc(m_tmp_inference);
|
||||
}
|
||||
|
||||
void ackerman::reset() {
|
||||
for (inference* inf : m_table) {
|
||||
m.dec_ref(inf->a);
|
||||
m.dec_ref(inf->b);
|
||||
m.dec_ref(inf->c);
|
||||
}
|
||||
m_table.reset();
|
||||
m_queue = nullptr;
|
||||
}
|
||||
|
||||
void ackerman::insert(expr* a, expr* b, expr* lca) {
|
||||
if (a->get_id() > b->get_id())
|
||||
std::swap(a, b);
|
||||
inference& inf = *m_tmp_inference;
|
||||
inf.a = a;
|
||||
inf.b = b;
|
||||
inf.c = lca;
|
||||
inf.is_cc = false;
|
||||
insert();
|
||||
}
|
||||
|
||||
void ackerman::insert(app* a, app* b) {
|
||||
if (a->get_id() > b->get_id())
|
||||
std::swap(a, b);
|
||||
inference& inf = *m_tmp_inference;
|
||||
inf.a = a;
|
||||
inf.b = b;
|
||||
inf.c = nullptr;
|
||||
inf.is_cc = true;
|
||||
insert();
|
||||
}
|
||||
|
||||
void ackerman::remove_from_queue(inference* inf) {
|
||||
if (m_queue->m_next == m_queue) {
|
||||
SASSERT(inf == m_queue);
|
||||
m_queue = nullptr;
|
||||
return;
|
||||
}
|
||||
if (m_queue == inf)
|
||||
m_queue = inf->m_next;
|
||||
auto* next = inf->m_next;
|
||||
auto* prev = inf->m_prev;
|
||||
prev->m_next = next;
|
||||
next->m_prev = prev;
|
||||
}
|
||||
|
||||
void ackerman::push_to_front(inference* inf) {
|
||||
if (!m_queue) {
|
||||
m_queue = inf;
|
||||
}
|
||||
else if (m_queue != inf) {
|
||||
auto* next = inf->m_next;
|
||||
auto* prev = inf->m_prev;
|
||||
prev->m_next = next;
|
||||
next->m_prev = prev;
|
||||
inf->m_prev = m_queue->m_prev;
|
||||
inf->m_next = m_queue;
|
||||
m_queue->m_prev = inf;
|
||||
}
|
||||
}
|
||||
|
||||
void ackerman::insert() {
|
||||
inference* inf = m_tmp_inference;
|
||||
inference* other = m_table.insert_if_not_there(inf);
|
||||
if (other == inf) {
|
||||
m.inc_ref(inf->a);
|
||||
m.inc_ref(inf->b);
|
||||
m.inc_ref(inf->c);
|
||||
}
|
||||
else
|
||||
new_tmp();
|
||||
other->m_count++;
|
||||
push_to_front(other);
|
||||
}
|
||||
|
||||
void ackerman::remove(inference* inf) {
|
||||
remove_from_queue(inf);
|
||||
m_table.erase(inf);
|
||||
m.dec_ref(inf->a);
|
||||
m.dec_ref(inf->b);
|
||||
m.dec_ref(inf->c);
|
||||
dealloc(inf);
|
||||
}
|
||||
|
||||
void ackerman::new_tmp() {
|
||||
m_tmp_inference = alloc(inference);
|
||||
m_tmp_inference->m_next = m_tmp_inference->m_prev = m_tmp_inference;
|
||||
m_tmp_inference->m_count = 0;
|
||||
}
|
||||
|
||||
void ackerman::cg_conflict_eh(expr * n1, expr * n2) {
|
||||
if (s.m_config.m_dack != DACK_ROOT)
|
||||
return;
|
||||
if (!is_app(n1) || !is_app(n2))
|
||||
return;
|
||||
app* a = to_app(n1);
|
||||
app* b = to_app(n2);
|
||||
if (a->get_decl() != b->get_decl() || a->get_num_args() != b->get_num_args())
|
||||
return;
|
||||
insert(a, b);
|
||||
gc();
|
||||
}
|
||||
|
||||
void ackerman::used_eq_eh(expr* a, expr* b, expr* c) {
|
||||
if (!s.m_config.m_dack_eq)
|
||||
return;
|
||||
if (a == b || a == c || b == c)
|
||||
return;
|
||||
insert(a, b, c);
|
||||
gc();
|
||||
}
|
||||
|
||||
void ackerman::used_cc_eh(app* a, app* b) {
|
||||
if (s.m_config.m_dack != DACK_CR)
|
||||
return;
|
||||
SASSERT(a->get_decl() == b->get_decl());
|
||||
SASSERT(a->get_num_args() == b->get_num_args());
|
||||
insert(a, b);
|
||||
gc();
|
||||
}
|
||||
|
||||
void ackerman::gc() {
|
||||
m_num_propagations_since_last_gc++;
|
||||
if (m_num_propagations_since_last_gc <= s.m_config.m_dack_gc)
|
||||
return;
|
||||
m_num_propagations_since_last_gc = 0;
|
||||
|
||||
while (m_table.size() > m_gc_threshold)
|
||||
remove(m_queue->m_prev);
|
||||
|
||||
m_gc_threshold *= 110;
|
||||
m_gc_threshold /= 100;
|
||||
m_gc_threshold++;
|
||||
}
|
||||
|
||||
void ackerman::propagate() {
|
||||
SASSERT(s.s().at_base_lvl());
|
||||
auto* n = m_queue;
|
||||
inference* k = nullptr;
|
||||
unsigned num_prop = static_cast<unsigned>(s.s().stats().m_conflict * s.m_config.m_dack_factor);
|
||||
num_prop = std::min(num_prop, m_table.size());
|
||||
for (unsigned i = 0; i < num_prop; ++i, n = k) {
|
||||
k = n->m_next;
|
||||
if (n->m_count < s.m_config.m_dack_threshold)
|
||||
continue;
|
||||
if (n->is_cc)
|
||||
add_cc(n->a, n->b);
|
||||
else
|
||||
add_eq(n->a, n->b, n->c);
|
||||
remove(n);
|
||||
}
|
||||
}
|
||||
|
||||
void ackerman::add_cc(expr* _a, expr* _b) {
|
||||
app* a = to_app(_a);
|
||||
app* b = to_app(_b);
|
||||
sat::literal_vector lits;
|
||||
unsigned sz = a->get_num_args();
|
||||
for (unsigned i = 0; i < sz; ++i) {
|
||||
expr_ref eq(m.mk_eq(a->get_arg(i), b->get_arg(i)), m);
|
||||
sat::literal lit = s.internalize(eq, true, false);
|
||||
lits.push_back(~lit);
|
||||
}
|
||||
expr_ref eq(m.mk_eq(a, b), m);
|
||||
lits.push_back(s.internalize(eq, false, false));
|
||||
s.s().mk_clause(lits, true);
|
||||
}
|
||||
|
||||
void ackerman::add_eq(expr* a, expr* b, expr* c) {
|
||||
sat::literal lits[3];
|
||||
expr_ref eq1(m.mk_eq(a, c), m);
|
||||
expr_ref eq2(m.mk_eq(b, c), m);
|
||||
expr_ref eq3(m.mk_eq(a, b), m);
|
||||
lits[0] = s.internalize(eq1, true, false);
|
||||
lits[1] = s.internalize(eq2, true, false);
|
||||
lits[2] = s.internalize(eq3, false, false);
|
||||
s.s().mk_clause(3, lits, true);
|
||||
}
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue