mirror of
https://github.com/Z3Prover/z3
synced 2025-04-22 00:26:38 +00:00
Merge branch 'master' into permutation_test
This commit is contained in:
commit
c9054c97e7
15 changed files with 297 additions and 127 deletions
2
.github/workflows/coverage.yml
vendored
2
.github/workflows/coverage.yml
vendored
|
@ -3,6 +3,8 @@ name: Code Coverage
|
|||
on:
|
||||
push:
|
||||
branches: [ master ]
|
||||
pull_request:
|
||||
branches: [ master ]
|
||||
schedule:
|
||||
- cron: "0 11 * * *"
|
||||
|
||||
|
|
2
.github/workflows/docker-image.yml
vendored
2
.github/workflows/docker-image.yml
vendored
|
@ -41,7 +41,7 @@ jobs:
|
|||
type=edge
|
||||
type=sha,prefix=ubuntu-20.04-bare-z3-sha-
|
||||
- name: Build and push Bare Z3 Docker Image
|
||||
uses: docker/build-push-action@v6.4.0
|
||||
uses: docker/build-push-action@v6.5.0
|
||||
with:
|
||||
context: .
|
||||
push: true
|
||||
|
|
|
@ -1412,8 +1412,10 @@ class HTMLFormatter(Formatter):
|
|||
ys_pp = group(seq(ys))
|
||||
if a.is_forall():
|
||||
header = "∀"
|
||||
else:
|
||||
elif a.is_exists():
|
||||
header = "∃"
|
||||
else:
|
||||
header = "λ"
|
||||
return group(compose(to_format(header, 1),
|
||||
indent(1, compose(ys_pp, to_format(" :"), line_break(), body_pp))))
|
||||
|
||||
|
|
|
@ -220,17 +220,33 @@ namespace datatype {
|
|||
}
|
||||
|
||||
namespace decl {
|
||||
|
||||
|
||||
plugin::~plugin() {
|
||||
finalize();
|
||||
}
|
||||
|
||||
void plugin::finalize() {
|
||||
for (auto& kv : m_defs) {
|
||||
dealloc(kv.m_value);
|
||||
}
|
||||
for (auto& kv : m_defs)
|
||||
dealloc(kv.m_value);
|
||||
m_defs.reset();
|
||||
m_util = nullptr; // force deletion
|
||||
reset();
|
||||
}
|
||||
|
||||
void plugin::reset() {
|
||||
m_datatype2constructors.reset();
|
||||
m_datatype2nonrec_constructor.reset();
|
||||
m_constructor2accessors.reset();
|
||||
m_constructor2recognizer.reset();
|
||||
m_recognizer2constructor.reset();
|
||||
m_accessor2constructor.reset();
|
||||
m_is_recursive.reset();
|
||||
m_is_enum.reset();
|
||||
std::for_each(m_vectors.begin(), m_vectors.end(), delete_proc<ptr_vector<func_decl> >());
|
||||
m_vectors.reset();
|
||||
dealloc(m_asts);
|
||||
m_asts = nullptr;
|
||||
++m_start;
|
||||
}
|
||||
|
||||
util & plugin::u() const {
|
||||
|
@ -578,6 +594,7 @@ namespace datatype {
|
|||
if (m_defs.find(s, d))
|
||||
dealloc(d);
|
||||
m_defs.remove(s);
|
||||
reset();
|
||||
}
|
||||
|
||||
bool plugin::is_value_visit(bool unique, expr * arg, ptr_buffer<app> & todo) const {
|
||||
|
@ -799,7 +816,7 @@ namespace datatype {
|
|||
for (unsigned i = 0; i < n; ++i) {
|
||||
sort* ps = get_datatype_parameter_sort(s, i);
|
||||
sz = get_sort_size(params, ps);
|
||||
m_refs.push_back(sz);
|
||||
plugin().m_refs.push_back(sz);
|
||||
S.insert(d.params().get(i), sz);
|
||||
}
|
||||
auto ss = d.sort_size();
|
||||
|
@ -896,7 +913,7 @@ namespace datatype {
|
|||
}
|
||||
TRACE("datatype", tout << "set sort size " << s << "\n";);
|
||||
d.set_sort_size(param_size::size::mk_plus(s_add));
|
||||
m_refs.reset();
|
||||
plugin().m_refs.reset();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1008,9 +1025,7 @@ namespace datatype {
|
|||
util::util(ast_manager & m):
|
||||
m(m),
|
||||
m_family_id(null_family_id),
|
||||
m_plugin(nullptr),
|
||||
m_asts(m),
|
||||
m_start(0) {
|
||||
m_plugin(nullptr) {
|
||||
}
|
||||
|
||||
|
||||
|
@ -1027,24 +1042,24 @@ namespace datatype {
|
|||
|
||||
|
||||
util::~util() {
|
||||
std::for_each(m_vectors.begin(), m_vectors.end(), delete_proc<ptr_vector<func_decl> >());
|
||||
|
||||
}
|
||||
|
||||
ptr_vector<func_decl> const * util::get_datatype_constructors(sort * ty) {
|
||||
SASSERT(is_datatype(ty));
|
||||
ptr_vector<func_decl> * r = nullptr;
|
||||
if (m_datatype2constructors.find(ty, r))
|
||||
if (plugin().m_datatype2constructors.find(ty, r))
|
||||
return r;
|
||||
r = alloc(ptr_vector<func_decl>);
|
||||
m_asts.push_back(ty);
|
||||
m_vectors.push_back(r);
|
||||
m_datatype2constructors.insert(ty, r);
|
||||
plugin().add_ast(ty);
|
||||
plugin().m_vectors.push_back(r);
|
||||
plugin().m_datatype2constructors.insert(ty, r);
|
||||
if (!is_declared(ty))
|
||||
m.raise_exception("datatype constructors have not been created");
|
||||
def const& d = get_def(ty);
|
||||
for (constructor const* c : d) {
|
||||
func_decl_ref f = c->instantiate(ty);
|
||||
m_asts.push_back(f);
|
||||
plugin().add_ast(f);
|
||||
r->push_back(f);
|
||||
}
|
||||
return r;
|
||||
|
@ -1053,13 +1068,13 @@ namespace datatype {
|
|||
ptr_vector<func_decl> const * util::get_constructor_accessors(func_decl * con) {
|
||||
SASSERT(is_constructor(con));
|
||||
ptr_vector<func_decl> * res = nullptr;
|
||||
if (m_constructor2accessors.find(con, res)) {
|
||||
if (plugin().m_constructor2accessors.find(con, res)) {
|
||||
return res;
|
||||
}
|
||||
res = alloc(ptr_vector<func_decl>);
|
||||
m_asts.push_back(con);
|
||||
m_vectors.push_back(res);
|
||||
m_constructor2accessors.insert(con, res);
|
||||
plugin().add_ast(con);
|
||||
plugin().m_vectors.push_back(res);
|
||||
plugin().m_constructor2accessors.insert(con, res);
|
||||
sort * datatype = con->get_range();
|
||||
def const& d = get_def(datatype);
|
||||
for (constructor const* c : d) {
|
||||
|
@ -1067,7 +1082,7 @@ namespace datatype {
|
|||
for (accessor const* a : *c) {
|
||||
func_decl_ref fn = a->instantiate(datatype);
|
||||
res->push_back(fn);
|
||||
m_asts.push_back(fn);
|
||||
plugin().add_ast(fn);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
@ -1086,7 +1101,7 @@ namespace datatype {
|
|||
func_decl * util::get_constructor_recognizer(func_decl * con) {
|
||||
SASSERT(is_constructor(con));
|
||||
func_decl * d = nullptr;
|
||||
if (m_constructor2recognizer.find(con, d))
|
||||
if (plugin().m_constructor2recognizer.find(con, d))
|
||||
return d;
|
||||
sort * datatype = con->get_range();
|
||||
def const& dd = get_def(datatype);
|
||||
|
@ -1097,9 +1112,9 @@ namespace datatype {
|
|||
parameter ps[2] = { parameter(con), parameter(r) };
|
||||
d = m.mk_func_decl(fid(), OP_DT_RECOGNISER, 2, ps, 1, &datatype);
|
||||
SASSERT(d);
|
||||
m_asts.push_back(con);
|
||||
m_asts.push_back(d);
|
||||
m_constructor2recognizer.insert(con, d);
|
||||
plugin().add_ast(con);
|
||||
plugin().add_ast(d);
|
||||
plugin().m_constructor2recognizer.insert(con, d);
|
||||
return d;
|
||||
}
|
||||
|
||||
|
@ -1120,10 +1135,10 @@ namespace datatype {
|
|||
bool util::is_recursive(sort * ty) {
|
||||
SASSERT(is_datatype(ty));
|
||||
bool r = false;
|
||||
if (!m_is_recursive.find(ty, r)) {
|
||||
if (!plugin().m_is_recursive.find(ty, r)) {
|
||||
r = is_recursive_core(ty);
|
||||
m_is_recursive.insert(ty, r);
|
||||
m_asts.push_back(ty);
|
||||
plugin().m_is_recursive.insert(ty, r);
|
||||
plugin().add_ast(ty);
|
||||
}
|
||||
return r;
|
||||
}
|
||||
|
@ -1147,21 +1162,21 @@ namespace datatype {
|
|||
if (!is_datatype(s))
|
||||
return false;
|
||||
bool r = false;
|
||||
if (m_is_enum.find(s, r))
|
||||
if (plugin().m_is_enum.find(s, r))
|
||||
return r;
|
||||
ptr_vector<func_decl> const& cnstrs = *get_datatype_constructors(s);
|
||||
r = true;
|
||||
for (unsigned i = 0; r && i < cnstrs.size(); ++i)
|
||||
r = cnstrs[i]->get_arity() == 0;
|
||||
m_is_enum.insert(s, r);
|
||||
m_asts.push_back(s);
|
||||
plugin().m_is_enum.insert(s, r);
|
||||
plugin().add_ast(s);
|
||||
return r;
|
||||
}
|
||||
|
||||
func_decl * util::get_accessor_constructor(func_decl * accessor) {
|
||||
SASSERT(is_accessor(accessor));
|
||||
func_decl * r = nullptr;
|
||||
if (m_accessor2constructor.find(accessor, r))
|
||||
if (plugin().m_accessor2constructor.find(accessor, r))
|
||||
return r;
|
||||
sort * datatype = accessor->get_domain(0);
|
||||
symbol c_id = accessor->get_parameter(1).get_symbol();
|
||||
|
@ -1174,26 +1189,15 @@ namespace datatype {
|
|||
}
|
||||
}
|
||||
r = fn;
|
||||
m_accessor2constructor.insert(accessor, r);
|
||||
m_asts.push_back(accessor);
|
||||
m_asts.push_back(r);
|
||||
plugin().m_accessor2constructor.insert(accessor, r);
|
||||
plugin().add_ast(accessor);
|
||||
plugin().add_ast(r);
|
||||
return r;
|
||||
}
|
||||
|
||||
|
||||
void util::reset() {
|
||||
m_datatype2constructors.reset();
|
||||
m_datatype2nonrec_constructor.reset();
|
||||
m_constructor2accessors.reset();
|
||||
m_constructor2recognizer.reset();
|
||||
m_recognizer2constructor.reset();
|
||||
m_accessor2constructor.reset();
|
||||
m_is_recursive.reset();
|
||||
m_is_enum.reset();
|
||||
std::for_each(m_vectors.begin(), m_vectors.end(), delete_proc<ptr_vector<func_decl> >());
|
||||
m_vectors.reset();
|
||||
m_asts.reset();
|
||||
++m_start;
|
||||
plugin().reset();
|
||||
}
|
||||
|
||||
|
||||
|
@ -1205,7 +1209,7 @@ namespace datatype {
|
|||
func_decl * util::get_non_rec_constructor(sort * ty) {
|
||||
SASSERT(is_datatype(ty));
|
||||
cnstr_depth cd;
|
||||
if (m_datatype2nonrec_constructor.find(ty, cd))
|
||||
if (plugin().m_datatype2nonrec_constructor.find(ty, cd))
|
||||
return cd.first;
|
||||
ptr_vector<sort> forbidden_set;
|
||||
forbidden_set.push_back(ty);
|
||||
|
@ -1222,7 +1226,7 @@ namespace datatype {
|
|||
each T_i is not a datatype or it is a datatype t not in forbidden_set,
|
||||
and get_non_rec_constructor_core(T_i, forbidden_set union { T_i })
|
||||
*/
|
||||
util::cnstr_depth util::get_non_rec_constructor_core(sort * ty, ptr_vector<sort> & forbidden_set) {
|
||||
cnstr_depth util::get_non_rec_constructor_core(sort * ty, ptr_vector<sort> & forbidden_set) {
|
||||
// We must select a constructor c(T_1, ..., T_n):T such that
|
||||
// 1) T_i's are not recursive
|
||||
// If there is no such constructor, then we select one that
|
||||
|
@ -1231,7 +1235,7 @@ namespace datatype {
|
|||
ptr_vector<func_decl> const& constructors = *get_datatype_constructors(ty);
|
||||
array_util autil(m);
|
||||
cnstr_depth result(nullptr, 0);
|
||||
if (m_datatype2nonrec_constructor.find(ty, result))
|
||||
if (plugin().m_datatype2nonrec_constructor.find(ty, result))
|
||||
return result;
|
||||
TRACE("util_bug", tout << "get-non-rec constructor: " << sort_ref(ty, m) << "\n";
|
||||
tout << "forbidden: ";
|
||||
|
@ -1273,9 +1277,9 @@ namespace datatype {
|
|||
}
|
||||
}
|
||||
if (result.first) {
|
||||
m_asts.push_back(result.first);
|
||||
m_asts.push_back(ty);
|
||||
m_datatype2nonrec_constructor.insert(ty, result);
|
||||
plugin().add_ast(result.first);
|
||||
plugin().add_ast(ty);
|
||||
plugin().m_datatype2nonrec_constructor.insert(ty, result);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
@ -1291,6 +1295,7 @@ namespace datatype {
|
|||
IF_VERBOSE(0, verbose_stream() << f->get_name() << "\n");
|
||||
for (constructor* c : d)
|
||||
IF_VERBOSE(0, verbose_stream() << "!= " << c->name() << "\n");
|
||||
return UINT_MAX;
|
||||
SASSERT(false);
|
||||
UNREACHABLE();
|
||||
return 0;
|
||||
|
|
|
@ -198,6 +198,8 @@ namespace datatype {
|
|||
def* translate(ast_translation& tr, util& u);
|
||||
};
|
||||
|
||||
typedef std::pair<func_decl*, unsigned> cnstr_depth;
|
||||
|
||||
namespace decl {
|
||||
|
||||
class plugin : public decl_plugin {
|
||||
|
@ -213,6 +215,7 @@ namespace datatype {
|
|||
|
||||
void log_axiom_definitions(symbol const& s, sort * new_sort);
|
||||
|
||||
|
||||
public:
|
||||
plugin(): m_id_counter(0), m_class_id(0), m_has_nested_rec(false) {}
|
||||
~plugin() override;
|
||||
|
@ -259,6 +262,25 @@ namespace datatype {
|
|||
|
||||
bool has_nested_rec() const { return m_has_nested_rec; }
|
||||
|
||||
void reset();
|
||||
|
||||
|
||||
obj_map<sort, ptr_vector<func_decl>*> m_datatype2constructors;
|
||||
obj_map<sort, cnstr_depth> m_datatype2nonrec_constructor;
|
||||
obj_map<func_decl, ptr_vector<func_decl>*> m_constructor2accessors;
|
||||
obj_map<func_decl, func_decl*> m_constructor2recognizer;
|
||||
obj_map<func_decl, func_decl*> m_recognizer2constructor;
|
||||
obj_map<func_decl, func_decl*> m_accessor2constructor;
|
||||
obj_map<sort, bool> m_is_recursive;
|
||||
obj_map<sort, bool> m_is_enum;
|
||||
mutable obj_map<sort, bool> m_is_fully_interp;
|
||||
mutable ast_ref_vector* m_asts = nullptr;
|
||||
sref_vector<param_size::size> m_refs;
|
||||
ptr_vector<ptr_vector<func_decl> > m_vectors;
|
||||
unsigned m_start = 0;
|
||||
mutable ptr_vector<sort> m_fully_interp_trail;
|
||||
void add_ast(ast* a) const { if (!m_asts) m_asts = alloc(ast_ref_vector, *m_manager); m_asts->push_back(a); }
|
||||
|
||||
private:
|
||||
bool is_value_visit(bool unique, expr * arg, ptr_buffer<app> & todo) const;
|
||||
bool is_value_aux(bool unique, app * arg) const;
|
||||
|
@ -295,25 +317,10 @@ namespace datatype {
|
|||
ast_manager & m;
|
||||
mutable family_id m_family_id;
|
||||
mutable decl::plugin* m_plugin;
|
||||
typedef std::pair<func_decl*, unsigned> cnstr_depth;
|
||||
|
||||
|
||||
family_id fid() const;
|
||||
|
||||
obj_map<sort, ptr_vector<func_decl> *> m_datatype2constructors;
|
||||
obj_map<sort, cnstr_depth> m_datatype2nonrec_constructor;
|
||||
obj_map<func_decl, ptr_vector<func_decl> *> m_constructor2accessors;
|
||||
obj_map<func_decl, func_decl *> m_constructor2recognizer;
|
||||
obj_map<func_decl, func_decl *> m_recognizer2constructor;
|
||||
obj_map<func_decl, func_decl *> m_accessor2constructor;
|
||||
obj_map<sort, bool> m_is_recursive;
|
||||
obj_map<sort, bool> m_is_enum;
|
||||
mutable obj_map<sort, bool> m_is_fully_interp;
|
||||
mutable ast_ref_vector m_asts;
|
||||
sref_vector<param_size::size> m_refs;
|
||||
ptr_vector<ptr_vector<func_decl> > m_vectors;
|
||||
unsigned m_start;
|
||||
mutable ptr_vector<sort> m_fully_interp_trail;
|
||||
|
||||
|
||||
cnstr_depth get_non_rec_constructor_core(sort * ty, ptr_vector<sort> & forbidden_set);
|
||||
|
||||
friend class decl::plugin;
|
||||
|
|
|
@ -97,42 +97,41 @@ public:
|
|||
};
|
||||
|
||||
struct statistics {
|
||||
unsigned m_make_feasible;
|
||||
unsigned m_total_iterations;
|
||||
unsigned m_iters_with_no_cost_growing;
|
||||
unsigned m_num_factorizations;
|
||||
unsigned m_num_of_implied_bounds;
|
||||
unsigned m_need_to_solve_inf;
|
||||
unsigned m_max_cols;
|
||||
unsigned m_max_rows;
|
||||
unsigned m_gcd_calls;
|
||||
unsigned m_gcd_conflicts;
|
||||
unsigned m_cube_calls;
|
||||
unsigned m_cube_success;
|
||||
unsigned m_patches;
|
||||
unsigned m_patches_success;
|
||||
unsigned m_hnf_cutter_calls;
|
||||
unsigned m_hnf_cuts;
|
||||
unsigned m_nla_calls;
|
||||
unsigned m_gomory_cuts;
|
||||
unsigned m_nla_add_bounds;
|
||||
unsigned m_nla_propagate_bounds;
|
||||
unsigned m_nla_propagate_eq;
|
||||
unsigned m_nla_lemmas;
|
||||
unsigned m_nra_calls;
|
||||
unsigned m_nla_bounds_improvements;
|
||||
unsigned m_horner_calls;
|
||||
unsigned m_horner_conflicts;
|
||||
unsigned m_cross_nested_forms;
|
||||
unsigned m_grobner_calls;
|
||||
unsigned m_grobner_conflicts;
|
||||
unsigned m_offset_eqs;
|
||||
unsigned m_fixed_eqs;
|
||||
::statistics m_st;
|
||||
statistics() { reset(); }
|
||||
unsigned m_make_feasible = 0;
|
||||
unsigned m_total_iterations = 0;
|
||||
unsigned m_iters_with_no_cost_growing = 0;
|
||||
unsigned m_num_factorizations = 0;
|
||||
unsigned m_num_of_implied_bounds = 0;
|
||||
unsigned m_need_to_solve_inf = 0;
|
||||
unsigned m_max_cols = 0;
|
||||
unsigned m_max_rows = 0;
|
||||
unsigned m_gcd_calls = 0;
|
||||
unsigned m_gcd_conflicts = 0;
|
||||
unsigned m_cube_calls = 0;
|
||||
unsigned m_cube_success = 0;
|
||||
unsigned m_patches = 0;
|
||||
unsigned m_patches_success = 0;
|
||||
unsigned m_hnf_cutter_calls = 0;
|
||||
unsigned m_hnf_cuts = 0;
|
||||
unsigned m_nla_calls = 0;
|
||||
unsigned m_gomory_cuts = 0;
|
||||
unsigned m_nla_add_bounds = 0;
|
||||
unsigned m_nla_propagate_bounds = 0;
|
||||
unsigned m_nla_propagate_eq = 0;
|
||||
unsigned m_nla_lemmas = 0;
|
||||
unsigned m_nra_calls = 0;
|
||||
unsigned m_nla_bounds_improvements = 0;
|
||||
unsigned m_horner_calls = 0;
|
||||
unsigned m_horner_conflicts = 0;
|
||||
unsigned m_cross_nested_forms = 0;
|
||||
unsigned m_grobner_calls = 0;
|
||||
unsigned m_grobner_conflicts = 0;
|
||||
unsigned m_offset_eqs = 0;
|
||||
unsigned m_fixed_eqs = 0;
|
||||
::statistics m_st = {};
|
||||
|
||||
void reset() {
|
||||
memset(this, 0, sizeof(*this));
|
||||
m_st.reset();
|
||||
*this = statistics{};
|
||||
}
|
||||
void collect_statistics(::statistics& st) const {
|
||||
st.update("arith-factorizations", m_num_factorizations);
|
||||
|
|
|
@ -79,7 +79,7 @@ public:
|
|||
ref(static_matrix & m, unsigned row, unsigned col):m_matrix(m), m_row(row), m_col(col) {}
|
||||
ref & operator=(T const & v) { m_matrix.set( m_row, m_col, v); return *this; }
|
||||
|
||||
ref operator=(ref & v) { m_matrix.set(m_row, m_col, v.m_matrix.get(v.m_row, v.m_col)); return *this; }
|
||||
ref operator=(ref & v) { m_matrix.set(m_row, m_col, v.m_matrix.get_elem(v.m_row, v.m_col)); return *this; }
|
||||
|
||||
operator T () const { return m_matrix.get_elem(m_row, m_col); }
|
||||
};
|
||||
|
|
|
@ -92,7 +92,7 @@ static_matrix<T, X>::static_matrix(static_matrix const &A, unsigned * /* basis *
|
|||
init_row_columns(m, m);
|
||||
for (; m-- > 0; )
|
||||
for (auto & col : A.m_columns[m])
|
||||
set(col.var(), m, A.get_value_of_column_cell(col));
|
||||
set(col.var(), m, A.get_column_cell(col));
|
||||
}
|
||||
|
||||
template <typename T, typename X> void static_matrix<T, X>::clear() {
|
||||
|
|
|
@ -141,6 +141,8 @@ namespace nlsat {
|
|||
auto& a = *to_ineq_atom(a1);
|
||||
if (a.size() != 2)
|
||||
continue;
|
||||
if (a.is_root_atom())
|
||||
continue;
|
||||
|
||||
auto* p = a.p(0);
|
||||
auto* q = a.p(1);
|
||||
|
@ -229,6 +231,10 @@ namespace nlsat {
|
|||
}
|
||||
break;
|
||||
}
|
||||
default:
|
||||
SASSERT(a.is_root_atom());
|
||||
UNREACHABLE();
|
||||
break;
|
||||
}
|
||||
IF_VERBOSE(3,
|
||||
s.display(verbose_stream(), c) << " ->\n";
|
||||
|
|
|
@ -101,7 +101,7 @@ struct mbp_basic_tg::impl {
|
|||
bool is_or = m.is_or(term);
|
||||
app *c = to_app(term);
|
||||
bool t = is_or ? any_of(*c, is_true) : all_of(*c, is_true);
|
||||
bool f = is_or ? all_of(*c, is_false) : all_of(*c, is_false);
|
||||
bool f = is_or ? all_of(*c, is_false) : any_of(*c, is_false);
|
||||
if (t || f) {
|
||||
mark_seen(term);
|
||||
progress = true;
|
||||
|
|
|
@ -1,3 +1,20 @@
|
|||
/*++
|
||||
Copyright (c) 2024 Microsoft Corporation
|
||||
|
||||
Module Name:
|
||||
|
||||
tst_dlist.cpp
|
||||
|
||||
Abstract:
|
||||
|
||||
Test dlist module
|
||||
|
||||
Author:
|
||||
|
||||
Chuyue Sun 2024-07-18.
|
||||
|
||||
--*/
|
||||
|
||||
#include <cassert>
|
||||
#include <iostream>
|
||||
#include "util/dlist.h"
|
||||
|
@ -160,10 +177,12 @@ void tst_dlist() {
|
|||
test_pop();
|
||||
test_insert_after();
|
||||
test_insert_before();
|
||||
#if 0
|
||||
test_remove_from();
|
||||
test_push_to_front();
|
||||
test_detach();
|
||||
test_invariant();
|
||||
test_contains();
|
||||
#endif
|
||||
std::cout << "All tests passed." << std::endl;
|
||||
}
|
||||
|
|
|
@ -12,6 +12,7 @@ Abstract:
|
|||
Author:
|
||||
|
||||
Leonardo de Moura (leonardo) 2006-09-12.
|
||||
Chuyue Sun (liviasun) 2024-07-18.
|
||||
|
||||
Revision History:
|
||||
|
||||
|
@ -20,7 +21,6 @@ Revision History:
|
|||
#include<iostream>
|
||||
#include<unordered_set>
|
||||
#include<stdlib.h>
|
||||
|
||||
#include "util/hashtable.h"
|
||||
|
||||
|
||||
|
@ -119,11 +119,126 @@ static void tst3() {
|
|||
ENSURE(h2.size() == 2);
|
||||
}
|
||||
|
||||
// Custom hash and equality functions for testing
|
||||
struct my_hash {
|
||||
unsigned operator()(int x) const { return x; }
|
||||
};
|
||||
|
||||
struct my_eq {
|
||||
bool operator()(int x, int y) const { return x == y; }
|
||||
};
|
||||
|
||||
void test_hashtable_constructors() {
|
||||
hashtable<int, my_hash, my_eq> ht;
|
||||
VERIFY(ht.empty());
|
||||
VERIFY(ht.size() == 0);
|
||||
VERIFY(ht.capacity() == DEFAULT_HASHTABLE_INITIAL_CAPACITY);
|
||||
|
||||
// Copy constructor
|
||||
hashtable<int, my_hash, my_eq> ht_copy(ht);
|
||||
VERIFY(ht_copy.empty());
|
||||
VERIFY(ht_copy.size() == 0);
|
||||
VERIFY(ht_copy.capacity() == ht.capacity());
|
||||
|
||||
// Move constructor
|
||||
hashtable<int, my_hash, my_eq> ht_move(std::move(ht));
|
||||
VERIFY(ht_move.empty());
|
||||
VERIFY(ht_move.size() == 0);
|
||||
VERIFY(ht_move.capacity() == ht_copy.capacity());
|
||||
}
|
||||
|
||||
void test_hashtable_insert() {
|
||||
hashtable<int, my_hash, my_eq> ht;
|
||||
ht.insert(1);
|
||||
VERIFY(!ht.empty());
|
||||
VERIFY(ht.size() == 1);
|
||||
int value;
|
||||
VERIFY(ht.find(1, value) && value == 1);
|
||||
}
|
||||
|
||||
void test_hashtable_remove() {
|
||||
hashtable<int, my_hash, my_eq> ht;
|
||||
ht.insert(1);
|
||||
ht.remove(1);
|
||||
VERIFY(ht.empty());
|
||||
VERIFY(ht.size() == 0);
|
||||
}
|
||||
|
||||
void test_hashtable_find() {
|
||||
hashtable<int, my_hash, my_eq> ht;
|
||||
ht.insert(1);
|
||||
int value;
|
||||
VERIFY(ht.find(1, value) && value == 1);
|
||||
VERIFY(!ht.find(2, value));
|
||||
}
|
||||
|
||||
void test_hashtable_contains() {
|
||||
hashtable<int, my_hash, my_eq> ht;
|
||||
ht.insert(1);
|
||||
VERIFY(ht.contains(1));
|
||||
VERIFY(!ht.contains(2));
|
||||
}
|
||||
|
||||
void test_hashtable_reset() {
|
||||
hashtable<int, my_hash, my_eq> ht;
|
||||
ht.insert(1);
|
||||
ht.reset();
|
||||
VERIFY(ht.empty());
|
||||
VERIFY(ht.size() == 0);
|
||||
}
|
||||
|
||||
void test_hashtable_finalize() {
|
||||
hashtable<int, my_hash, my_eq> ht;
|
||||
ht.insert(1);
|
||||
ht.finalize();
|
||||
VERIFY(ht.empty());
|
||||
VERIFY(ht.size() == 0);
|
||||
}
|
||||
|
||||
void test_hashtable_iterators() {
|
||||
hashtable<int, my_hash, my_eq> ht;
|
||||
ht.insert(1);
|
||||
ht.insert(2);
|
||||
ht.insert(3);
|
||||
|
||||
int count = 0;
|
||||
for(auto it = ht.begin(); it != ht.end(); ++it) {
|
||||
++count;
|
||||
}
|
||||
VERIFY(count == 3);
|
||||
}
|
||||
|
||||
void test_hashtable_operators() {
|
||||
hashtable<int, my_hash, my_eq> ht1;
|
||||
hashtable<int, my_hash, my_eq> ht2;
|
||||
|
||||
ht1.insert(1);
|
||||
ht2.insert(2);
|
||||
|
||||
ht1 |= ht2;
|
||||
VERIFY(ht1.contains(1));
|
||||
VERIFY(ht1.contains(2));
|
||||
|
||||
ht1 &= ht2;
|
||||
VERIFY(!ht1.contains(1));
|
||||
VERIFY(ht1.contains(2));
|
||||
}
|
||||
|
||||
void tst_hashtable() {
|
||||
tst3();
|
||||
for (int i = 0; i < 100; i++)
|
||||
tst2();
|
||||
tst1();
|
||||
test_hashtable_constructors();
|
||||
test_hashtable_insert();
|
||||
test_hashtable_remove();
|
||||
test_hashtable_find();
|
||||
test_hashtable_contains();
|
||||
test_hashtable_reset();
|
||||
test_hashtable_finalize();
|
||||
test_hashtable_iterators();
|
||||
test_hashtable_operators();
|
||||
std::cout << "All tests passed!" << std::endl;
|
||||
}
|
||||
#else
|
||||
void tst_hashtable() {
|
||||
|
|
|
@ -155,23 +155,15 @@ public:
|
|||
elem->init(elem);
|
||||
}
|
||||
|
||||
bool invariant() const {
|
||||
auto* e = this;
|
||||
const T* slow = static_cast<const T*>(this);
|
||||
const T* fast = m_next;
|
||||
bool looped = false;
|
||||
// m_next of each node should point back to m_prev of the following node,
|
||||
// and m_prev of each node should point forward to m_next of the preceding node.
|
||||
while (slow != fast) {
|
||||
if (fast->m_prev->m_next != fast || fast->m_next->m_prev != fast)
|
||||
return false;
|
||||
fast = fast->m_next;
|
||||
looped = looped || (fast == static_cast<const T*>(this));
|
||||
if (!looped && fast == m_next)
|
||||
// We should be able to traverse back to the starting node.
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
bool invariant() const {
|
||||
auto* e = this;
|
||||
do {
|
||||
if (e->m_next->m_prev != e)
|
||||
return false;
|
||||
e = e->m_next;
|
||||
}
|
||||
while (e != this);
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool contains(T const* list, T const* elem) {
|
||||
|
|
|
@ -12,6 +12,7 @@ Abstract:
|
|||
Author:
|
||||
|
||||
Leonardo de Moura (leonardo) 2006-09-11.
|
||||
Chuyue Sun (liviasun) 2024-07-18.
|
||||
|
||||
Revision History:
|
||||
|
||||
|
@ -639,6 +640,19 @@ public:
|
|||
|
||||
#ifdef Z3DEBUG
|
||||
bool check_invariant() {
|
||||
// The capacity must always be a power of two.
|
||||
if (!is_power_of_two(m_capacity))
|
||||
return false;
|
||||
|
||||
// The number of deleted plus the size must not exceed the capacity.
|
||||
if (m_num_deleted + m_size > m_capacity)
|
||||
return false;
|
||||
|
||||
// Checking that m_num_deleted is less than or equal to m_size.
|
||||
if (m_num_deleted > m_size) {
|
||||
return false;
|
||||
}
|
||||
|
||||
entry * curr = m_table;
|
||||
entry * end = m_table + m_capacity;
|
||||
unsigned num_deleted = 0;
|
||||
|
|
|
@ -36,6 +36,7 @@ void permutation::swap(unsigned i, unsigned j) noexcept {
|
|||
unsigned j_prime = m_p[j];
|
||||
std::swap(m_p[i], m_p[j]);
|
||||
std::swap(m_inv_p[i_prime], m_inv_p[j_prime]);
|
||||
SASSERT(check_invariant());
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -66,11 +67,19 @@ void permutation::display(std::ostream & out) const {
|
|||
bool permutation::check_invariant() const {
|
||||
SASSERT(m_p.size() == m_inv_p.size());
|
||||
unsigned n = m_p.size();
|
||||
bool_vector check_vector(n, false); // To check for duplicate and out-of-range values
|
||||
for (unsigned i = 0; i < n; i++) {
|
||||
unsigned pi = m_p[i];
|
||||
SASSERT(m_p[i] < n);
|
||||
SASSERT(m_inv_p[i] < n);
|
||||
SASSERT(m_p[m_inv_p[i]] == i);
|
||||
SASSERT(m_inv_p[m_p[i]] == i);
|
||||
// Check the inversion hasn't been checked yet
|
||||
if (check_vector[pi]) {
|
||||
return false;
|
||||
}
|
||||
// Mark this value as checked
|
||||
check_vector[pi] = true;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue