ACEC/term.cpp
2022-10-21 19:34:18 +08:00

277 lines
6.8 KiB
C++

/*------------------------------------------------------------------------*/
/*! \file term.cpp
\brief contains the class Term and further functions to
manipulate terms
Part of AMulet2.1 : AIG Multiplier Verification Tool.
Copyright(C) 2020, 2021 Daniela Kaufmann, Johannes Kepler University Linz
*/
/*------------------------------------------------------------------------*/
#include "term.h"
/*------------------------------------------------------------------------*/
Term::Term(const Var * _v, Term * _r, uint64_t _hash, Term * _n):
variable(_v), ref(1), hash(_hash), next(_n) {
if (_r) rest = _r->copy();
else
rest = 0;
}
/*------------------------------------------------------------------------*/
Term * Term::copy() {
assert(ref > 0);
++ref;
assert(ref);
return this;
}
/*------------------------------------------------------------------------*/
void Term::print(FILE * file) const {
const Term * tmp = this;
if (!tmp) fputc_unlocked('0', file);
while (tmp) {
fputs_unlocked(tmp->get_var_name(), file);
tmp = tmp->get_rest();
if (tmp) fputc_unlocked('*', file);
}
}
/*------------------------------------------------------------------------*/
unsigned Term::size() const {
const Term * tmp = this;
if (!tmp) return 0;
int i = 0;
while (tmp) {
i++;
tmp = tmp->get_rest();
}
return i;
}
/*------------------------------------------------------------------------*/
int Term::cmp(const Term *t) const {
const Term * tmp1 = this;
if (!tmp1) return -1;
const Term * tmp2 = t;
if (!tmp2) return 1;
if (tmp1 != tmp2) {
while (tmp1 && tmp2) {
if (tmp1->get_var_level() > tmp2->get_var_level()) return 1;
else if (tmp1->get_var_level() < tmp2->get_var_level()) return -1;
tmp1 = tmp1->get_rest();
tmp2 = tmp2->get_rest();
}
if (tmp1) return 1;
else if (tmp2) return -1;
}
return 0;
}
/*------------------------------------------------------------------------*/
bool Term::contains(const Var *v) const {
assert(v);
const Term * t = this;
while (t) {
if (t->get_var() == v) return 1;
else if (t->get_var_level() < v->get_level()) return 0;
t = t->get_rest();
}
return 0;
}
/*------------------------------------------------------------------------*/
uint64_t size_terms;
uint64_t current_terms;
Term ** term_table;
/*------------------------------------------------------------------------*/
uint64_t compute_hash_term(const Var * variable, const Term * rest) {
assert(variable);
uint64_t res = rest ? rest->get_hash() : 0;
res *= get_nonces_entry(0);
res += variable->get_hash();
res *= get_nonces_entry(1);
return res;
}
/*------------------------------------------------------------------------*/
void enlarge_terms() {
uint64_t new_size_terms = size_terms ? 2*size_terms : 1;
Term ** new_term_table = new Term*[new_size_terms]();
for (uint64_t i = 0; i < size_terms; i++) {
for (Term * m = term_table[i], * n; m; m = n) {
uint64_t h = m->get_hash() &(new_size_terms - 1);
n = m->get_next();
m->set_next(new_term_table[h]);
new_term_table[h] = m;
}
}
delete[] term_table;
term_table = new_term_table;
size_terms = new_size_terms;
}
/*------------------------------------------------------------------------*/
Term * new_term(const Var * variable, Term * rest) {
if (current_terms == size_terms) enlarge_terms();
const uint64_t hash = compute_hash_term(variable, rest);
const uint64_t h = hash &(size_terms - 1);
Term * res;
for (res = term_table[h];
res &&(res->get_var() != variable || res->get_rest() != rest);
res = res->get_next())
{}
if (res) {
res->inc_ref(); // here we extend that we found term once more
} else {
res = new Term(variable, rest, hash, term_table[h]);
term_table[h] = res;
current_terms++;
}
return res;
}
/*------------------------------------------------------------------------*/
void deallocate_term(Term * t) {
while (t) {
assert(t->get_ref() > 0);
if (t->dec_ref() > 0) break; // t is still used
Term * rest = t->get_rest();
const uint64_t h = t->get_hash() &(size_terms - 1);
Term * p = term_table[h];
if (p == t) { term_table[h] = t->get_next();
} else {
Term * p2;
while ((p2 = p->get_next()) != t) p = p2;
p->set_next(t->get_next());
}
assert(current_terms);
current_terms--;
delete(t);
t = rest;
}
}
/*------------------------------------------------------------------------*/
void deallocate_terms() {
for (uint64_t i = 0; i < size_terms; i++) {
for (Term * m = term_table[i], *n; m; m = n) {
n = m->get_next();
assert(current_terms);
current_terms--;
delete(m);
}
}
delete[] term_table;
}
/*------------------------------------------------------------------------*/
static std::stack<const Var*> vstack; // /< used to build a term
/*------------------------------------------------------------------------*/
void add_to_vstack(const Var* v) {
assert(v);
vstack.push(v);
}
bool var_cmp(const Var* a, const Var* b) {
return a->get_level() > b->get_level();
}
/*------------------------------------------------------------------------*/
Term * build_term_from_stack() {
std::vector<const Var*> tmp_vec;
while(!vstack.empty()) tmp_vec.push_back(vstack.top()), vstack.pop();
std::sort(tmp_vec.begin(), tmp_vec.end(), var_cmp);
for(auto v : tmp_vec) vstack.push(v);
Term * res = 0;
while (!vstack.empty()) {
Term * t = new_term(vstack.top(), res);
assert(t);
vstack.pop();
deallocate_term(res);
res = t;
}
return res;
}
/*------------------------------------------------------------------------*/
Term * multiply_term(Term * t1, Term * t2) {
if (!t1 || !t2) return 0;
if (t1 == t2) return t1->copy();
const Term * tmp1 = t1;
const Term * tmp2 = t2;
while (tmp1 && tmp2) {
if (tmp1->get_var_level() > tmp2->get_var_level()) {
vstack.push(tmp1->get_var());
tmp1 = tmp1->get_rest();
} else if (tmp1->get_var_level() < tmp2->get_var_level()) {
vstack.push(tmp2->get_var());
tmp2 = tmp2->get_rest();
} else {
vstack.push(tmp1->get_var());
tmp1 = tmp1->get_rest();
tmp2 = tmp2->get_rest();
}
}
while (tmp1) {
vstack.push(tmp1->get_var());
tmp1 = tmp1->get_rest();
}
while (tmp2) {
vstack.push(tmp2->get_var());
tmp2 = tmp2->get_rest();
}
Term * t = build_term_from_stack();
return t;
}
/*------------------------------------------------------------------------*/
Term * remainder(const Term * t, const Var * v) {
assert(v);
while (t) {
const Var * v1 = t->get_var();
if (v1 == v) {
t = t->get_rest();
} else {
vstack.push(v1);
t = t->get_rest();
}
}
Term * res = build_term_from_stack();
return res;
}