mirror of
https://github.com/Z3Prover/z3
synced 2025-04-23 17:15:31 +00:00
more cleanup
Signed-off-by: Leonardo de Moura <leonardo@microsoft.com>
This commit is contained in:
parent
c2e95bb0c5
commit
683687b153
15 changed files with 2 additions and 508 deletions
File diff suppressed because it is too large
Load diff
3688
src/util/imdd.cpp
3688
src/util/imdd.cpp
File diff suppressed because it is too large
Load diff
849
src/util/imdd.h
849
src/util/imdd.h
|
@ -1,849 +0,0 @@
|
|||
/*++
|
||||
Copyright (c) 2006 Microsoft Corporation
|
||||
|
||||
Module Name:
|
||||
|
||||
imdd.h
|
||||
|
||||
Abstract:
|
||||
|
||||
Interval based Multiple-valued Decision Diagrams.
|
||||
|
||||
Author:
|
||||
|
||||
Leonardo de Moura (leonardo) 2010-10-13.
|
||||
|
||||
Revision History:
|
||||
|
||||
--*/
|
||||
#ifndef _IMDD_H_
|
||||
#define _IMDD_H_
|
||||
|
||||
#include"id_gen.h"
|
||||
#include"hashtable.h"
|
||||
#include"map.h"
|
||||
#include"obj_hashtable.h"
|
||||
#include"obj_pair_hashtable.h"
|
||||
#include"buffer.h"
|
||||
#include"interval_skip_list.h"
|
||||
#include"region.h"
|
||||
#include"obj_ref.h"
|
||||
|
||||
class imdd;
|
||||
class imdd_manager;
|
||||
|
||||
/**
|
||||
\brief Manager for skip-lists used to implement IMDD nodes.
|
||||
*/
|
||||
class sl_imdd_manager : public random_level_manager {
|
||||
imdd_manager * m_manager; // real manager
|
||||
small_object_allocator & m_alloc;
|
||||
friend class imdd_manager;
|
||||
public:
|
||||
sl_imdd_manager(small_object_allocator & alloc):m_alloc(alloc) {}
|
||||
void * allocate(size_t size) { return m_alloc.allocate(size); }
|
||||
void deallocate(size_t size, void* p) { m_alloc.deallocate(size, p); }
|
||||
void inc_ref_eh(imdd * v);
|
||||
void dec_ref_eh(imdd * v);
|
||||
};
|
||||
|
||||
#define IMDD_BUCKET_CAPACITY 128
|
||||
#define IMDD_MAX_LEVEL 32
|
||||
|
||||
typedef interval_skip_list<unsigned_interval_skip_list_traits<imdd*,
|
||||
default_eq<imdd*>,
|
||||
IMDD_BUCKET_CAPACITY,
|
||||
IMDD_MAX_LEVEL,
|
||||
true, /* support ref-counting */
|
||||
sl_imdd_manager> > imdd_children;
|
||||
|
||||
typedef interval_skip_list<unsigned_interval_skip_list_traits<unsigned,
|
||||
default_eq<unsigned>,
|
||||
IMDD_BUCKET_CAPACITY,
|
||||
IMDD_MAX_LEVEL,
|
||||
false,
|
||||
sl_manager_base<unsigned> > > sl_interval_set;
|
||||
|
||||
/*
|
||||
Notes:
|
||||
|
||||
- We use reference counting for garbage collecting IMDDs nodes.
|
||||
|
||||
- Each IMDD node has a "memoized" flag. If the flag is true, the we use hash-consing for this node.
|
||||
|
||||
- The children of a memoized node must be memoized.
|
||||
|
||||
- The children of a non-memoized node may be memoized.
|
||||
|
||||
- The "memoized" flag cannot be reset after it was set.
|
||||
|
||||
- The result of some operations may be cached. We only use caching for
|
||||
operations processing memoized nodes.
|
||||
|
||||
- For non-memoized nodes, if m_ref_count <= 1, destructive updates may be performed by some operations.
|
||||
|
||||
- IMPORTANT: "memoized" flag == false doesn't imply m_ref_count <= 1.
|
||||
*/
|
||||
|
||||
|
||||
/**
|
||||
\brief IMDDs
|
||||
*/
|
||||
class imdd {
|
||||
|
||||
protected:
|
||||
friend class imdd_manager;
|
||||
|
||||
unsigned m_id; //!< Unique ID
|
||||
unsigned m_ref_count;
|
||||
unsigned m_arity:30;
|
||||
unsigned m_memoized:1;
|
||||
unsigned m_dead:1;
|
||||
imdd_children m_children;
|
||||
|
||||
void inc_ref() {
|
||||
m_ref_count ++;
|
||||
}
|
||||
|
||||
void dec_ref() {
|
||||
SASSERT(m_ref_count > 0);
|
||||
m_ref_count --;
|
||||
}
|
||||
|
||||
void mark_as_memoized(bool flag = true) {
|
||||
SASSERT(is_memoized() != flag);
|
||||
m_memoized = flag;
|
||||
}
|
||||
|
||||
void mark_as_dead() { SASSERT(!m_dead); m_dead = true; }
|
||||
|
||||
void replace_children(sl_imdd_manager & m, sbuffer<imdd_children::entry> & new_children);
|
||||
|
||||
public:
|
||||
imdd(sl_imdd_manager & m, unsigned id, unsigned arity):m_id(id), m_ref_count(0), m_arity(arity), m_memoized(false), m_dead(false), m_children(m) {}
|
||||
unsigned get_id() const { return m_id; }
|
||||
unsigned get_ref_count() const { return m_ref_count; }
|
||||
bool is_memoized() const { return m_memoized; }
|
||||
bool is_shared() const { return m_ref_count > 1; }
|
||||
bool is_dead() const { return m_dead; }
|
||||
unsigned get_arity() const { return m_arity; }
|
||||
imdd_children::iterator begin_children() const { return m_children.begin(); }
|
||||
imdd_children::iterator end_children() const { return m_children.end(); }
|
||||
unsigned hc_hash() const; // hash code for hash-consing.
|
||||
bool hc_equal(imdd const * other) const; // eq function for hash-consing
|
||||
bool empty() const { return m_children.empty(); }
|
||||
unsigned hash() const { return m_id; }
|
||||
unsigned memory() const { return sizeof(imdd) + m_children.memory() - sizeof(imdd_children); }
|
||||
};
|
||||
|
||||
// -----------------------------------
|
||||
//
|
||||
// IMDD hash-consing
|
||||
//
|
||||
// -----------------------------------
|
||||
|
||||
// this is the internal hashing functor for hash-consing IMDDs.
|
||||
struct imdd_hash_proc {
|
||||
unsigned operator()(imdd const * d) const { return d->hc_hash(); }
|
||||
};
|
||||
|
||||
// This is the internal comparison functor for hash-consing IMDDs.
|
||||
struct imdd_eq_proc {
|
||||
bool operator()(imdd const * d1, imdd const * d2) const { return d1->hc_equal(d2); }
|
||||
};
|
||||
|
||||
typedef ptr_hashtable<imdd, imdd_hash_proc, imdd_eq_proc> imdd_table;
|
||||
typedef obj_hashtable<imdd> imdd_cache;
|
||||
typedef obj_map<imdd, imdd*> imdd2imdd_cache;
|
||||
typedef obj_pair_map<imdd, imdd, imdd*> imdd_pair2imdd_cache;
|
||||
typedef obj_pair_map<imdd, imdd, bool> imdd_pair2bool_cache;
|
||||
typedef obj_map<imdd, sl_interval_set*> imdd2intervals;
|
||||
|
||||
typedef std::pair<imdd*, unsigned> imdd_value_pair;
|
||||
|
||||
struct fi_cache_entry {
|
||||
imdd * m_d;
|
||||
unsigned m_lower;
|
||||
unsigned m_upper;
|
||||
unsigned m_hash;
|
||||
unsigned m_num_result;
|
||||
imdd_value_pair m_result[0];
|
||||
|
||||
void mk_hash() {
|
||||
m_hash = hash_u_u(m_d->get_id(), hash_u_u(m_lower, m_upper));
|
||||
}
|
||||
|
||||
fi_cache_entry(imdd * d, unsigned l, unsigned u):
|
||||
m_d(d),
|
||||
m_lower(l),
|
||||
m_upper(u) {
|
||||
mk_hash();
|
||||
}
|
||||
|
||||
fi_cache_entry(imdd * d, unsigned l, unsigned u, unsigned num, imdd_value_pair result[]):
|
||||
m_d(d),
|
||||
m_lower(l),
|
||||
m_upper(u),
|
||||
m_num_result(num) {
|
||||
mk_hash();
|
||||
memcpy(m_result, result, sizeof(imdd_value_pair)*num);
|
||||
}
|
||||
|
||||
unsigned hash() const {
|
||||
return m_hash;
|
||||
}
|
||||
|
||||
bool operator==(fi_cache_entry const & other) const {
|
||||
return
|
||||
m_d == other.m_d &&
|
||||
m_lower == other.m_lower &&
|
||||
m_upper == other.m_upper;
|
||||
}
|
||||
};
|
||||
|
||||
typedef obj_hashtable<fi_cache_entry> imdd_fi_cache;
|
||||
typedef union {
|
||||
imdd * m_d;
|
||||
fi_cache_entry * m_entry;
|
||||
} mk_fi_result;
|
||||
|
||||
struct filter_cache_entry {
|
||||
imdd * m_d;
|
||||
imdd * m_r;
|
||||
unsigned m_hash;
|
||||
unsigned m_ctx_size;
|
||||
unsigned m_ctx[0]; // lower and upper bounds that are part of the context.
|
||||
|
||||
static unsigned get_obj_size(unsigned ctx_size) {
|
||||
return sizeof(filter_cache_entry) + ctx_size * sizeof(unsigned);
|
||||
}
|
||||
|
||||
void mk_hash() {
|
||||
if (m_ctx_size > 0)
|
||||
m_hash = string_hash(reinterpret_cast<char *>(m_ctx), m_ctx_size * sizeof(unsigned), m_d->get_id());
|
||||
else
|
||||
m_hash = m_d->get_id();
|
||||
}
|
||||
|
||||
filter_cache_entry(imdd * d, imdd * r, unsigned ctx_size, unsigned * ctx):
|
||||
m_d(d),
|
||||
m_r(r),
|
||||
m_ctx_size(ctx_size) {
|
||||
memcpy(m_ctx, ctx, sizeof(unsigned)*m_ctx_size);
|
||||
mk_hash();
|
||||
}
|
||||
|
||||
unsigned hash() const {
|
||||
return m_hash;
|
||||
}
|
||||
|
||||
bool operator==(filter_cache_entry const & other) const {
|
||||
if (m_d != other.m_d)
|
||||
return false;
|
||||
if (m_ctx_size != other.m_ctx_size)
|
||||
return false;
|
||||
for (unsigned i = 0; i < m_ctx_size; i++)
|
||||
if (m_ctx[i] != other.m_ctx[i])
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
typedef obj_hashtable<filter_cache_entry> imdd_mk_filter_cache;
|
||||
|
||||
typedef obj_ref<imdd, imdd_manager> imdd_ref;
|
||||
|
||||
class imdd_manager {
|
||||
typedef imdd_children::entry entry;
|
||||
small_object_allocator m_alloc;
|
||||
id_gen m_id_gen;
|
||||
vector<imdd_table> m_tables; // we keep a table for each height.
|
||||
sl_imdd_manager m_sl_manager;
|
||||
unsigned m_simple_max_entries; //!< maximum number of entries in a "simple" node.
|
||||
bool m_delay_dealloc;
|
||||
ptr_vector<imdd> m_to_delete; //!< list of IMDDs marked as dead. These IMDDs may still be in cache tables.
|
||||
|
||||
// generic cache and todo-lists
|
||||
ptr_vector<imdd> m_worklist;
|
||||
imdd_cache m_visited;
|
||||
|
||||
void mark_as_dead(imdd * d);
|
||||
void deallocate_imdd(imdd * d);
|
||||
void delete_imdd(imdd * d);
|
||||
|
||||
class delay_dealloc;
|
||||
friend class delay_dealloc;
|
||||
|
||||
class delay_dealloc {
|
||||
imdd_manager & m_manager;
|
||||
bool m_delay_dealloc_value;
|
||||
unsigned m_to_delete_size;
|
||||
public:
|
||||
delay_dealloc(imdd_manager & m):
|
||||
m_manager(m),
|
||||
m_delay_dealloc_value(m_manager.m_delay_dealloc),
|
||||
m_to_delete_size(m_manager.m_to_delete.size()) {
|
||||
m_manager.m_delay_dealloc = true;
|
||||
}
|
||||
~delay_dealloc();
|
||||
};
|
||||
|
||||
bool is_simple_node(imdd * d) const;
|
||||
|
||||
void add_child(imdd * d, unsigned lower, unsigned upper, imdd * child) {
|
||||
d->m_children.insert(m_sl_manager, lower, upper, child);
|
||||
}
|
||||
|
||||
void add_child(imdd * d, unsigned value, imdd * child) {
|
||||
add_child(d, value, value, child);
|
||||
}
|
||||
|
||||
void remove_child(imdd * d, unsigned lower, unsigned upper) {
|
||||
d->m_children.remove(m_sl_manager, lower, upper);
|
||||
}
|
||||
|
||||
imdd * copy_main(imdd * d);
|
||||
|
||||
imdd * insert_main(imdd * d, unsigned b, unsigned e, bool destructive, bool memoize_res);
|
||||
|
||||
imdd * remove_main(imdd * d, unsigned b, unsigned e, bool destructive, bool memoize_res);
|
||||
|
||||
imdd2imdd_cache m_mk_product_cache;
|
||||
struct null2imdd_proc;
|
||||
struct mk_product_proc;
|
||||
friend struct mk_product_proc;
|
||||
imdd * mk_product_core(imdd * d1, imdd * d2, bool destructive, bool memoize);
|
||||
imdd * mk_product_main(imdd * d1, imdd * d2, bool destructive, bool memoize_res);
|
||||
|
||||
imdd2imdd_cache m_add_facts_cache;
|
||||
ptr_vector<imdd> m_add_facts_new_children;
|
||||
void init_add_facts_new_children(unsigned num, unsigned const * lowers, unsigned const * uppers, bool memoize_res);
|
||||
imdd * add_facts_core(imdd * d, unsigned num, unsigned const * lowers, unsigned const * uppers, bool destructive, bool memoize_res);
|
||||
imdd * add_facts_main(imdd * d, unsigned num, unsigned const * lowers, unsigned const * uppers, bool destructive, bool memoize_res);
|
||||
|
||||
imdd2imdd_cache m_remove_facts_cache;
|
||||
imdd * remove_facts_core(imdd * d, unsigned num, unsigned const * lowers, unsigned const * uppers, bool destructive, bool memoize_res);
|
||||
imdd * remove_facts_main(imdd * d, unsigned num, unsigned const * lowers, unsigned const * uppers, bool destructive, bool memoize_res);
|
||||
|
||||
|
||||
imdd2imdd_cache m_defrag_cache;
|
||||
imdd * defrag_core(imdd * d);
|
||||
|
||||
imdd_pair2imdd_cache m_union_cache;
|
||||
void push_back_entries(unsigned head, imdd_children::iterator & it, imdd_children::iterator & end,
|
||||
imdd_children::push_back_proc & push_back, bool & children_memoized);
|
||||
void push_back_upto(unsigned & head, imdd_children::iterator & it, imdd_children::iterator & end, unsigned limit,
|
||||
imdd_children::push_back_proc & push_back, bool & children_memoized);
|
||||
void move_head(unsigned & head, imdd_children::iterator & it, imdd_children::iterator & end, unsigned new_head);
|
||||
void copy_upto(unsigned & head, imdd_children::iterator & it, imdd_children::iterator & end, unsigned limit, sbuffer<entry> & result);
|
||||
void reset_union_cache();
|
||||
imdd * mk_union_core(imdd * d1, imdd * d2, bool destructive, bool memoize_res);
|
||||
imdd * mk_union_main(imdd * d1, imdd * d2, bool destructive, bool memoize_res);
|
||||
void mk_union_core_dupdt(imdd_ref & d1, imdd * d2, bool memoize_res);
|
||||
void mk_union_core(imdd * d1, imdd * d2, imdd_ref & r, bool memoize_res);
|
||||
|
||||
imdd_pair2bool_cache m_is_equal_cache;
|
||||
bool is_equal_core(imdd * d1, imdd * d2);
|
||||
|
||||
imdd_pair2bool_cache m_subsumes_cache;
|
||||
bool subsumes_core(imdd * d1, imdd * d2);
|
||||
|
||||
imdd2imdd_cache m_complement_cache;
|
||||
imdd * mk_complement_core(imdd * d, unsigned num, unsigned const * mins, unsigned const * maxs, bool destructive, bool memoize_res);
|
||||
imdd * mk_complement_main(imdd * d, unsigned num, unsigned const * mins, unsigned const * maxs, bool destructive, bool memoize_res);
|
||||
|
||||
imdd2imdd_cache m_filter_equal_cache;
|
||||
imdd * mk_filter_equal_core(imdd * d, unsigned vidx, unsigned value, bool destructive, bool memoize_res);
|
||||
imdd * mk_filter_equal_main(imdd * d, unsigned vidx, unsigned value, bool destructive, bool memoize_res);
|
||||
|
||||
|
||||
// original
|
||||
imdd2intervals m_imdd2interval_set;
|
||||
ptr_vector<sl_interval_set> m_alloc_is;
|
||||
typedef sl_manager_base<unsigned> sl_imanager;
|
||||
void reset_fi_intervals(sl_imanager& m);
|
||||
sl_interval_set const* init_fi_intervals(sl_imanager& m, imdd* d, unsigned var, unsigned num_found);
|
||||
|
||||
imdd2imdd_cache m_fi_top_cache;
|
||||
imdd_fi_cache m_fi_bottom_cache;
|
||||
unsigned m_fi_num_vars;
|
||||
unsigned * m_fi_begin_vars;
|
||||
unsigned * m_fi_end_vars;
|
||||
region m_fi_entries;
|
||||
bool is_fi_var(unsigned v) const { return std::find(m_fi_begin_vars, m_fi_end_vars, v) != m_fi_end_vars; }
|
||||
fi_cache_entry * mk_fi_cache_entry(imdd * d, unsigned lower, unsigned upper, unsigned num_pairs, imdd_value_pair pairs[]);
|
||||
mk_fi_result mk_filter_identical_core(imdd * d, unsigned offset, unsigned num_found, unsigned lower, unsigned upper,
|
||||
bool destructive, bool memoize_res);
|
||||
imdd * mk_filter_identical_main(imdd * d, unsigned num_vars, unsigned * vars, bool destructive, bool memoize_res);
|
||||
|
||||
// v2
|
||||
obj_map<imdd, imdd*> m_filter_identical_cache;
|
||||
void filter_identical_core2(imdd* d, unsigned num_vars, unsigned b, unsigned e, ptr_vector<imdd>& ch);
|
||||
imdd* filter_identical_core2(imdd* d, unsigned var, unsigned num_vars, bool memoize_res);
|
||||
void filter_identical_main2(imdd * d, imdd_ref& r, unsigned num_vars, unsigned * vars, bool destructive, bool memoize_res);
|
||||
void swap_in(imdd * d, imdd_ref& r, unsigned num_vars, unsigned * vars);
|
||||
void swap_out(imdd * d, imdd_ref& r, unsigned num_vars, unsigned * vars);
|
||||
|
||||
// v3
|
||||
struct interval {
|
||||
unsigned m_lo;
|
||||
unsigned m_hi;
|
||||
interval(unsigned lo, unsigned hi): m_lo(lo), m_hi(hi) {}
|
||||
};
|
||||
struct interval_dd : public interval {
|
||||
imdd* m_dd;
|
||||
interval_dd(unsigned lo, unsigned hi, imdd* d): interval(lo, hi), m_dd(d) {}
|
||||
};
|
||||
template<typename I>
|
||||
class id_map {
|
||||
unsigned m_T;
|
||||
unsigned_vector m_Ts;
|
||||
svector<svector<I>*> m_vecs;
|
||||
unsigned_vector m_alloc;
|
||||
unsigned m_first_free;
|
||||
void hard_reset() {
|
||||
std::for_each(m_vecs.begin(), m_vecs.end(), delete_proc<svector<I> >());
|
||||
m_alloc.reset();
|
||||
m_first_free = 0;
|
||||
m_vecs.reset();
|
||||
m_Ts.reset();
|
||||
m_T = 0;
|
||||
}
|
||||
|
||||
void allocate_entry(unsigned id) {
|
||||
if (m_vecs[id]) {
|
||||
return;
|
||||
}
|
||||
while (m_first_free < m_alloc.size()) {
|
||||
if (m_vecs[m_first_free] && m_Ts[m_first_free] < m_T) {
|
||||
svector<I>* v = m_vecs[m_first_free];
|
||||
m_vecs[m_first_free] = 0;
|
||||
m_vecs[id] = v;
|
||||
++m_first_free;
|
||||
return;
|
||||
}
|
||||
++m_first_free;
|
||||
}
|
||||
m_vecs[id] = alloc(svector<I>);
|
||||
m_alloc.push_back(id);
|
||||
}
|
||||
public:
|
||||
id_map():m_T(0) {}
|
||||
~id_map() { hard_reset(); }
|
||||
void reset() { ++m_T; m_first_free = 0; if (m_T == UINT_MAX) hard_reset(); }
|
||||
svector<I>& init(imdd* d) {
|
||||
unsigned id = d->get_id();
|
||||
if (id >= m_vecs.size()) {
|
||||
m_vecs.resize(id+1);
|
||||
m_Ts.resize(id+1);
|
||||
}
|
||||
if (m_Ts[id] < m_T) {
|
||||
allocate_entry(id);
|
||||
m_vecs[id]->reset();
|
||||
m_Ts[id] = m_T;
|
||||
}
|
||||
return *m_vecs[id];
|
||||
}
|
||||
|
||||
typedef svector<I> data;
|
||||
struct iterator {
|
||||
unsigned m_offset;
|
||||
id_map const& m;
|
||||
iterator(unsigned o, id_map const& m):m_offset(o),m(m) {}
|
||||
data const & operator*() const { return *m.m_vecs[m_offset]; }
|
||||
data const * operator->() const { return &(operator*()); }
|
||||
data * operator->() { return &(operator*()); }
|
||||
iterator & operator++() { ++m_offset; return move_to_used(); }
|
||||
iterator operator++(int) { iterator tmp = *this; ++*this; return tmp; }
|
||||
bool operator==(iterator const & it) const { return m_offset == it.m_offset; }
|
||||
bool operator!=(iterator const & it) const { return m_offset != it.m_offset; }
|
||||
iterator & move_to_used() {
|
||||
while (m_offset < m.m_vecs.size() &&
|
||||
m.m_Ts[m_offset] < m.m_T) {
|
||||
++m_offset;
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
};
|
||||
iterator begin() const { return iterator(0, *this).move_to_used(); }
|
||||
iterator end() const { return iterator(m_vecs.size(), *this); }
|
||||
};
|
||||
typedef id_map<interval > filter_id_map;
|
||||
typedef id_map<interval_dd > filter_idd_map;
|
||||
filter_id_map m_nodes;
|
||||
filter_idd_map m_nodes_dd;
|
||||
svector<interval_dd> m_i_nodes_dd, m_i_nodes_dd_tmp;
|
||||
svector<interval> m_i_nodes, m_i_nodes_tmp;
|
||||
unsigned_vector m_offsets;
|
||||
void filter_identical_main3(imdd * d, imdd_ref& r, unsigned num_vars, unsigned * vars, bool destructive, bool memoize_res);
|
||||
void filter_identical_main3(imdd * d, imdd_ref& r, unsigned v1, bool del1, unsigned v2, bool del2, bool memoize_res);
|
||||
imdd* filter_identical_loop3(imdd * d, unsigned v1, bool del1, unsigned v2, bool del2, bool memoize_res);
|
||||
void refine_intervals(svector<interval>& i_nodes, svector<interval_dd> const& i_nodes_dd);
|
||||
void merge_intervals(svector<interval>& dst, svector<interval> const& src);
|
||||
imdd* filter_identical_mk_nodes(imdd* d, unsigned v, bool del1, bool del2, bool memoize_res);
|
||||
void print_filter_idd(std::ostream& out, filter_idd_map const& m);
|
||||
void print_interval_dd(std::ostream& out, svector<interval_dd> const& m);
|
||||
|
||||
|
||||
|
||||
unsigned m_proj_num_vars;
|
||||
unsigned * m_proj_begin_vars;
|
||||
unsigned * m_proj_end_vars;
|
||||
imdd2imdd_cache m_proj_cache;
|
||||
bool is_proj_var(unsigned v) const { return std::find(m_proj_begin_vars, m_proj_end_vars, v) != m_proj_end_vars; }
|
||||
void mk_project_init(unsigned num_vars, unsigned * vars);
|
||||
void mk_project_core(imdd * d, imdd_ref & r, unsigned var, unsigned num_found, bool memoize_res);
|
||||
void mk_project_dupdt_core(imdd_ref & d, unsigned var, unsigned num_found, bool memoize_res);
|
||||
|
||||
imdd2imdd_cache m_swap_cache;
|
||||
imdd * m_swap_new_child;
|
||||
bool m_swap_granchildren_memoized;
|
||||
imdd * mk_swap_new_child(unsigned lower, unsigned upper, imdd * child);
|
||||
void mk_swap_acc1_dupdt(imdd_ref & d, unsigned lower, unsigned upper, imdd * grandchild, bool memoize_res);
|
||||
void mk_swap_acc1(imdd * d, imdd_ref & r, unsigned lower, unsigned upper, imdd * grandchild, bool memoize_res);
|
||||
void mk_swap_acc2(imdd_ref & r, unsigned lower1, unsigned upper1, unsigned lower2, unsigned upper2, imdd * grandchild, bool memoize_res);
|
||||
void mk_swap_top_vars(imdd * d, imdd_ref & r, bool memoize_res);
|
||||
imdd * mk_swap_memoize(imdd * d);
|
||||
void mk_swap_core(imdd * d, imdd_ref & r, unsigned vidx, bool memoize_res);
|
||||
void mk_swap_dupdt_core(imdd_ref & d, unsigned vidx, bool memoize_res);
|
||||
|
||||
imdd2imdd_cache m_add_bounded_var_cache;
|
||||
imdd * add_bounded_var_core(imdd * d, unsigned before_vidx, unsigned lower, unsigned upper, bool destructive, bool memoize_res);
|
||||
imdd * add_bounded_var_main(imdd * d, unsigned before_vidx, unsigned lower, unsigned upper, bool destructive, bool memoize_res);
|
||||
|
||||
friend struct distinct_proc;
|
||||
imdd * mk_distinct_imdd(unsigned l1, unsigned u1, unsigned l2, unsigned u2, imdd * d, bool memoize_res = true);
|
||||
|
||||
imdd_mk_filter_cache m_filter_cache;
|
||||
region m_filter_entries;
|
||||
unsigned m_filter_num_vars;
|
||||
unsigned * m_filter_begin_vars;
|
||||
unsigned * m_filter_end_vars;
|
||||
unsigned_vector m_filter_context;
|
||||
bool is_filter_var(unsigned v) const { return std::find(m_filter_begin_vars, m_filter_end_vars, v) != m_filter_end_vars; }
|
||||
filter_cache_entry * mk_filter_cache_entry(imdd * d, unsigned ctx_sz, unsigned * ctx, imdd * r);
|
||||
imdd * is_mk_filter_cached(imdd * d, unsigned ctx_sz, unsigned * ctx);
|
||||
void cache_mk_filter(imdd * d, unsigned ctx_sz, unsigned * ctx, imdd * r);
|
||||
void init_mk_filter(unsigned arity, unsigned num_vars, unsigned * vars);
|
||||
template<typename FilterProc>
|
||||
void mk_filter_dupdt_core(imdd_ref & d, unsigned vidx, unsigned num_found, FilterProc & proc, bool memoize_res);
|
||||
template<typename FilterProc>
|
||||
void mk_filter_core(imdd * d, imdd_ref & r, unsigned vidx, unsigned num_found, FilterProc & proc, bool memoize_res);
|
||||
/**
|
||||
\brief Filter the elements of the given IMDD using the given filter.
|
||||
|
||||
The FilterProc template parameter is a filter for computing subsets of sets of the form:
|
||||
|
||||
[L_1, U_1] X [L_2, U_2] X ... X [L_n, U_n] X d (where d is an IMDD)
|
||||
|
||||
where n == num_vars
|
||||
|
||||
The subset of elements is returned as an IMDD.
|
||||
|
||||
FilterProc must have a method of the form:
|
||||
|
||||
void operator()(unsigned * lowers_uppers, imdd * d, imdd_ref & r, bool memoize_res);
|
||||
|
||||
The size of the array lowers_uppers is 2*num_vars
|
||||
|
||||
The arity of the resultant IMDD must be num_vars + d->get_arity().
|
||||
*/
|
||||
template<typename FilterProc>
|
||||
void mk_filter_dupdt(imdd_ref & d, unsigned num_vars, unsigned * vars, FilterProc & proc, bool memoize_res = true);
|
||||
template<typename FilterProc>
|
||||
void mk_filter(imdd * d, imdd_ref & r, unsigned num_vars, unsigned * vars, FilterProc & proc, bool memoize_res = true);
|
||||
|
||||
imdd * mk_disequal_imdd(unsigned l1, unsigned u1, unsigned value, imdd * d, bool memoize_res);
|
||||
friend struct disequal_proc;
|
||||
|
||||
public:
|
||||
imdd_manager();
|
||||
|
||||
void inc_ref(imdd * d) {
|
||||
if (d)
|
||||
d->inc_ref();
|
||||
}
|
||||
|
||||
void dec_ref(imdd * d) {
|
||||
if (d) {
|
||||
d->dec_ref();
|
||||
if (d->get_ref_count() == 0)
|
||||
delete_imdd(d);
|
||||
}
|
||||
}
|
||||
|
||||
unsigned get_num_nodes(imdd const * d) const;
|
||||
|
||||
// count number of keys (rows) in table as if table is uncompressed.
|
||||
size_t get_num_rows(imdd const* d) const;
|
||||
|
||||
unsigned memory(imdd const * d) const;
|
||||
|
||||
private:
|
||||
imdd * _mk_empty(unsigned arity);
|
||||
|
||||
public:
|
||||
imdd * mk_empty(unsigned arity) {
|
||||
imdd * r = _mk_empty(arity);
|
||||
STRACE("imdd_trace", tout << "mk_empty(" << arity << ", 0x" << r << ");\n";);
|
||||
return r;
|
||||
}
|
||||
|
||||
private:
|
||||
imdd * memoize(imdd * d);
|
||||
|
||||
public:
|
||||
void memoize(imdd_ref const & d, imdd_ref & r) { r = memoize(d.get()); }
|
||||
|
||||
void memoize(imdd_ref & d) { d = memoize(d.get()); }
|
||||
|
||||
imdd * memoize_new_imdd_if(bool cond, imdd * r) {
|
||||
if (cond && is_simple_node(r)) {
|
||||
SASSERT(!r->is_shared());
|
||||
imdd * can_r = memoize(r);
|
||||
if (can_r != r) {
|
||||
SASSERT(r->get_ref_count() == 0);
|
||||
delete_imdd(r);
|
||||
}
|
||||
return can_r;
|
||||
}
|
||||
return r;
|
||||
}
|
||||
|
||||
public:
|
||||
void defrag(imdd_ref & d);
|
||||
|
||||
void unmemoize(imdd * d);
|
||||
|
||||
void unmemoize_rec(imdd * d);
|
||||
|
||||
void copy(imdd * d, imdd_ref & r) { r = copy_main(d); }
|
||||
|
||||
void insert_dupdt(imdd_ref & d, unsigned b, unsigned e, bool memoize_res = true) {
|
||||
d = insert_main(d, b, e, true, memoize_res);
|
||||
}
|
||||
|
||||
void insert(imdd * d, imdd_ref & r, unsigned b, unsigned e, bool memoize_res = true) {
|
||||
r = insert_main(d, b, e, false, memoize_res);
|
||||
}
|
||||
|
||||
void mk_product_dupdt(imdd_ref & d1, imdd * d2, bool memoize_res = true) {
|
||||
d1 = mk_product_main(d1.get(), d2, true, memoize_res);
|
||||
}
|
||||
|
||||
void mk_product(imdd * d1, imdd * d2, imdd_ref & r, bool memoize_res = true) {
|
||||
r = mk_product_main(d1, d2, false, memoize_res);
|
||||
STRACE("imdd_trace", tout << "mk_product(0x" << d1 << ", 0x" << d2 << ", 0x" << r.get() << ", " << memoize_res << ");\n";);
|
||||
}
|
||||
|
||||
void mk_union_dupdt(imdd_ref & d1, imdd * d2, bool memoize_res = true) {
|
||||
d1 = mk_union_main(d1.get(), d2, true, memoize_res);
|
||||
}
|
||||
|
||||
void mk_union(imdd * d1, imdd * d2, imdd_ref & r, bool memoize_res = true) {
|
||||
r = mk_union_main(d1, d2, false, memoize_res);
|
||||
STRACE("imdd_trace", tout << "mk_union(0x" << d1 << ", 0x" << d2 << ", 0x" << r.get() << ", " << memoize_res << ");\n";);
|
||||
}
|
||||
|
||||
void mk_complement_dupdt(imdd_ref & d, unsigned num, unsigned const * mins, unsigned const * maxs, bool memoize_res = true) {
|
||||
d = mk_complement_main(d, num, mins, maxs, true, memoize_res);
|
||||
}
|
||||
|
||||
void mk_complement(imdd * d, imdd_ref & r, unsigned num, unsigned const * mins, unsigned const * maxs, bool memoize_res = true) {
|
||||
r = mk_complement_main(d, num, mins, maxs, false, memoize_res);
|
||||
|
||||
STRACE("imdd_trace", tout << "mk_complement(0x" << d << ", 0x" << r.get() << ", ";
|
||||
for (unsigned i = 0; i < num; i++) tout << mins[i] << ", " << maxs[i] << ", ";
|
||||
tout << memoize_res << ");\n";);
|
||||
}
|
||||
|
||||
void mk_filter_equal_dupdt(imdd_ref & d, unsigned vidx, unsigned value, bool memoize_res = true) {
|
||||
d = mk_filter_equal_main(d, vidx, value, true, memoize_res);
|
||||
}
|
||||
|
||||
void mk_filter_equal(imdd * d, imdd_ref & r, unsigned vidx, unsigned value, bool memoize_res = true) {
|
||||
r = mk_filter_equal_main(d, vidx, value, false, memoize_res);
|
||||
|
||||
STRACE("imdd_trace", tout << "mk_filter_equal(0x" << d << ", 0x" << r.get() << ", " << vidx << ", " << value << ", " << memoize_res << ");\n";);
|
||||
}
|
||||
|
||||
void mk_filter_identical_dupdt(imdd_ref & d, unsigned num_vars, unsigned * vars, bool memoize_res = true) {
|
||||
// d = mk_filter_identical_main(d, num_vars, vars, true, memoize_res);
|
||||
filter_identical_main3(d, d, num_vars, vars, true, memoize_res);
|
||||
}
|
||||
|
||||
void mk_filter_identical(imdd * d, imdd_ref & r, unsigned num_vars, unsigned * vars, bool memoize_res = true) {
|
||||
filter_identical_main3(d, r, num_vars, vars, false, memoize_res);
|
||||
|
||||
STRACE("imdd_trace", tout << "mk_filter_identical(0x" << d << ", 0x" << r.get() << ", ";
|
||||
for (unsigned i = 0; i < num_vars; i++) tout << vars[i] << ", ";
|
||||
tout << memoize_res << ");\n";);
|
||||
}
|
||||
|
||||
void mk_project_dupdt(imdd_ref & d, unsigned num_vars, unsigned * vars, bool memoize_res = true);
|
||||
|
||||
void mk_project(imdd * d, imdd_ref & r, unsigned num_vars, unsigned * vars, bool memoize_res = true);
|
||||
|
||||
// swap vidx and vidx+1
|
||||
void mk_swap_dupdt(imdd_ref & d, unsigned vidx, bool memoize_res = true);
|
||||
|
||||
// swap vidx and vidx+1
|
||||
void mk_swap(imdd * d, imdd_ref & r, unsigned vidx, bool memoize_res = true);
|
||||
|
||||
void add_facts_dupdt(imdd_ref & d, unsigned num, unsigned const * lowers, unsigned const * uppers, bool memoize_res = true) {
|
||||
d = add_facts_main(d, num, lowers, uppers, true, memoize_res);
|
||||
}
|
||||
|
||||
void add_facts(imdd * d, imdd_ref & r, unsigned num, unsigned const * lowers, unsigned const * uppers, bool memoize_res = true) {
|
||||
r = add_facts_main(d, num, lowers, uppers, false, memoize_res);
|
||||
|
||||
STRACE("imdd_trace", tout << "add_facts(0x" << d << ", 0x" << r.get() << ", ";
|
||||
for (unsigned i = 0; i < num; i++) tout << lowers[i] << ", " << uppers[i] << ", ";
|
||||
tout << memoize_res << ");\n";);
|
||||
}
|
||||
|
||||
void add_fact_dupdt(imdd_ref & d, unsigned num, unsigned const * values, bool memoize_res = true) {
|
||||
add_facts_dupdt(d, num, values, values, memoize_res);
|
||||
}
|
||||
|
||||
void add_fact(imdd * d, imdd_ref & r, unsigned num, unsigned const * values, bool memoize_res = true) {
|
||||
add_facts(d, r, num, values, values, memoize_res);
|
||||
}
|
||||
|
||||
void add_bounded_var_dupdt(imdd_ref & d, unsigned before_vidx, unsigned lower, unsigned upper, bool memoize_res = true) {
|
||||
d = add_bounded_var_main(d, before_vidx, lower, upper, true, memoize_res);
|
||||
}
|
||||
|
||||
void add_bounded_var(imdd * d, imdd_ref & r, unsigned before_vidx, unsigned lower, unsigned upper, bool memoize_res = true) {
|
||||
r = add_bounded_var_main(d, before_vidx, lower, upper, false, memoize_res);
|
||||
}
|
||||
|
||||
void mk_filter_distinct_dupdt(imdd_ref & d, unsigned v1, unsigned v2, bool memoize_res = true);
|
||||
|
||||
void mk_filter_distinct(imdd * d, imdd_ref & r, unsigned v1, unsigned v2, bool memoize_res = true);
|
||||
|
||||
void mk_filter_disequal_dupdt(imdd_ref & d, unsigned var, unsigned value, bool memoize_res = true);
|
||||
|
||||
void mk_filter_disequal(imdd * d, imdd_ref & r, unsigned var, unsigned value, bool memoize_res = true);
|
||||
|
||||
void mk_join(imdd * d1, imdd * d2, imdd_ref & r, unsigned_vector const& vars1, unsigned_vector const& vars2, bool memoize_res = true);
|
||||
|
||||
void mk_join_project(imdd * d1, imdd * d2, imdd_ref & r,
|
||||
unsigned_vector const& vars1, unsigned_vector const& vars2,
|
||||
unsigned_vector const& proj_vars, bool memoize_res = true);
|
||||
|
||||
void mk_join_dupdt(imdd_ref & d1, imdd * d2, unsigned num_vars, unsigned const * vars1, unsigned const * vars2, bool memoize_res = true);
|
||||
|
||||
void remove_facts_dupdt(imdd_ref & d, unsigned num, unsigned const * lowers, unsigned const * uppers);
|
||||
|
||||
void remove_facts(imdd * d, imdd_ref & r, unsigned num, unsigned const * lowers, unsigned const * uppers);
|
||||
|
||||
bool is_equal(imdd * d1, imdd * d2);
|
||||
|
||||
bool contains(imdd * d, unsigned num, unsigned const * values) const;
|
||||
|
||||
bool contains(imdd * d, unsigned v) const { return contains(d, 1, &v); }
|
||||
|
||||
bool contains(imdd * d, unsigned v1, unsigned v2) const { unsigned vs[2] = {v1, v2}; return contains(d, 2, vs); }
|
||||
|
||||
bool contains(imdd * d, unsigned v1, unsigned v2, unsigned v3) const { unsigned vs[3] = {v1,v2,v3}; return contains(d, 3, vs); }
|
||||
|
||||
bool subsumes(imdd * d1, imdd * d2);
|
||||
|
||||
bool is_subset(imdd * d1, imdd * d2) { return subsumes(d2, d1); }
|
||||
|
||||
private:
|
||||
void display(std::ostream & out, imdd const * d, unsigned_vector & intervals, bool & first) const;
|
||||
|
||||
public:
|
||||
void display(std::ostream & out, imdd const * d) const;
|
||||
|
||||
void display_ll(std::ostream & out, imdd const * d) const;
|
||||
|
||||
/**
|
||||
\brief Execute proc (once) in each node in the IMDD rooted by d.
|
||||
*/
|
||||
template<typename Proc>
|
||||
void for_each(imdd * d, Proc & proc) const {
|
||||
// for_each is a generic procedure, we don't know what proc will actually do.
|
||||
// So, it is not safe to reuse m_worklist and m_visited.
|
||||
ptr_buffer<imdd,128> worklist;
|
||||
imdd_cache visited;
|
||||
worklist.push_back(d);
|
||||
while (!worklist.empty()) {
|
||||
d = worklist.back();
|
||||
worklist.pop_back();
|
||||
if (d->is_shared() && visited.contains(d))
|
||||
continue;
|
||||
if (d->is_shared())
|
||||
visited.insert(d);
|
||||
proc(d);
|
||||
if (d->get_arity() > 1) {
|
||||
imdd_children::iterator it = d->begin_children();
|
||||
imdd_children::iterator end = d->end_children();
|
||||
for (; it != end; ++it)
|
||||
worklist.push_back(it->val());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class iterator {
|
||||
bool m_done;
|
||||
svector<imdd_children::iterator> m_iterators;
|
||||
svector<unsigned> m_element;
|
||||
|
||||
void begin_iterators(imdd const * curr, unsigned start_idx);
|
||||
|
||||
public:
|
||||
iterator():m_done(true) {}
|
||||
iterator(imdd_manager const & m, imdd const * d);
|
||||
|
||||
unsigned get_arity() const { return m_element.size(); }
|
||||
unsigned * operator*() const { return m_element.c_ptr(); }
|
||||
iterator & operator++();
|
||||
|
||||
bool operator==(iterator const & it) const;
|
||||
bool operator!=(iterator const & it) const { return !operator==(it); }
|
||||
};
|
||||
|
||||
friend class iterator;
|
||||
|
||||
iterator begin(imdd const * d) const { return iterator(*this, d); }
|
||||
iterator end(imdd const * d) const { return iterator(); }
|
||||
};
|
||||
|
||||
inline std::ostream & operator<<(std::ostream & out, imdd_ref const & r) {
|
||||
r.get_manager().display(out, r.get());
|
||||
return out;
|
||||
}
|
||||
|
||||
struct mk_imdd_pp {
|
||||
imdd * m_d;
|
||||
imdd_manager & m_manager;
|
||||
mk_imdd_pp(imdd * d, imdd_manager & m):m_d(d), m_manager(m) {}
|
||||
};
|
||||
|
||||
inline mk_imdd_pp mk_pp(imdd * d, imdd_manager & m) {
|
||||
return mk_imdd_pp(d, m);
|
||||
}
|
||||
|
||||
inline std::ostream & operator<<(std::ostream & out, mk_imdd_pp const & pp) {
|
||||
pp.m_manager.display(out, pp.m_d);
|
||||
return out;
|
||||
}
|
||||
|
||||
struct mk_imdd_ll_pp : public mk_imdd_pp {
|
||||
mk_imdd_ll_pp(imdd * d, imdd_manager & m):mk_imdd_pp(d, m) {}
|
||||
};
|
||||
|
||||
inline mk_imdd_ll_pp mk_ll_pp(imdd * d, imdd_manager & m) {
|
||||
return mk_imdd_ll_pp(d, m);
|
||||
}
|
||||
|
||||
inline std::ostream & operator<<(std::ostream & out, mk_imdd_ll_pp const & pp) {
|
||||
pp.m_manager.display_ll(out, pp.m_d);
|
||||
return out;
|
||||
}
|
||||
|
||||
#endif /* _IMDD_H_ */
|
||||
|
|
@ -1,353 +0,0 @@
|
|||
/*++
|
||||
Copyright (c) 2012 Microsoft Corporation
|
||||
|
||||
Module Name:
|
||||
|
||||
interval.h
|
||||
|
||||
Abstract:
|
||||
|
||||
Goodies/Templates for interval arithmetic
|
||||
|
||||
Author:
|
||||
|
||||
Leonardo de Moura (leonardo) 2012-07-19.
|
||||
|
||||
Revision History:
|
||||
|
||||
--*/
|
||||
#ifndef _INTERVAL_H_
|
||||
#define _INTERVAL_H_
|
||||
|
||||
#include"mpq.h"
|
||||
#include"ext_numeral.h"
|
||||
|
||||
/**
|
||||
\brief Default configuration for interval manager.
|
||||
It is used for documenting the required interface.
|
||||
*/
|
||||
class im_default_config {
|
||||
unsynch_mpq_manager & m_manager;
|
||||
public:
|
||||
typedef unsynch_mpq_manager numeral_manager;
|
||||
typedef mpq numeral;
|
||||
|
||||
// Every configuration object must provide an interval type.
|
||||
// The actual fields are irrelevant, the interval manager
|
||||
// accesses interval data using the following API.
|
||||
struct interval {
|
||||
numeral m_lower;
|
||||
numeral m_upper;
|
||||
unsigned m_lower_open:1;
|
||||
unsigned m_upper_open:1;
|
||||
unsigned m_lower_inf:1;
|
||||
unsigned m_upper_inf:1;
|
||||
};
|
||||
|
||||
// Should be NOOPs for precise numeral types.
|
||||
// For imprecise types (e.g., floats) it should set the rounding mode.
|
||||
void round_to_minus_inf() {}
|
||||
void round_to_plus_inf() {}
|
||||
void set_rounding(bool to_plus_inf) {}
|
||||
|
||||
// Getters
|
||||
numeral const & lower(interval const & a) const { return a.m_lower; }
|
||||
numeral const & upper(interval const & a) const { return a.m_upper; }
|
||||
numeral & lower(interval & a) { return a.m_lower; }
|
||||
numeral & upper(interval & a) { return a.m_upper; }
|
||||
bool lower_is_open(interval const & a) const { return a.m_lower_open; }
|
||||
bool upper_is_open(interval const & a) const { return a.m_upper_open; }
|
||||
bool lower_is_inf(interval const & a) const { return a.m_lower_inf; }
|
||||
bool upper_is_inf(interval const & a) const { return a.m_upper_inf; }
|
||||
|
||||
// Setters
|
||||
void set_lower(interval & a, numeral const & n) { m_manager.set(a.m_lower, n); }
|
||||
void set_upper(interval & a, numeral const & n) { m_manager.set(a.m_upper, n); }
|
||||
void set_lower_is_open(interval & a, bool v) { a.m_lower_open = v; }
|
||||
void set_upper_is_open(interval & a, bool v) { a.m_upper_open = v; }
|
||||
void set_lower_is_inf(interval & a, bool v) { a.m_lower_inf = v; }
|
||||
void set_upper_is_inf(interval & a, bool v) { a.m_upper_inf = v; }
|
||||
|
||||
// Reference to numeral manager
|
||||
numeral_manager & m() const { return m_manager; }
|
||||
|
||||
im_default_config(numeral_manager & m):m_manager(m) {}
|
||||
};
|
||||
|
||||
#define DEP_IN_LOWER1 1
|
||||
#define DEP_IN_UPPER1 2
|
||||
#define DEP_IN_LOWER2 4
|
||||
#define DEP_IN_UPPER2 8
|
||||
|
||||
typedef short bound_deps;
|
||||
inline bool dep_in_lower1(bound_deps d) { return (d & DEP_IN_LOWER1) != 0; }
|
||||
inline bool dep_in_lower2(bound_deps d) { return (d & DEP_IN_LOWER2) != 0; }
|
||||
inline bool dep_in_upper1(bound_deps d) { return (d & DEP_IN_UPPER1) != 0; }
|
||||
inline bool dep_in_upper2(bound_deps d) { return (d & DEP_IN_UPPER2) != 0; }
|
||||
inline bound_deps dep1_to_dep2(bound_deps d) {
|
||||
SASSERT(!dep_in_lower2(d) && !dep_in_upper2(d));
|
||||
bound_deps r = d << 2;
|
||||
SASSERT(dep_in_lower1(d) == dep_in_lower2(r));
|
||||
SASSERT(dep_in_upper1(d) == dep_in_upper2(r));
|
||||
SASSERT(!dep_in_lower1(r) && !dep_in_upper1(r));
|
||||
return r;
|
||||
}
|
||||
|
||||
/**
|
||||
\brief Interval dependencies for unary and binary operations on intervals.
|
||||
It contains the dependencies for the output lower and upper bounds
|
||||
for the resultant interval.
|
||||
*/
|
||||
struct interval_deps {
|
||||
bound_deps m_lower_deps;
|
||||
bound_deps m_upper_deps;
|
||||
};
|
||||
|
||||
template<typename C>
|
||||
class interval_manager {
|
||||
typedef typename C::numeral_manager numeral_manager;
|
||||
typedef typename numeral_manager::numeral numeral;
|
||||
typedef typename C::interval interval;
|
||||
|
||||
C m_c;
|
||||
numeral m_result_lower;
|
||||
numeral m_result_upper;
|
||||
numeral m_mul_ad;
|
||||
numeral m_mul_bc;
|
||||
numeral m_mul_ac;
|
||||
numeral m_mul_bd;
|
||||
numeral m_one;
|
||||
numeral m_minus_one;
|
||||
numeral m_inv_k;
|
||||
|
||||
unsigned m_pi_n;
|
||||
interval m_pi_div_2;
|
||||
interval m_pi;
|
||||
interval m_3_pi_div_2;
|
||||
interval m_2_pi;
|
||||
|
||||
volatile bool m_cancel;
|
||||
|
||||
void round_to_minus_inf() { m_c.round_to_minus_inf(); }
|
||||
void round_to_plus_inf() { m_c.round_to_plus_inf(); }
|
||||
void set_rounding(bool to_plus_inf) { m_c.set_rounding(to_plus_inf); }
|
||||
|
||||
ext_numeral_kind lower_kind(interval const & a) const { return m_c.lower_is_inf(a) ? EN_MINUS_INFINITY : EN_NUMERAL; }
|
||||
ext_numeral_kind upper_kind(interval const & a) const { return m_c.upper_is_inf(a) ? EN_PLUS_INFINITY : EN_NUMERAL; }
|
||||
|
||||
void set_lower(interval & a, numeral const & n) { m_c.set_lower(a, n); }
|
||||
void set_upper(interval & a, numeral const & n) { m_c.set_upper(a, n); }
|
||||
void set_lower_is_open(interval & a, bool v) { m_c.set_lower_is_open(a, v); }
|
||||
void set_upper_is_open(interval & a, bool v) { m_c.set_upper_is_open(a, v); }
|
||||
void set_lower_is_inf(interval & a, bool v) { m_c.set_lower_is_inf(a, v); }
|
||||
void set_upper_is_inf(interval & a, bool v) { m_c.set_upper_is_inf(a, v); }
|
||||
|
||||
void nth_root_slow(numeral const & a, unsigned n, numeral const & p, numeral & lo, numeral & hi);
|
||||
void A_div_x_n(numeral const & A, numeral const & x, unsigned n, bool to_plus_inf, numeral & r);
|
||||
void rough_approx_nth_root(numeral const & a, unsigned n, numeral & o);
|
||||
void approx_nth_root(numeral const & a, unsigned n, numeral const & p, numeral & o);
|
||||
void nth_root_pos(numeral const & A, unsigned n, numeral const & p, numeral & lo, numeral & hi);
|
||||
void nth_root(numeral const & a, unsigned n, numeral const & p, numeral & lo, numeral & hi);
|
||||
|
||||
void pi_series(int x, numeral & r, bool to_plus_inf);
|
||||
void fact(unsigned n, numeral & o);
|
||||
void sine_series(numeral const & a, unsigned k, bool upper, numeral & o);
|
||||
void cosine_series(numeral const & a, unsigned k, bool upper, numeral & o);
|
||||
void e_series(unsigned k, bool upper, numeral & o);
|
||||
|
||||
void div_mul(numeral const & k, interval const & a, interval & b, bool inv_k);
|
||||
|
||||
void checkpoint();
|
||||
|
||||
public:
|
||||
interval_manager(C const & c);
|
||||
~interval_manager();
|
||||
|
||||
void set_cancel(bool f) { m_cancel = f; }
|
||||
|
||||
numeral_manager & m() const { return m_c.m(); }
|
||||
|
||||
void del(interval & a);
|
||||
|
||||
numeral const & lower(interval const & a) const { return m_c.lower(a); }
|
||||
numeral const & upper(interval const & a) const { return m_c.upper(a); }
|
||||
numeral & lower(interval & a) { return m_c.lower(a); }
|
||||
numeral & upper(interval & a) { return m_c.upper(a); }
|
||||
bool lower_is_open(interval const & a) const { return m_c.lower_is_open(a); }
|
||||
bool upper_is_open(interval const & a) const { return m_c.upper_is_open(a); }
|
||||
bool lower_is_inf(interval const & a) const { return m_c.lower_is_inf(a); }
|
||||
bool upper_is_inf(interval const & a) const { return m_c.upper_is_inf(a); }
|
||||
|
||||
bool lower_is_neg(interval const & a) const { return ::is_neg(m(), lower(a), lower_kind(a)); }
|
||||
bool lower_is_pos(interval const & a) const { return ::is_pos(m(), lower(a), lower_kind(a)); }
|
||||
bool lower_is_zero(interval const & a) const { return ::is_zero(m(), lower(a), lower_kind(a)); }
|
||||
|
||||
bool upper_is_neg(interval const & a) const { return ::is_neg(m(), upper(a), upper_kind(a)); }
|
||||
bool upper_is_pos(interval const & a) const { return ::is_pos(m(), upper(a), upper_kind(a)); }
|
||||
bool upper_is_zero(interval const & a) const { return ::is_zero(m(), upper(a), upper_kind(a)); }
|
||||
|
||||
bool is_P(interval const & n) const { return lower_is_pos(n) || lower_is_zero(n); }
|
||||
bool is_P0(interval const & n) const { return lower_is_zero(n) && !lower_is_open(n); }
|
||||
bool is_P1(interval const & n) const { return lower_is_pos(n) || (lower_is_zero(n) && lower_is_open(n)); }
|
||||
bool is_N(interval const & n) const { return upper_is_neg(n) || upper_is_zero(n); }
|
||||
bool is_N0(interval const & n) const { return upper_is_zero(n) && !upper_is_open(n); }
|
||||
bool is_N1(interval const & n) const { return upper_is_neg(n) || (upper_is_zero(n) && upper_is_open(n)); }
|
||||
bool is_M(interval const & n) const { return lower_is_neg(n) && upper_is_pos(n); }
|
||||
bool is_zero(interval const & n) const { return lower_is_zero(n) && upper_is_zero(n); }
|
||||
|
||||
void set(interval & t, interval const & s);
|
||||
|
||||
bool eq(interval const & a, interval const & b) const;
|
||||
|
||||
/**
|
||||
\brief Set lower bound to -oo.
|
||||
*/
|
||||
void reset_lower(interval & a);
|
||||
|
||||
/**
|
||||
\brief Set upper bound to +oo.
|
||||
*/
|
||||
void reset_upper(interval & a);
|
||||
|
||||
/**
|
||||
\brief Set interval to (-oo, oo)
|
||||
*/
|
||||
void reset(interval & a);
|
||||
|
||||
/**
|
||||
\brief Return true if the given interval contains 0.
|
||||
*/
|
||||
bool contains_zero(interval const & n) const;
|
||||
|
||||
/**
|
||||
\brief Return true if n contains v.
|
||||
*/
|
||||
bool contains(interval const & n, numeral const & v) const;
|
||||
|
||||
void display(std::ostream & out, interval const & n) const;
|
||||
|
||||
bool check_invariant(interval const & n) const;
|
||||
|
||||
/**
|
||||
\brief b <- -a
|
||||
*/
|
||||
void neg(interval const & a, interval & b, interval_deps & b_deps);
|
||||
void neg(interval const & a, interval & b);
|
||||
void neg_jst(interval const & a, interval_deps & b_deps);
|
||||
|
||||
/**
|
||||
\brief c <- a + b
|
||||
*/
|
||||
void add(interval const & a, interval const & b, interval & c, interval_deps & c_deps);
|
||||
void add(interval const & a, interval const & b, interval & c);
|
||||
void add_jst(interval const & a, interval const & b, interval_deps & c_deps);
|
||||
|
||||
/**
|
||||
\brief c <- a - b
|
||||
*/
|
||||
void sub(interval const & a, interval const & b, interval & c, interval_deps & c_deps);
|
||||
void sub(interval const & a, interval const & b, interval & c);
|
||||
void sub_jst(interval const & a, interval const & b, interval_deps & c_deps);
|
||||
|
||||
/**
|
||||
\brief b <- k * a
|
||||
*/
|
||||
void mul(numeral const & k, interval const & a, interval & b, interval_deps & b_deps);
|
||||
void mul(numeral const & k, interval const & a, interval & b) { div_mul(k, a, b, false); }
|
||||
void mul_jst(numeral const & k, interval const & a, interval_deps & b_deps);
|
||||
/**
|
||||
\brief b <- (n/d) * a
|
||||
*/
|
||||
void mul(int n, int d, interval const & a, interval & b);
|
||||
|
||||
/**
|
||||
\brief b <- a/k
|
||||
|
||||
\remark For imprecise numerals, this is not equivalent to
|
||||
m().inv(k)
|
||||
mul(k, a, b)
|
||||
|
||||
That is, we must invert k rounding towards +oo or -oo depending whether we
|
||||
are computing a lower or upper bound.
|
||||
*/
|
||||
void div(interval const & a, numeral const & k, interval & b, interval_deps & b_deps);
|
||||
void div(interval const & a, numeral const & k, interval & b) { div_mul(k, a, b, true); }
|
||||
void div_jst(interval const & a, numeral const & k, interval_deps & b_deps) { mul_jst(k, a, b_deps); }
|
||||
|
||||
/**
|
||||
\brief c <- a * b
|
||||
*/
|
||||
void mul(interval const & a, interval const & b, interval & c, interval_deps & c_deps);
|
||||
void mul(interval const & a, interval const & b, interval & c);
|
||||
void mul_jst(interval const & a, interval const & b, interval_deps & c_deps);
|
||||
|
||||
/**
|
||||
\brief b <- a^n
|
||||
*/
|
||||
void power(interval const & a, unsigned n, interval & b, interval_deps & b_deps);
|
||||
void power(interval const & a, unsigned n, interval & b);
|
||||
void power_jst(interval const & a, unsigned n, interval_deps & b_deps);
|
||||
|
||||
/**
|
||||
\brief b <- a^(1/n) with precision p.
|
||||
|
||||
\pre if n is even, then a must not contain negative numbers.
|
||||
*/
|
||||
void nth_root(interval const & a, unsigned n, numeral const & p, interval & b, interval_deps & b_deps);
|
||||
void nth_root(interval const & a, unsigned n, numeral const & p, interval & b);
|
||||
void nth_root_jst(interval const & a, unsigned n, numeral const & p, interval_deps & b_deps);
|
||||
|
||||
/**
|
||||
\brief Given an equation x^n = y and an interval for y, compute the solution set for x with precision p.
|
||||
|
||||
\pre if n is even, then !lower_is_neg(y)
|
||||
*/
|
||||
void xn_eq_y(interval const & y, unsigned n, numeral const & p, interval & x, interval_deps & x_deps);
|
||||
void xn_eq_y(interval const & y, unsigned n, numeral const & p, interval & x);
|
||||
void xn_eq_y_jst(interval const & y, unsigned n, numeral const & p, interval_deps & x_deps);
|
||||
|
||||
/**
|
||||
\brief b <- 1/a
|
||||
\pre !contains_zero(a)
|
||||
*/
|
||||
void inv(interval const & a, interval & b, interval_deps & b_deps);
|
||||
void inv(interval const & a, interval & b);
|
||||
void inv_jst(interval const & a, interval_deps & b_deps);
|
||||
|
||||
/**
|
||||
\brief c <- a/b
|
||||
\pre !contains_zero(b)
|
||||
\pre &a == &c (that is, c should not be an alias for a)
|
||||
*/
|
||||
void div(interval const & a, interval const & b, interval & c, interval_deps & c_deps);
|
||||
void div(interval const & a, interval const & b, interval & c);
|
||||
void div_jst(interval const & a, interval const & b, interval_deps & c_deps);
|
||||
|
||||
/**
|
||||
\brief Store in r an interval that contains the number pi.
|
||||
The size of the interval is (1/15)*(1/16^n)
|
||||
*/
|
||||
void pi(unsigned n, interval & r);
|
||||
|
||||
/**
|
||||
\brief Set the precision of the internal interval representing pi.
|
||||
*/
|
||||
void set_pi_prec(unsigned n);
|
||||
|
||||
/**
|
||||
\brief Set the precision of the internal interval representing pi to a precision of at least n.
|
||||
*/
|
||||
void set_pi_at_least_prec(unsigned n);
|
||||
|
||||
void sine(numeral const & a, unsigned k, numeral & lo, numeral & hi);
|
||||
|
||||
void cosine(numeral const & a, unsigned k, numeral & lo, numeral & hi);
|
||||
|
||||
/**
|
||||
\brief Store in r the Euler's constant e.
|
||||
The size of the interval is 4/(k+1)!
|
||||
*/
|
||||
void e(unsigned k, interval & r);
|
||||
};
|
||||
|
||||
#endif
|
File diff suppressed because it is too large
Load diff
File diff suppressed because it is too large
Load diff
|
@ -1,642 +0,0 @@
|
|||
/*++
|
||||
Copyright (c) 2006 Microsoft Corporation
|
||||
|
||||
Module Name:
|
||||
|
||||
old_interval.cpp
|
||||
|
||||
Abstract:
|
||||
|
||||
<abstract>
|
||||
|
||||
Author:
|
||||
|
||||
Leonardo de Moura (leonardo) 2008-12-09.
|
||||
|
||||
Revision History:
|
||||
|
||||
--*/
|
||||
|
||||
#include"old_interval.h"
|
||||
|
||||
void ext_numeral::neg() {
|
||||
switch (m_kind) {
|
||||
case MINUS_INFINITY: m_kind = PLUS_INFINITY; break;
|
||||
case FINITE: m_value.neg(); break;
|
||||
case PLUS_INFINITY: m_kind = MINUS_INFINITY; break;
|
||||
}
|
||||
}
|
||||
|
||||
ext_numeral & ext_numeral::operator+=(ext_numeral const & other) {
|
||||
SASSERT(!is_infinite() || !other.is_infinite() || m_kind == other.m_kind);
|
||||
if (is_infinite())
|
||||
return *this;
|
||||
SASSERT(m_kind == FINITE);
|
||||
switch (other.m_kind) {
|
||||
case MINUS_INFINITY:
|
||||
m_kind = MINUS_INFINITY;
|
||||
m_value.reset();
|
||||
return *this;
|
||||
case FINITE:
|
||||
m_value += other.m_value;
|
||||
return *this;
|
||||
case PLUS_INFINITY:
|
||||
m_kind = PLUS_INFINITY;
|
||||
m_value.reset();
|
||||
return *this;
|
||||
}
|
||||
UNREACHABLE();
|
||||
return *this;
|
||||
}
|
||||
|
||||
ext_numeral & ext_numeral::operator-=(ext_numeral const & other) {
|
||||
SASSERT(!is_infinite() || !other.is_infinite() || (m_kind != other.m_kind));
|
||||
if (is_infinite())
|
||||
return *this;
|
||||
SASSERT(m_kind == FINITE);
|
||||
switch (other.m_kind) {
|
||||
case MINUS_INFINITY:
|
||||
m_kind = PLUS_INFINITY;
|
||||
m_value.reset();
|
||||
return *this;
|
||||
case FINITE:
|
||||
m_value -= other.m_value;
|
||||
return *this;
|
||||
case PLUS_INFINITY:
|
||||
m_kind = MINUS_INFINITY;
|
||||
m_value.reset();
|
||||
return *this;
|
||||
}
|
||||
UNREACHABLE();
|
||||
return *this;
|
||||
}
|
||||
|
||||
ext_numeral & ext_numeral::operator*=(ext_numeral const & other) {
|
||||
if (is_zero() || other.is_zero()) {
|
||||
m_kind = FINITE;
|
||||
m_value.reset();
|
||||
return *this;
|
||||
}
|
||||
|
||||
if (is_infinite() || other.is_infinite()) {
|
||||
if (sign() == other.sign())
|
||||
m_kind = PLUS_INFINITY;
|
||||
else
|
||||
m_kind = MINUS_INFINITY;
|
||||
m_value.reset();
|
||||
return *this;
|
||||
}
|
||||
|
||||
SASSERT(m_kind == FINITE);
|
||||
m_value *= other.m_value;
|
||||
return *this;
|
||||
}
|
||||
|
||||
void ext_numeral::expt(unsigned n) {
|
||||
switch (m_kind) {
|
||||
case MINUS_INFINITY:
|
||||
if (n % 2 == 0)
|
||||
m_kind = PLUS_INFINITY;
|
||||
return;
|
||||
case FINITE:
|
||||
m_value = m_value.expt(n);
|
||||
break;
|
||||
case PLUS_INFINITY:
|
||||
// do nothing
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void ext_numeral::inv() {
|
||||
SASSERT(!is_zero());
|
||||
if (is_infinite()) {
|
||||
m_kind = FINITE;
|
||||
m_value.reset();
|
||||
}
|
||||
else {
|
||||
m_value = rational(1) / m_value;
|
||||
}
|
||||
}
|
||||
|
||||
void ext_numeral::display(std::ostream & out) const {
|
||||
switch (m_kind) {
|
||||
case MINUS_INFINITY:
|
||||
out << "-oo";
|
||||
break;
|
||||
case FINITE:
|
||||
out << m_value;
|
||||
break;
|
||||
case PLUS_INFINITY:
|
||||
out << "oo";
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
bool operator==(ext_numeral const & n1, ext_numeral const & n2) {
|
||||
return n1.m_kind == n2.m_kind && (n1.is_infinite() || n1.m_value == n2.m_value);
|
||||
}
|
||||
|
||||
bool operator<(ext_numeral const & n1, ext_numeral const & n2) {
|
||||
if (n1.is_infinite())
|
||||
return n1.m_kind == ext_numeral::MINUS_INFINITY && n2.m_kind != ext_numeral::MINUS_INFINITY;
|
||||
if (n2.is_infinite())
|
||||
return n2.m_kind != ext_numeral::MINUS_INFINITY;
|
||||
return n1.m_value < n2.m_value;
|
||||
}
|
||||
|
||||
/**
|
||||
\brief Create interval (-oo, oo)
|
||||
*/
|
||||
interval::interval(v_dependency_manager & m):
|
||||
m_manager(m),
|
||||
m_lower(false),
|
||||
m_upper(true),
|
||||
m_lower_open(true),
|
||||
m_upper_open(true),
|
||||
m_lower_dep(0),
|
||||
m_upper_dep(0) {
|
||||
}
|
||||
|
||||
/**
|
||||
\brief Create intervals [l,u], (l,u], [l, u), (l,u), where l and u are numerals.
|
||||
*/
|
||||
interval::interval(v_dependency_manager & m, rational const & lower, bool l_open, v_dependency * l_dep, rational const & upper, bool u_open, v_dependency * u_dep):
|
||||
m_manager(m),
|
||||
m_lower(lower),
|
||||
m_upper(upper),
|
||||
m_lower_open(l_open),
|
||||
m_upper_open(u_open),
|
||||
m_lower_dep(l_dep),
|
||||
m_upper_dep(u_dep) {
|
||||
SASSERT(lower <= upper);
|
||||
SASSERT(lower != upper || !l_open || !u_open);
|
||||
}
|
||||
|
||||
/**
|
||||
\brief Create intervals [l,u], (l,u], [l, u), (l,u), where l and u are ext_numerals.
|
||||
*/
|
||||
interval::interval(v_dependency_manager & m, ext_numeral const & lower, bool l_open, v_dependency * l_dep, ext_numeral const & upper, bool u_open, v_dependency * u_dep):
|
||||
m_manager(m),
|
||||
m_lower(lower),
|
||||
m_upper(upper),
|
||||
m_lower_open(l_open),
|
||||
m_upper_open(u_open),
|
||||
m_lower_dep(l_dep),
|
||||
m_upper_dep(u_dep) {
|
||||
SASSERT(lower <= upper);
|
||||
SASSERT(lower != upper || !l_open || !u_open);
|
||||
}
|
||||
|
||||
/**
|
||||
\brief Create interval [val,val]
|
||||
*/
|
||||
interval::interval(v_dependency_manager & m, rational const & val, v_dependency * l_dep, v_dependency * u_dep):
|
||||
m_manager(m),
|
||||
m_lower(val),
|
||||
m_upper(val),
|
||||
m_lower_open(false),
|
||||
m_upper_open(false),
|
||||
m_lower_dep(l_dep),
|
||||
m_upper_dep(u_dep) {
|
||||
}
|
||||
|
||||
/**
|
||||
\brief Create intervals (-oo, val], (-oo, val), [val, oo), (val, oo)
|
||||
*/
|
||||
interval::interval(v_dependency_manager & m, rational const & val, bool open, bool lower, v_dependency * d):
|
||||
m_manager(m) {
|
||||
if (lower) {
|
||||
m_lower = ext_numeral(val);
|
||||
m_lower_open = open;
|
||||
m_lower_dep = d;
|
||||
m_upper = ext_numeral(true);
|
||||
m_upper_open = true;
|
||||
m_upper_dep = 0;
|
||||
}
|
||||
else {
|
||||
m_lower = ext_numeral(false);
|
||||
m_lower_open = true;
|
||||
m_lower_dep = 0;
|
||||
m_upper = ext_numeral(val);
|
||||
m_upper_open = open;
|
||||
m_upper_dep = d;
|
||||
}
|
||||
}
|
||||
|
||||
interval::interval(interval const & other):
|
||||
m_manager(other.m_manager),
|
||||
m_lower(other.m_lower),
|
||||
m_upper(other.m_upper),
|
||||
m_lower_open(other.m_lower_open),
|
||||
m_upper_open(other.m_upper_open),
|
||||
m_lower_dep(other.m_lower_dep),
|
||||
m_upper_dep(other.m_upper_dep) {
|
||||
}
|
||||
|
||||
interval & interval::operator=(interval const & other) {
|
||||
m_lower = other.m_lower;
|
||||
m_upper = other.m_upper;
|
||||
m_lower_open = other.m_lower_open;
|
||||
m_upper_open = other.m_upper_open;
|
||||
m_lower_dep = other.m_lower_dep;
|
||||
m_upper_dep = other.m_upper_dep;
|
||||
return *this;
|
||||
}
|
||||
|
||||
interval & interval::operator+=(interval const & other) {
|
||||
m_lower += other.m_lower;
|
||||
m_upper += other.m_upper;
|
||||
m_lower_open |= other.m_lower_open;
|
||||
m_upper_open |= other.m_upper_open;
|
||||
m_lower_dep = m_lower.is_infinite() ? 0 : m_manager.mk_join(m_lower_dep, other.m_lower_dep);
|
||||
m_upper_dep = m_upper.is_infinite() ? 0 : m_manager.mk_join(m_upper_dep, other.m_upper_dep);
|
||||
return *this;
|
||||
}
|
||||
|
||||
void interval::neg() {
|
||||
std::swap(m_lower, m_upper);
|
||||
std::swap(m_lower_open, m_upper_open);
|
||||
std::swap(m_lower_dep, m_upper_dep);
|
||||
m_lower.neg();
|
||||
m_upper.neg();
|
||||
}
|
||||
|
||||
interval & interval::operator-=(interval const & other) {
|
||||
interval tmp(other);
|
||||
tmp.neg();
|
||||
return operator+=(tmp);
|
||||
}
|
||||
|
||||
v_dependency * interval::join(v_dependency * d1, v_dependency * d2, v_dependency * d3, v_dependency * d4) {
|
||||
return m_manager.mk_join(m_manager.mk_join(d1, d2), m_manager.mk_join(d3,d4));
|
||||
}
|
||||
|
||||
/**
|
||||
\brief Create a new v_dependency using d1, d2, and (opt1 or opt2).
|
||||
*/
|
||||
v_dependency * interval::join_opt(v_dependency * d1, v_dependency * d2, v_dependency * opt1, v_dependency * opt2) {
|
||||
if (opt1 == d1 || opt1 == d2)
|
||||
return join(d1, d2);
|
||||
if (opt2 == d1 || opt2 == d2)
|
||||
return join(d1, d2);
|
||||
if (opt1 == 0 || opt2 == 0)
|
||||
return join(d1, d2);
|
||||
// TODO: more opts...
|
||||
return join(d1, d2, opt1);
|
||||
}
|
||||
|
||||
interval & interval::operator*=(interval const & other) {
|
||||
#if Z3DEBUG || _TRACE
|
||||
bool contains_zero1 = contains_zero();
|
||||
bool contains_zero2 = other.contains_zero();
|
||||
#endif
|
||||
if (is_zero()) {
|
||||
return *this;
|
||||
}
|
||||
if (other.is_zero()) {
|
||||
*this = other;
|
||||
return *this;
|
||||
}
|
||||
|
||||
ext_numeral const & a = m_lower;
|
||||
ext_numeral const & b = m_upper;
|
||||
ext_numeral const & c = other.m_lower;
|
||||
ext_numeral const & d = other.m_upper;
|
||||
bool a_o = m_lower_open;
|
||||
bool b_o = m_upper_open;
|
||||
bool c_o = other.m_lower_open;
|
||||
bool d_o = other.m_upper_open;
|
||||
v_dependency * a_d = m_lower_dep;
|
||||
v_dependency * b_d = m_upper_dep;
|
||||
v_dependency * c_d = other.m_lower_dep;
|
||||
v_dependency * d_d = other.m_upper_dep;
|
||||
|
||||
TRACE("interval_bug", tout << "operator*= " << *this << " " << other << "\n";);
|
||||
|
||||
if (is_N()) {
|
||||
if (other.is_N()) {
|
||||
// x <= b <= 0, y <= d <= 0 --> b*d <= x*y
|
||||
// a <= x <= b <= 0, c <= y <= d <= 0 --> x*y <= a*c (we can use the fact that x or y is always negative (i.e., b is neg or d is neg))
|
||||
TRACE("interval_bug", tout << "(N, N)\n";);
|
||||
ext_numeral new_lower = b * d;
|
||||
ext_numeral new_upper = a * c;
|
||||
// if b = 0 (and the interval is closed), then the lower bound is closed
|
||||
m_lower_open = (is_N0() || other.is_N0()) ? false : (b_o || d_o);
|
||||
m_upper_open = a_o || c_o; SASSERT(a.is_neg() && c.is_neg());
|
||||
m_lower = new_lower;
|
||||
m_upper = new_upper;
|
||||
m_lower_dep = m_lower.is_infinite() ? 0 : join(b_d, d_d);
|
||||
m_upper_dep = m_upper.is_infinite() ? 0 : join_opt(a_d, c_d, b_d, d_d);
|
||||
}
|
||||
else if (other.is_M()) {
|
||||
// a <= x <= b <= 0, y <= d, d > 0 --> a*d <= x*y (uses the fact that b is not positive)
|
||||
// a <= x <= b <= 0, c <= y, c < 0 --> x*y <= a*c (uses the fact that b is not positive)
|
||||
TRACE("interval_bug", tout << "(N, M)\n";);
|
||||
ext_numeral new_lower = a * d; SASSERT(new_lower.is_neg());
|
||||
ext_numeral new_upper = a * c; SASSERT(new_upper.is_pos());
|
||||
m_lower_open = a_o || d_o;
|
||||
m_upper_open = a_o || c_o;
|
||||
m_lower = new_lower;
|
||||
m_upper = new_upper;
|
||||
m_lower_dep = m_lower.is_infinite() ? 0 : join(a_d, d_d, b_d);
|
||||
m_upper_dep = m_upper.is_infinite() ? 0 : join(a_d, c_d, b_d);
|
||||
}
|
||||
else {
|
||||
// a <= x <= b <= 0, 0 <= c <= y <= d --> a*d <= x*y (uses the fact that x is neg (b is not positive) or y is pos (c is not negative))
|
||||
// x <= b <= 0, 0 <= c <= y --> x*y <= b*c
|
||||
TRACE("interval_bug", tout << "(N, P)\n";);
|
||||
SASSERT(other.is_P());
|
||||
ext_numeral new_lower = a * d;
|
||||
ext_numeral new_upper = b * c;
|
||||
bool is_N0_old = is_N0(); // see comment in (P, N) case
|
||||
m_lower_open = a_o || d_o; SASSERT(a.is_neg() && d.is_pos());
|
||||
m_upper_open = (is_N0_old || other.is_P0()) ? false : (b_o || c_o);
|
||||
m_lower = new_lower;
|
||||
m_upper = new_upper;
|
||||
m_lower_dep = m_lower.is_infinite() ? 0 : join_opt(a_d, d_d, b_d, c_d);
|
||||
m_upper_dep = m_upper.is_infinite() ? 0 : join(b_d, c_d);
|
||||
}
|
||||
}
|
||||
else if (is_M()) {
|
||||
if (other.is_N()) {
|
||||
// b > 0, x <= b, c <= y <= d <= 0 --> b*c <= x*y (uses the fact that d is not positive)
|
||||
// a < 0, a <= x, c <= y <= d <= 0 --> x*y <= a*c (uses the fact that d is not positive)
|
||||
TRACE("interval_bug", tout << "(M, N)\n";);
|
||||
ext_numeral new_lower = b * c; SASSERT(new_lower.is_neg());
|
||||
ext_numeral new_upper = a * c; SASSERT(new_upper.is_pos());
|
||||
m_lower_open = b_o || c_o; SASSERT(b.is_pos() && c.is_neg());
|
||||
m_upper_open = a_o || c_o; SASSERT(a.is_neg() && c.is_neg());
|
||||
m_lower = new_lower;
|
||||
m_upper = new_upper;
|
||||
m_lower_dep = m_lower.is_infinite() ? 0 : join(b_d, c_d, d_d);
|
||||
m_upper_dep = m_upper.is_infinite() ? 0 : join(a_d, c_d, d_d);
|
||||
}
|
||||
else if (other.is_M()) {
|
||||
TRACE("interval_bug", tout << "(M, M)\n";);
|
||||
SASSERT(!a.is_zero() && !b.is_zero() && !c.is_zero() && !d.is_zero());
|
||||
ext_numeral ad = a*d; SASSERT(!ad.is_zero());
|
||||
ext_numeral bc = b*c; SASSERT(!bc.is_zero());
|
||||
ext_numeral ac = a*c; SASSERT(!ac.is_zero());
|
||||
ext_numeral bd = b*d; SASSERT(!bd.is_zero());
|
||||
bool ad_o = a_o || d_o;
|
||||
bool bc_o = b_o || c_o;
|
||||
bool ac_o = a_o || c_o;
|
||||
bool bd_o = b_o || d_o;
|
||||
if (ad < bc || (ad == bc && !ad_o && bc_o)) {
|
||||
m_lower = ad;
|
||||
m_lower_open = ad_o;
|
||||
}
|
||||
else {
|
||||
m_lower = bc;
|
||||
m_lower_open = bc_o;
|
||||
}
|
||||
if (ac > bd || (ac == bd && !ac_o && bd_o)) {
|
||||
m_upper = ac;
|
||||
m_upper_open = ac_o;
|
||||
}
|
||||
else {
|
||||
m_upper = bd;
|
||||
m_upper_open = bd_o;
|
||||
}
|
||||
m_lower_dep = m_lower.is_infinite() ? 0 : join(a_d, b_d, c_d, d_d);
|
||||
m_upper_dep = m_upper.is_infinite() ? 0 : join(a_d, b_d, c_d, d_d);
|
||||
}
|
||||
else {
|
||||
// a < 0, a <= x, 0 <= c <= y <= d --> a*d <= x*y (uses the fact that c is not negative)
|
||||
// b > 0, x <= b, 0 <= c <= y <= d --> x*y <= b*d (uses the fact that c is not negative)
|
||||
TRACE("interval_bug", tout << "(M, P)\n";);
|
||||
SASSERT(other.is_P());
|
||||
ext_numeral new_lower = a * d; SASSERT(new_lower.is_neg());
|
||||
ext_numeral new_upper = b * d; SASSERT(new_upper.is_pos());
|
||||
m_lower_open = a_o || d_o; SASSERT(a.is_neg() && d.is_pos());
|
||||
m_upper_open = b_o || d_o; SASSERT(b.is_pos() && d.is_pos());
|
||||
m_lower = new_lower;
|
||||
m_upper = new_upper;
|
||||
m_lower_dep = m_lower.is_infinite() ? 0 : join(a_d, d_d, c_d);
|
||||
m_upper_dep = m_upper.is_infinite() ? 0 : join(b_d, d_d, c_d);
|
||||
}
|
||||
}
|
||||
else {
|
||||
SASSERT(is_P());
|
||||
if (other.is_N()) {
|
||||
// 0 <= a <= x <= b, c <= y <= d <= 0 --> x*y <= b*c (uses the fact that x is pos (a is not neg) or y is neg (d is not pos))
|
||||
// 0 <= a <= x, y <= d <= 0 --> a*d <= x*y
|
||||
TRACE("interval_bug", tout << "(P, N)\n";);
|
||||
ext_numeral new_lower = b * c;
|
||||
ext_numeral new_upper = a * d;
|
||||
bool is_P0_old = is_P0(); // cache the value of is_P0(), since it may be affected by the next update.
|
||||
m_lower_open = b_o || c_o; SASSERT(b.is_pos() && c.is_neg());
|
||||
m_upper_open = (is_P0_old || other.is_N0()) ? false : a_o || d_o;
|
||||
m_lower = new_lower;
|
||||
m_upper = new_upper;
|
||||
m_lower_dep = m_lower.is_infinite() ? 0 : join_opt(b_d, c_d, a_d, d_d);
|
||||
m_upper_dep = m_upper.is_infinite() ? 0 : join(a_d, d_d);
|
||||
}
|
||||
else if (other.is_M()) {
|
||||
// 0 <= a <= x <= b, c <= y --> b*c <= x*y (uses the fact that a is not negative)
|
||||
// 0 <= a <= x <= b, y <= d --> x*y <= b*d (uses the fact that a is not negative)
|
||||
TRACE("interval_bug", tout << "(P, M)\n";);
|
||||
ext_numeral new_lower = b * c; SASSERT(new_lower.is_neg());
|
||||
ext_numeral new_upper = b * d; SASSERT(new_upper.is_pos());
|
||||
m_lower_open = b_o || c_o;
|
||||
m_upper_open = b_o || d_o;
|
||||
m_lower = new_lower;
|
||||
m_upper = new_upper;
|
||||
m_lower_dep = m_lower.is_infinite() ? 0 : join(b_d, c_d, a_d);
|
||||
m_upper_dep = m_upper.is_infinite() ? 0 : join(b_d, d_d, a_d);
|
||||
}
|
||||
else {
|
||||
// 0 <= a <= x, 0 <= c <= y --> a*c <= x*y
|
||||
// x <= b, y <= d --> x*y <= b*d (uses the fact that x is pos (a is not negative) or y is pos (c is not negative))
|
||||
TRACE("interval_bug", tout << "(P, P)\n";);
|
||||
SASSERT(other.is_P());
|
||||
ext_numeral new_lower = a * c;
|
||||
ext_numeral new_upper = b * d;
|
||||
m_lower_open = (is_P0() || other.is_P0()) ? false : a_o || c_o;
|
||||
m_upper_open = b_o || d_o; SASSERT(b.is_pos() && d.is_pos());
|
||||
m_lower = new_lower;
|
||||
m_upper = new_upper;
|
||||
m_lower_dep = m_lower.is_infinite() ? 0 : join(a_d, c_d);
|
||||
m_upper_dep = m_upper.is_infinite() ? 0 : join_opt(b_d, d_d, a_d, c_d);
|
||||
}
|
||||
}
|
||||
TRACE("interval_bug", tout << "operator*= result: " << *this << "\n";);
|
||||
CTRACE("interval", !(!(contains_zero1 || contains_zero2) || contains_zero()),
|
||||
tout << "contains_zero1: " << contains_zero1 << ", contains_zero2: " << contains_zero2 << ", contains_zero(): " << contains_zero() << "\n";);
|
||||
SASSERT(!(contains_zero1 || contains_zero2) || contains_zero());
|
||||
return *this;
|
||||
}
|
||||
|
||||
bool interval::contains_zero() const {
|
||||
TRACE("interval_zero_bug", tout << "contains_zero info: " << *this << "\n";
|
||||
tout << "m_lower.is_neg(): " << m_lower.is_neg() << "\n";
|
||||
tout << "m_lower.is_zero: " << m_lower.is_zero() << "\n";
|
||||
tout << "m_lower_open: " << m_lower_open << "\n";
|
||||
tout << "m_upper.is_pos(): " << m_upper.is_pos() << "\n";
|
||||
tout << "m_upper.is_zero: " << m_upper.is_zero() << "\n";
|
||||
tout << "m_upper_open: " << m_upper_open << "\n";
|
||||
tout << "result: " << ((m_lower.is_neg() || (m_lower.is_zero() && !m_lower_open)) && (m_upper.is_pos() || (m_upper.is_zero() && !m_upper_open))) << "\n";);
|
||||
return
|
||||
(m_lower.is_neg() || (m_lower.is_zero() && !m_lower_open)) &&
|
||||
(m_upper.is_pos() || (m_upper.is_zero() && !m_upper_open));
|
||||
}
|
||||
|
||||
bool interval::contains(rational const& v) const {
|
||||
if (!inf().is_infinite()) {
|
||||
if (v < inf().to_rational()) return false;
|
||||
if (v == inf().to_rational() && m_lower_open) return false;
|
||||
}
|
||||
if (!sup().is_infinite()) {
|
||||
if (v > sup().to_rational()) return false;
|
||||
if (v == sup().to_rational() && m_upper_open) return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
interval & interval::inv() {
|
||||
// If the interval [l,u] does not contain 0, then 1/[l,u] = [1/u, 1/l]
|
||||
SASSERT(!contains_zero());
|
||||
if (is_P1()) {
|
||||
// 0 < a <= x --> 1/x <= 1/a
|
||||
// 0 < a <= x <= b --> 1/b <= 1/x (use lower and upper bounds)
|
||||
ext_numeral new_lower = m_upper; SASSERT(!m_upper.is_zero());
|
||||
new_lower.inv();
|
||||
ext_numeral new_upper;
|
||||
if (m_lower.is_zero()) {
|
||||
SASSERT(m_lower_open);
|
||||
ext_numeral plus_infinity(true);
|
||||
new_upper = plus_infinity;
|
||||
}
|
||||
else {
|
||||
new_upper = m_lower;
|
||||
new_upper.inv();
|
||||
}
|
||||
m_lower = new_lower;
|
||||
m_upper = new_upper;
|
||||
std::swap(m_lower_open, m_upper_open);
|
||||
v_dependency * new_upper_dep = m_lower_dep;
|
||||
SASSERT(!m_lower.is_infinite());
|
||||
m_lower_dep = m_manager.mk_join(m_lower_dep, m_upper_dep);
|
||||
m_upper_dep = new_upper_dep;
|
||||
}
|
||||
else if (is_N1()) {
|
||||
// x <= a < 0 --> 1/a <= 1/x
|
||||
// b <= x <= a < 0 --> 1/b <= 1/x (use lower and upper bounds)
|
||||
ext_numeral new_upper = m_lower; SASSERT(!m_lower.is_zero());
|
||||
new_upper.inv();
|
||||
ext_numeral new_lower;
|
||||
if (m_upper.is_zero()) {
|
||||
SASSERT(m_upper_open);
|
||||
ext_numeral minus_infinity(false);
|
||||
new_lower = minus_infinity;
|
||||
}
|
||||
else {
|
||||
new_lower = m_upper;
|
||||
new_lower.inv();
|
||||
}
|
||||
m_lower = new_lower;
|
||||
m_upper = new_upper;
|
||||
std::swap(m_lower_open, m_upper_open);
|
||||
v_dependency * new_lower_dep = m_upper_dep;
|
||||
SASSERT(!m_upper.is_infinite());
|
||||
m_upper_dep = m_manager.mk_join(m_lower_dep, m_upper_dep);
|
||||
m_lower_dep = new_lower_dep;
|
||||
}
|
||||
else {
|
||||
UNREACHABLE();
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
interval & interval::operator/=(interval const & other) {
|
||||
SASSERT(!other.contains_zero());
|
||||
if (is_zero()) {
|
||||
// 0/other = 0 if other != 0
|
||||
TRACE("interval", other.display_with_dependencies(tout););
|
||||
if (other.m_lower.is_pos() || (other.m_lower.is_zero() && other.m_lower_open)) {
|
||||
// other.lower > 0
|
||||
m_lower_dep = join(m_lower_dep, other.m_lower_dep);
|
||||
m_upper_dep = join(m_upper_dep, other.m_lower_dep);
|
||||
}
|
||||
else {
|
||||
// assertion must hold since !other.contains_zero()
|
||||
SASSERT(other.m_upper.is_neg() || (other.m_upper.is_zero() && other.m_upper_open));
|
||||
// other.upper < 0
|
||||
m_lower_dep = join(m_lower_dep, other.m_upper_dep);
|
||||
m_upper_dep = join(m_upper_dep, other.m_upper_dep);
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
else {
|
||||
interval tmp(other);
|
||||
tmp.inv();
|
||||
return operator*=(tmp);
|
||||
}
|
||||
}
|
||||
|
||||
void interval::expt(unsigned n) {
|
||||
if (n == 1)
|
||||
return;
|
||||
if (n % 2 == 0) {
|
||||
if (m_lower.is_pos()) {
|
||||
// [l, u]^n = [l^n, u^n] if l > 0
|
||||
// 0 < a <= x --> a^n <= x^n (lower bound guarantees that is positive)
|
||||
// 0 < a <= x <= b --> x^n <= b^n (use lower and upper bound -- need the fact that x is positive)
|
||||
m_lower.expt(n);
|
||||
m_upper.expt(n);
|
||||
m_upper_dep = m_upper.is_infinite() ? 0 : m_manager.mk_join(m_lower_dep, m_upper_dep);
|
||||
}
|
||||
else if (m_upper.is_neg()) {
|
||||
// [l, u]^n = [u^n, l^n] if u < 0
|
||||
// a <= x <= b < 0 --> x^n <= a^n (use lower and upper bound -- need the fact that x is negative)
|
||||
// x <= b < 0 --> b^n <= x^n
|
||||
std::swap(m_lower, m_upper);
|
||||
std::swap(m_lower_open, m_upper_open);
|
||||
std::swap(m_lower_dep, m_upper_dep);
|
||||
m_lower.expt(n);
|
||||
m_upper.expt(n);
|
||||
m_upper_dep = m_upper.is_infinite() ? 0 : m_manager.mk_join(m_lower_dep, m_upper_dep);
|
||||
}
|
||||
else {
|
||||
// [l, u]^n = [0, max{l^n, u^n}] otherwise
|
||||
// we need both bounds to justify upper bound
|
||||
TRACE("interval", tout << "before: " << m_lower << " " << m_upper << " " << n << "\n";);
|
||||
m_lower.expt(n);
|
||||
m_upper.expt(n);
|
||||
TRACE("interval", tout << "after: " << m_lower << " " << m_upper << "\n";);
|
||||
if (m_lower > m_upper || (m_lower == m_upper && !m_lower_open && m_upper_open)) {
|
||||
m_upper = m_lower;
|
||||
m_upper_open = m_lower_open;
|
||||
}
|
||||
m_upper_dep = m_upper.is_infinite() ? 0 : m_manager.mk_join(m_lower_dep, m_upper_dep);
|
||||
m_lower = ext_numeral(0);
|
||||
m_lower_open = false;
|
||||
m_lower_dep = 0;
|
||||
}
|
||||
}
|
||||
else {
|
||||
// Remark: when n is odd x^n is monotonic.
|
||||
m_lower.expt(n);
|
||||
m_upper.expt(n);
|
||||
}
|
||||
}
|
||||
|
||||
void interval::display(std::ostream & out) const {
|
||||
out << (m_lower_open ? "(" : "[") << m_lower << ", " << m_upper << (m_upper_open ? ")" : "]");
|
||||
}
|
||||
|
||||
void interval::display_with_dependencies(std::ostream & out) const {
|
||||
ptr_vector<void> vs;
|
||||
m_manager.linearize(m_lower_dep, vs);
|
||||
m_manager.linearize(m_upper_dep, vs);
|
||||
out << "[";
|
||||
display(out);
|
||||
out << ", ";
|
||||
bool first = true;
|
||||
::display(out, vs.begin(), vs.end(), ", ", first);
|
||||
out << "]";
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
|
@ -1,138 +0,0 @@
|
|||
/*++
|
||||
Copyright (c) 2006 Microsoft Corporation
|
||||
|
||||
Module Name:
|
||||
|
||||
old_interval.h
|
||||
|
||||
Abstract:
|
||||
|
||||
Old interval class. It is still used in some modules.
|
||||
|
||||
Author:
|
||||
|
||||
Leonardo de Moura (leonardo) 2008-12-09.
|
||||
|
||||
Revision History:
|
||||
|
||||
--*/
|
||||
#ifndef _OLD_INTERVAL_H_
|
||||
#define _OLD_INTERVAL_H_
|
||||
|
||||
#include"rational.h"
|
||||
#include"dependency.h"
|
||||
|
||||
class ext_numeral {
|
||||
public:
|
||||
enum kind { MINUS_INFINITY, FINITE, PLUS_INFINITY };
|
||||
private:
|
||||
kind m_kind;
|
||||
rational m_value;
|
||||
explicit ext_numeral(kind k):m_kind(k) {}
|
||||
public:
|
||||
ext_numeral():m_kind(FINITE) {} /* zero */
|
||||
explicit ext_numeral(bool plus_infinity):m_kind(plus_infinity ? PLUS_INFINITY : MINUS_INFINITY) {}
|
||||
explicit ext_numeral(rational const & val):m_kind(FINITE), m_value(val) {}
|
||||
explicit ext_numeral(int i):m_kind(FINITE), m_value(i) {}
|
||||
ext_numeral(ext_numeral const & other):m_kind(other.m_kind), m_value(other.m_value) {}
|
||||
bool is_infinite() const { return m_kind != FINITE; }
|
||||
bool sign() const { return m_kind == MINUS_INFINITY || (m_kind == FINITE && m_value.is_neg()); }
|
||||
void neg();
|
||||
bool is_zero() const { return m_kind == FINITE && m_value.is_zero(); }
|
||||
bool is_neg() const { return sign(); }
|
||||
bool is_pos() const { return !is_neg() && !is_zero(); }
|
||||
rational const & to_rational() const { SASSERT(!is_infinite()); return m_value; }
|
||||
ext_numeral & operator+=(ext_numeral const & other);
|
||||
ext_numeral & operator-=(ext_numeral const & other);
|
||||
ext_numeral & operator*=(ext_numeral const & other);
|
||||
void inv();
|
||||
void expt(unsigned n);
|
||||
void display(std::ostream & out) const;
|
||||
friend bool operator==(ext_numeral const & n1, ext_numeral const & n2);
|
||||
friend bool operator<(ext_numeral const & n1, ext_numeral const & n2);
|
||||
};
|
||||
|
||||
bool operator==(ext_numeral const & n1, ext_numeral const & n2);
|
||||
bool operator<(ext_numeral const & n1, ext_numeral const & n2);
|
||||
inline bool operator!=(ext_numeral const & n1, ext_numeral const & n2) { return !operator==(n1,n2); }
|
||||
inline bool operator>(ext_numeral const & n1, ext_numeral const & n2) { return operator<(n2, n1); }
|
||||
inline bool operator<=(ext_numeral const & n1, ext_numeral const & n2) { return !operator>(n1, n2); }
|
||||
inline bool operator>=(ext_numeral const & n1, ext_numeral const & n2) { return !operator<(n1, n2); }
|
||||
inline ext_numeral operator+(ext_numeral const & n1, ext_numeral const & n2) { return ext_numeral(n1) += n2; }
|
||||
inline ext_numeral operator-(ext_numeral const & n1, ext_numeral const & n2) { return ext_numeral(n1) -= n2; }
|
||||
inline ext_numeral operator*(ext_numeral const & n1, ext_numeral const & n2) { return ext_numeral(n1) *= n2; }
|
||||
inline std::ostream & operator<<(std::ostream & out, ext_numeral const & n) { n.display(out); return out; }
|
||||
|
||||
class old_interval {
|
||||
v_dependency_manager & m_manager;
|
||||
ext_numeral m_lower;
|
||||
ext_numeral m_upper;
|
||||
bool m_lower_open;
|
||||
bool m_upper_open;
|
||||
v_dependency * m_lower_dep; // justification for the lower bound
|
||||
v_dependency * m_upper_dep; // justification for the upper bound
|
||||
|
||||
v_dependency * join(v_dependency * d1, v_dependency * d2) { return m_manager.mk_join(d1, d2); }
|
||||
v_dependency * join(v_dependency * d1, v_dependency * d2, v_dependency * d3) { return m_manager.mk_join(m_manager.mk_join(d1, d2), d3); }
|
||||
v_dependency * join(v_dependency * d1, v_dependency * d2, v_dependency * d3, v_dependency * d4);
|
||||
v_dependency * join_opt(v_dependency * d1, v_dependency * d2, v_dependency * opt1, v_dependency * opt2);
|
||||
|
||||
public:
|
||||
explicit old_interval(v_dependency_manager & m);
|
||||
explicit old_interval(v_dependency_manager & m, rational const & lower, bool l_open, v_dependency * l_dep, rational const & upper, bool u_open, v_dependency * u_dep);
|
||||
explicit old_interval(v_dependency_manager & m, rational const & val, v_dependency * l_dep = 0, v_dependency * u_dep = 0);
|
||||
explicit old_interval(v_dependency_manager & m, rational const & val, bool open, bool lower, v_dependency * d);
|
||||
explicit old_interval(v_dependency_manager & m, ext_numeral const& lower, bool l_open, v_dependency * l_dep, ext_numeral const & upper, bool u_open, v_dependency * u_dep);
|
||||
old_interval(old_interval const & other);
|
||||
|
||||
bool minus_infinity() const { return m_lower.is_infinite(); }
|
||||
bool plus_infinity() const { return m_upper.is_infinite(); }
|
||||
bool is_lower_open() const { return m_lower_open; }
|
||||
bool is_upper_open() const { return m_upper_open; }
|
||||
v_dependency * get_lower_dependencies() const { return m_lower_dep; }
|
||||
v_dependency * get_upper_dependencies() const { return m_upper_dep; }
|
||||
rational const & get_lower_value() const { SASSERT(!minus_infinity()); return m_lower.to_rational(); }
|
||||
rational const & get_upper_value() const { SASSERT(!plus_infinity()); return m_upper.to_rational(); }
|
||||
old_interval & operator=(old_interval const & other);
|
||||
old_interval & operator+=(old_interval const & other);
|
||||
old_interval & operator-=(old_interval const & other);
|
||||
old_interval & operator*=(old_interval const & other);
|
||||
old_interval & operator*=(rational const & value);
|
||||
old_interval & operator/=(old_interval const & other);
|
||||
bool operator==(old_interval const & other) const { return m_lower == other.m_lower && m_upper == other.m_upper && m_lower_open == other.m_lower_open && m_upper_open == other.m_upper_open; }
|
||||
bool contains_zero() const;
|
||||
bool contains(rational const& v) const;
|
||||
old_interval & inv();
|
||||
void expt(unsigned n);
|
||||
void neg();
|
||||
void display(std::ostream & out) const;
|
||||
void display_with_dependencies(std::ostream & out) const;
|
||||
bool is_P() const { return m_lower.is_pos() || m_lower.is_zero(); }
|
||||
bool is_P0() const { return m_lower.is_zero() && !m_lower_open; }
|
||||
bool is_P1() const { return m_lower.is_pos() || (m_lower.is_zero() && m_lower_open); }
|
||||
bool is_N() const { return m_upper.is_neg() || m_upper.is_zero(); }
|
||||
bool is_N0() const { return m_upper.is_zero() && !m_upper_open; }
|
||||
bool is_N1() const { return m_upper.is_neg() || (m_upper.is_zero() && m_upper_open); }
|
||||
bool is_M() const { return m_lower.is_neg() && m_upper.is_pos(); }
|
||||
bool is_zero() const { return m_lower.is_zero() && m_upper.is_zero(); }
|
||||
|
||||
ext_numeral const& inf() const { return m_lower; }
|
||||
ext_numeral const& sup() const { return m_upper; }
|
||||
};
|
||||
|
||||
inline old_interval operator+(old_interval const & i1, old_interval const & i2) { return old_interval(i1) += i2; }
|
||||
inline old_interval operator-(old_interval const & i1, old_interval const & i2) { return old_interval(i1) -= i2; }
|
||||
inline old_interval operator*(old_interval const & i1, old_interval const & i2) { return old_interval(i1) *= i2; }
|
||||
inline old_interval operator/(old_interval const & i1, old_interval const & i2) { return old_interval(i1) /= i2; }
|
||||
inline old_interval expt(old_interval const & i, unsigned n) { old_interval tmp(i); tmp.expt(n); return tmp; }
|
||||
inline std::ostream & operator<<(std::ostream & out, old_interval const & i) { i.display(out); return out; }
|
||||
|
||||
struct interval_detail{};
|
||||
inline std::pair<old_interval, interval_detail> wd(old_interval const & i) { interval_detail d; return std::make_pair(i, d); }
|
||||
inline std::ostream & operator<<(std::ostream & out, std::pair<old_interval, interval_detail> const & p) { p.first.display_with_dependencies(out); return out; }
|
||||
|
||||
// allow "customers" of this file to keep using interval
|
||||
#define interval old_interval
|
||||
|
||||
#endif /* _OLD_INTERVAL_H_ */
|
||||
|
|
@ -1,871 +0,0 @@
|
|||
/*++
|
||||
Copyright (c) 2006 Microsoft Corporation
|
||||
|
||||
Module Name:
|
||||
|
||||
skip_list_base.h
|
||||
|
||||
Abstract:
|
||||
|
||||
<abstract>
|
||||
|
||||
Author:
|
||||
|
||||
Leonardo de Moura (leonardo) 2010-10-01.
|
||||
|
||||
Revision History:
|
||||
|
||||
WARNING: IT IS NOT SAFE TO STORE KEYS, VALUES in the SKIP_LIST that need non-default constructors/destructors.
|
||||
|
||||
--*/
|
||||
#ifndef _SKIP_LIST_BASE_H_
|
||||
#define _SKIP_LIST_BASE_H_
|
||||
|
||||
#include<memory.h>
|
||||
#include"util.h"
|
||||
#include"memory_manager.h"
|
||||
#include"small_object_allocator.h"
|
||||
#include"trace.h"
|
||||
|
||||
#ifdef _MSC_VER
|
||||
#pragma warning(disable : 4200)
|
||||
#endif
|
||||
|
||||
/*
|
||||
This file defines a base class for implementing skip-list like data-structures.
|
||||
This base class is relies on a manager for providing some basic services.
|
||||
The manager is a template parameter.
|
||||
|
||||
A Skip-list manager is responsible for:
|
||||
|
||||
- Providing primitives for allocating/deallocating memory
|
||||
void * allocate(size_t size);
|
||||
void deallocate(size_t size, void* p);
|
||||
- Generating random skip-list levels efficiently
|
||||
unsigned random_level(unsigned max_level);
|
||||
- Call-backs that will be invoked when a reference for a "value" stored in the skip-list is incremented/decremented.
|
||||
void inc_ref_eh(value const & v);
|
||||
void dec_ref_eh(value const & h);
|
||||
*/
|
||||
|
||||
/**
|
||||
\brief Base class for generating random_levels.
|
||||
*/
|
||||
class random_level_manager {
|
||||
#define SL_BITS_IN_RANDOM 16
|
||||
unsigned m_random_data;
|
||||
unsigned m_random_bits:16;
|
||||
unsigned m_random_left:16;
|
||||
|
||||
unsigned random_value() {
|
||||
return ((m_random_data = m_random_data * 214013L + 2531011L) >> 16) & 0xffff;
|
||||
}
|
||||
|
||||
void init_random() {
|
||||
m_random_data = 0;
|
||||
m_random_bits = random_value();
|
||||
m_random_left = SL_BITS_IN_RANDOM/2;
|
||||
}
|
||||
public:
|
||||
random_level_manager() {
|
||||
init_random();
|
||||
}
|
||||
|
||||
unsigned random_level(unsigned max_level) {
|
||||
unsigned level = 1;
|
||||
unsigned b;
|
||||
do {
|
||||
b = m_random_bits&3;
|
||||
if (!b)
|
||||
level++;
|
||||
m_random_bits >>= 2;
|
||||
m_random_left--;
|
||||
if (m_random_left == 0) {
|
||||
m_random_bits = random_value();
|
||||
m_random_left = SL_BITS_IN_RANDOM/2;
|
||||
}
|
||||
} while (!b);
|
||||
return (level > max_level ? max_level : level);
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
/**
|
||||
\brief Basic skip-list manager.
|
||||
The class is parametrized by the Value type that is stored in the skip-list.
|
||||
*/
|
||||
template<typename Value>
|
||||
class sl_manager_base : public random_level_manager {
|
||||
typedef Value value;
|
||||
|
||||
small_object_allocator m_alloc;
|
||||
|
||||
public:
|
||||
void * allocate(size_t size) {
|
||||
return m_alloc.allocate(size);
|
||||
}
|
||||
|
||||
void deallocate(size_t size, void* p) {
|
||||
m_alloc.deallocate(size, p);
|
||||
}
|
||||
|
||||
void inc_ref_eh(value const & v) {
|
||||
/* do nothing */
|
||||
}
|
||||
|
||||
void dec_ref_eh(value const & h) {
|
||||
/* do nothing */
|
||||
}
|
||||
};
|
||||
|
||||
#define SL_SIZE_NUM_BITS 12
|
||||
#define SL_CAPACITY_NUM_BITS SL_SIZE_NUM_BITS
|
||||
#define SL_MAX_CAPACITY ((1 << SL_SIZE_NUM_BITS) - 1)
|
||||
#define SL_LEVEL_NUM_BITS 8
|
||||
#define SL_MAX_LEVEL ((1 << SL_LEVEL_NUM_BITS) - 1)
|
||||
COMPILE_TIME_ASSERT(SL_SIZE_NUM_BITS == SL_CAPACITY_NUM_BITS);
|
||||
COMPILE_TIME_ASSERT(SL_SIZE_NUM_BITS + SL_CAPACITY_NUM_BITS + SL_LEVEL_NUM_BITS == 32);
|
||||
|
||||
/**
|
||||
\brief Base (template) class for implementing skip-list like data-structures where
|
||||
entries are stored in buckets to improve cache behavior.
|
||||
|
||||
The Traits template parameter must provide:
|
||||
|
||||
- a definition for the class Traits::manager
|
||||
- a definition for the class Traits::entry which provides:
|
||||
- a definition for the types key and value
|
||||
- the methods:
|
||||
key const & begin_key() const
|
||||
key const & end_key() const
|
||||
value const & val() const
|
||||
void set_begin_key(key const & k)
|
||||
void set_end_key(key const & k)
|
||||
void set_val(value const & v)
|
||||
void display(ostream & out) const
|
||||
- the maximal number of levels Traits::max_level
|
||||
- the maximal capacity of each bucket Traits::max_capacity
|
||||
- the initial capacity of the first bucket Traits::initial_capacity
|
||||
- flag for reference counting support Traits::ref_count. If this flag is true
|
||||
the methods inc_ref_eh and dec_ref_eh in the manager object will be invoked.
|
||||
- the methods
|
||||
bool lt(key const & k1, key const & k2)
|
||||
bool eq(key const & k1, key const & k2)
|
||||
bool val_eq(value const & v1, value const & v2)
|
||||
key succ(key const & k)
|
||||
key pred(key const & k)
|
||||
*/
|
||||
template<typename Traits>
|
||||
class skip_list_base : protected Traits {
|
||||
protected:
|
||||
typedef typename Traits::entry entry;
|
||||
public:
|
||||
typedef typename Traits::manager manager;
|
||||
typedef typename entry::key key;
|
||||
typedef typename entry::value value;
|
||||
|
||||
struct bucket {
|
||||
unsigned m_size:SL_SIZE_NUM_BITS; //!< number of entries stored in the bucket.
|
||||
unsigned m_capacity:SL_CAPACITY_NUM_BITS; //!< capacity (number of entries) that can be stored in the bucket.
|
||||
unsigned m_level:SL_LEVEL_NUM_BITS;
|
||||
char m_extra[0];
|
||||
|
||||
static unsigned get_obj_size(unsigned num_lvls, unsigned capacity) {
|
||||
return sizeof(bucket) + num_lvls*sizeof(bucket*) + capacity*sizeof(entry);
|
||||
}
|
||||
|
||||
entry * get_entries() { return reinterpret_cast<entry*>(m_extra); }
|
||||
entry const * get_entries() const { return reinterpret_cast<entry const *>(m_extra); }
|
||||
|
||||
bucket ** next_vect() { return reinterpret_cast<bucket**>(get_entries() + m_capacity); }
|
||||
bucket * const * next_vect() const { return reinterpret_cast<bucket* const *>(get_entries() + m_capacity); }
|
||||
|
||||
bucket(unsigned lvl, unsigned capacity = Traits::max_capacity):
|
||||
m_size(0),
|
||||
m_capacity(capacity),
|
||||
m_level(lvl) {
|
||||
memset(next_vect(), 0, sizeof(bucket*)*lvl);
|
||||
}
|
||||
|
||||
unsigned level() const { return m_level; }
|
||||
unsigned size() const { return m_size; }
|
||||
unsigned capacity() const { return m_capacity; }
|
||||
bool empty() const { return size() == 0; }
|
||||
void set_size(unsigned sz) { m_size = sz; }
|
||||
void shrink(unsigned delta) { m_size -= delta; }
|
||||
void expand(unsigned delta) { m_size += delta; }
|
||||
entry & first_entry() { SASSERT(!empty()); return get_entries()[0]; }
|
||||
entry & last_entry() { SASSERT(!empty()); return get_entries()[size() - 1]; }
|
||||
entry const & first_entry() const { SASSERT(!empty()); return get_entries()[0]; }
|
||||
entry const & last_entry() const { SASSERT(!empty()); return get_entries()[size() - 1]; }
|
||||
entry const & get(unsigned idx) const { SASSERT(idx < size()); return get_entries()[idx]; }
|
||||
entry & get(unsigned idx) { SASSERT(idx < size()); return get_entries()[idx]; }
|
||||
void set(unsigned idx, entry const & e) { SASSERT(idx < capacity()); get_entries()[idx] = e; }
|
||||
bucket * get_next(unsigned idx) const { return next_vect()[idx]; }
|
||||
void set_next(unsigned idx, bucket * bt) { SASSERT(idx < level()); next_vect()[idx] = bt; }
|
||||
};
|
||||
|
||||
// Only the header bucket has zero entries.
|
||||
bucket * m_header;
|
||||
|
||||
bucket * first_bucket() const {
|
||||
return m_header->get_next(0);
|
||||
}
|
||||
|
||||
#ifdef Z3DEBUG
|
||||
/**
|
||||
\brief (debugging only) Return the predecessor bucket of the given bucket.
|
||||
|
||||
\pre bt != m_header, and bt is a bucket of the list.
|
||||
*/
|
||||
bucket * pred_bucket(bucket * bt) const {
|
||||
SASSERT(bt != m_header);
|
||||
bucket * curr = m_header;
|
||||
while (curr->get_next(0) != bt) {
|
||||
curr = curr->get_next(0);
|
||||
SASSERT(curr != 0); // bt is not in the list
|
||||
}
|
||||
return curr;
|
||||
}
|
||||
#endif
|
||||
|
||||
bool lt(key const & k1, key const & k2) const { return Traits::lt(k1, k2); }
|
||||
|
||||
bool gt(key const & k1, key const & k2) const { return lt(k2, k1); }
|
||||
|
||||
bool geq(key const & k1, key const & k2) const { return !lt(k1, k2); }
|
||||
|
||||
bool leq(key const & k1, key const & k2) const { return !gt(k1, k2); }
|
||||
|
||||
/**
|
||||
\brief Create a new bucket of the given level.
|
||||
*/
|
||||
static bucket * mk_bucket(manager & m, unsigned lvl, unsigned capacity = Traits::max_capacity) {
|
||||
void * mem = m.allocate(bucket::get_obj_size(lvl, capacity));
|
||||
return new (mem) bucket(lvl, capacity);
|
||||
}
|
||||
|
||||
static bucket * mk_header(manager & m, unsigned lvl) {
|
||||
return mk_bucket(m, lvl, 0);
|
||||
}
|
||||
|
||||
static void inc_ref(manager & m, value const & v) {
|
||||
if (Traits::ref_count)
|
||||
m.inc_ref_eh(v);
|
||||
}
|
||||
|
||||
static void dec_ref(manager & m, value const & v) {
|
||||
if (Traits::ref_count)
|
||||
m.dec_ref_eh(v);
|
||||
}
|
||||
|
||||
/**
|
||||
\brief Invoke dec_ref_eh for each value stored in the bucket.
|
||||
*/
|
||||
static void dec_ref(manager & m, bucket * bt) {
|
||||
if (Traits::ref_count) {
|
||||
unsigned sz = bt->size();
|
||||
for (unsigned i = 0; i < sz; i++)
|
||||
m.dec_ref_eh(bt->get(i).val());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
\brief Deallocate the given bucket.
|
||||
|
||||
\remark This method invokes dec_ref_eh for each value in the bucket.
|
||||
*/
|
||||
template<bool DecRef>
|
||||
static void deallocate_bucket(manager & m, bucket * bt) {
|
||||
if (DecRef)
|
||||
dec_ref(m, bt);
|
||||
unsigned sz = bucket::get_obj_size(bt->level(), bt->capacity());
|
||||
bt->~bucket();
|
||||
m.deallocate(sz, bt);
|
||||
}
|
||||
|
||||
/**
|
||||
\brief Deallocate all buckets in the skip list.
|
||||
|
||||
\remark This method invokes dec_ref_eh for each value in the list.
|
||||
*/
|
||||
template<bool DecRef>
|
||||
void deallocate_list(manager & m) {
|
||||
bucket * curr = m_header;
|
||||
while (curr != 0) {
|
||||
bucket * old = curr;
|
||||
curr = curr->get_next(0);
|
||||
deallocate_bucket<DecRef>(m, old);
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef Z3DEBUG
|
||||
/**
|
||||
\brief Check the following property
|
||||
|
||||
for all i \in [0, b->level()) . pred_vect[i]->get_next(i) == b
|
||||
*/
|
||||
bool check_pred_vect(bucket * bt, bucket * pred_vect[]) {
|
||||
if (bt == 0)
|
||||
return true;
|
||||
for (unsigned i = 0; i < bt->level(); i++) {
|
||||
SASSERT(pred_vect[i]->get_next(i) == bt);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
#endif
|
||||
|
||||
/**
|
||||
\brief Delete the given buffer and update the forward/next pointer of the buckets in pred_vect.
|
||||
|
||||
\remark This method invokes dec_ref_eh for each value in the bucket.
|
||||
*/
|
||||
void del_bucket(manager & m, bucket * bt, bucket * pred_vect[]) {
|
||||
SASSERT(check_pred_vect(bt, pred_vect));
|
||||
for (unsigned i = 0; i < bt->level(); i++)
|
||||
pred_vect[i]->set_next(i, bt->get_next(i));
|
||||
deallocate_bucket<true>(m, bt);
|
||||
}
|
||||
|
||||
/**
|
||||
\brief Update the \c pred_vect vector from levels [0, bt->level()).
|
||||
That is, bt will be now the "predecessor" for these levels.
|
||||
*/
|
||||
static void update_predecessor_vector(bucket * pred_vect [], bucket * bt) {
|
||||
unsigned lvl = bt->level();
|
||||
for (unsigned i = 0; i < lvl; i++) {
|
||||
pred_vect[i] = bt;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
\brief Similar to the previous method, but the updated vector is stored in new_pred_vect.
|
||||
*/
|
||||
void update_predecessor_vector(bucket * pred_vect[], bucket * bt, bucket * new_pred_vect[]) {
|
||||
unsigned bt_lvl = bt->level();
|
||||
for (unsigned i = 0; i < bt_lvl; i++) {
|
||||
new_pred_vect[i] = bt;
|
||||
}
|
||||
unsigned list_lvl = level();
|
||||
for (unsigned i = bt_lvl; i < list_lvl; i++) {
|
||||
new_pred_vect[i] = pred_vect[i];
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
\brief Return the list level.
|
||||
*/
|
||||
unsigned level() const {
|
||||
return m_header->level();
|
||||
}
|
||||
|
||||
/**
|
||||
\brief Expand/Increase the number of levels in the header.
|
||||
*/
|
||||
void expand_header(manager & m, unsigned new_lvl) {
|
||||
SASSERT(new_lvl > level());
|
||||
bucket * new_header = mk_header(m, new_lvl);
|
||||
// copy forward pointers of the old header.
|
||||
unsigned old_lvl = level();
|
||||
for (unsigned i = 0; i < old_lvl; i++)
|
||||
new_header->set_next(i, m_header->get_next(i));
|
||||
// update header
|
||||
deallocate_bucket<false>(m, m_header);
|
||||
m_header = new_header;
|
||||
}
|
||||
|
||||
/**
|
||||
\brief Increase list level to lvl if lvl > level()
|
||||
*/
|
||||
void update_list_level(manager & m, unsigned lvl) {
|
||||
if (lvl > level()) {
|
||||
expand_header(m, lvl);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
\brief Increase list level (and store m_header in the new levels in pred_vect) if lvl > level().
|
||||
*/
|
||||
void update_list_level(manager & m, unsigned lvl, bucket * pred_vect[]) {
|
||||
if (lvl > level()) {
|
||||
bucket * old_header = m_header;
|
||||
unsigned old_lvl = m_header->level();
|
||||
expand_header(m, lvl);
|
||||
for (unsigned i = 0; i < old_lvl; i++) {
|
||||
if (pred_vect[i] == old_header)
|
||||
pred_vect[i] = m_header;
|
||||
}
|
||||
for (unsigned i = old_lvl; i < lvl; i++) {
|
||||
pred_vect[i] = m_header;
|
||||
}
|
||||
SASSERT(level() == lvl);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
\brief Add first entry to the list.
|
||||
|
||||
\remark This method will invoke inc_ref_eh for e.val()
|
||||
*/
|
||||
void insert_first_entry(manager & m, entry const & e) {
|
||||
unsigned lvl = m.random_level(Traits::max_level);
|
||||
bucket * new_bucket = mk_bucket(m, lvl, Traits::initial_capacity);
|
||||
update_list_level(m, lvl);
|
||||
for (unsigned i = 0; i < lvl; i++) {
|
||||
m_header->set_next(i, new_bucket);
|
||||
}
|
||||
inc_ref(m, e.val());
|
||||
new_bucket->set_size(1);
|
||||
new_bucket->set(0, e);
|
||||
}
|
||||
|
||||
/**
|
||||
\brief Expand the capacity of the first-bucket in a skip-list with only one bucket.
|
||||
This method assumes the capacity of the first-bucket < Traits::max_capacity
|
||||
*/
|
||||
void expand_first_bucket(manager & m) {
|
||||
bucket * f = first_bucket();
|
||||
SASSERT(f != 0);
|
||||
SASSERT(f->get_next(0) == 0);
|
||||
SASSERT(f->capacity() < Traits::max_capacity);
|
||||
unsigned old_capacity = f->capacity();
|
||||
SASSERT(old_capacity > 0);
|
||||
unsigned new_capacity = old_capacity * 2;
|
||||
if (new_capacity > Traits::max_capacity)
|
||||
new_capacity = Traits::max_capacity;
|
||||
unsigned lvl = f->level();
|
||||
bucket * new_f = mk_bucket(m, lvl, new_capacity);
|
||||
unsigned sz = f->size();
|
||||
new_f->set_size(sz);
|
||||
for (unsigned i = 0; i < sz; i++)
|
||||
new_f->set(i, f->get(i));
|
||||
for (unsigned i = 0; i < lvl; i++)
|
||||
m_header->set_next(i, new_f);
|
||||
deallocate_bucket<false>(m, f);
|
||||
SASSERT(first_bucket() == new_f);
|
||||
}
|
||||
|
||||
/**
|
||||
\brief Create a new bucket and divide the elements in bt between bt and the new bucket.
|
||||
*/
|
||||
void splice(manager & m, bucket * bt, bucket * pred_vect[]) {
|
||||
SASSERT(bt->capacity() == Traits::max_capacity);
|
||||
unsigned bt_lvl = bt->level();
|
||||
unsigned new_bucket_lvl = m.random_level(Traits::max_level);
|
||||
bucket * new_bucket = mk_bucket(m, new_bucket_lvl);
|
||||
update_list_level(m, new_bucket_lvl, pred_vect);
|
||||
unsigned _lvl = std::min(bt_lvl, new_bucket_lvl);
|
||||
for (unsigned i = 0; i < _lvl; i++) {
|
||||
new_bucket->set_next(i, bt->get_next(i));
|
||||
bt->set_next(i, new_bucket);
|
||||
}
|
||||
for (unsigned i = bt_lvl; i < new_bucket_lvl; i++) {
|
||||
new_bucket->set_next(i, pred_vect[i]->get_next(i));
|
||||
pred_vect[i]->set_next(i, new_bucket);
|
||||
}
|
||||
unsigned old_size = bt->size();
|
||||
SASSERT(old_size >= 2);
|
||||
unsigned mid = old_size/2;
|
||||
new_bucket->set_size(old_size - mid);
|
||||
unsigned i = mid;
|
||||
unsigned j = 0;
|
||||
for (; i < old_size; i++, j++) {
|
||||
new_bucket->set(j, bt->get(i));
|
||||
}
|
||||
bt->set_size(mid);
|
||||
SASSERT(!bt->empty());
|
||||
SASSERT(!new_bucket->empty());
|
||||
}
|
||||
|
||||
/**
|
||||
\brief Open space at position idx. The number of entries in bt is increased by one.
|
||||
|
||||
\remark This method will *NOT* invoke inc_ref_eh
|
||||
*/
|
||||
void open_space(bucket * bt, unsigned idx) {
|
||||
SASSERT(bt->size() < bt->capacity());
|
||||
SASSERT(idx <= bt->size());
|
||||
unsigned i = bt->size();
|
||||
while (i > idx) {
|
||||
bt->set(i, bt->get(i-1));
|
||||
i--;
|
||||
}
|
||||
bt->expand(1);
|
||||
}
|
||||
|
||||
/**
|
||||
\brief Open two spaces at position idx. The number of entries in bt is increased by one.
|
||||
|
||||
\remark This method will *NOT* invoke inc_ref_eh
|
||||
*/
|
||||
void open_2spaces(bucket * bt, unsigned idx) {
|
||||
SASSERT(bt->size() < bt->capacity() - 1);
|
||||
SASSERT(idx <= bt->size());
|
||||
unsigned i = bt->size() + 1;
|
||||
unsigned end = idx + 1;
|
||||
while (i > end) {
|
||||
bt->set(i, bt->get(i-2));
|
||||
i--;
|
||||
}
|
||||
bt->expand(2);
|
||||
}
|
||||
|
||||
/**
|
||||
\brief Delete entry at position idx.
|
||||
|
||||
\remark This method will invoke dec_ref_eh for the value stored in entry at position idx.
|
||||
*/
|
||||
void del_entry(manager & m, bucket * bt, unsigned idx) {
|
||||
SASSERT(!bt->empty());
|
||||
SASSERT(idx < bt->size());
|
||||
dec_ref(m, bt->get(idx).val());
|
||||
unsigned sz = bt->size();
|
||||
for (unsigned i = idx; i < sz - 1; i++) {
|
||||
bt->set(i, bt->get(i+1));
|
||||
}
|
||||
bt->shrink(1);
|
||||
}
|
||||
|
||||
/**
|
||||
\brief Create a copy of the skip list.
|
||||
|
||||
\remark This method will invoke inc_ref_eh for all values copied.
|
||||
*/
|
||||
void clone_core(manager & m, skip_list_base * new_list) const {
|
||||
bucket * pred_vect[Traits::max_level];
|
||||
unsigned lvl = level();
|
||||
new_list->update_list_level(m, lvl);
|
||||
bucket * new_header = new_list->m_header;
|
||||
for (unsigned i = 0; i < lvl; i++)
|
||||
pred_vect[i] = new_header;
|
||||
bucket * curr = first_bucket();
|
||||
while (curr != 0) {
|
||||
unsigned curr_lvl = curr->level();
|
||||
bucket * new_bucket = new_list->mk_bucket(m, curr_lvl, curr->capacity());
|
||||
for (unsigned i = 0; i < curr_lvl; i++) {
|
||||
pred_vect[i]->set_next(i, new_bucket);
|
||||
pred_vect[i] = new_bucket;
|
||||
}
|
||||
unsigned curr_sz = curr->size();
|
||||
for (unsigned i = 0; i < curr_sz; i++) {
|
||||
entry const & curr_entry = curr->get(i);
|
||||
inc_ref(m, curr_entry.val());
|
||||
new_bucket->set(i, curr_entry);
|
||||
}
|
||||
new_bucket->set_size(curr_sz);
|
||||
curr = curr->get_next(0);
|
||||
}
|
||||
}
|
||||
|
||||
public:
|
||||
skip_list_base():
|
||||
m_header(0) {
|
||||
SASSERT(Traits::max_capacity >= 2);
|
||||
SASSERT(Traits::initial_capacity >= 2);
|
||||
SASSERT(Traits::initial_capacity <= Traits::max_capacity);
|
||||
SASSERT(Traits::max_level >= 1);
|
||||
SASSERT(Traits::max_capacity <= SL_MAX_CAPACITY);
|
||||
SASSERT(Traits::max_level <= SL_MAX_LEVEL);
|
||||
}
|
||||
|
||||
skip_list_base(manager & m):
|
||||
m_header(0) {
|
||||
SASSERT(Traits::max_capacity >= 2);
|
||||
SASSERT(Traits::initial_capacity >= 2);
|
||||
SASSERT(Traits::initial_capacity <= Traits::max_capacity);
|
||||
SASSERT(Traits::max_level >= 1);
|
||||
SASSERT(Traits::max_capacity <= SL_MAX_CAPACITY);
|
||||
SASSERT(Traits::max_level <= SL_MAX_LEVEL);
|
||||
init(m);
|
||||
}
|
||||
|
||||
~skip_list_base() {
|
||||
SASSERT(m_header == 0);
|
||||
}
|
||||
|
||||
void deallocate(manager & m) {
|
||||
deallocate_list<true>(m);
|
||||
m_header = 0;
|
||||
}
|
||||
|
||||
/**
|
||||
\brief Deallocate the list but do not invoke dec_ref_eh.
|
||||
*/
|
||||
void deallocate_no_decref(manager & m) {
|
||||
deallocate_list<false>(m);
|
||||
m_header = 0;
|
||||
}
|
||||
|
||||
/**
|
||||
\brief Initialize a list that was created using the default constructor.
|
||||
It can be used also to initialized a list deallocated using the method #deallocate.
|
||||
*/
|
||||
void init(manager & m) {
|
||||
SASSERT(m_header == 0);
|
||||
m_header = mk_header(m, 1);
|
||||
}
|
||||
|
||||
/**
|
||||
\brief Remove all elements from the skip-list.
|
||||
*/
|
||||
void reset(manager & m) {
|
||||
deallocate_list<true>(m);
|
||||
m_header = mk_header(m, 1);
|
||||
}
|
||||
|
||||
/**
|
||||
\brief Remove all elements from the skip-list without invoking dec_ref_eh.
|
||||
*/
|
||||
void reset_no_decref(manager & m) {
|
||||
deallocate_list<false>(m);
|
||||
m_header = mk_header(m, 1);
|
||||
}
|
||||
|
||||
/**
|
||||
\brief Return true if the list is empty.
|
||||
*/
|
||||
bool empty() const {
|
||||
SASSERT(m_header != 0);
|
||||
return first_bucket() == 0;
|
||||
}
|
||||
|
||||
protected:
|
||||
/**
|
||||
\brief Return the position of the bucket in the skip list.
|
||||
*/
|
||||
unsigned get_bucket_idx(bucket const * bt) const {
|
||||
bucket * curr = m_header;
|
||||
unsigned pos = 0;
|
||||
while (curr != 0) {
|
||||
if (curr == bt)
|
||||
return pos;
|
||||
pos++;
|
||||
curr = curr->get_next(0);
|
||||
}
|
||||
UNREACHABLE();
|
||||
return pos;
|
||||
}
|
||||
|
||||
/**
|
||||
\brief Display the given entry.
|
||||
*/
|
||||
void display(std::ostream & out, entry const & e) const {
|
||||
e.display(out);
|
||||
}
|
||||
|
||||
/**
|
||||
\brief Display a reference to the given bucket.
|
||||
*/
|
||||
void display_bucket_ref(std::ostream & out, bucket const * bt) const {
|
||||
if (bt == 0)
|
||||
out << "NIL";
|
||||
else
|
||||
out << "#" << get_bucket_idx(bt);
|
||||
}
|
||||
|
||||
/**
|
||||
\brief Display the predecessor vector.
|
||||
*/
|
||||
void display_predecessor_vector(std::ostream & out, bucket const * const pred_vect[]) const {
|
||||
for (unsigned i = 0; i < level(); i++) {
|
||||
out << i << ": ";
|
||||
display_bucket_ref(out, pred_vect[i]);
|
||||
if (pred_vect[i]) {
|
||||
out << " -> ";
|
||||
display_bucket_ref(out, pred_vect[i]->get_next(i));
|
||||
}
|
||||
out << "\n";
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
\brief Display the successors of the given bucket.
|
||||
*/
|
||||
void display_successors(std::ostream & out, bucket const * bt) const {
|
||||
out << "[";
|
||||
for (unsigned i = 0; i < bt->level(); i++) {
|
||||
if (i > 0) out << ", ";
|
||||
display_bucket_ref(out, bt->get_next(i));
|
||||
}
|
||||
out << "]";
|
||||
}
|
||||
|
||||
/**
|
||||
\brief Display the given bucket.
|
||||
*/
|
||||
void display(std::ostream & out, bucket const * bt) const {
|
||||
if (bt == 0) {
|
||||
out << "NIL\n";
|
||||
return;
|
||||
}
|
||||
out << "bucket ";
|
||||
display_bucket_ref(out, bt);
|
||||
out << ", capacity: " << bt->capacity() << "\n";
|
||||
out << "successors: ";
|
||||
display_successors(out, bt);
|
||||
out << "\n";
|
||||
out << "entries:\n";
|
||||
for (unsigned i = 0; i < bt->size(); i++) {
|
||||
display(out, bt->get(i));
|
||||
out << "\n";
|
||||
}
|
||||
out << "----------\n";
|
||||
}
|
||||
|
||||
public:
|
||||
/**
|
||||
\brief Dump the skip list for debugging purposes.
|
||||
It assumes that key and value types implement operator <<.
|
||||
*/
|
||||
void display_physical(std::ostream & out) const {
|
||||
out << "{\nskip-list level: " << m_header->level() << "\n";
|
||||
bucket * curr = m_header;
|
||||
while (curr != 0) {
|
||||
display(out, curr);
|
||||
curr = curr->get_next(0);
|
||||
}
|
||||
out << "}\n";
|
||||
}
|
||||
|
||||
void display(std::ostream & out) const {
|
||||
bucket * curr = m_header;
|
||||
while (curr != 0) {
|
||||
unsigned sz = curr->size();
|
||||
for (unsigned i = 0; i < sz; i++) {
|
||||
if (i > 0)
|
||||
out << " ";
|
||||
curr->get(i).display(out);
|
||||
}
|
||||
curr = curr->get_next(0);
|
||||
}
|
||||
}
|
||||
|
||||
protected:
|
||||
/**
|
||||
\brief Return true if bucket b2 can be reached from b1 following get_next(i) pointers
|
||||
*/
|
||||
bool is_reachable_at_i(bucket const * bt1, bucket const * bt2, unsigned i) const {
|
||||
bucket * curr = bt1->get_next(i);
|
||||
while (curr != 0) {
|
||||
if (curr == bt2)
|
||||
return true;
|
||||
curr = curr->get_next(i);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
protected:
|
||||
static void display_size_info_core(std::ostream & out, unsigned cls_size) {
|
||||
out << "sizeof root: " << cls_size << "\n";
|
||||
out << "bucket max capacity: " << Traits::max_capacity << "\n";
|
||||
out << "bucket max level: " << Traits::max_level << "\n";
|
||||
out << "sizeof(bucket): " << sizeof(bucket) << " + " << sizeof(bucket*) << "*lvl + " << sizeof(entry) << "*capacity\n";
|
||||
out << "sizeof(usual bucket): " << (sizeof(bucket) + sizeof(entry)*Traits::max_capacity) << " + " << sizeof(bucket*) << "*lvl\n";
|
||||
out << "sizeof(max. bucket): " << (sizeof(bucket) + sizeof(entry)*Traits::max_capacity + sizeof(bucket*)*Traits::max_level) << "\n";
|
||||
out << "sizeof(entry): " << sizeof(entry) << "\n";
|
||||
out << "sizeof empty: " << cls_size + bucket::get_obj_size(1, 0) << "\n";;
|
||||
out << "sizeof singleton: ["
|
||||
<< (cls_size + bucket::get_obj_size(1, 0) + bucket::get_obj_size(1, Traits::initial_capacity)) << ", "
|
||||
<< (cls_size +
|
||||
bucket::get_obj_size(Traits::max_level, 0) +
|
||||
bucket::get_obj_size(Traits::max_level, Traits::max_capacity)) << "]\n";
|
||||
}
|
||||
|
||||
public:
|
||||
/**
|
||||
\brief Return true if skip-list has more than k buckets (not considering the header).
|
||||
|
||||
\remark This method is for debugging purposes.
|
||||
*/
|
||||
bool has_more_than_k_buckets(unsigned k) const {
|
||||
bucket * curr = first_bucket();
|
||||
while (curr != 0 && k > 0) {
|
||||
curr = curr->get_next(0);
|
||||
k--;
|
||||
}
|
||||
return curr != 0;
|
||||
}
|
||||
|
||||
/**
|
||||
\brief Return true if the skip-list has more than k entries.
|
||||
*/
|
||||
bool has_more_than_k_entries(unsigned k) const {
|
||||
bucket * curr = first_bucket();
|
||||
while (curr != 0 && k >= curr->size()) {
|
||||
k -= curr->size();
|
||||
curr = curr->get_next(0);
|
||||
}
|
||||
SASSERT(curr == 0 || curr->size() > k);
|
||||
return curr != 0;
|
||||
}
|
||||
|
||||
protected:
|
||||
/**
|
||||
\brief Return the amount of memory consumed by the list.
|
||||
*/
|
||||
unsigned memory_core(unsigned cls_size) const {
|
||||
unsigned r = 0;
|
||||
r += cls_size;
|
||||
bucket * curr = m_header;
|
||||
while (curr != 0) {
|
||||
r += bucket::get_obj_size(curr->level(), curr->capacity());
|
||||
curr = curr->get_next(0);
|
||||
}
|
||||
return r;
|
||||
}
|
||||
|
||||
public:
|
||||
/**
|
||||
\brief Compress the buckets of the skip-list.
|
||||
Make sure that all, but the last bucket, have at least \c load entries.
|
||||
|
||||
\remark If load > Traits::max_capacity, then it assumes load = Traits::max_capacity.
|
||||
*/
|
||||
void compress(manager & m, unsigned load = Traits::max_capacity/2) {
|
||||
if (load > Traits::max_capacity)
|
||||
load = Traits::max_capacity;
|
||||
bucket * pred_vect[Traits::max_level];
|
||||
update_predecessor_vector(pred_vect, m_header);
|
||||
bucket * curr = first_bucket();
|
||||
while (curr != 0) {
|
||||
update_predecessor_vector(pred_vect, curr);
|
||||
bucket * next = curr->get_next(0);
|
||||
while (curr->size() < load && next != 0) {
|
||||
// steal entries of the successor bucket.
|
||||
unsigned deficit = load - curr->size();
|
||||
unsigned next_size = next->size();
|
||||
if (next_size <= deficit) {
|
||||
for (unsigned i = 0, j = curr->size(); i < next_size; i++, j++) {
|
||||
curr->set(j, next->get(i));
|
||||
}
|
||||
curr->expand(next_size);
|
||||
bucket * new_next = next->get_next(0);
|
||||
del_bucket(m, next, pred_vect);
|
||||
next = new_next;
|
||||
SASSERT(curr->size() <= load);
|
||||
}
|
||||
else {
|
||||
for (unsigned i = 0, j = curr->size(); i < deficit; i++, j++) {
|
||||
curr->set(j, next->get(i));
|
||||
}
|
||||
curr->expand(deficit);
|
||||
for (unsigned i = deficit, j = 0; i < next_size; i++, j++) {
|
||||
next->set(j, next->get(i));
|
||||
}
|
||||
next->set_size(next_size - deficit);
|
||||
SASSERT(curr->size() == load);
|
||||
}
|
||||
}
|
||||
curr = curr->get_next(0);
|
||||
}
|
||||
}
|
||||
|
||||
void swap(skip_list_base & other) {
|
||||
bucket * tmp = m_header;
|
||||
m_header = other.m_header;
|
||||
other.m_header = tmp;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
#endif
|
Loading…
Add table
Add a link
Reference in a new issue