mirror of
https://github.com/Z3Prover/z3
synced 2025-04-23 17:15:31 +00:00
Reorganizing source code. Created util dir
Signed-off-by: Leonardo de Moura <leonardo@microsoft.com>
This commit is contained in:
parent
630ba0c675
commit
2c464d413d
153 changed files with 0 additions and 0 deletions
61
src/util/approx_nat.cpp
Normal file
61
src/util/approx_nat.cpp
Normal file
|
@ -0,0 +1,61 @@
|
|||
/*++
|
||||
Copyright (c) 2007 Microsoft Corporation
|
||||
|
||||
Module Name:
|
||||
|
||||
approx_nat.cpp
|
||||
|
||||
Abstract:
|
||||
|
||||
Approximated natural numbers. It performs operations on the set [0, ..., 2^{n-2}, huge].
|
||||
Where huge represents all numbers greater than 2^{n-2}.
|
||||
|
||||
Author:
|
||||
|
||||
Leonardo (leonardo) 2008-01-11
|
||||
|
||||
Notes:
|
||||
|
||||
--*/
|
||||
#include"approx_nat.h"
|
||||
|
||||
approx_nat::approx_nat(unsigned val) {
|
||||
m_value = val > m_limit ? UINT_MAX : val;
|
||||
}
|
||||
|
||||
approx_nat & approx_nat::operator=(unsigned val) {
|
||||
m_value = val > m_limit ? UINT_MAX : val;
|
||||
return *this;
|
||||
}
|
||||
|
||||
approx_nat & approx_nat::operator+=(unsigned w) {
|
||||
if (is_huge())
|
||||
return *this;
|
||||
if (w > m_limit) {
|
||||
m_value = UINT_MAX;
|
||||
return *this;
|
||||
}
|
||||
m_value += w;
|
||||
if (m_value > m_limit)
|
||||
m_value = UINT_MAX;
|
||||
return *this;
|
||||
}
|
||||
|
||||
approx_nat & approx_nat::operator*=(unsigned w) {
|
||||
if (is_huge())
|
||||
return *this;
|
||||
unsigned long long r = static_cast<unsigned long long>(m_value) * static_cast<unsigned long long>(w);
|
||||
if (r > m_limit)
|
||||
m_value = UINT_MAX;
|
||||
else
|
||||
m_value = static_cast<unsigned>(r);
|
||||
return *this;
|
||||
}
|
||||
|
||||
std::ostream & operator<<(std::ostream & target, approx_nat const & w) {
|
||||
if (w.is_huge())
|
||||
target << "[huge]";
|
||||
else
|
||||
target << w.get_value();
|
||||
return target;
|
||||
}
|
45
src/util/approx_nat.h
Normal file
45
src/util/approx_nat.h
Normal file
|
@ -0,0 +1,45 @@
|
|||
/*++
|
||||
Copyright (c) 2007 Microsoft Corporation
|
||||
|
||||
Module Name:
|
||||
|
||||
approx_nat.h
|
||||
|
||||
Abstract:
|
||||
|
||||
Approximated natural numbers. It performs operations on the set [0, ..., 2^{n-2}, huge].
|
||||
Where huge represents all numbers greater than 2^{n-2}.
|
||||
|
||||
Author:
|
||||
|
||||
Leonardo (leonardo) 2008-01-11
|
||||
|
||||
Notes:
|
||||
|
||||
--*/
|
||||
#ifndef _APPROX_NAT_H_
|
||||
#define _APPROX_NAT_H_
|
||||
|
||||
#include<iostream>
|
||||
#include<limits.h>
|
||||
|
||||
class approx_nat {
|
||||
unsigned m_value;
|
||||
static const unsigned m_limit = UINT_MAX >> 2;
|
||||
public:
|
||||
approx_nat():m_value(0) {}
|
||||
explicit approx_nat(unsigned val);
|
||||
bool is_huge() const { return m_value == UINT_MAX; }
|
||||
unsigned get_value() const { return m_value; }
|
||||
approx_nat & operator=(unsigned w);
|
||||
approx_nat & operator+=(unsigned w);
|
||||
approx_nat & operator+=(approx_nat const & w) { return operator+=(w.m_value); }
|
||||
approx_nat & operator*=(unsigned w);
|
||||
approx_nat & operator*=(approx_nat const & w) { return operator*=(w.m_value); }
|
||||
bool operator<(unsigned w) const { return !is_huge() && m_value < w; }
|
||||
bool operator<(approx_nat const & w) const { return !is_huge() && !w.is_huge() && m_value < w.m_value; }
|
||||
};
|
||||
|
||||
std::ostream & operator<<(std::ostream & target, approx_nat const & w);
|
||||
|
||||
#endif /* _APPROX_NAT_H_ */
|
52
src/util/approx_set.cpp
Normal file
52
src/util/approx_set.cpp
Normal file
|
@ -0,0 +1,52 @@
|
|||
/*++
|
||||
Copyright (c) 2006 Microsoft Corporation
|
||||
|
||||
Module Name:
|
||||
|
||||
approx_set.cpp
|
||||
|
||||
Abstract:
|
||||
|
||||
Approximated sets.
|
||||
|
||||
Author:
|
||||
|
||||
Leonardo de Moura (leonardo) 2007-03-02.
|
||||
|
||||
Revision History:
|
||||
|
||||
--*/
|
||||
|
||||
#include"approx_set.h"
|
||||
|
||||
void approx_set::display(std::ostream & out) const {
|
||||
out << "{";
|
||||
bool first = true;
|
||||
unsigned long long s = m_set;
|
||||
for (unsigned i = 0; i < approx_set_traits<unsigned long long>::capacity; i++) {
|
||||
if ((s & 1) != 0) {
|
||||
if (first) {
|
||||
first = false;
|
||||
}
|
||||
else {
|
||||
out << ", ";
|
||||
}
|
||||
out << i;
|
||||
}
|
||||
s = s >> 1;
|
||||
}
|
||||
out << "}";
|
||||
}
|
||||
|
||||
unsigned approx_set::size() const {
|
||||
unsigned long long tmp = m_set;
|
||||
unsigned r = 0;
|
||||
while (tmp > 0) {
|
||||
if ((tmp & 1) != 0) {
|
||||
r++;
|
||||
}
|
||||
tmp = tmp >> 1;
|
||||
}
|
||||
return r;
|
||||
}
|
||||
|
236
src/util/approx_set.h
Normal file
236
src/util/approx_set.h
Normal file
|
@ -0,0 +1,236 @@
|
|||
/*++
|
||||
Copyright (c) 2006 Microsoft Corporation
|
||||
|
||||
Module Name:
|
||||
|
||||
approx_set.h
|
||||
|
||||
Abstract:
|
||||
|
||||
Approximated sets.
|
||||
|
||||
Author:
|
||||
|
||||
Leonardo de Moura (leonardo) 2007-03-02.
|
||||
|
||||
Revision History:
|
||||
|
||||
--*/
|
||||
#ifndef _APPROX_SET_H_
|
||||
#define _APPROX_SET_H_
|
||||
#include<iostream>
|
||||
#include"debug.h"
|
||||
|
||||
template<typename T> class approx_set_traits;
|
||||
|
||||
template <> class approx_set_traits<unsigned long long> {
|
||||
public:
|
||||
static const unsigned capacity = 64;
|
||||
static const unsigned long long zero = 0ull;
|
||||
static const unsigned long long one = 1ull;
|
||||
};
|
||||
COMPILE_TIME_ASSERT(sizeof(unsigned long long) == 8);
|
||||
|
||||
template <> class approx_set_traits<unsigned> {
|
||||
public:
|
||||
static const unsigned capacity = 32;
|
||||
static const unsigned zero = 0;
|
||||
static const unsigned one = 1;
|
||||
};
|
||||
COMPILE_TIME_ASSERT(sizeof(unsigned) == 4);
|
||||
|
||||
template<typename T, typename T2U_Proc, typename R=unsigned long long>
|
||||
class approx_set_tpl : private T2U_Proc {
|
||||
protected:
|
||||
R m_set;
|
||||
|
||||
unsigned e2u(T const & e) const { return T2U_Proc::operator()(e); }
|
||||
|
||||
R u2s(unsigned u) const { return (approx_set_traits<R>::one << (u & (approx_set_traits<R>::capacity - 1))); }
|
||||
|
||||
R e2s(T const & e) const { return u2s(e2u(e)); }
|
||||
|
||||
static approx_set_tpl r2s(R const & s) { approx_set_tpl r; r.m_set = s; return r; }
|
||||
|
||||
public:
|
||||
approx_set_tpl():
|
||||
m_set(approx_set_traits<R>::zero) {
|
||||
}
|
||||
|
||||
explicit approx_set_tpl(T const & e):
|
||||
m_set(e2s(e)) {
|
||||
}
|
||||
|
||||
approx_set_tpl(unsigned sz, T const * es):
|
||||
m_set(approx_set_traits<R>::zero) {
|
||||
for (unsigned i = 0; i < sz; i++)
|
||||
insert(es[i]);
|
||||
}
|
||||
|
||||
approx_set_tpl(approx_set_tpl const & s):
|
||||
m_set(s.m_set) {
|
||||
}
|
||||
|
||||
void insert(T const & e) {
|
||||
m_set |= e2s(e);
|
||||
}
|
||||
|
||||
bool may_contain(T const & e) const {
|
||||
return (m_set & e2s(e)) != approx_set_traits<R>::zero;
|
||||
}
|
||||
|
||||
bool must_not_contain(T const & e) const {
|
||||
return !may_contain(e);
|
||||
}
|
||||
|
||||
friend inline approx_set_tpl mk_union(approx_set_tpl const & s1, approx_set_tpl const & s2) {
|
||||
return r2s(s1.m_set | s2.m_set);
|
||||
}
|
||||
|
||||
friend inline approx_set_tpl mk_intersection(approx_set_tpl const & s1, approx_set_tpl const & s2) {
|
||||
return r2s(s1.m_set & s2.m_set);
|
||||
}
|
||||
|
||||
void operator|=(approx_set_tpl const & other) {
|
||||
m_set |= other.m_set;
|
||||
}
|
||||
|
||||
void operator&=(approx_set_tpl const & other) {
|
||||
m_set &= other.m_set;
|
||||
}
|
||||
|
||||
void operator-=(approx_set_tpl const & other) {
|
||||
m_set &= ~(other.m_set);
|
||||
}
|
||||
|
||||
bool empty() const {
|
||||
return m_set == approx_set_traits<R>::zero;
|
||||
}
|
||||
|
||||
friend inline bool empty(approx_set_tpl const & s) {
|
||||
return s.empty();
|
||||
}
|
||||
|
||||
bool must_not_subset(approx_set_tpl const & s2) const {
|
||||
return (m_set & ~(s2.m_set)) != approx_set_traits<R>::zero;
|
||||
}
|
||||
|
||||
friend inline bool must_not_subset(approx_set_tpl const & s1, approx_set_tpl const & s2) {
|
||||
return s1.must_not_subset(s2);
|
||||
}
|
||||
|
||||
bool must_not_subsume(approx_set_tpl const & s2) const {
|
||||
return must_not_subset(s2);
|
||||
}
|
||||
|
||||
friend inline bool must_not_subsume(approx_set_tpl const & s1, approx_set_tpl const & s2) {
|
||||
return s1.must_not_subset(s2);
|
||||
}
|
||||
|
||||
friend inline bool must_not_eq(approx_set_tpl const & s1, approx_set_tpl const & s2) { return s1.m_set != s2.m_set; }
|
||||
|
||||
friend inline bool may_eq(approx_set_tpl const & s1, approx_set_tpl const & s2) { return s1.m_set == s2.m_set; }
|
||||
|
||||
/**
|
||||
\brief Return if s1 and s2 are the same approximated set.
|
||||
*/
|
||||
bool equiv(approx_set_tpl const & s2) const { return m_set == s2.m_set; }
|
||||
friend inline bool equiv(approx_set_tpl const & s1, approx_set_tpl const & s2) { return s1.m_set == s2.m_set; }
|
||||
|
||||
/**
|
||||
\brief Return true if the approximation of s1 is a subset of the approximation of s2.
|
||||
*/
|
||||
friend inline bool approx_subset(approx_set_tpl const & s1, approx_set_tpl const & s2) {
|
||||
return s2.equiv(mk_union(s1, s2));
|
||||
}
|
||||
|
||||
void reset() {
|
||||
m_set = approx_set_traits<R>::zero;
|
||||
}
|
||||
|
||||
bool empty_intersection(approx_set_tpl const & other) const {
|
||||
return mk_intersection(*this, other).empty();
|
||||
}
|
||||
};
|
||||
|
||||
struct u2u { unsigned operator()(unsigned u) const { return u; } };
|
||||
|
||||
typedef approx_set_tpl<unsigned, u2u> u_approx_set;
|
||||
|
||||
#define APPROX_SET_CAPACITY (approx_set_traits<unsigned long long>::capacity)
|
||||
|
||||
class approx_set : public u_approx_set {
|
||||
public:
|
||||
approx_set():u_approx_set() {}
|
||||
approx_set(unsigned e):u_approx_set(e) {}
|
||||
|
||||
class iterator {
|
||||
unsigned long long m_set;
|
||||
unsigned m_val;
|
||||
void move_to_next() {
|
||||
// TODO: this code can be optimized in platforms with special
|
||||
// instructions to count leading (trailing) zeros in a word.
|
||||
while (m_set > 0) {
|
||||
if ((m_set & 1ull) != 0) {
|
||||
return;
|
||||
}
|
||||
m_val ++;
|
||||
m_set = m_set >> 1;
|
||||
}
|
||||
}
|
||||
public:
|
||||
iterator(unsigned long long s):
|
||||
m_set(s),
|
||||
m_val(0) {
|
||||
move_to_next();
|
||||
}
|
||||
|
||||
unsigned operator*() const {
|
||||
return m_val;
|
||||
}
|
||||
|
||||
iterator & operator++() {
|
||||
m_val++;
|
||||
m_set = m_set >> 1;
|
||||
move_to_next();
|
||||
return *this;
|
||||
}
|
||||
|
||||
iterator operator++(int) {
|
||||
iterator tmp = *this;
|
||||
++*this;
|
||||
return tmp;
|
||||
}
|
||||
|
||||
bool operator==(iterator const & it) const {
|
||||
return m_set == it.m_set;
|
||||
}
|
||||
|
||||
bool operator!=(iterator const & it) const {
|
||||
return m_set != it.m_set;
|
||||
}
|
||||
};
|
||||
|
||||
iterator begin() const {
|
||||
return iterator(m_set);
|
||||
}
|
||||
|
||||
static iterator end() {
|
||||
return iterator(0);
|
||||
}
|
||||
|
||||
void display(std::ostream & out) const;
|
||||
|
||||
unsigned size() const;
|
||||
|
||||
// for backward compatibility
|
||||
friend inline bool operator==(approx_set const & s1, approx_set const & s2) { return may_eq(s1, s2); }
|
||||
};
|
||||
|
||||
inline std::ostream & operator<<(std::ostream & out, approx_set const & s) {
|
||||
s.display(out);
|
||||
return out;
|
||||
}
|
||||
|
||||
#endif /* _APPROX_SET_H_ */
|
||||
|
205
src/util/array.h
Normal file
205
src/util/array.h
Normal file
|
@ -0,0 +1,205 @@
|
|||
/*++
|
||||
Copyright (c) 2006 Microsoft Corporation
|
||||
|
||||
Module Name:
|
||||
|
||||
array.h
|
||||
|
||||
Abstract:
|
||||
|
||||
Fixed size arrays
|
||||
|
||||
Author:
|
||||
|
||||
Leonardo de Moura (leonardo) 2011-01-26.
|
||||
|
||||
Revision History:
|
||||
|
||||
--*/
|
||||
#ifndef __ARRAY_H_
|
||||
#define __ARRAY_H_
|
||||
|
||||
template<typename T, bool CallDestructors=true>
|
||||
class array {
|
||||
public:
|
||||
// Return the space needed to store an array of size sz.
|
||||
static size_t space(size_t sz) { return sizeof(T)*sz + sizeof(size_t); }
|
||||
|
||||
private:
|
||||
#define ARRAY_SIZE_IDX -1
|
||||
T * m_data;
|
||||
void destroy_elements() {
|
||||
iterator it = begin();
|
||||
iterator e = end();
|
||||
for (; it != e; ++it) {
|
||||
it->~T();
|
||||
}
|
||||
}
|
||||
|
||||
char * raw_ptr() const { return reinterpret_cast<char*>(reinterpret_cast<size_t*>(m_data) - 1); }
|
||||
|
||||
array & operator=(array const & source);
|
||||
|
||||
void set_data(void * mem, size_t sz) {
|
||||
size_t * _mem = static_cast<size_t*>(mem);
|
||||
*_mem = sz;
|
||||
_mem ++;
|
||||
m_data = reinterpret_cast<T*>(_mem);
|
||||
}
|
||||
|
||||
template<typename Allocator>
|
||||
void allocate(Allocator & a, size_t sz) {
|
||||
size_t * mem = reinterpret_cast<size_t*>(a.allocate(space(sz)));
|
||||
set_data(mem, sz);
|
||||
}
|
||||
|
||||
void init() {
|
||||
iterator it = begin();
|
||||
iterator e = end();
|
||||
for (; it != e; ++it) {
|
||||
new (it) T();
|
||||
}
|
||||
}
|
||||
|
||||
void init(T const * vs) {
|
||||
iterator it = begin();
|
||||
iterator e = end();
|
||||
for (; it != e; ++it, ++vs) {
|
||||
new (it) T(*vs);
|
||||
}
|
||||
}
|
||||
|
||||
public:
|
||||
typedef T data;
|
||||
typedef T * iterator;
|
||||
typedef const T * const_iterator;
|
||||
|
||||
array():m_data(0) {}
|
||||
|
||||
/**
|
||||
\brief Store the array in the given chunk of memory (mem).
|
||||
This chunck should be big enough to store space(sz) bytes.
|
||||
*/
|
||||
array(void * mem, size_t sz, T const * vs) {
|
||||
DEBUG_CODE(m_data = 0;);
|
||||
set(mem, sz, vs);
|
||||
}
|
||||
|
||||
// WARNING: the memory allocated will not be automatically freed.
|
||||
array(void * mem, size_t sz, bool init_mem) {
|
||||
DEBUG_CODE(m_data = 0;);
|
||||
set_data(mem, sz);
|
||||
if (init_mem)
|
||||
init();
|
||||
}
|
||||
|
||||
// WARNING: the memory allocated will not be automatically freed.
|
||||
template<typename Allocator>
|
||||
array(Allocator & a, size_t sz, T const * vs) {
|
||||
DEBUG_CODE(m_data = 0;);
|
||||
set(a, sz, vs);
|
||||
}
|
||||
|
||||
// WARNING: the memory allocated will not be automatically freed.
|
||||
template<typename Allocator>
|
||||
array(Allocator & a, size_t sz, bool init_mem) {
|
||||
DEBUG_CODE(m_data = 0;);
|
||||
allocate(a, sz);
|
||||
if (init_mem)
|
||||
init();
|
||||
}
|
||||
|
||||
// WARNING: this does not free the memory used to store the array.
|
||||
// You must free it yourself, or use finalize.
|
||||
~array() {
|
||||
if (m_data && CallDestructors)
|
||||
destroy_elements();
|
||||
}
|
||||
|
||||
// Free the memory used to store the array.
|
||||
template<typename Allocator>
|
||||
void finalize(Allocator & a) {
|
||||
if (m_data) {
|
||||
if (CallDestructors)
|
||||
destroy_elements();
|
||||
a.deallocate(size(), raw_ptr);
|
||||
m_data = 0;
|
||||
}
|
||||
}
|
||||
|
||||
void set(void * mem, size_t sz, T const * vs) {
|
||||
SASSERT(m_data == 0);
|
||||
set_data(mem, sz);
|
||||
init(vs);
|
||||
}
|
||||
|
||||
template<typename Allocator>
|
||||
void set(Allocator & a, size_t sz, T const * vs) {
|
||||
SASSERT(m_data == 0);
|
||||
allocate(a, sz);
|
||||
init(sz, vs);
|
||||
}
|
||||
|
||||
size_t size() const {
|
||||
if (m_data == 0) {
|
||||
return 0;
|
||||
}
|
||||
return reinterpret_cast<size_t *>(m_data)[SIZE_IDX];
|
||||
}
|
||||
|
||||
bool empty() const { return m_data == 0; }
|
||||
|
||||
T & operator[](size_t idx) {
|
||||
SASSERT(idx < size());
|
||||
return m_data[idx];
|
||||
}
|
||||
|
||||
T const & operator[](size_t idx) const {
|
||||
SASSERT(idx < size());
|
||||
return m_data[idx];
|
||||
}
|
||||
|
||||
iterator begin() {
|
||||
return m_data;
|
||||
}
|
||||
|
||||
iterator end() {
|
||||
return m_data + size();
|
||||
}
|
||||
|
||||
const_iterator begin() const {
|
||||
return m_data;
|
||||
}
|
||||
|
||||
const_iterator end() const {
|
||||
return m_data + size();
|
||||
}
|
||||
|
||||
T * c_ptr() { return m_data; }
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
class ptr_array : public array<T *, false> {
|
||||
public:
|
||||
ptr_array() {}
|
||||
ptr_array(void * mem, size_t sz, T * const * vs):array<T*, false>(mem, sz, vs) {}
|
||||
template<typename Allocator>
|
||||
ptr_array(Allocator & a, size_t sz, T * const * vs):array<T*, false>(a, sz, vs) {}
|
||||
ptr_array(void * mem, size_t sz, bool init_mem):array<T*, false>(mem, sz, init_mem) {}
|
||||
template<typename Allocator>
|
||||
ptr_array(Allocator & a, size_t sz, bool init_mem):array<T*, false>(a, sz, init_mem) {}
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
class sarray : public array<T, false> {
|
||||
public:
|
||||
sarray() {}
|
||||
sarray(void * mem, size_t sz, T const * vs):array<T, false>(mem, sz, vs) {}
|
||||
template<typename Allocator>
|
||||
sarray(Allocator & a, size_t sz, T const * vs):array<T, false>(a, sz, vs) {}
|
||||
sarray(void * mem, size_t sz, bool init_mem):array<T, false>(mem, sz, init_mem) {}
|
||||
template<typename Allocator>
|
||||
sarray(Allocator & a, size_t sz, bool init_mem):array<T, false>(a, sz, init_mem) {}
|
||||
};
|
||||
|
||||
#endif
|
162
src/util/array_map.h
Normal file
162
src/util/array_map.h
Normal file
|
@ -0,0 +1,162 @@
|
|||
/*++
|
||||
Copyright (c) 2006 Microsoft Corporation
|
||||
|
||||
Module Name:
|
||||
|
||||
array_map.h
|
||||
|
||||
Abstract:
|
||||
|
||||
A mapping for keys that can be mapped to unsigned integers.
|
||||
|
||||
Author:
|
||||
|
||||
Leonardo de Moura (leonardo) 2008-01-03.
|
||||
|
||||
Revision History:
|
||||
|
||||
--*/
|
||||
#ifndef _ARRAY_MAP_H_
|
||||
#define _ARRAY_MAP_H_
|
||||
|
||||
#include"vector.h"
|
||||
#include"optional.h"
|
||||
|
||||
/**
|
||||
\brief Implements a mapping from Key to Data.
|
||||
|
||||
Plugin must provide the following functions:
|
||||
- void ins_eh(Key const & k, Data const & d);
|
||||
- void del_eh(Key const & k, Data const & d);
|
||||
- unsigned to_int(Key const & k);
|
||||
*/
|
||||
template<typename Key, typename Data, typename Plugin, bool CallDestructors=true>
|
||||
class array_map {
|
||||
|
||||
struct entry {
|
||||
Key m_key;
|
||||
Data m_data;
|
||||
unsigned m_timestamp;
|
||||
entry(Key const & k, Data const & d, unsigned t): m_key(k), m_data(d), m_timestamp(t) {}
|
||||
};
|
||||
|
||||
unsigned m_timestamp;
|
||||
unsigned m_garbage;
|
||||
unsigned m_non_garbage;
|
||||
static const unsigned m_gc_threshold = 10000;
|
||||
vector<optional<entry>, CallDestructors > m_map;
|
||||
Plugin m_plugin;
|
||||
|
||||
bool is_current(optional<entry> const& e) const {
|
||||
return e->m_timestamp == m_timestamp;
|
||||
}
|
||||
|
||||
optional<entry> const & get_core(Key const & k) const {
|
||||
unsigned id = m_plugin.to_int(k);
|
||||
if (id < m_map.size()) {
|
||||
optional<entry> const & e = m_map[id];
|
||||
if (e && is_current(e)) {
|
||||
return e;
|
||||
}
|
||||
}
|
||||
return optional<entry>::undef();
|
||||
}
|
||||
|
||||
void really_flush() {
|
||||
typename vector<optional<entry> >::iterator it = m_map.begin();
|
||||
typename vector<optional<entry> >::iterator end = m_map.end();
|
||||
for (; it != end; ++it) {
|
||||
optional<entry> & e = *it;
|
||||
if (e) {
|
||||
m_plugin.del_eh(e->m_key, e->m_data);
|
||||
e.set_invalid();
|
||||
}
|
||||
}
|
||||
m_garbage = 0;
|
||||
m_non_garbage = 0;
|
||||
}
|
||||
|
||||
|
||||
public:
|
||||
|
||||
array_map(Plugin const & p = Plugin()):m_timestamp(0), m_garbage(0), m_non_garbage(0), m_plugin(p) {}
|
||||
~array_map() { really_flush(); }
|
||||
|
||||
bool contains(Key const & k) const {
|
||||
return get_core(k);
|
||||
}
|
||||
|
||||
Data const & get(Key const & k) const {
|
||||
optional<entry> const & e = get_core(k);
|
||||
SASSERT(e);
|
||||
return e->m_data;
|
||||
}
|
||||
|
||||
void reset() {
|
||||
if (m_timestamp < UINT_MAX) {
|
||||
m_timestamp++;
|
||||
}
|
||||
else {
|
||||
really_flush();
|
||||
m_timestamp = 0;
|
||||
}
|
||||
}
|
||||
|
||||
void insert(Key const & k, Data const & d) {
|
||||
unsigned id = m_plugin.to_int(k);
|
||||
if (id >= m_map.size()) {
|
||||
m_map.resize(id + 1, optional<entry>::undef());
|
||||
}
|
||||
|
||||
m_plugin.ins_eh(k, d);
|
||||
optional<entry> & e = m_map[id];
|
||||
if (e) {
|
||||
if (!is_current(e)) {
|
||||
--m_garbage;
|
||||
++m_non_garbage;
|
||||
}
|
||||
m_plugin.del_eh(e->m_key, e->m_data);
|
||||
}
|
||||
else {
|
||||
++m_non_garbage;
|
||||
}
|
||||
e = entry(k, d, m_timestamp);
|
||||
}
|
||||
|
||||
void erase(Key const & k) {
|
||||
unsigned id = m_plugin.to_int(k);
|
||||
if (id < m_map.size()) {
|
||||
optional<entry> & e = m_map[id];
|
||||
if (e) {
|
||||
m_plugin.del_eh(e->m_key, e->m_data);
|
||||
if (is_current(e)) {
|
||||
SASSERT(m_non_garbage > 0);
|
||||
--m_non_garbage;
|
||||
}
|
||||
else {
|
||||
SASSERT(m_garbage > 0);
|
||||
--m_garbage;
|
||||
}
|
||||
e.set_invalid();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void flush() {
|
||||
m_garbage += m_non_garbage;
|
||||
m_non_garbage = 0;
|
||||
if (m_garbage > m_gc_threshold) {
|
||||
really_flush();
|
||||
}
|
||||
else {
|
||||
reset();
|
||||
}
|
||||
}
|
||||
|
||||
void finalize() {
|
||||
really_flush();
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
#endif /* _ARRAY_MAP_H_ */
|
114
src/util/backtrackable_set.h
Normal file
114
src/util/backtrackable_set.h
Normal file
|
@ -0,0 +1,114 @@
|
|||
/*++
|
||||
Copyright (c) 2006 Microsoft Corporation
|
||||
|
||||
Module Name:
|
||||
|
||||
backtrackable_set.h
|
||||
|
||||
Abstract:
|
||||
|
||||
Quick hack for support backtrackable sets.
|
||||
|
||||
Author:
|
||||
|
||||
Leonardo de Moura (leonardo) 2011-01-08.
|
||||
|
||||
Revision History:
|
||||
|
||||
--*/
|
||||
#ifndef _BACKTRACKABLE_SET_H_
|
||||
#define _BACKTRACKABLE_SET_H_
|
||||
|
||||
#include"vector.h"
|
||||
|
||||
template<typename T>
|
||||
struct default_eh {
|
||||
void operator()(T const & e, bool ins) {}
|
||||
};
|
||||
|
||||
// quick hack for having backtrackable sets.
|
||||
//
|
||||
// EV is a big hack, it should be used with care.
|
||||
//
|
||||
template<typename Set, typename T, typename EV=default_eh<T> >
|
||||
class backtrackable_set : private EV {
|
||||
enum trail_kind { DEL, INS };
|
||||
typedef std::pair<trail_kind, T> trail_obj;
|
||||
Set m_set;
|
||||
svector<trail_obj> m_trail;
|
||||
svector<unsigned> m_scopes;
|
||||
|
||||
public:
|
||||
typedef typename Set::iterator iterator;
|
||||
|
||||
backtrackable_set(EV const & ev = EV()):
|
||||
EV(ev) {
|
||||
}
|
||||
|
||||
void insert(T const & e) {
|
||||
if (m_scopes.empty()) {
|
||||
m_set.insert(e);
|
||||
}
|
||||
else if (!m_set.contains(e)) {
|
||||
m_set.insert(e);
|
||||
m_trail.push_back(std::make_pair(INS, e));
|
||||
}
|
||||
}
|
||||
|
||||
void erase(T const & e) {
|
||||
if (m_scopes.empty()) {
|
||||
m_set.insert(e);
|
||||
}
|
||||
else if (m_set.contains(e)) {
|
||||
m_set.erase(e);
|
||||
m_trail.push_back(std::make_pair(DEL, e));
|
||||
}
|
||||
}
|
||||
|
||||
bool contains(T const & e) const {
|
||||
return m_set.contains(e);
|
||||
}
|
||||
|
||||
bool empty() const {
|
||||
return m_set.empty();
|
||||
}
|
||||
|
||||
void push_scope() {
|
||||
m_scopes.push_back(m_trail.size());
|
||||
}
|
||||
|
||||
void pop_scope() {
|
||||
unsigned old_sz = m_scopes.back();
|
||||
m_scopes.pop_back();
|
||||
SASSERT(old_sz <= m_trail.size());
|
||||
while (m_trail.size() > old_sz) {
|
||||
trail_obj & t = m_trail.back();
|
||||
if (t.first == INS) {
|
||||
this->operator()(t.second, true);
|
||||
m_set.erase(t.second);
|
||||
}
|
||||
else {
|
||||
SASSERT(t.first == DEL);
|
||||
this->operator()(t.second, false);
|
||||
m_set.insert(t.second);
|
||||
}
|
||||
m_trail.pop_back();
|
||||
}
|
||||
}
|
||||
|
||||
void reset() {
|
||||
m_scopes.reset();
|
||||
m_trail.reset();
|
||||
m_set.reset();
|
||||
}
|
||||
|
||||
iterator begin() const {
|
||||
return m_set.begin();
|
||||
}
|
||||
|
||||
iterator end() const {
|
||||
return m_set.end();
|
||||
}
|
||||
};
|
||||
|
||||
#endif
|
363
src/util/basic_interval.h
Normal file
363
src/util/basic_interval.h
Normal file
|
@ -0,0 +1,363 @@
|
|||
/*++
|
||||
Copyright (c) 2011 Microsoft Corporation
|
||||
|
||||
Module Name:
|
||||
|
||||
basic_interval.h
|
||||
|
||||
Abstract:
|
||||
|
||||
Basic interval arithmetic template for precise numerals: mpz, mpq, mpbq.
|
||||
Only basic support is provided.
|
||||
There is no support for:
|
||||
- minus and plus infinity bounds.
|
||||
- mixed open/closed intervals such as (2, 3]
|
||||
The main customer of this package is the algebraic_number module.
|
||||
|
||||
Author:
|
||||
|
||||
Leonardo de Moura (leonardo) 2012-12-04.
|
||||
|
||||
Revision History:
|
||||
|
||||
--*/
|
||||
#ifndef _BASIC_INTERVAL_H_
|
||||
#define _BASIC_INTERVAL_H_
|
||||
|
||||
template<typename numeral_manager, bool closed>
|
||||
class basic_interval_manager {
|
||||
public:
|
||||
typedef typename numeral_manager::numeral bound;
|
||||
|
||||
class interval {
|
||||
friend class basic_interval_manager;
|
||||
bound m_lower;
|
||||
bound m_upper;
|
||||
public:
|
||||
interval() {}
|
||||
bound const & lower() const { return m_lower; }
|
||||
bound const & upper() const { return m_upper; }
|
||||
bound & lower() { return m_lower; }
|
||||
bound & upper() { return m_upper; }
|
||||
};
|
||||
|
||||
class scoped_interval {
|
||||
basic_interval_manager & m_manager;
|
||||
interval m_interval;
|
||||
public:
|
||||
scoped_interval(basic_interval_manager & m):m_manager(m) {}
|
||||
~scoped_interval() { m_manager.del(m_interval); }
|
||||
|
||||
basic_interval_manager & m() const { return m_manager; }
|
||||
operator interval const &() const { return m_interval; }
|
||||
operator interval&() { return m_interval; }
|
||||
interval const & get() const { return m_interval; }
|
||||
interval & get() { return m_interval; }
|
||||
void reset() { m().reset(m_interval); }
|
||||
void swap(scoped_interval & a) { m().swap(m_interval, a.m_interval); }
|
||||
void swap(interval & a) { m().swap(m_interval, a); }
|
||||
bound const & lower() const { return m_interval.lower(); }
|
||||
bound const & upper() const { return m_interval.upper(); }
|
||||
bound & lower() { return m_interval.lower(); }
|
||||
bound & upper() { return m_interval.upper(); }
|
||||
|
||||
friend std::ostream & operator<<(std::ostream & out, scoped_interval const & a) {
|
||||
a.m().display(out, a.get());
|
||||
return out;
|
||||
}
|
||||
};
|
||||
|
||||
protected:
|
||||
numeral_manager & m_manager;
|
||||
bound m_mul_curr;
|
||||
bound m_mul_max;
|
||||
bound m_mul_min;
|
||||
|
||||
public:
|
||||
typedef interval numeral; // allow intervals to be used by algorithms parameterized by numeral_manager
|
||||
|
||||
basic_interval_manager(numeral_manager & m):
|
||||
m_manager(m) {
|
||||
}
|
||||
|
||||
~basic_interval_manager() {
|
||||
m().del(m_mul_curr);
|
||||
m().del(m_mul_max);
|
||||
m().del(m_mul_min);
|
||||
}
|
||||
|
||||
numeral_manager & m() const { return m_manager; }
|
||||
|
||||
/**
|
||||
\brief Delete interval
|
||||
*/
|
||||
void del(interval & a) {
|
||||
m().del(a.m_lower);
|
||||
m().del(a.m_upper);
|
||||
}
|
||||
|
||||
/**
|
||||
\brief Delete and reset lower and upper bounds to 0
|
||||
*/
|
||||
void reset(interval & a) {
|
||||
m().reset(a.m_lower);
|
||||
m().reset(a.m_upper);
|
||||
}
|
||||
|
||||
bound const & lower(interval const & a) {
|
||||
return a.lower();
|
||||
}
|
||||
|
||||
bound const & upper(interval const & a) {
|
||||
return a.upper();
|
||||
}
|
||||
|
||||
/**
|
||||
\brief a <- (lower, upper)
|
||||
*/
|
||||
void set(interval & a, bound const & lower, bound const & upper) {
|
||||
SASSERT(m().le(lower, upper));
|
||||
m().set(a.m_lower, lower);
|
||||
m().set(a.m_upper, upper);
|
||||
}
|
||||
|
||||
/**
|
||||
\brief a <- b
|
||||
*/
|
||||
void set(interval & a, interval const & b) {
|
||||
set(a, b.m_lower, b.m_upper);
|
||||
}
|
||||
|
||||
/**
|
||||
\brief a <- (n, n)
|
||||
|
||||
Manager must be configured for closed intervals.
|
||||
*/
|
||||
void set(interval & a, bound const & n) {
|
||||
m().set(a.m_lower, n);
|
||||
m().set(a.m_upper, n);
|
||||
}
|
||||
|
||||
void set_lower(interval & a, bound const & n) {
|
||||
SASSERT(m().le(n, a.m_upper));
|
||||
m().set(a.m_lower, n);
|
||||
}
|
||||
|
||||
void set_upper(interval & a, bound const & n) {
|
||||
SASSERT(m().le(a.m_lower, n));
|
||||
m().set(a.m_upper, n);
|
||||
}
|
||||
|
||||
void swap(interval & a, interval & b) {
|
||||
m().swap(a.m_lower, b.m_lower);
|
||||
m().swap(a.m_upper, b.m_upper);
|
||||
}
|
||||
|
||||
/**
|
||||
\brief a <- -a
|
||||
*/
|
||||
void neg(interval & a) {
|
||||
m().neg(a.m_lower);
|
||||
m().neg(a.m_upper);
|
||||
m().swap(a.m_lower, a.m_upper);
|
||||
}
|
||||
|
||||
/**
|
||||
\brief Return true if a does not contain any value. We can
|
||||
only have empty intervals if the manager is configured to used
|
||||
open intervals.
|
||||
*/
|
||||
bool is_empty(interval const & a) {
|
||||
return !closed && m().eq(a.m_lower, a.m_upper);
|
||||
}
|
||||
|
||||
/**
|
||||
\brief Return true if all values in the given interval are positive.
|
||||
*/
|
||||
bool is_pos(interval const & a) { return (closed && m().is_pos(a.m_lower)) || (!closed && m().is_nonneg(a.m_lower)); }
|
||||
|
||||
/**
|
||||
\brief Return true if all values in the given interval are negative.
|
||||
*/
|
||||
bool is_neg(interval const & a) { return (closed && m().is_neg(a.m_upper)) || (!closed && m().is_nonpos(a.m_upper)); }
|
||||
|
||||
/**
|
||||
\brief Return true if 0 is in the interval.
|
||||
*/
|
||||
bool contains_zero(interval const & a) {
|
||||
return
|
||||
(closed && m().is_nonpos(a.m_lower) && m().is_nonneg(a.m_upper)) ||
|
||||
(!closed && m().is_neg(a.m_lower) && m().is_pos(a.m_upper));
|
||||
}
|
||||
|
||||
/**
|
||||
\brief Return true if all values in interval a are in interval b.
|
||||
*/
|
||||
bool is_subset(interval const & a, interval const & b) {
|
||||
return m().le(b.m_lower, a.m_lower) && m().le(a.m_upper, b.m_upper);
|
||||
}
|
||||
|
||||
/**
|
||||
\brief Return true if there is no value v s.t. v \in a and v \in b.
|
||||
*/
|
||||
bool disjoint(interval const & a, interval const & b) {
|
||||
return
|
||||
(closed && (m().lt(a.m_upper, b.m_lower) || m().lt(b.m_upper, a.m_lower))) ||
|
||||
(!closed && (m().le(a.m_upper, b.m_upper) || m().le(b.m_upper, a.m_lower)));
|
||||
}
|
||||
|
||||
/**
|
||||
\brief Return true if all elements in a are smaller than all elements in b.
|
||||
*/
|
||||
bool precedes(interval const & a, interval const & b) {
|
||||
return
|
||||
(closed && (m().lt(a.m_upper, b.m_lower))) ||
|
||||
(!closed && (m().le(a.m_upper, b.m_lower)));
|
||||
}
|
||||
|
||||
/**
|
||||
\brief Return true if all elements in a are smaller than b.
|
||||
*/
|
||||
bool precedes(interval const & a, bound const & b) {
|
||||
return
|
||||
(closed && (m().lt(a.m_upper, b))) ||
|
||||
(!closed && (m().le(a.m_upper, b)));
|
||||
}
|
||||
|
||||
/**
|
||||
\brief Return true if a is smaller than all elements in b.
|
||||
*/
|
||||
bool precedes(bound const & a, interval const & b) {
|
||||
return
|
||||
(closed && (m().lt(a, b.m_lower))) ||
|
||||
(!closed && (m().le(a, b.m_lower)));
|
||||
}
|
||||
|
||||
/**
|
||||
\brief a <- 1/a
|
||||
|
||||
\pre a.m_lower and m_upper must not be 0.
|
||||
\pre bound must be a field.
|
||||
*/
|
||||
void inv(interval & a) {
|
||||
SASSERT(numeral_manager::field());
|
||||
SASSERT(!contains_zero(a));
|
||||
SASSERT(!m().is_zero(a.m_lower) && !m().is_zero(a.m_upper));
|
||||
m().inv(a.m_lower);
|
||||
m().inv(a.m_upper);
|
||||
m().swap(a.m_lower, a.m_upper);
|
||||
}
|
||||
|
||||
/**
|
||||
\brief c <- a + b
|
||||
*/
|
||||
void add(interval const & a, interval const & b, interval & c) {
|
||||
m().add(a.m_lower, b.m_lower, c.m_lower);
|
||||
m().add(a.m_upper, b.m_upper, c.m_upper);
|
||||
}
|
||||
|
||||
/**
|
||||
\brief c <- a - b
|
||||
*/
|
||||
void sub(interval const & a, interval const & b, interval & c) {
|
||||
m().sub(a.m_lower, b.m_lower, c.m_lower);
|
||||
m().sub(a.m_upper, b.m_upper, c.m_upper);
|
||||
}
|
||||
|
||||
private:
|
||||
/**
|
||||
\brief Init the value of m_mul_max and m_mul_min using m_mul_curr
|
||||
*/
|
||||
void init_mul_max_min() {
|
||||
m().set(m_mul_min, m_mul_curr);
|
||||
m().swap(m_mul_max, m_mul_curr);
|
||||
}
|
||||
|
||||
/**
|
||||
\brief Update the value of m_mul_max and m_mul_min using m_mul_curr
|
||||
*/
|
||||
void update_mul_max_min() {
|
||||
if (m().lt(m_mul_curr, m_mul_min))
|
||||
m().set(m_mul_min, m_mul_curr);
|
||||
if (m().gt(m_mul_curr, m_mul_max))
|
||||
m().swap(m_mul_max, m_mul_curr);
|
||||
}
|
||||
|
||||
public:
|
||||
/**
|
||||
\brief c <- a * b
|
||||
*/
|
||||
void mul(interval const & a, interval const & b, interval & c) {
|
||||
m().mul(a.m_lower, b.m_lower, m_mul_curr);
|
||||
init_mul_max_min();
|
||||
m().mul(a.m_lower, b.m_upper, m_mul_curr);
|
||||
update_mul_max_min();
|
||||
m().mul(a.m_upper, b.m_lower, m_mul_curr);
|
||||
update_mul_max_min();
|
||||
m().mul(a.m_upper, b.m_upper, m_mul_curr);
|
||||
update_mul_max_min();
|
||||
m().swap(c.m_lower, m_mul_min);
|
||||
m().swap(c.m_upper, m_mul_max);
|
||||
}
|
||||
|
||||
/**
|
||||
\brief c <- a/b
|
||||
|
||||
\pre b m_lower and m_upper must not be 0
|
||||
\pre bound must be a field.
|
||||
*/
|
||||
void div(interval const & a, interval const & b, interval & c) {
|
||||
SASSERT(numeral_manager::field());
|
||||
SASSERT(!contains_zero(b));
|
||||
SASSERT(!m().is_zero(b.m_lower) && !m().is_zero(b.m_upper));
|
||||
m().div(a.m_lower, b.m_lower, m_mul_curr);
|
||||
init_mul_max_min();
|
||||
m().div(a.m_lower, b.m_upper, m_mul_curr);
|
||||
update_mul_max_min();
|
||||
m().div(a.m_upper, b.m_lower, m_mul_curr);
|
||||
update_mul_max_min();
|
||||
m().div(a.m_upper, b.m_upper, m_mul_curr);
|
||||
update_mul_max_min();
|
||||
m().swap(c.m_lower, m_mul_min);
|
||||
m().swap(c.m_upper, m_mul_max);
|
||||
}
|
||||
|
||||
/**
|
||||
\brief c <- a^n
|
||||
*/
|
||||
void power(interval const & a, unsigned n, interval & c) {
|
||||
// Let a be of the form (l, u)
|
||||
if (n % 2 == 1) {
|
||||
// n is odd
|
||||
// c <- (l^n, u^n)
|
||||
m().power(a.m_lower, n, c.m_lower);
|
||||
m().power(a.m_upper, n, c.m_upper);
|
||||
}
|
||||
else {
|
||||
SASSERT(n % 2 == 0);
|
||||
m().power(a.m_lower, n, c.m_lower);
|
||||
m().power(a.m_upper, n, c.m_upper);
|
||||
if (m().is_nonneg(a.m_lower)) {
|
||||
// n is even and l >= 0
|
||||
// c <- (l^n, u^n)
|
||||
return;
|
||||
}
|
||||
if (m().is_neg(a.m_upper)) {
|
||||
// n is even and u < 0
|
||||
// c <- (u^n, l^n)
|
||||
m().swap(c.m_lower, c.m_upper);
|
||||
return;
|
||||
}
|
||||
// c <- (0, max(l^n, u^n))
|
||||
if (m().gt(c.m_lower, c.m_upper))
|
||||
m().swap(c.m_lower, c.m_upper);
|
||||
m().reset(c.m_lower);
|
||||
}
|
||||
}
|
||||
|
||||
void display(std::ostream & out, interval const & a) {
|
||||
out << (closed ? "[" : "(") << m().to_string(a.m_lower) << ", " << m().to_string(a.m_upper) << (closed ? "]" : ")");
|
||||
}
|
||||
};
|
||||
|
||||
#endif
|
389
src/util/bit_util.cpp
Normal file
389
src/util/bit_util.cpp
Normal file
|
@ -0,0 +1,389 @@
|
|||
/*++
|
||||
Copyright (c) 2012 Microsoft Corporation
|
||||
|
||||
Module Name:
|
||||
|
||||
bit_util.cpp
|
||||
|
||||
Abstract:
|
||||
|
||||
Bit hacking utilities.
|
||||
|
||||
Author:
|
||||
|
||||
Leonardo de Moura (leonardo) 2012-09-11.
|
||||
|
||||
Revision History:
|
||||
|
||||
--*/
|
||||
#include"bit_util.h"
|
||||
#include"util.h"
|
||||
#include"debug.h"
|
||||
|
||||
/**
|
||||
\brief (Debugging version) Return the position of the most significant (set) bit of a
|
||||
nonzero unsigned integer.
|
||||
*/
|
||||
#ifdef Z3DEBUG
|
||||
unsigned slow_msb_pos(unsigned v) {
|
||||
SASSERT(v != 0);
|
||||
unsigned r = 0;
|
||||
while (v != 1) {
|
||||
v = v >> 1;
|
||||
r++;
|
||||
}
|
||||
return r;
|
||||
}
|
||||
#endif
|
||||
|
||||
/**
|
||||
\brief Return the position of the most significant (set) bit of a
|
||||
nonzero unsigned integer.
|
||||
*/
|
||||
unsigned msb_pos(unsigned v) {
|
||||
SASSERT(v != 0);
|
||||
#ifdef Z3DEBUG
|
||||
unsigned expected = slow_msb_pos(v);
|
||||
#endif
|
||||
unsigned r, shift;
|
||||
r = (v > 0xFFFF) << 4;
|
||||
v >>= r;
|
||||
shift = (v > 0xFF) << 3;
|
||||
v >>= shift;
|
||||
r |= shift;
|
||||
shift = (v > 0xF) << 2;
|
||||
v >>= shift;
|
||||
r |= shift;
|
||||
shift = (v > 0x3) << 1;
|
||||
v >>= shift;
|
||||
r |= shift;
|
||||
r |= (v >> 1);
|
||||
SASSERT(r == expected);
|
||||
return r;
|
||||
}
|
||||
|
||||
/**
|
||||
\brief Return the number of leading zeros bits in a nonzero unsigned integer.
|
||||
*/
|
||||
unsigned nlz_core(unsigned x) {
|
||||
SASSERT(x != 0);
|
||||
return 31 - msb_pos(x);
|
||||
}
|
||||
|
||||
/**
|
||||
\brief Return the number of leading zero bits in data (a number of sz words).
|
||||
*/
|
||||
unsigned nlz(unsigned sz, unsigned const * data) {
|
||||
unsigned r = 0;
|
||||
unsigned i = sz;
|
||||
while (i > 0) {
|
||||
--i;
|
||||
unsigned d = data[i];
|
||||
if (d == 0)
|
||||
r += 32;
|
||||
else
|
||||
return r + nlz_core(d);
|
||||
}
|
||||
return r;
|
||||
}
|
||||
|
||||
/**
|
||||
\brief Return the number of trailing zeros in a nonzero unsigned number.
|
||||
*/
|
||||
unsigned ntz_core(unsigned x) {
|
||||
SASSERT(x != 0);
|
||||
float f = static_cast<float>(x & static_cast<unsigned>(-static_cast<int>(x)));
|
||||
return (*reinterpret_cast<unsigned *>(&f) >> 23) - 0x7f;
|
||||
}
|
||||
|
||||
/**
|
||||
\brief Return the number of trailing zero bits in data (a number of sz words).
|
||||
*/
|
||||
unsigned ntz(unsigned sz, unsigned const * data) {
|
||||
unsigned r = 0;
|
||||
for (unsigned i = 0; i < sz; i++) {
|
||||
unsigned d = data[i];
|
||||
if (d == 0)
|
||||
r += 32;
|
||||
else
|
||||
return r + ntz_core(d);
|
||||
}
|
||||
return r;
|
||||
}
|
||||
|
||||
/**
|
||||
\brief dst <- src
|
||||
|
||||
Trucate if src_sz > dst_sz.
|
||||
Fill range [src_sz, dst_sz) of dst with zeros if dst_sz > src_sz.
|
||||
*/
|
||||
void copy(unsigned src_sz, unsigned const * src,
|
||||
unsigned dst_sz, unsigned * dst) {
|
||||
if (dst_sz >= src_sz) {
|
||||
unsigned i;
|
||||
for (i = 0; i < src_sz; i++)
|
||||
dst[i] = src[i];
|
||||
for (; i < dst_sz; i++)
|
||||
dst[i] = 0;
|
||||
}
|
||||
else {
|
||||
SASSERT(dst_sz < src_sz);
|
||||
for (unsigned i = 0; i < dst_sz; i++)
|
||||
dst[i] = src[i];
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
\brief Return true if all words of data are zero.
|
||||
*/
|
||||
bool is_zero(unsigned sz, unsigned const * data) {
|
||||
for (unsigned i = 0; i < sz; i++)
|
||||
if (data[i])
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
\brief Set all words of data to zero.
|
||||
*/
|
||||
void reset(unsigned sz, unsigned * data) {
|
||||
for (unsigned i = 0; i < sz; i++)
|
||||
data[i] = 0;
|
||||
}
|
||||
|
||||
/**
|
||||
\brief dst <- src << k
|
||||
Store in dst the result of shifting src k bits to the left.
|
||||
The result is truncated by dst_sz.
|
||||
|
||||
\pre src_sz != 0
|
||||
\pre dst_sz != 0
|
||||
*/
|
||||
void shl(unsigned src_sz, unsigned const * src, unsigned k,
|
||||
unsigned dst_sz, unsigned * dst) {
|
||||
SASSERT(src_sz != 0);
|
||||
SASSERT(dst_sz != 0);
|
||||
SASSERT(k != 0);
|
||||
unsigned word_shift = k / (8 * sizeof(unsigned));
|
||||
unsigned bit_shift = k % (8 * sizeof(unsigned));
|
||||
if (word_shift > 0) {
|
||||
unsigned j = src_sz;
|
||||
unsigned i = src_sz + word_shift;
|
||||
if (i > dst_sz) {
|
||||
if (j >= i - dst_sz)
|
||||
j -= (i - dst_sz);
|
||||
else
|
||||
j = 0;
|
||||
i = dst_sz;
|
||||
}
|
||||
else if (i < dst_sz) {
|
||||
for (unsigned r = i; r < dst_sz; r++)
|
||||
dst[r] = 0;
|
||||
}
|
||||
while (j > 0) {
|
||||
--j; --i;
|
||||
dst[i] = src[j];
|
||||
}
|
||||
while (i > 0) {
|
||||
--i;
|
||||
dst[i] = 0;
|
||||
}
|
||||
if (bit_shift > 0) {
|
||||
unsigned comp_shift = (8 * sizeof(unsigned)) - bit_shift;
|
||||
unsigned prev = 0;
|
||||
for (unsigned i = word_shift; i < dst_sz; i++) {
|
||||
unsigned new_prev = (dst[i] >> comp_shift);
|
||||
dst[i] <<= bit_shift;
|
||||
dst[i] |= prev;
|
||||
prev = new_prev;
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
unsigned comp_shift = (8 * sizeof(unsigned)) - bit_shift;
|
||||
unsigned prev = 0;
|
||||
if (src_sz > dst_sz)
|
||||
src_sz = dst_sz;
|
||||
for (unsigned i = 0; i < src_sz; i++) {
|
||||
unsigned new_prev = (src[i] >> comp_shift);
|
||||
dst[i] = src[i];
|
||||
dst[i] <<= bit_shift;
|
||||
dst[i] |= prev;
|
||||
prev = new_prev;
|
||||
}
|
||||
if (dst_sz > src_sz) {
|
||||
dst[src_sz] = prev;
|
||||
for (unsigned i = src_sz+1; i < dst_sz; i++)
|
||||
dst[i] = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
\brief dst <- src >> k
|
||||
Store in dst the result of shifting src k bits to the right.
|
||||
|
||||
\pre dst must have size sz.
|
||||
\pre src_sz != 0
|
||||
\pre dst_sz != 0
|
||||
*/
|
||||
void shr(unsigned sz, unsigned const * src, unsigned k, unsigned * dst) {
|
||||
unsigned digit_shift = k / (8 * sizeof(unsigned));
|
||||
if (digit_shift >= sz) {
|
||||
reset(sz, dst);
|
||||
return;
|
||||
}
|
||||
unsigned bit_shift = k % (8 * sizeof(unsigned));
|
||||
unsigned comp_shift = (8 * sizeof(unsigned)) - bit_shift;
|
||||
unsigned new_sz = sz - digit_shift;
|
||||
if (new_sz < sz) {
|
||||
unsigned i = 0;
|
||||
unsigned j = digit_shift;
|
||||
if (bit_shift != 0) {
|
||||
for (; i < new_sz - 1; i++, j++) {
|
||||
dst[i] = src[j];
|
||||
dst[i] >>= bit_shift;
|
||||
dst[i] |= (src[j+1] << comp_shift);
|
||||
}
|
||||
dst[i] = src[j];
|
||||
dst[i] >>= bit_shift;
|
||||
}
|
||||
else {
|
||||
for (; i < new_sz; i++, j++) {
|
||||
dst[i] = src[j];
|
||||
}
|
||||
}
|
||||
for (unsigned i = new_sz; i < sz; i++)
|
||||
dst[i] = 0;
|
||||
}
|
||||
else {
|
||||
SASSERT(new_sz == sz);
|
||||
SASSERT(bit_shift != 0);
|
||||
unsigned i = 0;
|
||||
for (; i < new_sz - 1; i++) {
|
||||
dst[i] = src[i];
|
||||
dst[i] >>= bit_shift;
|
||||
dst[i] |= (src[i+1] << comp_shift);
|
||||
}
|
||||
dst[i] = src[i];
|
||||
dst[i] >>= bit_shift;
|
||||
}
|
||||
}
|
||||
|
||||
void shr(unsigned src_sz, unsigned const * src, unsigned k, unsigned dst_sz, unsigned * dst) {
|
||||
unsigned digit_shift = k / (8 * sizeof(unsigned));
|
||||
if (digit_shift >= src_sz) {
|
||||
reset(dst_sz, dst);
|
||||
return;
|
||||
}
|
||||
unsigned bit_shift = k % (8 * sizeof(unsigned));
|
||||
unsigned comp_shift = (8 * sizeof(unsigned)) - bit_shift;
|
||||
unsigned new_sz = src_sz - digit_shift;
|
||||
if (digit_shift > 0) {
|
||||
unsigned i = 0;
|
||||
unsigned j = digit_shift;
|
||||
if (bit_shift != 0) {
|
||||
unsigned sz = new_sz;
|
||||
if (new_sz > dst_sz)
|
||||
sz = dst_sz;
|
||||
for (; i < sz - 1; i++, j++) {
|
||||
dst[i] = src[j];
|
||||
dst[i] >>= bit_shift;
|
||||
dst[i] |= (src[j+1] << comp_shift);
|
||||
}
|
||||
dst[i] = src[j];
|
||||
dst[i] >>= bit_shift;
|
||||
if (new_sz > dst_sz)
|
||||
dst[i] |= (src[j+1] << comp_shift);
|
||||
}
|
||||
else {
|
||||
if (new_sz > dst_sz)
|
||||
new_sz = dst_sz;
|
||||
for (; i < new_sz; i++, j++) {
|
||||
dst[i] = src[j];
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
SASSERT(new_sz == src_sz);
|
||||
SASSERT(bit_shift != 0);
|
||||
unsigned sz = new_sz;
|
||||
if (new_sz > dst_sz)
|
||||
sz = dst_sz;
|
||||
unsigned i = 0;
|
||||
for (; i < sz - 1; i++) {
|
||||
dst[i] = src[i];
|
||||
dst[i] >>= bit_shift;
|
||||
dst[i] |= (src[i+1] << comp_shift);
|
||||
}
|
||||
dst[i] = src[i];
|
||||
dst[i] >>= bit_shift;
|
||||
if (new_sz > dst_sz)
|
||||
dst[i] |= (src[i+1] << comp_shift);
|
||||
}
|
||||
for (unsigned i = new_sz; i < dst_sz; i++)
|
||||
dst[i] = 0;
|
||||
}
|
||||
|
||||
/**
|
||||
\brief Return true if one of the first k bits of src is not zero.
|
||||
*/
|
||||
bool has_one_at_first_k_bits(unsigned sz, unsigned const * data, unsigned k) {
|
||||
SASSERT(sz != 0);
|
||||
unsigned word_sz = k / (8 * sizeof(unsigned));
|
||||
if (word_sz > sz)
|
||||
word_sz = sz;
|
||||
for (unsigned i = 0; i < word_sz; i++) {
|
||||
if (data[i] != 0)
|
||||
return true;
|
||||
}
|
||||
if (word_sz < sz) {
|
||||
unsigned bit_sz = k % (8 * sizeof(unsigned));
|
||||
unsigned mask = (1 << bit_sz) - 1;
|
||||
return (data[word_sz] & mask) != 0;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool inc(unsigned sz, unsigned * data) {
|
||||
for (unsigned i = 0; i < sz; i++) {
|
||||
data[i]++;
|
||||
if (data[i] != 0)
|
||||
return true; // no overflow
|
||||
}
|
||||
return false; // overflow
|
||||
}
|
||||
|
||||
bool dec(unsigned sz, unsigned * data) {
|
||||
for (unsigned i = 0; i < sz; i++) {
|
||||
data[i]--;
|
||||
if (data[i] != UINT_MAX)
|
||||
return true; // no underflow
|
||||
}
|
||||
return false; // underflow
|
||||
}
|
||||
|
||||
bool lt(unsigned sz, unsigned * data1, unsigned * data2) {
|
||||
unsigned i = sz;
|
||||
while (i > 0) {
|
||||
--i;
|
||||
if (data1[i] < data2[i])
|
||||
return true;
|
||||
if (data1[i] > data2[i])
|
||||
return false;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool add(unsigned sz, unsigned const * a, unsigned const * b, unsigned * c) {
|
||||
unsigned k = 0;
|
||||
for (unsigned j = 0; j < sz; j++) {
|
||||
unsigned r = a[j] + b[j];
|
||||
bool c1 = r < a[j];
|
||||
c[j] = r + k;
|
||||
bool c2 = c[j] < r;
|
||||
k = c1 | c2;
|
||||
}
|
||||
return k == 0;
|
||||
}
|
||||
|
132
src/util/bit_util.h
Normal file
132
src/util/bit_util.h
Normal file
|
@ -0,0 +1,132 @@
|
|||
/*++
|
||||
Copyright (c) 2012 Microsoft Corporation
|
||||
|
||||
Module Name:
|
||||
|
||||
bit_util.h
|
||||
|
||||
Abstract:
|
||||
|
||||
Bit hacking utilities.
|
||||
|
||||
Author:
|
||||
|
||||
Leonardo de Moura (leonardo) 2012-09-11.
|
||||
|
||||
Revision History:
|
||||
|
||||
--*/
|
||||
#ifndef _BIT_UTIL_H_
|
||||
#define _BIT_UTIL_H_
|
||||
|
||||
/**
|
||||
\brief Return the position of the most significant (set) bit of a
|
||||
nonzero unsigned integer.
|
||||
*/
|
||||
unsigned msb_pos(unsigned v);
|
||||
|
||||
/**
|
||||
\brief Return the number of leading zeros bits in a nonzero unsigned integer.
|
||||
*/
|
||||
unsigned nlz_core(unsigned x);
|
||||
|
||||
/**
|
||||
\brief Return the number of leading zero bits in data (a number of sz words).
|
||||
*/
|
||||
unsigned nlz(unsigned sz, unsigned const * data);
|
||||
|
||||
/**
|
||||
\brief Return the number of trailing zeros in a nonzero unsigned number.
|
||||
*/
|
||||
unsigned ntz_core(unsigned x);
|
||||
|
||||
/**
|
||||
\brief Return the number of trailing zero bits in data (a number of sz words).
|
||||
*/
|
||||
unsigned ntz(unsigned sz, unsigned const * data);
|
||||
|
||||
/**
|
||||
\brief dst <- src
|
||||
|
||||
Trucate if src_sz > dst_sz.
|
||||
Fill range [src_sz, dst_sz) of dst with zeros if dst_sz > src_sz.
|
||||
*/
|
||||
void copy(unsigned src_sz, unsigned const * src, unsigned dst_sz, unsigned * dst);
|
||||
|
||||
/**
|
||||
\brief Return true if all words of data are zero.
|
||||
*/
|
||||
bool is_zero(unsigned sz, unsigned const * data);
|
||||
|
||||
/**
|
||||
\brief Set all words of data to zero.
|
||||
*/
|
||||
void reset(unsigned sz, unsigned * data);
|
||||
|
||||
/**
|
||||
\brief dst <- src << k
|
||||
Store in dst the result of shifting src k bits to the left.
|
||||
The result is truncated by dst_sz.
|
||||
|
||||
\pre src_sz != 0
|
||||
\pre dst_sz != 0
|
||||
*/
|
||||
void shl(unsigned src_sz, unsigned const * src, unsigned k, unsigned dst_sz, unsigned * dst);
|
||||
|
||||
/**
|
||||
\brief dst <- src >> k
|
||||
Store in dst the result of shifting src k bits to the right.
|
||||
|
||||
\pre dst must have size sz.
|
||||
\pre src_sz != 0
|
||||
\pre dst_sz != 0
|
||||
*/
|
||||
void shr(unsigned sz, unsigned const * src, unsigned k, unsigned * dst);
|
||||
|
||||
/**
|
||||
\brief dst <- src >> k
|
||||
Store in dst the result of shifting src k bits to the right.
|
||||
|
||||
Trucate if src_sz > dst_sz.
|
||||
Fill range [src_sz, dst_sz) of dst with zeros if dst_sz > src_sz.
|
||||
|
||||
\pre src_sz != 0
|
||||
\pre dst_sz != 0
|
||||
*/
|
||||
void shr(unsigned src_sz, unsigned const * src, unsigned k, unsigned dst_sz, unsigned * dst);
|
||||
|
||||
/**
|
||||
\brief Return true if one of the first k bits of src is not zero.
|
||||
*/
|
||||
bool has_one_at_first_k_bits(unsigned sz, unsigned const * data, unsigned k);
|
||||
|
||||
|
||||
/**
|
||||
\brief data <- data + 1
|
||||
|
||||
Return true if no overflow occurred.
|
||||
*/
|
||||
bool inc(unsigned sz, unsigned * data);
|
||||
|
||||
/**
|
||||
\brief data <- data - 1
|
||||
|
||||
Return true if no underflow occurred.
|
||||
*/
|
||||
bool dec(unsigned sz, unsigned * data);
|
||||
|
||||
/**
|
||||
\brief Return true if data1 < data2.
|
||||
|
||||
Both must have the same size.
|
||||
*/
|
||||
bool lt(unsigned sz, unsigned * data1, unsigned * data2);
|
||||
|
||||
|
||||
/**
|
||||
\brief Store in c the a+b. This procedure assumes that a,b,c are vectors of size sz.
|
||||
Return false if a+b overflows.
|
||||
*/
|
||||
bool add(unsigned sz, unsigned const * a, unsigned const * b, unsigned * c);
|
||||
|
||||
#endif
|
220
src/util/bit_vector.cpp
Normal file
220
src/util/bit_vector.cpp
Normal file
|
@ -0,0 +1,220 @@
|
|||
/*++
|
||||
Copyright (c) 2006 Microsoft Corporation
|
||||
|
||||
Module Name:
|
||||
|
||||
bitvector.cpp
|
||||
|
||||
Abstract:
|
||||
|
||||
Simple bitvector implementation
|
||||
|
||||
Author:
|
||||
|
||||
Leonardo de Moura (leonardo) 2006-10-03.
|
||||
|
||||
Revision History:
|
||||
|
||||
--*/
|
||||
|
||||
#include"bit_vector.h"
|
||||
#include"trace.h"
|
||||
|
||||
#define DEFAULT_CAPACITY 2
|
||||
|
||||
void bit_vector::expand_to(unsigned new_capacity) {
|
||||
unsigned * new_data = alloc_svect(unsigned, new_capacity);
|
||||
memset(new_data, 0, new_capacity * sizeof(unsigned));
|
||||
if (m_capacity > 0) {
|
||||
memcpy(new_data, m_data, m_capacity * sizeof(unsigned));
|
||||
dealloc_svect(m_data);
|
||||
}
|
||||
m_data = new_data;
|
||||
m_capacity = new_capacity;
|
||||
}
|
||||
|
||||
void bit_vector::resize(unsigned new_size, bool val) {
|
||||
if (new_size <= m_num_bits) {
|
||||
m_num_bits = new_size;
|
||||
return;
|
||||
}
|
||||
|
||||
TRACE("bit_vector", tout << "expanding: " << new_size << " capacity: " << m_capacity << " num words: "
|
||||
<< num_words(new_size) << "\n";);
|
||||
|
||||
if (num_words(new_size) > m_capacity) {
|
||||
expand_to((num_words(new_size) * 3 + 1) >> 1);
|
||||
}
|
||||
|
||||
|
||||
unsigned bwidx = m_num_bits/32;
|
||||
unsigned ewidx = num_words(new_size);
|
||||
unsigned * begin = m_data + bwidx;
|
||||
unsigned pos = m_num_bits % 32;
|
||||
unsigned mask = (1 << pos) - 1;
|
||||
int cval;
|
||||
|
||||
if (val) {
|
||||
*begin |= ~mask;
|
||||
cval = ~0;
|
||||
}
|
||||
else {
|
||||
*begin &= mask;
|
||||
cval = 0;
|
||||
}
|
||||
|
||||
TRACE("bit_vector",
|
||||
tout << "num_bits: " << m_num_bits << "\n";
|
||||
tout << "bwidx: " << bwidx << "\n";
|
||||
tout << "ewidx: " << ewidx << "\n";
|
||||
tout << "pos: " << pos << "\n";
|
||||
tout << "mask: " << std::hex << mask << "\n" << std::dec;
|
||||
tout << "cval: " << cval << "\n";);
|
||||
|
||||
if (bwidx < ewidx) {
|
||||
memset(begin + 1, cval, (ewidx - bwidx - 1) * sizeof(unsigned));
|
||||
}
|
||||
|
||||
m_num_bits = new_size;
|
||||
}
|
||||
|
||||
void bit_vector::shift_right(unsigned k) {
|
||||
if (k == 0)
|
||||
return;
|
||||
unsigned new_num_bits = m_num_bits + k;
|
||||
unsigned old_num_words = num_words(m_num_bits);
|
||||
unsigned new_num_words = num_words(new_num_bits);
|
||||
resize(m_num_bits + k, false);
|
||||
unsigned bit_shift = k % (8 * sizeof(unsigned));
|
||||
unsigned word_shift = k / (8 * sizeof(unsigned));
|
||||
if (word_shift > 0) {
|
||||
unsigned j = old_num_words;
|
||||
unsigned i = old_num_words + word_shift;
|
||||
while (j > 0) {
|
||||
--j; --i;
|
||||
m_data[i] = m_data[j];
|
||||
}
|
||||
while (i > 0) {
|
||||
--i;
|
||||
m_data[i] = 0;
|
||||
}
|
||||
}
|
||||
if (bit_shift > 0) {
|
||||
DEBUG_CODE({
|
||||
for (unsigned i = 0; i < word_shift; i++) {
|
||||
SASSERT(m_data[i] == 0);
|
||||
}
|
||||
});
|
||||
unsigned comp_shift = (8 * sizeof(unsigned)) - bit_shift;
|
||||
unsigned prev = 0;
|
||||
for (unsigned i = word_shift; i < new_num_words; i++) {
|
||||
unsigned new_prev = (m_data[i] >> comp_shift);
|
||||
m_data[i] <<= bit_shift;
|
||||
m_data[i] |= prev;
|
||||
prev = new_prev;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool bit_vector::operator==(bit_vector const & source) {
|
||||
if (m_num_bits != source.m_num_bits)
|
||||
return false;
|
||||
unsigned n = num_words();
|
||||
if (n == 0)
|
||||
return true;
|
||||
unsigned i;
|
||||
for (i = 0; i < n - 1; i++) {
|
||||
if (m_data[i] != source.m_data[i])
|
||||
return false;
|
||||
}
|
||||
unsigned bit_rest = source.m_num_bits % 32;
|
||||
unsigned mask = (1 << bit_rest) - 1;
|
||||
return (m_data[i] & mask) == (source.m_data[i] & mask);
|
||||
}
|
||||
|
||||
bit_vector & bit_vector::operator|=(bit_vector const & source) {
|
||||
if (size() < source.size())
|
||||
resize(source.size(), false);
|
||||
unsigned n1 = num_words();
|
||||
unsigned n2 = source.num_words();
|
||||
SASSERT(n2 <= n1);
|
||||
unsigned bit_rest = source.m_num_bits % 32;
|
||||
if (bit_rest == 0) {
|
||||
unsigned i = 0;
|
||||
for (i = 0; i < n2; i++)
|
||||
m_data[i] |= source.m_data[i];
|
||||
}
|
||||
else {
|
||||
unsigned i = 0;
|
||||
for (i = 0; i < n2 - 1; i++)
|
||||
m_data[i] |= source.m_data[i];
|
||||
unsigned mask = (1 << bit_rest) - 1;
|
||||
m_data[i] |= source.m_data[i] & mask;
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
bit_vector & bit_vector::operator&=(bit_vector const & source) {
|
||||
unsigned n1 = num_words();
|
||||
unsigned n2 = source.num_words();
|
||||
if (n1 == 0)
|
||||
return *this;
|
||||
if (n2 > n1) {
|
||||
for (unsigned i = 0; i < n1; i++)
|
||||
m_data[i] &= source.m_data[i];
|
||||
}
|
||||
else {
|
||||
SASSERT(n2 <= n1);
|
||||
unsigned bit_rest = source.m_num_bits % 32;
|
||||
unsigned i = 0;
|
||||
if (bit_rest == 0) {
|
||||
for (i = 0; i < n2; i++)
|
||||
m_data[i] &= source.m_data[i];
|
||||
}
|
||||
else {
|
||||
for (i = 0; i < n2 - 1; i++)
|
||||
m_data[i] &= source.m_data[i];
|
||||
unsigned mask = (1 << bit_rest) - 1;
|
||||
m_data[i] &= (source.m_data[i] & mask);
|
||||
|
||||
}
|
||||
for (i = n2; i < n1; i++)
|
||||
m_data[i] = 0;
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
void bit_vector::display(std::ostream & out) const {
|
||||
#if 1
|
||||
unsigned i = m_num_bits;
|
||||
while (i > 0) {
|
||||
--i;
|
||||
if (get(i))
|
||||
out << "1";
|
||||
else
|
||||
out << "0";
|
||||
}
|
||||
#else
|
||||
for (unsigned i = 0; i < m_num_bits; i++) {
|
||||
if (get(i))
|
||||
out << "1";
|
||||
else
|
||||
out << "0";
|
||||
if ((i + 1) % 32 == 0) out << "\n";
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
void fr_bit_vector::reset() {
|
||||
unsigned sz = size();
|
||||
vector<unsigned>::const_iterator it = m_one_idxs.begin();
|
||||
vector<unsigned>::const_iterator end = m_one_idxs.end();
|
||||
for (; it != end; ++it) {
|
||||
unsigned idx = *it;
|
||||
if (idx < sz)
|
||||
unset(idx);
|
||||
}
|
||||
m_one_idxs.reset();
|
||||
}
|
||||
|
||||
|
234
src/util/bit_vector.h
Normal file
234
src/util/bit_vector.h
Normal file
|
@ -0,0 +1,234 @@
|
|||
/*++
|
||||
Copyright (c) 2006 Microsoft Corporation
|
||||
|
||||
Module Name:
|
||||
|
||||
bit_vector.h
|
||||
|
||||
Abstract:
|
||||
|
||||
Simple bitvector implementation.
|
||||
|
||||
Author:
|
||||
|
||||
Leonardo de Moura (leonardo) 2006-10-03.
|
||||
|
||||
Revision History:
|
||||
|
||||
--*/
|
||||
#ifndef _BIT_VECTOR_H_
|
||||
#define _BIT_VECTOR_H_
|
||||
|
||||
#include<string.h>
|
||||
#include"debug.h"
|
||||
#include"vector.h"
|
||||
#include"memory_manager.h"
|
||||
|
||||
COMPILE_TIME_ASSERT(sizeof(unsigned) == 4);
|
||||
#define BV_DEFAULT_CAPACITY 2
|
||||
|
||||
class bit_vector {
|
||||
unsigned m_num_bits;
|
||||
unsigned m_capacity; //!< in words
|
||||
unsigned * m_data;
|
||||
|
||||
static unsigned get_pos_mask(unsigned bit_idx) {
|
||||
return 1 << (bit_idx % 32);
|
||||
}
|
||||
|
||||
static unsigned num_words(unsigned num_bits) {
|
||||
return (num_bits % 32) == 0 ? (num_bits / 32) : ((num_bits / 32) + 1);
|
||||
}
|
||||
|
||||
void expand_to(unsigned new_capacity);
|
||||
|
||||
void expand() {
|
||||
expand_to(m_capacity == 0 ? BV_DEFAULT_CAPACITY : ((m_capacity * 3 + 1) >> 1));
|
||||
}
|
||||
|
||||
unsigned get_bit_word(unsigned bit_idx) const {
|
||||
SASSERT(bit_idx < size());
|
||||
return m_data[bit_idx / 32];
|
||||
}
|
||||
|
||||
unsigned & get_bit_word(unsigned bit_idx) {
|
||||
SASSERT(bit_idx < size());
|
||||
return m_data[bit_idx / 32];
|
||||
}
|
||||
|
||||
public:
|
||||
bit_vector():
|
||||
m_num_bits(0),
|
||||
m_capacity(0),
|
||||
m_data(0) {
|
||||
}
|
||||
|
||||
bit_vector(bit_vector const & source):
|
||||
m_num_bits(source.m_num_bits),
|
||||
m_capacity(source.m_capacity),
|
||||
m_data(alloc_svect(unsigned, source.m_capacity)) {
|
||||
memcpy(m_data, source.m_data, source.m_capacity * sizeof(unsigned));
|
||||
}
|
||||
|
||||
bit_vector(unsigned const * source, int num_bits):
|
||||
m_num_bits(num_bits),
|
||||
m_capacity(num_words(num_bits)),
|
||||
m_data(alloc_svect(unsigned, m_capacity)) {
|
||||
memcpy(m_data, source, m_capacity * sizeof(unsigned));
|
||||
}
|
||||
|
||||
~bit_vector() {
|
||||
if (m_data) {
|
||||
dealloc_svect(m_data);
|
||||
}
|
||||
}
|
||||
|
||||
void reset() {
|
||||
memset(m_data, 0, m_capacity * sizeof(unsigned));
|
||||
m_num_bits = 0;
|
||||
}
|
||||
|
||||
void swap(bit_vector & other) {
|
||||
std::swap(m_data, other.m_data);
|
||||
std::swap(m_num_bits, other.m_num_bits);
|
||||
std::swap(m_capacity, other.m_capacity);
|
||||
}
|
||||
|
||||
// Increase the size of the bit_vector by k 0-bits.
|
||||
void shift_right(unsigned k);
|
||||
|
||||
void fill0() {
|
||||
memset(m_data, 0, m_capacity * sizeof(unsigned));
|
||||
}
|
||||
|
||||
unsigned size() const {
|
||||
return m_num_bits;
|
||||
}
|
||||
|
||||
bool empty() const {
|
||||
return m_num_bits != 0;
|
||||
}
|
||||
|
||||
unsigned num_words() const {
|
||||
return num_words(m_num_bits);
|
||||
}
|
||||
|
||||
unsigned get_word(unsigned word_idx) const {
|
||||
return m_data[word_idx];
|
||||
}
|
||||
|
||||
bool get(unsigned bit_idx) const {
|
||||
SASSERT(bit_idx < size());
|
||||
bool r = (get_bit_word(bit_idx) & get_pos_mask(bit_idx)) != 0;
|
||||
return r;
|
||||
}
|
||||
|
||||
void set(unsigned bit_idx) {
|
||||
SASSERT(bit_idx < size());
|
||||
get_bit_word(bit_idx) |= get_pos_mask(bit_idx);
|
||||
}
|
||||
|
||||
void unset(unsigned bit_idx) {
|
||||
SASSERT(bit_idx < size());
|
||||
get_bit_word(bit_idx) &= ~get_pos_mask(bit_idx);
|
||||
}
|
||||
|
||||
void set(unsigned bit_idx, bool val) {
|
||||
SASSERT(bit_idx < size());
|
||||
int _val = static_cast<int>(val);
|
||||
get_bit_word(bit_idx) ^= (-_val ^ get_bit_word(bit_idx)) & get_pos_mask(bit_idx);
|
||||
}
|
||||
|
||||
void push_back(bool val) {
|
||||
unsigned idx = m_num_bits;
|
||||
m_num_bits++;
|
||||
if (num_words(m_num_bits) > m_capacity) {
|
||||
expand();
|
||||
}
|
||||
set(idx, val);
|
||||
}
|
||||
|
||||
void pop_back() {
|
||||
SASSERT(m_num_bits > 0);
|
||||
m_num_bits--;
|
||||
}
|
||||
|
||||
bool back() const {
|
||||
SASSERT(!empty());
|
||||
bool r = get(m_num_bits - 1);
|
||||
return r;
|
||||
}
|
||||
|
||||
void shrink(unsigned new_size) {
|
||||
SASSERT(new_size <= m_num_bits);
|
||||
m_num_bits = new_size;
|
||||
}
|
||||
|
||||
void resize(unsigned new_size, bool val = false);
|
||||
|
||||
void reserve(unsigned sz, bool val = false) {
|
||||
if (sz > size())
|
||||
resize(sz, val);
|
||||
}
|
||||
|
||||
bool operator==(bit_vector const & other);
|
||||
|
||||
bool operator!=(bit_vector const & other) { return !operator==(other); }
|
||||
|
||||
bit_vector & operator=(bit_vector const & source) {
|
||||
m_num_bits = source.m_num_bits;
|
||||
if (m_capacity < source.m_capacity) {
|
||||
dealloc_svect(m_data);
|
||||
m_data = alloc_svect(unsigned, source.m_capacity);
|
||||
m_capacity = source.m_capacity;
|
||||
}
|
||||
memcpy(m_data, source.m_data, source.m_capacity * sizeof(unsigned));
|
||||
return *this;
|
||||
}
|
||||
|
||||
bit_vector & operator|=(bit_vector const & source);
|
||||
|
||||
bit_vector & operator&=(bit_vector const & source);
|
||||
|
||||
void display(std::ostream & out) const;
|
||||
};
|
||||
|
||||
inline std::ostream & operator<<(std::ostream & out, bit_vector const & b) {
|
||||
b.display(out);
|
||||
return out;
|
||||
}
|
||||
|
||||
/**
|
||||
\brief Bitvector class with fast reset.
|
||||
This class should be used if the reset is frequently called.
|
||||
*/
|
||||
class fr_bit_vector : private bit_vector {
|
||||
svector<unsigned> m_one_idxs;
|
||||
public:
|
||||
void reset();
|
||||
|
||||
void fill0() {
|
||||
bit_vector::fill0();
|
||||
m_one_idxs.reset();
|
||||
}
|
||||
|
||||
void set(unsigned idx) {
|
||||
m_one_idxs.push_back(idx);
|
||||
bit_vector::set(idx);
|
||||
}
|
||||
|
||||
void set(unsigned idx, bool val) {
|
||||
if (val)
|
||||
m_one_idxs.push_back(idx);
|
||||
bit_vector::set(idx, val);
|
||||
}
|
||||
|
||||
void push_back(bool val) {
|
||||
if (val)
|
||||
m_one_idxs.push_back(size());
|
||||
bit_vector::push_back(val);
|
||||
}
|
||||
};
|
||||
|
||||
#endif /* _BIT_VECTOR_H_ */
|
||||
|
256
src/util/buffer.h
Normal file
256
src/util/buffer.h
Normal file
|
@ -0,0 +1,256 @@
|
|||
/*++
|
||||
Copyright (c) 2006 Microsoft Corporation
|
||||
|
||||
Module Name:
|
||||
|
||||
buffer.h
|
||||
|
||||
Abstract:
|
||||
|
||||
<abstract>
|
||||
|
||||
Author:
|
||||
|
||||
Leonardo de Moura (leonardo) 2006-10-16.
|
||||
|
||||
Revision History:
|
||||
|
||||
--*/
|
||||
#ifndef _BUFFER_H_
|
||||
#define _BUFFER_H_
|
||||
|
||||
#include<string.h>
|
||||
#include"memory_manager.h"
|
||||
|
||||
template<typename T, bool CallDestructors=true, unsigned INITIAL_SIZE=16>
|
||||
class buffer {
|
||||
protected:
|
||||
T * m_buffer;
|
||||
unsigned m_pos;
|
||||
unsigned m_capacity;
|
||||
char m_initial_buffer[INITIAL_SIZE * sizeof(T)];
|
||||
|
||||
void free_memory() {
|
||||
if (m_buffer != reinterpret_cast<T*>(m_initial_buffer)) {
|
||||
memory::deallocate(m_buffer);
|
||||
}
|
||||
}
|
||||
|
||||
void expand() {
|
||||
unsigned new_capacity = m_capacity << 1;
|
||||
T * new_buffer = reinterpret_cast<T*>(memory::allocate(sizeof(T) * new_capacity));
|
||||
memcpy(new_buffer, m_buffer, m_pos * sizeof(T));
|
||||
free_memory();
|
||||
m_buffer = new_buffer;
|
||||
m_capacity = new_capacity;
|
||||
}
|
||||
|
||||
void destroy_elements() {
|
||||
iterator it = begin();
|
||||
iterator e = end();
|
||||
for (; it != e; ++it) {
|
||||
it->~T();
|
||||
}
|
||||
}
|
||||
|
||||
void destroy() {
|
||||
if (CallDestructors) {
|
||||
destroy_elements();
|
||||
}
|
||||
free_memory();
|
||||
}
|
||||
|
||||
public:
|
||||
typedef T data;
|
||||
typedef T * iterator;
|
||||
typedef const T * const_iterator;
|
||||
|
||||
buffer():
|
||||
m_buffer(reinterpret_cast<T *>(m_initial_buffer)),
|
||||
m_pos(0),
|
||||
m_capacity(INITIAL_SIZE) {
|
||||
}
|
||||
|
||||
buffer(const buffer & source):
|
||||
m_buffer(reinterpret_cast<T *>(m_initial_buffer)),
|
||||
m_pos(0),
|
||||
m_capacity(INITIAL_SIZE) {
|
||||
unsigned sz = source.size();
|
||||
for(unsigned i = 0; i < sz; i++) {
|
||||
push_back(source.m_buffer[i]);
|
||||
}
|
||||
}
|
||||
|
||||
buffer(unsigned sz, const T & elem):
|
||||
m_buffer(reinterpret_cast<T *>(m_initial_buffer)),
|
||||
m_pos(0),
|
||||
m_capacity(INITIAL_SIZE) {
|
||||
for (unsigned i = 0; i < sz; i++) {
|
||||
push_back(elem);
|
||||
}
|
||||
SASSERT(size() == sz);
|
||||
}
|
||||
|
||||
~buffer() {
|
||||
destroy();
|
||||
}
|
||||
|
||||
void reset() {
|
||||
if (CallDestructors) {
|
||||
destroy_elements();
|
||||
}
|
||||
m_pos = 0;
|
||||
}
|
||||
|
||||
void finalize() {
|
||||
destroy();
|
||||
m_buffer = reinterpret_cast<T *>(m_initial_buffer);
|
||||
m_pos = 0;
|
||||
m_capacity = INITIAL_SIZE;
|
||||
}
|
||||
|
||||
unsigned size() const {
|
||||
return m_pos;
|
||||
}
|
||||
|
||||
bool empty() const {
|
||||
return m_pos == 0;
|
||||
}
|
||||
|
||||
iterator begin() {
|
||||
return m_buffer;
|
||||
}
|
||||
|
||||
iterator end() {
|
||||
return m_buffer + size();
|
||||
}
|
||||
|
||||
void set_end(iterator it) {
|
||||
m_pos = static_cast<unsigned>(it - m_buffer);
|
||||
if (CallDestructors) {
|
||||
iterator e = end();
|
||||
for (; it != e; ++it) {
|
||||
it->~T();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const_iterator begin() const {
|
||||
return m_buffer;
|
||||
}
|
||||
|
||||
const_iterator end() const {
|
||||
return m_buffer + size();
|
||||
}
|
||||
|
||||
void push_back(const T & elem) {
|
||||
if (m_pos >= m_capacity)
|
||||
expand();
|
||||
new (m_buffer + m_pos) T(elem);
|
||||
m_pos++;
|
||||
}
|
||||
|
||||
void pop_back() {
|
||||
if (CallDestructors) {
|
||||
back().~T();
|
||||
}
|
||||
m_pos--;
|
||||
}
|
||||
|
||||
const T & back() const {
|
||||
SASSERT(!empty());
|
||||
SASSERT(m_pos > 0);
|
||||
return m_buffer[m_pos - 1];
|
||||
}
|
||||
|
||||
T & back() {
|
||||
SASSERT(!empty());
|
||||
SASSERT(m_pos > 0);
|
||||
return m_buffer[m_pos - 1];
|
||||
}
|
||||
|
||||
T * c_ptr() const {
|
||||
return m_buffer;
|
||||
}
|
||||
|
||||
void append(unsigned n, T const * elems) {
|
||||
for (unsigned i = 0; i < n; i++) {
|
||||
push_back(elems[i]);
|
||||
}
|
||||
}
|
||||
|
||||
void append(const buffer& source) {
|
||||
append(source.size(), source.c_ptr());
|
||||
}
|
||||
|
||||
T & operator[](unsigned idx) {
|
||||
SASSERT(idx < size());
|
||||
return m_buffer[idx];
|
||||
}
|
||||
|
||||
const T & operator[](unsigned idx) const {
|
||||
SASSERT(idx < size());
|
||||
return m_buffer[idx];
|
||||
}
|
||||
|
||||
T & get(unsigned idx) {
|
||||
SASSERT(idx < size());
|
||||
return m_buffer[idx];
|
||||
}
|
||||
|
||||
const T & get(unsigned idx) const {
|
||||
SASSERT(idx < size());
|
||||
return m_buffer[idx];
|
||||
}
|
||||
|
||||
void set(unsigned idx, T const & val) {
|
||||
SASSERT(idx < size());
|
||||
m_buffer[idx] = val;
|
||||
}
|
||||
|
||||
void resize(unsigned nsz, const T & elem=T()) {
|
||||
unsigned sz = size();
|
||||
if (nsz > sz) {
|
||||
for (unsigned i = sz; i < nsz; i++) {
|
||||
push_back(elem);
|
||||
}
|
||||
}
|
||||
else if (nsz < sz) {
|
||||
for (unsigned i = nsz; i < sz; i++) {
|
||||
pop_back();
|
||||
}
|
||||
}
|
||||
SASSERT(size() == nsz);
|
||||
}
|
||||
|
||||
void shrink(unsigned nsz) {
|
||||
unsigned sz = size();
|
||||
SASSERT(nsz <= sz);
|
||||
for (unsigned i = nsz; i < sz; i++)
|
||||
pop_back();
|
||||
SASSERT(size() == nsz);
|
||||
}
|
||||
|
||||
private:
|
||||
buffer& operator=(buffer const&);
|
||||
};
|
||||
|
||||
template<typename T, unsigned INITIAL_SIZE=16>
|
||||
class ptr_buffer : public buffer<T *, false, INITIAL_SIZE> {
|
||||
public:
|
||||
void append(unsigned n, T * const * elems) {
|
||||
for (unsigned i = 0; i < n; i++) {
|
||||
this->push_back(elems[i]);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
template<typename T, unsigned INITIAL_SIZE=16>
|
||||
class sbuffer : public buffer<T, false, INITIAL_SIZE> {
|
||||
public:
|
||||
sbuffer(): buffer<T, false, INITIAL_SIZE>() {}
|
||||
sbuffer(unsigned sz, const T& elem) : buffer<T, false, INITIAL_SIZE>(sz,elem) {}
|
||||
};
|
||||
|
||||
#endif /* _BUFFER_H_ */
|
||||
|
37
src/util/cancel_eh.h
Normal file
37
src/util/cancel_eh.h
Normal file
|
@ -0,0 +1,37 @@
|
|||
/*++
|
||||
Copyright (c) 2011 Microsoft Corporation
|
||||
|
||||
Module Name:
|
||||
|
||||
cancel_eh.h
|
||||
|
||||
Abstract:
|
||||
|
||||
Template for implementing simple event handler that just invokes cancel method.
|
||||
|
||||
Author:
|
||||
|
||||
Leonardo de Moura (leonardo) 2011-04-27.
|
||||
|
||||
Revision History:
|
||||
|
||||
--*/
|
||||
#ifndef _CANCEL_EH_H_
|
||||
#define _CANCEL_EH_H_
|
||||
|
||||
#include"event_handler.h"
|
||||
|
||||
/**
|
||||
\brief Generic event handler for invoking cancel method.
|
||||
*/
|
||||
template<typename T>
|
||||
class cancel_eh : public event_handler {
|
||||
T & m_obj;
|
||||
public:
|
||||
cancel_eh(T & o):m_obj(o) {}
|
||||
virtual void operator()() {
|
||||
m_obj.cancel();
|
||||
}
|
||||
};
|
||||
|
||||
#endif
|
672
src/util/chashtable.h
Normal file
672
src/util/chashtable.h
Normal file
|
@ -0,0 +1,672 @@
|
|||
/*++
|
||||
Copyright (c) 2011 Microsoft Corporation
|
||||
|
||||
Module Name:
|
||||
|
||||
chashtable.h
|
||||
|
||||
Abstract:
|
||||
|
||||
Hashtable with chaining.
|
||||
|
||||
The performance of the hashtable in hashtable.h deteriorates if
|
||||
there is a huge number of deletions. In this case, the hashtable
|
||||
starts to contain many cells marked as deleted, and insertion/deletion
|
||||
start to suffer.
|
||||
|
||||
The hashtable defined in this class addresses this problem by using
|
||||
chaining. Of course, there is the cost of storing the link to the next
|
||||
cell.
|
||||
|
||||
Author:
|
||||
|
||||
Leonardo de Moura (leonardo) 2011-04-14.
|
||||
|
||||
Revision History:
|
||||
|
||||
--*/
|
||||
#ifndef _CHASHTABLE_H_
|
||||
#define _CHASHTABLE_H_
|
||||
|
||||
#include"memory_manager.h"
|
||||
#include"debug.h"
|
||||
#include"trace.h"
|
||||
#ifdef Z3DEBUG
|
||||
#include"hashtable.h"
|
||||
#endif
|
||||
|
||||
#define CH_STATISTICS
|
||||
|
||||
#ifdef CH_STATISTICS
|
||||
#define CHS_CODE(CODE) { CODE }
|
||||
#else
|
||||
#define CHS_CODE(CODE)
|
||||
#endif
|
||||
|
||||
template<typename T, typename HashProc, typename EqProc>
|
||||
class chashtable : private HashProc, private EqProc {
|
||||
public:
|
||||
static const unsigned default_init_slots = 8;
|
||||
static const unsigned default_init_cellar = 2;
|
||||
|
||||
protected:
|
||||
struct cell {
|
||||
cell * m_next;
|
||||
T m_data;
|
||||
cell():m_next(reinterpret_cast<cell*>(1)) {}
|
||||
bool is_free() const { return m_next == reinterpret_cast<cell*>(1); }
|
||||
void mark_free() { m_next = reinterpret_cast<cell*>(1); }
|
||||
};
|
||||
|
||||
cell * m_table; // array of cells.
|
||||
unsigned m_capacity; // size of the array of cells.
|
||||
unsigned m_init_slots;
|
||||
unsigned m_init_cellar;
|
||||
unsigned m_slots; // m_slots < m_capacity, and m_slots is a power of two, the cells [m_slots, m_capacity) are used for chaining.
|
||||
unsigned m_used_slots; // m_used_slots <= m_slots (number of used slots).
|
||||
unsigned m_size; // number of occupied cells.
|
||||
#ifdef CH_STATISTICS
|
||||
unsigned m_collisions;
|
||||
#endif
|
||||
cell * m_next_cell;
|
||||
cell * m_free_cell;
|
||||
|
||||
unsigned get_hash(T const & d) const { return HashProc::operator()(d); }
|
||||
bool equals(T const & e1, T const & e2) const { return EqProc::operator()(e1, e2); }
|
||||
|
||||
static cell * alloc_table(unsigned sz) {
|
||||
return alloc_vect<cell>(sz);
|
||||
}
|
||||
|
||||
void delete_table() {
|
||||
dealloc_vect(m_table, m_capacity);
|
||||
}
|
||||
|
||||
// Return the next free cell in the cellar, and the number of used slots
|
||||
// Return 0 if the cellar is too small (unlikely but it might happen with a bad hash)
|
||||
cell * copy_table(cell * source, unsigned source_slots, unsigned source_capacity,
|
||||
cell * target, unsigned target_slots, unsigned target_capacity,
|
||||
unsigned & used_slots) {
|
||||
TRACE("chashtable", tout << "copy_table...\n";);
|
||||
SASSERT(target_slots >= source_slots);
|
||||
SASSERT(target_capacity >= source_capacity);
|
||||
unsigned target_mask = target_slots - 1;
|
||||
used_slots = 0;
|
||||
cell * source_end = source + source_slots;
|
||||
cell * target_cellar = target + target_slots;
|
||||
cell * target_end = target + target_capacity;
|
||||
for (cell * source_it = source; source_it != source_end; ++source_it) {
|
||||
if (!source_it->is_free()) {
|
||||
cell * list_it = source_it;
|
||||
do {
|
||||
unsigned h = get_hash(list_it->m_data);
|
||||
unsigned idx = h & target_mask;
|
||||
cell * target_it = target + idx;
|
||||
SASSERT(target_it >= target);
|
||||
SASSERT(target_it < target + target_slots);
|
||||
if (target_it->is_free()) {
|
||||
target_it->m_data = list_it->m_data;
|
||||
target_it->m_next = 0;
|
||||
used_slots++;
|
||||
}
|
||||
else {
|
||||
SASSERT((get_hash(target_it->m_data) & target_mask) == idx);
|
||||
if (target_cellar == target_end)
|
||||
return 0; // the cellar is too small...
|
||||
SASSERT(target_cellar >= target + target_slots);
|
||||
SASSERT(target_cellar < target_end);
|
||||
*target_cellar = *target_it;
|
||||
target_it->m_data = list_it->m_data;
|
||||
target_it->m_next = target_cellar;
|
||||
target_cellar++;
|
||||
}
|
||||
SASSERT(!target_it->is_free());
|
||||
list_it = list_it->m_next;
|
||||
}
|
||||
while (list_it != 0);
|
||||
}
|
||||
}
|
||||
#if 0
|
||||
TRACE("chashtable",
|
||||
for (unsigned i = 0; i < source_capacity; i++) {
|
||||
tout << i << ":[";
|
||||
if (source[i].m_next == 0)
|
||||
tout << "null";
|
||||
else if (source[i].m_next == reinterpret_cast<cell*>(1))
|
||||
tout << "X";
|
||||
else
|
||||
tout << (source[i].m_next - source);
|
||||
tout << ", " << source[i].m_data << "]\n";
|
||||
}
|
||||
tout << "\n";
|
||||
for (unsigned i = 0; i < target_capacity; i++) {
|
||||
tout << i << ":[";
|
||||
if (target[i].m_next == 0)
|
||||
tout << "null";
|
||||
else if (target[i].m_next == reinterpret_cast<cell*>(1))
|
||||
tout << "X";
|
||||
else
|
||||
tout << (target[i].m_next - target);
|
||||
tout << ", " << target[i].m_data << "]\n";
|
||||
}
|
||||
tout << "\n";);
|
||||
#endif
|
||||
return target_cellar;
|
||||
}
|
||||
|
||||
void expand_table() {
|
||||
unsigned curr_cellar = (m_capacity - m_slots);
|
||||
unsigned new_slots = m_slots * 2;
|
||||
unsigned new_cellar = curr_cellar * 2;
|
||||
while (true) {
|
||||
unsigned new_capacity = new_slots + new_cellar;
|
||||
cell * new_table = alloc_table(new_capacity);
|
||||
cell * next_cell = copy_table(m_table, m_slots, m_capacity,
|
||||
new_table, new_slots, new_capacity,
|
||||
m_used_slots);
|
||||
if (next_cell != 0) {
|
||||
delete_table();
|
||||
m_table = new_table;
|
||||
m_capacity = new_capacity;
|
||||
m_slots = new_slots;
|
||||
m_next_cell = next_cell;
|
||||
m_free_cell = 0;
|
||||
CASSERT("chashtable", check_invariant());
|
||||
return;
|
||||
}
|
||||
dealloc_vect(new_table, new_capacity);
|
||||
new_cellar *= 2;
|
||||
}
|
||||
}
|
||||
|
||||
bool has_free_cells() const {
|
||||
return m_free_cell != 0 || m_next_cell < m_table + m_capacity;
|
||||
}
|
||||
|
||||
cell * get_free_cell() {
|
||||
if (m_free_cell != 0) {
|
||||
cell * c = m_free_cell;
|
||||
m_free_cell = c->m_next;
|
||||
return c;
|
||||
}
|
||||
else {
|
||||
cell * c = m_next_cell;
|
||||
m_next_cell++;
|
||||
return c;
|
||||
}
|
||||
}
|
||||
|
||||
void recycle_cell(cell * c) {
|
||||
// c is in the cellar
|
||||
SASSERT(c >= m_table + m_slots);
|
||||
SASSERT(c < m_table + m_capacity);
|
||||
c->m_next = m_free_cell;
|
||||
m_free_cell = c;
|
||||
}
|
||||
|
||||
void init(unsigned slots, unsigned cellar) {
|
||||
m_capacity = slots + cellar;
|
||||
m_table = alloc_table(m_capacity);
|
||||
m_slots = slots;
|
||||
m_used_slots = 0;
|
||||
m_size = 0;
|
||||
m_next_cell = m_table + slots;
|
||||
m_free_cell = 0;
|
||||
}
|
||||
|
||||
public:
|
||||
chashtable(HashProc const & h = HashProc(),
|
||||
EqProc const & e = EqProc(),
|
||||
unsigned init_slots = default_init_slots,
|
||||
unsigned init_cellar = default_init_cellar):
|
||||
HashProc(h),
|
||||
EqProc(e) {
|
||||
SASSERT(is_power_of_two(init_slots));
|
||||
SASSERT(init_cellar > 0);
|
||||
m_init_slots = init_slots;
|
||||
m_init_cellar = init_cellar;
|
||||
init(m_init_slots, m_init_cellar);
|
||||
CHS_CODE(m_collisions = 0;);
|
||||
}
|
||||
|
||||
~chashtable() {
|
||||
#if 0
|
||||
cell * it = m_table;
|
||||
cell * end = m_table + m_slots;
|
||||
verbose_stream() << "[chashtable] free slots: ";
|
||||
for (; it != end; ++it) {
|
||||
if (it->is_free())
|
||||
verbose_stream() << (it - m_table) << " ";
|
||||
}
|
||||
verbose_stream() << "\n";
|
||||
#endif
|
||||
delete_table();
|
||||
}
|
||||
|
||||
void reset() {
|
||||
if (m_size == 0)
|
||||
return;
|
||||
finalize();
|
||||
}
|
||||
|
||||
void finalize() {
|
||||
delete_table();
|
||||
init(m_init_slots, m_init_cellar);
|
||||
}
|
||||
|
||||
bool empty() const {
|
||||
return m_size == 0;
|
||||
}
|
||||
|
||||
unsigned size() const {
|
||||
return m_size;
|
||||
}
|
||||
|
||||
unsigned capacity() const {
|
||||
return m_capacity;
|
||||
}
|
||||
|
||||
unsigned used_slots() const {
|
||||
return m_used_slots;
|
||||
}
|
||||
|
||||
void insert(T const & d) {
|
||||
if (!has_free_cells())
|
||||
expand_table();
|
||||
unsigned mask = m_slots - 1;
|
||||
unsigned h = get_hash(d);
|
||||
unsigned idx = h & mask;
|
||||
cell * c = m_table + idx;
|
||||
if (c->is_free()) {
|
||||
m_size++;
|
||||
m_used_slots++;
|
||||
c->m_data = d;
|
||||
c->m_next = 0;
|
||||
CASSERT("chashtable_bug", check_invariant());
|
||||
return;
|
||||
}
|
||||
else {
|
||||
cell * it = c;
|
||||
do {
|
||||
if (equals(it->m_data, d)) {
|
||||
// already there
|
||||
it->m_data = d;
|
||||
CASSERT("chashtable_bug", check_invariant());
|
||||
return;
|
||||
}
|
||||
CHS_CODE(m_collisions++;);
|
||||
it = it->m_next;
|
||||
}
|
||||
while (it != 0);
|
||||
// d is not in the table.
|
||||
m_size++;
|
||||
cell * new_c = get_free_cell();
|
||||
*new_c = *c;
|
||||
c->m_data = d;
|
||||
c->m_next = new_c;
|
||||
CASSERT("chashtable_bug", check_invariant());
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
T & insert_if_not_there(T const & d) {
|
||||
if (!has_free_cells())
|
||||
expand_table();
|
||||
unsigned mask = m_slots - 1;
|
||||
unsigned h = get_hash(d);
|
||||
unsigned idx = h & mask;
|
||||
cell * c = m_table + idx;
|
||||
if (c->is_free()) {
|
||||
m_size++;
|
||||
m_used_slots++;
|
||||
c->m_data = d;
|
||||
c->m_next = 0;
|
||||
CASSERT("chashtable_bug", check_invariant());
|
||||
return c->m_data;
|
||||
}
|
||||
else {
|
||||
cell * it = c;
|
||||
do {
|
||||
if (equals(it->m_data, d)) {
|
||||
// already there
|
||||
CASSERT("chashtable_bug", check_invariant());
|
||||
return it->m_data;
|
||||
}
|
||||
CHS_CODE(m_collisions++;);
|
||||
it = it->m_next;
|
||||
}
|
||||
while (it != 0);
|
||||
// d is not in the table.
|
||||
m_size++;
|
||||
cell * new_c = get_free_cell();
|
||||
*new_c = *c;
|
||||
c->m_data = d;
|
||||
c->m_next = new_c;
|
||||
CASSERT("chashtable_bug", check_invariant());
|
||||
return c->m_data;
|
||||
}
|
||||
}
|
||||
|
||||
bool insert_if_not_there2(T const & d) {
|
||||
if (!has_free_cells())
|
||||
expand_table();
|
||||
unsigned mask = m_slots - 1;
|
||||
unsigned h = get_hash(d);
|
||||
unsigned idx = h & mask;
|
||||
cell * c = m_table + idx;
|
||||
if (c->is_free()) {
|
||||
m_size++;
|
||||
m_used_slots++;
|
||||
c->m_data = d;
|
||||
c->m_next = 0;
|
||||
CASSERT("chashtable_bug", check_invariant());
|
||||
return true;
|
||||
}
|
||||
else {
|
||||
cell * it = c;
|
||||
do {
|
||||
if (equals(it->m_data, d)) {
|
||||
// already there
|
||||
CASSERT("chashtable_bug", check_invariant());
|
||||
return false;
|
||||
}
|
||||
CHS_CODE(m_collisions++;);
|
||||
it = it->m_next;
|
||||
}
|
||||
while (it != 0);
|
||||
// d is not in the table.
|
||||
m_size++;
|
||||
cell * new_c = get_free_cell();
|
||||
*new_c = *c;
|
||||
c->m_data = d;
|
||||
c->m_next = new_c;
|
||||
CASSERT("chashtable_bug", check_invariant());
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
bool contains(T const & d) const {
|
||||
unsigned mask = m_slots - 1;
|
||||
unsigned h = get_hash(d);
|
||||
unsigned idx = h & mask;
|
||||
cell * c = m_table + idx;
|
||||
if (c->is_free())
|
||||
return false;
|
||||
do {
|
||||
if (equals(c->m_data, d)) {
|
||||
return true;
|
||||
}
|
||||
CHS_CODE(const_cast<chashtable*>(this)->m_collisions++;);
|
||||
c = c->m_next;
|
||||
}
|
||||
while (c != 0);
|
||||
return false;
|
||||
}
|
||||
|
||||
T * find_core(T const & d) const {
|
||||
unsigned mask = m_slots - 1;
|
||||
unsigned h = get_hash(d);
|
||||
unsigned idx = h & mask;
|
||||
cell * c = m_table + idx;
|
||||
if (c->is_free())
|
||||
return 0;
|
||||
do {
|
||||
if (equals(c->m_data, d)) {
|
||||
return &(c->m_data);
|
||||
}
|
||||
CHS_CODE(const_cast<chashtable*>(this)->m_collisions++;);
|
||||
c = c->m_next;
|
||||
}
|
||||
while (c != 0);
|
||||
return 0;
|
||||
}
|
||||
|
||||
bool find(T const & d, T & r) {
|
||||
unsigned mask = m_slots - 1;
|
||||
unsigned h = get_hash(d);
|
||||
unsigned idx = h & mask;
|
||||
cell * c = m_table + idx;
|
||||
if (c->is_free())
|
||||
return false;
|
||||
do {
|
||||
if (equals(c->m_data, d)) {
|
||||
r = c->m_data;
|
||||
return true;
|
||||
}
|
||||
CHS_CODE(const_cast<chashtable*>(this)->m_collisions++;);
|
||||
c = c->m_next;
|
||||
}
|
||||
while (c != 0);
|
||||
return false;
|
||||
}
|
||||
|
||||
void erase(T const & d) {
|
||||
unsigned mask = m_slots - 1;
|
||||
unsigned h = get_hash(d);
|
||||
unsigned idx = h & mask;
|
||||
cell * c = m_table + idx;
|
||||
if (c->is_free())
|
||||
return;
|
||||
cell * prev = 0;
|
||||
do {
|
||||
if (equals(c->m_data, d)) {
|
||||
m_size--;
|
||||
if (prev == 0) {
|
||||
cell * next = c->m_next;
|
||||
if (next == 0) {
|
||||
m_used_slots--;
|
||||
c->mark_free();
|
||||
SASSERT(c->is_free());
|
||||
}
|
||||
else {
|
||||
*c = *next;
|
||||
recycle_cell(next);
|
||||
}
|
||||
}
|
||||
else {
|
||||
prev->m_next = c->m_next;
|
||||
recycle_cell(c);
|
||||
}
|
||||
CASSERT("chashtable_bug", check_invariant());
|
||||
return;
|
||||
}
|
||||
CHS_CODE(m_collisions++;);
|
||||
prev = c;
|
||||
c = c->m_next;
|
||||
}
|
||||
while (c != 0);
|
||||
}
|
||||
|
||||
class iterator {
|
||||
cell * m_it;
|
||||
cell * m_end;
|
||||
cell * m_list_it;
|
||||
|
||||
void move_to_used() {
|
||||
while (m_it != m_end) {
|
||||
if (!m_it->is_free()) {
|
||||
m_list_it = m_it;
|
||||
return;
|
||||
}
|
||||
m_it++;
|
||||
}
|
||||
m_list_it = 0;
|
||||
}
|
||||
|
||||
public:
|
||||
iterator(cell * start, cell * end): m_it(start), m_end(end) { move_to_used(); }
|
||||
iterator():m_it(0), m_end(0), m_list_it(0) {}
|
||||
T & operator*() {
|
||||
return m_list_it->m_data;
|
||||
}
|
||||
T const & operator*() const {
|
||||
return m_list_it->m_data;
|
||||
}
|
||||
T const * operator->() const { return &(operator*()); }
|
||||
T * operator->() { return &(operator*()); }
|
||||
iterator & operator++() {
|
||||
m_list_it = m_list_it->m_next;
|
||||
if (m_list_it == 0) {
|
||||
m_it++;
|
||||
move_to_used();
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
iterator operator++(int) { iterator tmp = *this; ++*this; return tmp; }
|
||||
bool operator==(iterator const & it) const { return m_list_it == it.m_list_it; }
|
||||
bool operator!=(iterator const & it) const { return m_list_it != it.m_list_it; }
|
||||
};
|
||||
|
||||
iterator begin() const { return iterator(m_table, m_table + m_slots); }
|
||||
iterator end() const { return iterator(); }
|
||||
|
||||
void swap(chashtable & other) {
|
||||
std::swap(m_table, other.m_table);
|
||||
std::swap(m_capacity, other.m_capacity);
|
||||
std::swap(m_init_slots, other.m_init_slots);
|
||||
std::swap(m_init_cellar, other.m_init_cellar);
|
||||
std::swap(m_slots, other.m_slots);
|
||||
std::swap(m_used_slots, other.m_used_slots);
|
||||
std::swap(m_size, other.m_size);
|
||||
#ifdef CH_STATISTICS
|
||||
std::swap(m_collisions, other.m_collisions);
|
||||
#endif
|
||||
std::swap(m_next_cell, other.m_next_cell);
|
||||
std::swap(m_free_cell, other.m_free_cell);
|
||||
}
|
||||
|
||||
unsigned collisions() const {
|
||||
#ifdef CH_STATISTICS
|
||||
return m_collisions;
|
||||
#else
|
||||
return 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
#ifdef Z3DEBUG
|
||||
bool check_invariant() const {
|
||||
ptr_addr_hashtable<cell> visited;
|
||||
unsigned sz = 0;
|
||||
cell * _end = m_table + m_slots;
|
||||
for (cell * it = m_table; it != _end; ++it) {
|
||||
if (!it->is_free()) {
|
||||
cell * list_it = it;
|
||||
while (list_it != 0) {
|
||||
sz++;
|
||||
SASSERT(!visited.contains(list_it));
|
||||
visited.insert(list_it);
|
||||
list_it = list_it->m_next;
|
||||
}
|
||||
}
|
||||
}
|
||||
SASSERT(m_size == sz);
|
||||
return true;
|
||||
}
|
||||
#endif
|
||||
};
|
||||
|
||||
template<typename Key, typename Value, typename HashProc, typename EqProc>
|
||||
class cmap {
|
||||
public:
|
||||
struct key_value {
|
||||
Key m_key;
|
||||
Value m_value;
|
||||
key_value() {}
|
||||
key_value(Key const & k):m_key(k) {}
|
||||
key_value(Key const & k, Value const & v):m_key(k), m_value(v) {}
|
||||
};
|
||||
|
||||
protected:
|
||||
struct key_value_hash_proc : private HashProc {
|
||||
key_value_hash_proc(HashProc const & p):HashProc(p) {}
|
||||
unsigned operator()(key_value const & d) const { return HashProc::operator()(d.m_key); }
|
||||
};
|
||||
|
||||
struct key_value_eq_proc : private EqProc {
|
||||
key_value_eq_proc(EqProc const & p):EqProc(p) {}
|
||||
bool operator()(key_value const & d1, key_value const & d2) const { return EqProc::operator()(d1.m_key, d2.m_key); }
|
||||
};
|
||||
|
||||
typedef chashtable<key_value, key_value_hash_proc, key_value_eq_proc> table;
|
||||
|
||||
table m_table;
|
||||
|
||||
public:
|
||||
cmap(HashProc const & h = HashProc(),
|
||||
EqProc const & e = EqProc(),
|
||||
unsigned init_slots = table::default_init_slots,
|
||||
unsigned init_cellar = table::default_init_cellar):
|
||||
m_table(key_value_hash_proc(h),
|
||||
key_value_eq_proc(e),
|
||||
init_slots,
|
||||
init_cellar) {
|
||||
}
|
||||
|
||||
typedef typename table::iterator iterator;
|
||||
|
||||
void reset() {
|
||||
m_table.reset();
|
||||
}
|
||||
|
||||
void finalize() {
|
||||
m_table.finalize();
|
||||
}
|
||||
|
||||
bool empty() const {
|
||||
return m_table.empty();
|
||||
}
|
||||
|
||||
unsigned size() const {
|
||||
return m_table.size();
|
||||
}
|
||||
|
||||
unsigned capacity() const {
|
||||
return m_table.capacity();
|
||||
}
|
||||
|
||||
unsigned used_slots() const {
|
||||
return m_table.used_slots();
|
||||
}
|
||||
|
||||
unsigned collisions() const {
|
||||
return m_table.collisions();
|
||||
}
|
||||
|
||||
iterator begin() const {
|
||||
return m_table.begin();
|
||||
}
|
||||
|
||||
iterator end() const {
|
||||
return m_table.end();
|
||||
}
|
||||
|
||||
void insert(Key const & k, Value const & v) {
|
||||
return m_table.insert(key_value(k, v));
|
||||
}
|
||||
|
||||
key_value & insert_if_not_there(Key const & k, Value const & v) {
|
||||
return m_table.insert_if_not_there(key_value(k, v));
|
||||
}
|
||||
|
||||
bool contains(Key const & k) const {
|
||||
return m_table.contains(key_value(k));
|
||||
}
|
||||
|
||||
key_value * find_core(Key const & k) const {
|
||||
return m_table.find_core(key_value(k));
|
||||
}
|
||||
|
||||
bool find(Key const & k, Value & v) const {
|
||||
key_value * e = m_table.find_core(key_value(k));
|
||||
if (e == 0)
|
||||
return false;
|
||||
v = e->m_value;
|
||||
return true;
|
||||
}
|
||||
|
||||
void erase(Key const & k) {
|
||||
m_table.erase(key_value(k));
|
||||
}
|
||||
};
|
||||
|
||||
#endif
|
45
src/util/critical_flet.h
Normal file
45
src/util/critical_flet.h
Normal file
|
@ -0,0 +1,45 @@
|
|||
/*++
|
||||
Copyright (c) 2011 Microsoft Corporation
|
||||
|
||||
Module Name:
|
||||
|
||||
critical flet.cpp
|
||||
|
||||
Abstract:
|
||||
|
||||
Version of flet using "omp critical" directive.
|
||||
|
||||
Warning: it uses omp critical section "critical_flet"
|
||||
|
||||
Author:
|
||||
|
||||
Leonardo de Moura (leonardo) 2011-05-12
|
||||
|
||||
Revision History:
|
||||
|
||||
--*/
|
||||
#ifndef _CRITICAL_FLET_H_
|
||||
#define _CRITICAL_FLET_H_
|
||||
|
||||
template<typename T>
|
||||
class critical_flet {
|
||||
T & m_ref;
|
||||
T m_old_value;
|
||||
public:
|
||||
critical_flet(T & ref, const T & new_value):
|
||||
m_ref(ref),
|
||||
m_old_value(ref) {
|
||||
#pragma omp critical (critical_flet)
|
||||
{
|
||||
m_ref = new_value;
|
||||
}
|
||||
}
|
||||
~critical_flet() {
|
||||
#pragma omp critical (critical_flet)
|
||||
{
|
||||
m_ref = m_old_value;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
#endif
|
110
src/util/debug.cpp
Normal file
110
src/util/debug.cpp
Normal file
|
@ -0,0 +1,110 @@
|
|||
/*++
|
||||
Copyright (c) 2006 Microsoft Corporation
|
||||
|
||||
Module Name:
|
||||
|
||||
debug.cpp
|
||||
|
||||
Abstract:
|
||||
|
||||
Basic debugging support.
|
||||
|
||||
Author:
|
||||
|
||||
Leonardo de Moura (leonardo) 2006-09-11.
|
||||
|
||||
Revision History:
|
||||
|
||||
--*/
|
||||
#include<cstdio>
|
||||
#ifndef _WINDOWS
|
||||
#include<unistd.h>
|
||||
#endif
|
||||
#include<iostream>
|
||||
#include"str_hashtable.h"
|
||||
|
||||
volatile bool g_enable_assertions = true;
|
||||
|
||||
void enable_assertions(bool f) {
|
||||
g_enable_assertions = f;
|
||||
}
|
||||
|
||||
bool assertions_enabled() {
|
||||
return g_enable_assertions;
|
||||
}
|
||||
|
||||
void notify_assertion_violation(const char * fileName, int line, const char * condition) {
|
||||
std::cerr << "ASSERTION VIOLATION\n";
|
||||
std::cerr << "File: " << fileName << "\n";
|
||||
std::cerr << "Line: " << line << "\n";
|
||||
std::cerr << condition << "\n";
|
||||
}
|
||||
|
||||
str_hashtable* g_enabled_debug_tags = 0;
|
||||
|
||||
static void init_debug_table() {
|
||||
if (!g_enabled_debug_tags) {
|
||||
g_enabled_debug_tags = alloc(str_hashtable);
|
||||
}
|
||||
}
|
||||
|
||||
void finalize_debug() {
|
||||
dealloc(g_enabled_debug_tags);
|
||||
g_enabled_debug_tags = 0;
|
||||
}
|
||||
|
||||
void enable_debug(const char * tag) {
|
||||
init_debug_table();
|
||||
g_enabled_debug_tags->insert(const_cast<char *>(tag));
|
||||
}
|
||||
|
||||
void disable_debug(const char * tag) {
|
||||
init_debug_table();
|
||||
g_enabled_debug_tags->erase(const_cast<char *>(tag));
|
||||
}
|
||||
|
||||
bool is_debug_enabled(const char * tag) {
|
||||
init_debug_table();
|
||||
return g_enabled_debug_tags->contains(const_cast<char *>(tag));
|
||||
}
|
||||
|
||||
#ifndef _WINDOWS
|
||||
void invoke_gdb() {
|
||||
char buffer[1024];
|
||||
int * x = 0;
|
||||
for (;;) {
|
||||
std::cerr << "(C)ontinue, (A)bort, (S)top, Invoke (G)DB\n";
|
||||
char result;
|
||||
std::cin >> result;
|
||||
switch(result) {
|
||||
case 'C':
|
||||
case 'c':
|
||||
return;
|
||||
case 'A':
|
||||
case 'a':
|
||||
exit(1);
|
||||
case 'S':
|
||||
case 's':
|
||||
// force seg fault...
|
||||
*x = 0;
|
||||
return;
|
||||
case 'G':
|
||||
case 'g':
|
||||
sprintf(buffer, "gdb -nw /proc/%d/exe %d", getpid(), getpid());
|
||||
std::cerr << "invoking GDB...\n";
|
||||
if (system(buffer) == 0) {
|
||||
std::cerr << "continuing the execution...\n";
|
||||
}
|
||||
else {
|
||||
std::cerr << "error starting GDB...\n";
|
||||
// forcing seg fault.
|
||||
int * x = 0;
|
||||
*x = 0;
|
||||
}
|
||||
return;
|
||||
default:
|
||||
std::cerr << "INVALID COMMAND\n";
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
99
src/util/debug.h
Normal file
99
src/util/debug.h
Normal file
|
@ -0,0 +1,99 @@
|
|||
/*++
|
||||
Copyright (c) 2006 Microsoft Corporation
|
||||
|
||||
Module Name:
|
||||
|
||||
debug.h
|
||||
|
||||
Abstract:
|
||||
|
||||
Basic debugging support.
|
||||
|
||||
Author:
|
||||
|
||||
Leonardo de Moura (leonardo) 2006-09-11.
|
||||
|
||||
Revision History:
|
||||
|
||||
--*/
|
||||
#ifndef _DEBUG_H_
|
||||
#define _DEBUG_H_
|
||||
|
||||
void enable_assertions(bool f);
|
||||
bool assertions_enabled();
|
||||
|
||||
#if 0
|
||||
#define _CRTDBG_MAP_ALLOC
|
||||
#include<stdlib.h>
|
||||
#include<new>
|
||||
#include<crtdbg.h>
|
||||
#endif
|
||||
|
||||
#include"error_codes.h"
|
||||
#include"warning.h"
|
||||
|
||||
#ifdef Z3DEBUG
|
||||
#define DEBUG_CODE(CODE) { CODE } ((void) 0)
|
||||
#else
|
||||
#define DEBUG_CODE(CODE) ((void) 0)
|
||||
#endif
|
||||
|
||||
#ifdef _WINDOWS
|
||||
#define INVOKE_DEBUGGER() __debugbreak()
|
||||
#else
|
||||
void invoke_gdb();
|
||||
#define INVOKE_DEBUGGER() invoke_gdb()
|
||||
#endif
|
||||
|
||||
void notify_assertion_violation(const char * file_name, int line, const char * condition);
|
||||
void enable_debug(const char * tag);
|
||||
void disable_debug(const char * tag);
|
||||
bool is_debug_enabled(const char * tag);
|
||||
|
||||
#define SASSERT(COND) DEBUG_CODE(if (assertions_enabled() && !(COND)) { notify_assertion_violation(__FILE__, __LINE__, #COND); INVOKE_DEBUGGER(); })
|
||||
#define CASSERT(TAG, COND) DEBUG_CODE(if (assertions_enabled() && is_debug_enabled(TAG) && !(COND)) { notify_assertion_violation(__FILE__, __LINE__, #COND); INVOKE_DEBUGGER(); })
|
||||
#define XASSERT(COND, EXTRA_CODE) DEBUG_CODE(if (assertions_enabled() && !(COND)) { notify_assertion_violation(__FILE__, __LINE__, #COND); { EXTRA_CODE } INVOKE_DEBUGGER(); })
|
||||
#define UNREACHABLE() DEBUG_CODE(notify_assertion_violation(__FILE__, __LINE__, "UNREACHABLE CODE WAS REACHED."); INVOKE_DEBUGGER();)
|
||||
#define NOT_IMPLEMENTED_YET() { std::cerr << "NOT IMPLEMENTED YET!\n"; UNREACHABLE(); exit(ERR_NOT_IMPLEMENTED_YET); } ((void) 0)
|
||||
|
||||
#ifdef Z3DEBUG
|
||||
#define VERIFY(_x_) if (!(_x_)) { \
|
||||
std::cerr << "Failed to verify: " << #_x_ << "\n"; \
|
||||
UNREACHABLE(); \
|
||||
}
|
||||
#else
|
||||
#define VERIFY(_x_) (_x_)
|
||||
#endif
|
||||
|
||||
#define MAKE_NAME2(LINE) zofty_ ## LINE
|
||||
#define MAKE_NAME(LINE) MAKE_NAME2(LINE)
|
||||
#define DBG_UNIQUE_NAME MAKE_NAME(__LINE__)
|
||||
#define COMPILE_TIME_ASSERT(expr) extern char DBG_UNIQUE_NAME[expr]
|
||||
|
||||
template<class T>
|
||||
class class_invariant
|
||||
{
|
||||
T* m_class;
|
||||
char const* m_module;
|
||||
public:
|
||||
class_invariant(T* cls) : m_class(cls), m_module(0) {
|
||||
SASSERT(cls->invariant());
|
||||
}
|
||||
class_invariant(T* cls, char const* module) : m_class(cls), m_module(module) {
|
||||
CASSERT(module, cls->invariant());
|
||||
}
|
||||
~class_invariant() {
|
||||
if (m_module) {
|
||||
CASSERT(m_module, m_class->invariant());
|
||||
}
|
||||
else {
|
||||
SASSERT(m_class->invariant());
|
||||
}
|
||||
}
|
||||
private:
|
||||
};
|
||||
|
||||
void finalize_debug();
|
||||
|
||||
#endif /* _DEBUG_H_ */
|
||||
|
68
src/util/dec_ref_util.h
Normal file
68
src/util/dec_ref_util.h
Normal file
|
@ -0,0 +1,68 @@
|
|||
/*++
|
||||
Copyright (c) 2011 Microsoft Corporation
|
||||
|
||||
Module Name:
|
||||
|
||||
map_util.h
|
||||
|
||||
Abstract:
|
||||
|
||||
Some goodies for managing reference counters
|
||||
stored in maps.
|
||||
|
||||
Author:
|
||||
|
||||
Leonardo (leonardo) 2011-06-07
|
||||
|
||||
Notes:
|
||||
|
||||
--*/
|
||||
#ifndef _MAP_UTIL_H_
|
||||
#define _MAP_UTIL_H_
|
||||
|
||||
/**
|
||||
\brief Decrement the reference counter of the keys and values stored in the map,
|
||||
then reset the map.
|
||||
*/
|
||||
template<typename Mng, typename Map>
|
||||
void dec_ref_key_values(Mng & m, Map & map) {
|
||||
typename Map::iterator it = map.begin();
|
||||
typename Map::iterator end = map.end();
|
||||
for (; it != end; ++it) {
|
||||
m.dec_ref(it->m_key);
|
||||
m.dec_ref(it->m_value);
|
||||
}
|
||||
map.reset();
|
||||
}
|
||||
|
||||
/**
|
||||
\brief Decrement the reference counter of the keys stored in the map,
|
||||
then reset the map.
|
||||
*/
|
||||
template<typename Mng, typename Map>
|
||||
void dec_ref_keys(Mng & m, Map & map) {
|
||||
typename Map::iterator it = map.begin();
|
||||
typename Map::iterator end = map.end();
|
||||
for (; it != end; ++it) {
|
||||
m.dec_ref(it->m_key);
|
||||
}
|
||||
map.reset();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
\brief Decrement the reference counter of the values stored in the map,
|
||||
then reset the map.
|
||||
*/
|
||||
template<typename Mng, typename Map>
|
||||
void dec_ref_values(Mng & m, Map & map) {
|
||||
typename Map::iterator it = map.begin();
|
||||
typename Map::iterator end = map.end();
|
||||
for (; it != end; ++it) {
|
||||
m.dec_ref(it->m_value);
|
||||
}
|
||||
map.reset();
|
||||
}
|
||||
|
||||
|
||||
#endif
|
326
src/util/dependency.h
Normal file
326
src/util/dependency.h
Normal file
|
@ -0,0 +1,326 @@
|
|||
/*++
|
||||
Copyright (c) 2006 Microsoft Corporation
|
||||
|
||||
Module Name:
|
||||
|
||||
dependency.h
|
||||
|
||||
Abstract:
|
||||
|
||||
<abstract>
|
||||
|
||||
Author:
|
||||
|
||||
Leonardo de Moura (leonardo) 2008-12-10.
|
||||
|
||||
Revision History:
|
||||
|
||||
--*/
|
||||
#ifndef _DEPENDENCY_H_
|
||||
#define _DEPENDENCY_H_
|
||||
|
||||
#include"vector.h"
|
||||
#include"region.h"
|
||||
|
||||
template<typename C>
|
||||
class dependency_manager {
|
||||
public:
|
||||
typedef typename C::value value;
|
||||
typedef typename C::value_manager value_manager;
|
||||
typedef typename C::allocator allocator;
|
||||
|
||||
class dependency {
|
||||
unsigned m_ref_count:30;
|
||||
unsigned m_mark:1;
|
||||
unsigned m_leaf:1;
|
||||
friend class dependency_manager;
|
||||
dependency(bool leaf):
|
||||
m_ref_count(0),
|
||||
m_mark(false),
|
||||
m_leaf(leaf) {
|
||||
}
|
||||
bool is_marked() const { return m_mark == 1; }
|
||||
void mark() { m_mark = true; }
|
||||
void unmark() { m_mark = false; }
|
||||
public:
|
||||
unsigned get_ref_count() const { return m_ref_count; }
|
||||
bool is_leaf() const { return m_leaf == 1; }
|
||||
};
|
||||
|
||||
private:
|
||||
struct join : public dependency {
|
||||
dependency * m_children[2];
|
||||
join(dependency * d1, dependency * d2):
|
||||
dependency(false) {
|
||||
m_children[0] = d1;
|
||||
m_children[1] = d2;
|
||||
}
|
||||
};
|
||||
|
||||
struct leaf : public dependency {
|
||||
value m_value;
|
||||
leaf(value const & v):
|
||||
dependency(true),
|
||||
m_value(v) {
|
||||
}
|
||||
};
|
||||
|
||||
static join * to_join(dependency * d) { SASSERT(!d->is_leaf()); return static_cast<join*>(d); }
|
||||
static leaf * to_leaf(dependency * d) { SASSERT(d->is_leaf()); return static_cast<leaf*>(d); }
|
||||
|
||||
value_manager & m_vmanager;
|
||||
allocator & m_allocator;
|
||||
ptr_vector<dependency> m_todo;
|
||||
|
||||
void inc_ref(value const & v) {
|
||||
if (C::ref_count)
|
||||
m_vmanager.inc_ref(v);
|
||||
}
|
||||
|
||||
void dec_ref(value const & v) {
|
||||
if (C::ref_count)
|
||||
m_vmanager.dec_ref(v);
|
||||
}
|
||||
|
||||
void del(dependency * d) {
|
||||
SASSERT(d);
|
||||
m_todo.push_back(d);
|
||||
while (!m_todo.empty()) {
|
||||
d = m_todo.back();
|
||||
m_todo.pop_back();
|
||||
if (d->is_leaf()) {
|
||||
dec_ref(to_leaf(d)->m_value);
|
||||
to_leaf(d)->~leaf();
|
||||
m_allocator.deallocate(sizeof(leaf), to_leaf(d));
|
||||
}
|
||||
else {
|
||||
for (unsigned i = 0; i < 2; i++) {
|
||||
dependency * c = to_join(d)->m_children[i];
|
||||
SASSERT(c->m_ref_count > 0);
|
||||
c->m_ref_count--;
|
||||
if (c->m_ref_count == 0)
|
||||
m_todo.push_back(c);
|
||||
}
|
||||
to_join(d)->~join();
|
||||
m_allocator.deallocate(sizeof(join), to_join(d));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void unmark_todo() {
|
||||
typename ptr_vector<dependency>::iterator it = m_todo.begin();
|
||||
typename ptr_vector<dependency>::iterator end = m_todo.end();
|
||||
for (; it != end; ++it) {
|
||||
(*it)->unmark();
|
||||
}
|
||||
m_todo.reset();
|
||||
}
|
||||
|
||||
public:
|
||||
|
||||
dependency_manager(value_manager & m, allocator & a):
|
||||
m_vmanager(m),
|
||||
m_allocator(a) {
|
||||
}
|
||||
|
||||
void inc_ref(dependency * d) {
|
||||
if (d)
|
||||
d->m_ref_count++;
|
||||
}
|
||||
|
||||
void dec_ref(dependency * d) {
|
||||
if (d) {
|
||||
SASSERT(d->m_ref_count > 0);
|
||||
d->m_ref_count--;
|
||||
if (d->m_ref_count == 0)
|
||||
del(d);
|
||||
}
|
||||
}
|
||||
|
||||
dependency * mk_empty() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
dependency * mk_leaf(value const & v) {
|
||||
void * mem = m_allocator.allocate(sizeof(leaf));
|
||||
inc_ref(v);
|
||||
return new (mem) leaf(v);
|
||||
}
|
||||
|
||||
dependency * mk_join(dependency * d1, dependency * d2) {
|
||||
if (d1 == 0) {
|
||||
return d2;
|
||||
}
|
||||
else if (d2 == 0) {
|
||||
return d1;
|
||||
}
|
||||
else if (d1 == d2) {
|
||||
return d1;
|
||||
}
|
||||
else {
|
||||
void * mem = m_allocator.allocate(sizeof(join));
|
||||
inc_ref(d1); inc_ref(d2);
|
||||
return new (mem) join(d1, d2);
|
||||
}
|
||||
}
|
||||
|
||||
bool contains(dependency * d, value const & v) {
|
||||
if (d) {
|
||||
m_todo.reset();
|
||||
d->mark();
|
||||
m_todo.push_back(d);
|
||||
unsigned qhead = 0;
|
||||
while (qhead < m_todo.size()) {
|
||||
dependency * d = m_todo[qhead];
|
||||
qhead++;
|
||||
if (d->is_leaf()) {
|
||||
if (to_leaf(d)->m_value == v) {
|
||||
unmark_todo();
|
||||
return true;
|
||||
}
|
||||
}
|
||||
else {
|
||||
for (unsigned i = 0; i < 2; i++) {
|
||||
dependency * child = to_join(d)->m_children[i];
|
||||
if (!child->is_marked()) {
|
||||
m_todo.push_back(child);
|
||||
child->mark();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
unmark_todo();
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void linearize(dependency * d, vector<value, false> & vs) {
|
||||
if (d) {
|
||||
m_todo.reset();
|
||||
d->mark();
|
||||
m_todo.push_back(d);
|
||||
unsigned qhead = 0;
|
||||
while (qhead < m_todo.size()) {
|
||||
dependency * d = m_todo[qhead];
|
||||
qhead++;
|
||||
if (d->is_leaf()) {
|
||||
vs.push_back(to_leaf(d)->m_value);
|
||||
}
|
||||
else {
|
||||
for (unsigned i = 0; i < 2; i++) {
|
||||
dependency * child = to_join(d)->m_children[i];
|
||||
if (!child->is_marked()) {
|
||||
m_todo.push_back(child);
|
||||
child->mark();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
unmark_todo();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
\brief Version of the dependency_manager where
|
||||
memory management is scoped (i.e., reference counting is ignored),
|
||||
and push_scope/pop_scope are used instead.
|
||||
|
||||
Value must be a primitive type such as an integer or pointer.
|
||||
*/
|
||||
template<typename Value>
|
||||
class scoped_dependency_manager {
|
||||
|
||||
class config {
|
||||
public:
|
||||
static const bool ref_count = true;
|
||||
|
||||
typedef Value value;
|
||||
|
||||
class value_manager {
|
||||
public:
|
||||
void inc_ref(value const & v) {
|
||||
}
|
||||
|
||||
void dec_ref(value const & v) {
|
||||
}
|
||||
};
|
||||
|
||||
class allocator {
|
||||
region m_region;
|
||||
public:
|
||||
void * allocate(size_t sz) {
|
||||
return m_region.allocate(sz);
|
||||
}
|
||||
|
||||
void deallocate(size_t sz, void * mem) {
|
||||
}
|
||||
|
||||
void push_scope() {
|
||||
m_region.push_scope();
|
||||
}
|
||||
|
||||
void pop_scope(unsigned num) {
|
||||
m_region.pop_scope(num);
|
||||
}
|
||||
|
||||
void reset() {
|
||||
m_region.reset();
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
typedef dependency_manager<config> dep_manager;
|
||||
public:
|
||||
typedef typename dep_manager::dependency dependency;
|
||||
typedef Value value;
|
||||
|
||||
private:
|
||||
typename config::value_manager m_vmanager;
|
||||
typename config::allocator m_allocator;
|
||||
dep_manager m_dep_manager;
|
||||
|
||||
public:
|
||||
scoped_dependency_manager():
|
||||
m_dep_manager(m_vmanager, m_allocator) {
|
||||
}
|
||||
|
||||
dependency * mk_empty() {
|
||||
return m_dep_manager.mk_empty();
|
||||
}
|
||||
|
||||
dependency * mk_leaf(value const & v) {
|
||||
return m_dep_manager.mk_leaf(v);
|
||||
}
|
||||
|
||||
dependency * mk_join(dependency * d1, dependency * d2) {
|
||||
return m_dep_manager.mk_join(d1, d2);
|
||||
}
|
||||
|
||||
bool contains(dependency * d, value const & v) {
|
||||
return m_dep_manager.contains(d, v);
|
||||
}
|
||||
|
||||
void linearize(dependency * d, vector<value, false> & vs) {
|
||||
return m_dep_manager.linearize(d, vs);
|
||||
}
|
||||
|
||||
void reset() {
|
||||
m_allocator.reset();
|
||||
}
|
||||
|
||||
void push_scope() {
|
||||
m_allocator.push_scope();
|
||||
}
|
||||
|
||||
void pop_scope(unsigned num_scopes) {
|
||||
m_allocator.pop_scope(num_scopes);
|
||||
}
|
||||
};
|
||||
|
||||
// Implement old dependency manager used by interval and groebner
|
||||
typedef scoped_dependency_manager<void*> v_dependency_manager;
|
||||
typedef scoped_dependency_manager<void*>::dependency v_dependency;
|
||||
|
||||
#endif /* _DEPENDENCY_H_ */
|
||||
|
29
src/util/dictionary.h
Normal file
29
src/util/dictionary.h
Normal file
|
@ -0,0 +1,29 @@
|
|||
/*++
|
||||
Copyright (c) 2011 Microsoft Corporation
|
||||
|
||||
Module Name:
|
||||
|
||||
dictionary.h
|
||||
|
||||
Abstract:
|
||||
|
||||
Author:
|
||||
|
||||
Leonardo (leonardo) 2011-03-01
|
||||
|
||||
Notes:
|
||||
|
||||
--*/
|
||||
#ifndef _DICTIONARY_H_
|
||||
#define _DICTIONARY_H_
|
||||
|
||||
#include"map.h"
|
||||
#include"symbol.h"
|
||||
|
||||
template<typename T>
|
||||
class dictionary : public map<symbol, T, symbol_hash_proc, symbol_eq_proc> {
|
||||
public:
|
||||
dictionary() {}
|
||||
};
|
||||
|
||||
#endif
|
137
src/util/dlist.h
Normal file
137
src/util/dlist.h
Normal file
|
@ -0,0 +1,137 @@
|
|||
/*++
|
||||
Copyright (c) 2011 Microsoft Corporation
|
||||
|
||||
Module Name:
|
||||
|
||||
dlist.h
|
||||
|
||||
Abstract:
|
||||
|
||||
Templates for manipulating doubly linked lists.
|
||||
|
||||
Author:
|
||||
|
||||
Leonardo de Moura (leonardo) 2011-01-25.
|
||||
|
||||
Revision History:
|
||||
|
||||
--*/
|
||||
#ifndef __DLIST_H_
|
||||
#define __DLIST_H_
|
||||
|
||||
/**
|
||||
Add element \c elem to the list headed by \c head.
|
||||
NextProc and PrevProc must have the methods:
|
||||
T * & operator()(T *);
|
||||
T * & operator()(T *);
|
||||
They should return the next and prev fields of the given object.
|
||||
*/
|
||||
template<typename T, typename NextProc, typename PrevProc>
|
||||
void dlist_add(T * & head, T * elem, NextProc const & next = NextProc(), PrevProc const & prev = PrevProc()) {
|
||||
SASSERT(prev(elem) == 0);
|
||||
SASSERT(next(elem) == 0);
|
||||
if (head == 0) {
|
||||
head = elem;
|
||||
}
|
||||
else {
|
||||
next(elem) = head;
|
||||
prev(head) = elem;
|
||||
head = elem;
|
||||
}
|
||||
}
|
||||
|
||||
template<typename T, typename NextProc, typename PrevProc>
|
||||
void dlist_del(T * & head, T * elem, NextProc const & next = NextProc(), PrevProc const & prev = PrevProc()) {
|
||||
T * & prev_elem = prev(elem);
|
||||
T * & next_elem = next(elem);
|
||||
if (head == elem) {
|
||||
SASSERT(prev_elem == 0);
|
||||
if (next_elem != 0)
|
||||
prev(next_elem) = 0;
|
||||
head = next_elem;
|
||||
}
|
||||
else {
|
||||
SASSERT(prev_elem != 0);
|
||||
next(prev_elem) = next_elem;
|
||||
if (next_elem != 0)
|
||||
prev(next_elem) = prev_elem;
|
||||
}
|
||||
prev_elem = 0;
|
||||
next_elem = 0;
|
||||
}
|
||||
|
||||
/**
|
||||
\brief Remove the head of the list. Return the old head.
|
||||
*/
|
||||
template<typename T, typename NextProc, typename PrevProc>
|
||||
T * dlist_pop(T * & head, NextProc const & next = NextProc(), PrevProc const & prev = PrevProc()) {
|
||||
if (head == 0) {
|
||||
return 0;
|
||||
}
|
||||
else {
|
||||
SASSERT(prev(head) == 0);
|
||||
T * r = head;
|
||||
head = next(head);
|
||||
if (head)
|
||||
prev(head) = 0;
|
||||
next(r) = 0;
|
||||
return r;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
\brief Insert new element after elem.
|
||||
*/
|
||||
template<typename T, typename NextProc, typename PrevProc>
|
||||
void dlist_insert_after(T * elem, T * new_elem, NextProc const & next = NextProc(), PrevProc const & prev = PrevProc()) {
|
||||
SASSERT(elem);
|
||||
SASSERT(new_elem);
|
||||
T * & old_next_elem = next(elem);
|
||||
prev(new_elem) = elem;
|
||||
next(new_elem) = old_next_elem;
|
||||
if (old_next_elem)
|
||||
prev(old_next_elem) = new_elem;
|
||||
// next(elem) = new_elem;
|
||||
old_next_elem = new_elem;
|
||||
}
|
||||
|
||||
template<typename T, typename NextProc>
|
||||
bool dlist_contains(T * head, T const * elem, NextProc const & next = NextProc()) {
|
||||
T * curr = head;
|
||||
while (curr != 0) {
|
||||
if (curr == elem)
|
||||
return true;
|
||||
curr = next(curr);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
template<typename T, typename NextProc>
|
||||
unsigned dlist_length(T * head, NextProc const & next = NextProc()) {
|
||||
unsigned r = 0;
|
||||
T * curr = head;
|
||||
while (curr != 0) {
|
||||
r++;
|
||||
curr = next(curr);
|
||||
}
|
||||
return r;
|
||||
}
|
||||
|
||||
template<typename T, typename NextProc, typename PrevProc>
|
||||
bool dlist_check_invariant(T * head, NextProc const & next = NextProc(), PrevProc const & prev = PrevProc()) {
|
||||
if (head == 0)
|
||||
return true;
|
||||
SASSERT(prev(head) == 0);
|
||||
T * old = head;
|
||||
T * curr = next(head);
|
||||
while (curr != 0) {
|
||||
SASSERT(prev(curr) == old);
|
||||
old = curr;
|
||||
curr = next(curr);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
|
103
src/util/double_manager.h
Normal file
103
src/util/double_manager.h
Normal file
|
@ -0,0 +1,103 @@
|
|||
/*++
|
||||
Copyright (c) 2006 Microsoft Corporation
|
||||
|
||||
Module Name:
|
||||
|
||||
double_manager.h
|
||||
|
||||
Abstract:
|
||||
|
||||
Simulates mpq interface using doubles
|
||||
|
||||
Author:
|
||||
|
||||
Leonardo de Moura (leonardo) 2011-06-09.
|
||||
|
||||
Revision History:
|
||||
|
||||
--*/
|
||||
#ifndef _DOUBLE_MANAGER_H_
|
||||
#define _DOUBLE_MANAGER_H_
|
||||
|
||||
#include<cmath>
|
||||
#include<string>
|
||||
#include<sstream>
|
||||
#include<iomanip>
|
||||
#include"util.h"
|
||||
#include"debug.h"
|
||||
#include"hash.h"
|
||||
#include"params.h"
|
||||
|
||||
/**
|
||||
\brief Create an interface for manipulating double numbers compatible with the one for mpq.
|
||||
*/
|
||||
class double_manager {
|
||||
double m_zero_tolerance;
|
||||
public:
|
||||
typedef double numeral;
|
||||
static bool precise() { return false; }
|
||||
|
||||
double_manager(params_ref const & p = params_ref()) { updt_params(p); }
|
||||
|
||||
void updt_params(params_ref const & p) {
|
||||
m_zero_tolerance = p.get_double(":zero-tolerance", 0.00000001);
|
||||
}
|
||||
|
||||
static void reset(double & a) { a = 0.0; }
|
||||
|
||||
static void del(double & a) { /* do nothing */ }
|
||||
static void add(double a, double b, double & c) { c = a + b; }
|
||||
// d <- a + b*c
|
||||
static void addmul(double a, double b, double c, double & d) { d = a + b*c; }
|
||||
// d <- a - b*c
|
||||
static void submul(double a, double b, double c, double & d) { d = a - b*c; }
|
||||
static void sub(double a, double b, double & c) { c = a - b; }
|
||||
static void mul(double a, double b, double & c) { c = a * b; }
|
||||
static void div(double a, double b, double & c) { c = a / b; }
|
||||
static void inv(double a, double & b) { b = 1 / a; }
|
||||
static void inv(double & a) { a = 1 / a; }
|
||||
static void neg(double & a) { a = -a; }
|
||||
static void abs(double & a) { if (a < 0.0) neg(a); }
|
||||
static void power(double a, unsigned p, double & b) {
|
||||
SASSERT(p <= INT_MAX);
|
||||
b = ::pow(a, static_cast<int>(p));
|
||||
}
|
||||
static void floor(double a, double & b) { b = ::floor(a); }
|
||||
static void ceil(double a, double & b) { b = ::ceil(a); }
|
||||
bool eq(double a, double b) const { return is_zero(a - b); }
|
||||
bool neq(double a, double b) const { return !eq(a, b); }
|
||||
static bool lt(double a, double b) { return a < b; }
|
||||
static bool le(double a, double b) { return a <= b; }
|
||||
static bool gt(double a, double b) { return a > b; }
|
||||
static bool ge(double a, double b) { return a >= b; }
|
||||
static void set(double & a, int n, int d) { a = static_cast<double>(n)/static_cast<double>(d); }
|
||||
static void set(double & a, double val) { a = val; }
|
||||
static void set(double & a, char const * val) { a = atof(val); }
|
||||
static void set(double & a, int val) { a = static_cast<double>(val); }
|
||||
static void set(double & a, unsigned val) { a = static_cast<double>(val); }
|
||||
static void set(double & a, int64 val) { a = static_cast<double>(val); }
|
||||
static void set(double & a, uint64 val) { a = static_cast<double>(val); }
|
||||
static void swap(double & a, double & b) { std::swap(a, b); }
|
||||
bool is_pos(double a) const { return a > m_zero_tolerance; }
|
||||
bool is_neg(double a) const { return a < m_zero_tolerance; }
|
||||
bool is_zero(double a) const { return -m_zero_tolerance <= a && a <= m_zero_tolerance; }
|
||||
bool is_nonpos(double a) const { return !is_pos(a); }
|
||||
bool is_nonneg(double a) const { return !is_neg(a); }
|
||||
static bool is_one(double a) { return a == 1.0; }
|
||||
static bool is_minus_one(double a) { return a == -1.0; }
|
||||
static bool is_int(double a) { return a == ::floor(a); }
|
||||
static std::string to_string(double a) {
|
||||
std::ostringstream sstream;
|
||||
sstream << std::setprecision(12) << a;
|
||||
return sstream.str();
|
||||
}
|
||||
|
||||
static unsigned hash(double a) {
|
||||
return hash_ull(static_cast<uint64>(a));
|
||||
}
|
||||
};
|
||||
|
||||
COMPILE_TIME_ASSERT(sizeof(uint64) == sizeof(double));
|
||||
|
||||
#endif /* _DOUBLE_MANAGER_H_ */
|
||||
|
28
src/util/event_handler.h
Normal file
28
src/util/event_handler.h
Normal file
|
@ -0,0 +1,28 @@
|
|||
/*++
|
||||
Copyright (c) 2011 Microsoft Corporation
|
||||
|
||||
Module Name:
|
||||
|
||||
event_handler.h
|
||||
|
||||
Abstract:
|
||||
|
||||
Abstract event handler.
|
||||
|
||||
Author:
|
||||
|
||||
Leonardo de Moura (leonardo) 2011-04-26.
|
||||
|
||||
Revision History:
|
||||
|
||||
--*/
|
||||
#ifndef _EVENT_HANDLER_H_
|
||||
#define _EVENT_HANDLER_H_
|
||||
|
||||
class event_handler {
|
||||
public:
|
||||
virtual ~event_handler() {}
|
||||
virtual void operator()() = 0;
|
||||
};
|
||||
|
||||
#endif
|
52
src/util/ext_gcd.h
Normal file
52
src/util/ext_gcd.h
Normal file
|
@ -0,0 +1,52 @@
|
|||
/*++
|
||||
Copyright (c) 2006 Microsoft Corporation
|
||||
|
||||
Module Name:
|
||||
|
||||
ext_gcd.h
|
||||
|
||||
Abstract:
|
||||
|
||||
<abstract>
|
||||
|
||||
Author:
|
||||
|
||||
Leonardo de Moura (leonardo) 2007-06-09.
|
||||
|
||||
Revision History:
|
||||
|
||||
--*/
|
||||
#ifndef _EXT_GCD_H_
|
||||
#define _EXT_GCD_H_
|
||||
|
||||
template<typename numeral>
|
||||
void extended_gcd(const numeral & in_a, const numeral & in_b, numeral & gcd, numeral & x, numeral & y) {
|
||||
numeral a = in_a;
|
||||
numeral b = in_b;
|
||||
x = numeral(0);
|
||||
y = numeral(1);
|
||||
numeral lastx(1);
|
||||
numeral lasty(0);
|
||||
numeral tmp;
|
||||
numeral quotient;
|
||||
while (!b.is_zero()) {
|
||||
tmp = b;
|
||||
quotient = div(a, b);
|
||||
b = mod(a, b);
|
||||
a = tmp;
|
||||
|
||||
tmp = x;
|
||||
x = lastx - (quotient * x);
|
||||
lastx = tmp;
|
||||
|
||||
tmp = y;
|
||||
y = lasty - (quotient * y);
|
||||
lasty = tmp;
|
||||
}
|
||||
gcd = a;
|
||||
x = lastx;
|
||||
y = lasty;
|
||||
}
|
||||
|
||||
#endif /* _EXT_GCD_H_ */
|
||||
|
335
src/util/ext_numeral.h
Normal file
335
src/util/ext_numeral.h
Normal file
|
@ -0,0 +1,335 @@
|
|||
/*++
|
||||
Copyright (c) 2011 Microsoft Corporation
|
||||
|
||||
Module Name:
|
||||
|
||||
ext_numeral.h
|
||||
|
||||
Abstract:
|
||||
|
||||
Goodies for handling extended numerals such as R union { -oo, +oo }.
|
||||
We can have extended sets of mpq, mpz, mpbq, mpf, etc.
|
||||
|
||||
Author:
|
||||
|
||||
Leonardo de Moura (leonardo) 2011-12-04.
|
||||
|
||||
Revision History:
|
||||
|
||||
--*/
|
||||
#ifndef _EXT_NUMERAL_H_
|
||||
#define _EXT_NUMERAL_H_
|
||||
|
||||
#include<iostream>
|
||||
#include"debug.h"
|
||||
|
||||
enum ext_numeral_kind { EN_MINUS_INFINITY, EN_NUMERAL, EN_PLUS_INFINITY };
|
||||
|
||||
template<typename numeral_manager>
|
||||
bool is_zero(numeral_manager & m,
|
||||
typename numeral_manager::numeral const & a,
|
||||
ext_numeral_kind ak) {
|
||||
return ak == EN_NUMERAL && m.is_zero(a);
|
||||
}
|
||||
|
||||
template<typename numeral_manager>
|
||||
bool is_pos(numeral_manager & m,
|
||||
typename numeral_manager::numeral const & a,
|
||||
ext_numeral_kind ak) {
|
||||
return ak == EN_PLUS_INFINITY || (ak == EN_NUMERAL && m.is_pos(a));
|
||||
}
|
||||
|
||||
template<typename numeral_manager>
|
||||
bool is_neg(numeral_manager & m,
|
||||
typename numeral_manager::numeral const & a,
|
||||
ext_numeral_kind ak) {
|
||||
return ak == EN_MINUS_INFINITY || (ak == EN_NUMERAL && m.is_neg(a));
|
||||
}
|
||||
|
||||
inline bool is_infinite(ext_numeral_kind ak) { return ak != EN_NUMERAL; }
|
||||
|
||||
template<typename numeral_manager>
|
||||
void set(numeral_manager & m,
|
||||
typename numeral_manager::numeral & a,
|
||||
ext_numeral_kind & ak,
|
||||
typename numeral_manager::numeral const & b,
|
||||
ext_numeral_kind bk) {
|
||||
m.set(a, b);
|
||||
ak = bk;
|
||||
}
|
||||
|
||||
template<typename numeral_manager>
|
||||
void reset(numeral_manager & m,
|
||||
typename numeral_manager::numeral & a,
|
||||
ext_numeral_kind & ak) {
|
||||
m.reset(a);
|
||||
ak = EN_NUMERAL;
|
||||
}
|
||||
|
||||
template<typename numeral_manager>
|
||||
void neg(numeral_manager & m,
|
||||
typename numeral_manager::numeral & a,
|
||||
ext_numeral_kind & ak) {
|
||||
switch (ak) {
|
||||
case EN_MINUS_INFINITY:
|
||||
ak = EN_PLUS_INFINITY;
|
||||
break;
|
||||
case EN_NUMERAL:
|
||||
m.neg(a);
|
||||
break;
|
||||
case EN_PLUS_INFINITY:
|
||||
ak = EN_MINUS_INFINITY;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
template<typename numeral_manager>
|
||||
void inv(numeral_manager & m,
|
||||
typename numeral_manager::numeral & a,
|
||||
ext_numeral_kind & ak) {
|
||||
SASSERT(numeral_manager::field());
|
||||
switch (ak) {
|
||||
case EN_MINUS_INFINITY:
|
||||
ak = EN_NUMERAL;
|
||||
m.reset(a);
|
||||
break;
|
||||
case EN_NUMERAL:
|
||||
SASSERT(!m.is_zero(a));
|
||||
m.inv(a);
|
||||
break;
|
||||
case EN_PLUS_INFINITY:
|
||||
ak = EN_NUMERAL;
|
||||
m.reset(a);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
template<typename numeral_manager>
|
||||
void add(numeral_manager & m,
|
||||
typename numeral_manager::numeral const & a,
|
||||
ext_numeral_kind ak,
|
||||
typename numeral_manager::numeral const & b,
|
||||
ext_numeral_kind bk,
|
||||
typename numeral_manager::numeral & c,
|
||||
ext_numeral_kind & ck) {
|
||||
SASSERT(!(ak == EN_MINUS_INFINITY && bk == EN_PLUS_INFINITY)); // result is undefined
|
||||
SASSERT(!(ak == EN_PLUS_INFINITY && bk == EN_MINUS_INFINITY)); // result is undefined
|
||||
if (ak != EN_NUMERAL) {
|
||||
m.reset(c);
|
||||
ck = ak;
|
||||
}
|
||||
else if (bk != EN_NUMERAL) {
|
||||
m.reset(c);
|
||||
ck = bk;
|
||||
}
|
||||
else {
|
||||
m.add(a, b, c);
|
||||
ck = EN_NUMERAL;
|
||||
}
|
||||
}
|
||||
|
||||
template<typename numeral_manager>
|
||||
void sub(numeral_manager & m,
|
||||
typename numeral_manager::numeral const & a,
|
||||
ext_numeral_kind ak,
|
||||
typename numeral_manager::numeral const & b,
|
||||
ext_numeral_kind bk,
|
||||
typename numeral_manager::numeral & c,
|
||||
ext_numeral_kind & ck) {
|
||||
SASSERT(!(ak == EN_MINUS_INFINITY && bk == EN_MINUS_INFINITY)); // result is undefined
|
||||
SASSERT(!(ak == EN_PLUS_INFINITY && bk == EN_PLUS_INFINITY)); // result is undefined
|
||||
if (ak != EN_NUMERAL) {
|
||||
SASSERT(bk != ak);
|
||||
m.reset(c);
|
||||
ck = ak;
|
||||
}
|
||||
else {
|
||||
switch (bk) {
|
||||
case EN_MINUS_INFINITY:
|
||||
m.reset(c);
|
||||
ck = EN_PLUS_INFINITY;
|
||||
break;
|
||||
case EN_NUMERAL:
|
||||
m.sub(a, b, c);
|
||||
ck = EN_NUMERAL;
|
||||
break;
|
||||
case EN_PLUS_INFINITY:
|
||||
m.reset(c);
|
||||
ck = EN_MINUS_INFINITY;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
template<typename numeral_manager>
|
||||
void mul(numeral_manager & m,
|
||||
typename numeral_manager::numeral const & a,
|
||||
ext_numeral_kind ak,
|
||||
typename numeral_manager::numeral const & b,
|
||||
ext_numeral_kind bk,
|
||||
typename numeral_manager::numeral & c,
|
||||
ext_numeral_kind & ck) {
|
||||
if (is_zero(m, a, ak) || is_zero(m, b, bk)) {
|
||||
m.reset(c);
|
||||
ck = EN_NUMERAL;
|
||||
}
|
||||
else if (is_infinite(ak) || is_infinite(bk)) {
|
||||
if (is_pos(m, a, ak) == is_pos(m, b, bk))
|
||||
ck = EN_PLUS_INFINITY;
|
||||
else
|
||||
ck = EN_MINUS_INFINITY;
|
||||
m.reset(c);
|
||||
}
|
||||
else {
|
||||
ck = EN_NUMERAL;
|
||||
m.mul(a, b, c);
|
||||
}
|
||||
}
|
||||
|
||||
template<typename numeral_manager>
|
||||
void div(numeral_manager & m,
|
||||
typename numeral_manager::numeral const & a,
|
||||
ext_numeral_kind ak,
|
||||
typename numeral_manager::numeral const & b,
|
||||
ext_numeral_kind bk,
|
||||
typename numeral_manager::numeral & c,
|
||||
ext_numeral_kind & ck) {
|
||||
SASSERT(!is_zero(m, b, bk));
|
||||
if (is_zero(m, a, ak)) {
|
||||
SASSERT(!is_zero(m, b, bk));
|
||||
m.reset(c);
|
||||
ck = EN_NUMERAL;
|
||||
}
|
||||
else if (is_infinite(ak)) {
|
||||
SASSERT(!is_infinite(bk));
|
||||
if (is_pos(m, a, ak) == is_pos(m, b, bk))
|
||||
ck = EN_PLUS_INFINITY;
|
||||
else
|
||||
ck = EN_MINUS_INFINITY;
|
||||
m.reset(c);
|
||||
}
|
||||
else if (is_infinite(bk)) {
|
||||
SASSERT(!is_infinite(ak));
|
||||
m.reset(c);
|
||||
ck = EN_NUMERAL;
|
||||
}
|
||||
else {
|
||||
ck = EN_NUMERAL;
|
||||
m.div(a, b, c);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
template<typename numeral_manager>
|
||||
void power(numeral_manager & m,
|
||||
typename numeral_manager::numeral & a,
|
||||
ext_numeral_kind & ak,
|
||||
unsigned n) {
|
||||
switch (ak) {
|
||||
case EN_MINUS_INFINITY:
|
||||
if (n % 2 == 0)
|
||||
ak = EN_PLUS_INFINITY;
|
||||
break;
|
||||
case EN_NUMERAL:
|
||||
m.power(a, n, a);
|
||||
break;
|
||||
case EN_PLUS_INFINITY:
|
||||
break; // do nothing
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
\brief Return true if (a,ak) == (b,bk).
|
||||
*/
|
||||
template<typename numeral_manager>
|
||||
bool eq(numeral_manager & m,
|
||||
typename numeral_manager::numeral const & a,
|
||||
ext_numeral_kind ak,
|
||||
typename numeral_manager::numeral const & b,
|
||||
ext_numeral_kind bk) {
|
||||
if (ak == EN_NUMERAL) {
|
||||
return bk == EN_NUMERAL && m.eq(a, b);
|
||||
}
|
||||
else {
|
||||
return ak == bk;
|
||||
}
|
||||
}
|
||||
|
||||
template<typename numeral_manager>
|
||||
bool neq(numeral_manager & m,
|
||||
typename numeral_manager::numeral const & a,
|
||||
ext_numeral_kind ak,
|
||||
typename numeral_manager::numeral const & b,
|
||||
ext_numeral_kind bk) {
|
||||
return !eq(m, a, ak, b, bk);
|
||||
}
|
||||
|
||||
template<typename numeral_manager>
|
||||
bool lt(numeral_manager & m,
|
||||
typename numeral_manager::numeral const & a,
|
||||
ext_numeral_kind ak,
|
||||
typename numeral_manager::numeral const & b,
|
||||
ext_numeral_kind bk) {
|
||||
switch (ak) {
|
||||
case EN_MINUS_INFINITY:
|
||||
return bk != EN_MINUS_INFINITY;
|
||||
case EN_NUMERAL:
|
||||
switch (bk) {
|
||||
case EN_MINUS_INFINITY:
|
||||
return false;
|
||||
case EN_NUMERAL:
|
||||
return m.lt(a, b);
|
||||
case EN_PLUS_INFINITY:
|
||||
return true;
|
||||
default:
|
||||
UNREACHABLE();
|
||||
return false;
|
||||
}
|
||||
case EN_PLUS_INFINITY:
|
||||
return false;
|
||||
default:
|
||||
UNREACHABLE();
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
template<typename numeral_manager>
|
||||
bool gt(numeral_manager & m,
|
||||
typename numeral_manager::numeral const & a,
|
||||
ext_numeral_kind ak,
|
||||
typename numeral_manager::numeral const & b,
|
||||
ext_numeral_kind bk) {
|
||||
return lt(m, b, bk, a, ak);
|
||||
}
|
||||
|
||||
template<typename numeral_manager>
|
||||
bool le(numeral_manager & m,
|
||||
typename numeral_manager::numeral const & a,
|
||||
ext_numeral_kind ak,
|
||||
typename numeral_manager::numeral const & b,
|
||||
ext_numeral_kind bk) {
|
||||
return !gt(m, a, ak, b, bk);
|
||||
}
|
||||
|
||||
template<typename numeral_manager>
|
||||
bool ge(numeral_manager & m,
|
||||
typename numeral_manager::numeral const & a,
|
||||
ext_numeral_kind ak,
|
||||
typename numeral_manager::numeral const & b,
|
||||
ext_numeral_kind bk) {
|
||||
return !lt(m, a, ak, b, bk);
|
||||
}
|
||||
|
||||
template<typename numeral_manager>
|
||||
void display(std::ostream & out,
|
||||
numeral_manager & m,
|
||||
typename numeral_manager::numeral const & a,
|
||||
ext_numeral_kind ak) {
|
||||
switch (ak) {
|
||||
case EN_MINUS_INFINITY: out << "-oo"; break;
|
||||
case EN_NUMERAL: m.display(out, a); break;
|
||||
case EN_PLUS_INFINITY: out << "+oo"; break;
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
167
src/util/f2n.h
Normal file
167
src/util/f2n.h
Normal file
|
@ -0,0 +1,167 @@
|
|||
/*++
|
||||
Copyright (c) 2012 Microsoft Corporation
|
||||
|
||||
Module Name:
|
||||
|
||||
f2n.h
|
||||
|
||||
Abstract:
|
||||
|
||||
Template for wrapping a float-like API as a numeral-like API.
|
||||
The basic idea is to have the rounding mode as an implicit argument.
|
||||
|
||||
Author:
|
||||
|
||||
Leonardo de Moura (leonardo) 2012-07-30.
|
||||
|
||||
Revision History:
|
||||
|
||||
--*/
|
||||
#ifndef __F2N_H_
|
||||
#define __F2N_H_
|
||||
|
||||
#include"mpf.h"
|
||||
|
||||
template<typename fmanager>
|
||||
class f2n {
|
||||
public:
|
||||
typedef typename fmanager::numeral numeral;
|
||||
struct exception {};
|
||||
|
||||
private:
|
||||
fmanager & m_manager;
|
||||
mpf_rounding_mode m_mode;
|
||||
unsigned m_ebits;
|
||||
unsigned m_sbits;
|
||||
numeral m_tmp1;
|
||||
numeral m_one;
|
||||
|
||||
void check(numeral const & n) { if (!m().is_regular(n)) throw exception(); }
|
||||
|
||||
public:
|
||||
static bool field() { return true; }
|
||||
static bool precise() { return false; }
|
||||
|
||||
f2n(fmanager & m, unsigned ebits = 11, unsigned sbits = 53):m_manager(m), m_mode(MPF_ROUND_TOWARD_POSITIVE), m_ebits(ebits), m_sbits(sbits) {
|
||||
m_manager.set(m_one, ebits, sbits, 1);
|
||||
}
|
||||
|
||||
~f2n() {
|
||||
m().del(m_tmp1);
|
||||
m().del(m_one);
|
||||
}
|
||||
|
||||
void set_rounding_mode(mpf_rounding_mode m) { m_mode = m; }
|
||||
mpf_rounding_mode rounding_mode() const { return m_mode; }
|
||||
void round_to_plus_inf() { m_mode = MPF_ROUND_TOWARD_POSITIVE; }
|
||||
void round_to_minus_inf() { m_mode = MPF_ROUND_TOWARD_NEGATIVE; }
|
||||
void set_rounding(bool to_plus_inf) { if (to_plus_inf) round_to_plus_inf(); else round_to_minus_inf(); }
|
||||
unsigned ebits() const { return m_ebits; }
|
||||
unsigned sbits() const { return m_sbits; }
|
||||
|
||||
fmanager & m() const { return m_manager; }
|
||||
|
||||
double to_double(numeral & x) const { return m().to_double(x); }
|
||||
|
||||
void del(numeral & x) { m().del(x); }
|
||||
|
||||
void abs(numeral & o) { m().abs(o); }
|
||||
void abs(numeral const & x, numeral & o) { m().abs(x, o); }
|
||||
|
||||
void neg(numeral & o) { m().neg(o); }
|
||||
void neg(numeral const & x, numeral & o) { m().neg(x, o); }
|
||||
|
||||
bool is_zero(numeral const & x) { return m().is_zero(x); }
|
||||
bool is_neg(numeral const & x) { return m().is_neg(x) && !m().is_zero(x); /* it is not clear whether actual hardware returns true for is_neg(0-) */ }
|
||||
bool is_pos(numeral const & x) { return m().is_pos(x) && !m().is_zero(x); }
|
||||
bool is_nonneg(numeral const & x) { return !is_neg(x); }
|
||||
bool is_nonpos(numeral const & x) { return !is_pos(x); }
|
||||
|
||||
void set(numeral & o, int value) { m().set(o, m_ebits, m_sbits, value); check(o); }
|
||||
void set(numeral & o, int n, int d) { m().set(o, m_ebits, m_sbits, m_mode, n, d); check(o); }
|
||||
void set(numeral & o, double x) { m().set(o, m_ebits, m_sbits, x); check(o); }
|
||||
void set(numeral & o, unsigned value) { m().set(o, m_ebits, m_sbits, (double)value); check(o); }
|
||||
void set(numeral & o, numeral const & x) { m().set(o, x); check(o); }
|
||||
void set(numeral & o, mpq const & x) { m().set(o, m_ebits, m_sbits, m_mode, x); check(o); }
|
||||
void reset(numeral & o) { m().reset(o, m_ebits, m_sbits); }
|
||||
static void swap(numeral & x, numeral & y) { x.swap(y); }
|
||||
|
||||
void add(numeral const & x, numeral const & y, numeral & o) { m().add(m_mode, x, y, o); check(o); }
|
||||
void sub(numeral const & x, numeral const & y, numeral & o) { m().sub(m_mode, x, y, o); check(o); }
|
||||
void mul(numeral const & x, numeral const & y, numeral & o) { m().mul(m_mode, x, y, o); check(o); }
|
||||
void div(numeral const & x, numeral const & y, numeral & o) { m().div(m_mode, x, y, o); check(o); }
|
||||
void inv(numeral & o) { numeral a; set(a, 1); div(a, o, o); del(a); check(o); }
|
||||
void inv(numeral const & x, numeral & o) { set(o, x); inv(o); }
|
||||
void inc(numeral & x) { add(x, m_one, x); }
|
||||
void dec(numeral & x) { sub(x, m_one, x); }
|
||||
|
||||
void power(numeral const & a, unsigned p, numeral & b) {
|
||||
unsigned mask = 1;
|
||||
numeral power;
|
||||
set(power, a);
|
||||
set(b, 1);
|
||||
while (mask <= p) {
|
||||
if (mask & p)
|
||||
mul(b, power, b);
|
||||
mul(power, power, power);
|
||||
mask = mask << 1;
|
||||
}
|
||||
del(power);
|
||||
check(b);
|
||||
}
|
||||
|
||||
// Store the floor of a into b. Return true if a is an integer.
|
||||
// Throws an exception if the result cannot be computed precisely.
|
||||
void floor(numeral const & a, numeral & b) {
|
||||
SASSERT(m().is_regular(a));
|
||||
// Claim: If a is a regular float, then floor(a) is an integer that can be precisely represented.
|
||||
// Justification: (for the case a is nonnegative)
|
||||
// If 0 <= a > 2^sbits(), then a is an integer, and floor(a) == a
|
||||
// If 0 <= a <= 2^sbits(), then floor(a) is representable since every integer less than 2^sbit
|
||||
m().round_to_integral(MPF_ROUND_TOWARD_NEGATIVE, a, m_tmp1);
|
||||
SASSERT(m().is_regular(m_tmp1));
|
||||
if (m().le(m_tmp1, a)) {
|
||||
m().set(b, m_tmp1);
|
||||
}
|
||||
else {
|
||||
// the rounding mode doesn't matter for the following operation.
|
||||
m().sub(MPF_ROUND_TOWARD_NEGATIVE, m_tmp1, m_one, b);
|
||||
}
|
||||
SASSERT(m().is_regular(b));
|
||||
}
|
||||
|
||||
void ceil(numeral const & a, numeral & b) {
|
||||
SASSERT(m().is_regular(a));
|
||||
// See comment in floor
|
||||
m().round_to_integral(MPF_ROUND_TOWARD_POSITIVE, a, m_tmp1);
|
||||
SASSERT(m().is_regular(m_tmp1));
|
||||
if (m().ge(m_tmp1, a)) {
|
||||
m().set(b, m_tmp1);
|
||||
}
|
||||
else {
|
||||
// the rounding mode doesn't matter for the following operation.
|
||||
m().add(MPF_ROUND_TOWARD_NEGATIVE, m_tmp1, m_one, b);
|
||||
}
|
||||
SASSERT(m().is_regular(b));
|
||||
}
|
||||
|
||||
unsigned prev_power_of_two(numeral const & a) { return m().prev_power_of_two(a); }
|
||||
|
||||
bool eq(numeral const & x, numeral const & y) { return m().eq(x, y); }
|
||||
bool lt(numeral const & x, numeral const & y) { return m().lt(x, y); }
|
||||
bool le(numeral const & x, numeral const & y) { return m().le(x, y); }
|
||||
bool gt(numeral const & x, numeral const & y) { return m().gt(x, y); }
|
||||
bool ge(numeral const & x, numeral const & y) { return m().ge(x, y); }
|
||||
|
||||
bool is_int(numeral const & x) { return m().is_int(x); }
|
||||
bool is_one(numeral const & x) { return m().is_one(x); }
|
||||
bool is_minus_one(numeral const & x) { numeral & _x = const_cast<numeral &>(x); m().neg(_x); bool r = m().is_one(_x); m().neg(_x); return r; }
|
||||
|
||||
std::string to_string(numeral const & a) { return m().to_string(a); }
|
||||
std::string to_rational_string(numeral const & a) { return m().to_rational_string(a); }
|
||||
void display(std::ostream & out, numeral const & a) { out << to_string(a); }
|
||||
void display_decimal(std::ostream & out, numeral const & a, unsigned k) { m().display_decimal(out, a, k); }
|
||||
void display_smt2(std::ostream & out, numeral const & a, bool decimal) { m().display_smt2(out, a, decimal); }
|
||||
};
|
||||
|
||||
#endif
|
214
src/util/fvi.h
Normal file
214
src/util/fvi.h
Normal file
|
@ -0,0 +1,214 @@
|
|||
/*++
|
||||
Copyright (c) 2006 Microsoft Corporation
|
||||
|
||||
Module Name:
|
||||
|
||||
fvi.h
|
||||
|
||||
Abstract:
|
||||
|
||||
Feature Vector Indexing.
|
||||
|
||||
Author:
|
||||
|
||||
Leonardo de Moura (leonardo) 2008-02-01.
|
||||
|
||||
Revision History:
|
||||
|
||||
--*/
|
||||
#ifndef _FVI_H_
|
||||
#define _FVI_H_
|
||||
|
||||
#include"splay_tree_map.h"
|
||||
#include"hashtable.h"
|
||||
#include"vector.h"
|
||||
|
||||
/**
|
||||
\brief A feature vector indexing for objects of type T *.
|
||||
|
||||
ToVector is a functor for converting T into a vector of natural numbers.
|
||||
It should provide a method:
|
||||
- void operator(T * d, unsigned * f);
|
||||
This method should fill the vector f with the features of d.
|
||||
|
||||
Hash: functor for computing the hashcode of T *.
|
||||
|
||||
Eq : functor for comparing T pointers.
|
||||
*/
|
||||
template<typename T, typename ToVector, typename Hash, typename Eq=ptr_eq<T> >
|
||||
class fvi : private ToVector {
|
||||
public:
|
||||
struct statistics {
|
||||
unsigned m_size;
|
||||
unsigned m_num_nodes;
|
||||
unsigned m_num_leaves;
|
||||
unsigned m_min_leaf_size;
|
||||
unsigned m_avg_leaf_size;
|
||||
unsigned m_max_leaf_size;
|
||||
statistics() { reset(); }
|
||||
|
||||
void reset() {
|
||||
m_size = m_num_nodes = m_num_leaves = m_avg_leaf_size = m_max_leaf_size = 0;
|
||||
m_min_leaf_size = UINT_MAX;
|
||||
}
|
||||
};
|
||||
|
||||
private:
|
||||
struct ucompare {
|
||||
int operator()(unsigned i1, unsigned i2) const {
|
||||
if (i1 < i2) return -1;
|
||||
if (i1 > i2) return 1;
|
||||
return 0;
|
||||
}
|
||||
};
|
||||
|
||||
struct node {
|
||||
node() {}
|
||||
virtual ~node() {}
|
||||
virtual bool is_leaf() const = 0;
|
||||
};
|
||||
|
||||
typedef splay_tree_map<unsigned, node *, ucompare> children;
|
||||
|
||||
struct non_leaf : public node {
|
||||
children m_children;
|
||||
non_leaf() {}
|
||||
|
||||
struct delete_children {
|
||||
void operator()(unsigned k, node * n) const {
|
||||
dealloc(n);
|
||||
}
|
||||
};
|
||||
|
||||
virtual ~non_leaf() {
|
||||
delete_children visitor;
|
||||
m_children.visit(visitor);
|
||||
m_children.reset();
|
||||
}
|
||||
|
||||
virtual bool is_leaf() const { return false; }
|
||||
};
|
||||
|
||||
typedef ptr_hashtable<T, Hash, Eq> set;
|
||||
|
||||
struct leaf : public node {
|
||||
set m_set;
|
||||
leaf() {}
|
||||
virtual ~leaf() {}
|
||||
virtual bool is_leaf() const { return true; }
|
||||
};
|
||||
|
||||
unsigned m_num_features;
|
||||
svector<unsigned> m_tmp_buffer;
|
||||
non_leaf * m_root;
|
||||
|
||||
struct stop {};
|
||||
|
||||
template<typename Visitor>
|
||||
void visit_leaf(leaf * n, Visitor & v, bool le) const {
|
||||
typename set::iterator it = n->m_set.begin();
|
||||
typename set::iterator end = n->m_set.end();
|
||||
for (; it != end; ++it)
|
||||
if (!v(*it))
|
||||
throw stop();
|
||||
}
|
||||
|
||||
template<typename Visitor>
|
||||
struct non_leaf_visitor {
|
||||
fvi const & m_owner;
|
||||
unsigned m_fidx;
|
||||
Visitor & m_visitor;
|
||||
bool m_le;
|
||||
|
||||
non_leaf_visitor(fvi const & o, unsigned fidx, Visitor & v, bool le):
|
||||
m_owner(o), m_fidx(fidx), m_visitor(v), m_le(le) {}
|
||||
|
||||
void operator()(unsigned k, node * n) {
|
||||
if (n->is_leaf())
|
||||
m_owner.visit_leaf(static_cast<leaf*>(n), m_visitor, m_le);
|
||||
else
|
||||
m_owner.visit_non_leaf(static_cast<non_leaf*>(n), m_fidx + 1, m_visitor, m_le);
|
||||
}
|
||||
};
|
||||
|
||||
template<typename Visitor>
|
||||
void visit_non_leaf(non_leaf * n, unsigned fidx, Visitor & v, bool le) const {
|
||||
// Remark: this function is recursive, but there is no risk
|
||||
// of stack overflow since the number of features is small.
|
||||
non_leaf_visitor<Visitor> v2(*this, fidx, v, le);
|
||||
if (le)
|
||||
n->m_children.visit_le(v2, m_tmp_buffer[fidx]);
|
||||
else
|
||||
n->m_children.visit_ge(v2, m_tmp_buffer[fidx]);
|
||||
}
|
||||
|
||||
#ifdef Z3DEBUG
|
||||
bool m_visiting;
|
||||
#endif
|
||||
|
||||
void to_fvector(T * d) const {
|
||||
fvi * _this = const_cast<fvi *>(this);
|
||||
_this->ToVector::operator()(d, _this->m_tmp_buffer.c_ptr());
|
||||
}
|
||||
|
||||
struct non_leaf_stat_visitor {
|
||||
fvi const & m_owner;
|
||||
statistics & m_stats;
|
||||
non_leaf_stat_visitor(fvi const & o, statistics & st):m_owner(o), m_stats(st) {}
|
||||
void operator()(unsigned k, node * n);
|
||||
};
|
||||
|
||||
void stats(leaf * n, statistics & result) const;
|
||||
void stats(non_leaf * n, statistics & result) const;
|
||||
|
||||
struct non_leaf_collect_visitor {
|
||||
fvi const & m_owner;
|
||||
ptr_vector<T> & m_elems;
|
||||
non_leaf_collect_visitor(fvi const & o, ptr_vector<T> & elems):m_owner(o), m_elems(elems) {}
|
||||
void operator()(unsigned k, node * n);
|
||||
};
|
||||
|
||||
void collect(leaf * n, ptr_vector<T> & result) const;
|
||||
void collect(non_leaf * n, ptr_vector<T> & result) const;
|
||||
|
||||
public:
|
||||
fvi(unsigned num_features, ToVector const & t = ToVector());
|
||||
~fvi() { reset(); dealloc(m_root); }
|
||||
|
||||
void insert(T * d);
|
||||
bool contains(T * d) const;
|
||||
void erase(T * d);
|
||||
void reset();
|
||||
|
||||
/**
|
||||
\brief Traverse the elements that have features smaller (greater) or equal than the one of the given element.
|
||||
|
||||
For each visited element the following method of v is executed:
|
||||
|
||||
- bool operator()(T * d)
|
||||
|
||||
If false is returned, the traversal is aborted.
|
||||
|
||||
\warning The object cannot be updated during the traversal.
|
||||
*/
|
||||
template<typename Visitor>
|
||||
void visit(T * d, Visitor & v, bool le = true) const {
|
||||
DEBUG_CODE(const_cast<fvi*>(this)->m_visiting = true;);
|
||||
to_fvector(d);
|
||||
try {
|
||||
visit_non_leaf(m_root, 0, v, le);
|
||||
}
|
||||
catch (stop) {
|
||||
}
|
||||
DEBUG_CODE(const_cast<fvi*>(this)->m_visiting = false;);
|
||||
}
|
||||
|
||||
void stats(statistics & result) const;
|
||||
|
||||
/**
|
||||
\brief Copy to result the set of elements stored in the index.
|
||||
*/
|
||||
void collect(ptr_vector<T> & result) const;
|
||||
};
|
||||
|
||||
#endif /* _FVI_H_ */
|
199
src/util/fvi_def.h
Normal file
199
src/util/fvi_def.h
Normal file
|
@ -0,0 +1,199 @@
|
|||
/*++
|
||||
Copyright (c) 2006 Microsoft Corporation
|
||||
|
||||
Module Name:
|
||||
|
||||
fvi_def.h
|
||||
|
||||
Abstract:
|
||||
|
||||
Feature Vector Indexing.
|
||||
|
||||
Author:
|
||||
|
||||
Leonardo de Moura (leonardo) 2008-02-01.
|
||||
|
||||
Revision History:
|
||||
|
||||
--*/
|
||||
#ifndef _FVI_DEF_H_
|
||||
#define _FVI_DEF_H_
|
||||
|
||||
#include"fvi.h"
|
||||
#include"splay_tree_def.h"
|
||||
#include"buffer.h"
|
||||
|
||||
template<typename T, typename ToVector, typename Hash, typename Eq>
|
||||
fvi<T, ToVector, Hash, Eq>::fvi(unsigned num_features, ToVector const & t):
|
||||
ToVector(t),
|
||||
m_num_features(num_features),
|
||||
m_root(0) {
|
||||
m_tmp_buffer.resize(num_features, 0);
|
||||
m_root = alloc(non_leaf);
|
||||
SASSERT(num_features >= 2);
|
||||
DEBUG_CODE(m_visiting = false;);
|
||||
}
|
||||
|
||||
template<typename T, typename ToVector, typename Hash, typename Eq>
|
||||
void fvi<T, ToVector, Hash, Eq>::reset() {
|
||||
SASSERT(!m_visiting);
|
||||
dealloc(m_root);
|
||||
m_root = alloc(non_leaf);
|
||||
}
|
||||
|
||||
template<typename T, typename ToVector, typename Hash, typename Eq>
|
||||
void fvi<T, ToVector, Hash, Eq>::insert(T * d) {
|
||||
SASSERT(!m_visiting);
|
||||
to_fvector(d);
|
||||
non_leaf * n = m_root;
|
||||
unsigned i = 0;
|
||||
for (; i < m_num_features - 1; i++) {
|
||||
node * child = 0;
|
||||
if (!n->m_children.find(m_tmp_buffer[i], child)) {
|
||||
child = alloc(non_leaf);
|
||||
n->m_children.insert(m_tmp_buffer[i], child);
|
||||
}
|
||||
SASSERT(child);
|
||||
SASSERT(!child->is_leaf());
|
||||
n = static_cast<non_leaf*>(child);
|
||||
}
|
||||
node * l = 0;
|
||||
SASSERT(i == m_num_features - 1);
|
||||
if (!n->m_children.find(m_tmp_buffer[i], l)) {
|
||||
l = alloc(leaf);
|
||||
n->m_children.insert(m_tmp_buffer[i], l);
|
||||
}
|
||||
SASSERT(l);
|
||||
SASSERT(l->is_leaf());
|
||||
static_cast<leaf*>(l)->m_set.insert(d);
|
||||
}
|
||||
|
||||
template<typename T, typename ToVector, typename Hash, typename Eq>
|
||||
bool fvi<T, ToVector, Hash, Eq>::contains(T * d) const {
|
||||
to_fvector(d);
|
||||
non_leaf * n = m_root;
|
||||
node * child;
|
||||
unsigned i = 0;
|
||||
for (; i < m_num_features - 1; i++) {
|
||||
if (!n->m_children.find(m_tmp_buffer[i], child))
|
||||
return false;
|
||||
SASSERT(child);
|
||||
SASSERT(!child->is_leaf());
|
||||
n = static_cast<non_leaf*>(child);
|
||||
}
|
||||
SASSERT(i == m_num_features - 1);
|
||||
return
|
||||
n->m_children.find(m_tmp_buffer[i], child) &&
|
||||
static_cast<leaf*>(child)->m_set.contains(d);
|
||||
}
|
||||
|
||||
template<typename T, typename ToVector, typename Hash, typename Eq>
|
||||
void fvi<T, ToVector, Hash, Eq>::erase(T * d) {
|
||||
SASSERT(!m_visiting);
|
||||
SASSERT(contains(d));
|
||||
ptr_buffer<non_leaf> path;
|
||||
to_fvector(d);
|
||||
non_leaf * n = m_root;
|
||||
node * child;
|
||||
unsigned i = 0;
|
||||
for (; i < m_num_features - 1; i++) {
|
||||
path.push_back(n);
|
||||
if (!n->m_children.find(m_tmp_buffer[i], child)) {
|
||||
UNREACHABLE();
|
||||
}
|
||||
SASSERT(child);
|
||||
SASSERT(!child->is_leaf());
|
||||
n = static_cast<non_leaf*>(child);
|
||||
}
|
||||
path.push_back(n);
|
||||
SASSERT(i == m_num_features - 1);
|
||||
if (!n->m_children.find(m_tmp_buffer[i], child)) {
|
||||
UNREACHABLE();
|
||||
}
|
||||
SASSERT(child);
|
||||
SASSERT(child->is_leaf());
|
||||
leaf * l = static_cast<leaf*>(child);
|
||||
l->m_set.erase(d);
|
||||
if (l->m_set.empty()) {
|
||||
dealloc(l);
|
||||
while (true) {
|
||||
non_leaf * n = path.back();
|
||||
n->m_children.erase(m_tmp_buffer[i]);
|
||||
path.pop_back();
|
||||
i--;
|
||||
if (!n->m_children.empty() || n == m_root)
|
||||
break;
|
||||
dealloc(n);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
template<typename T, typename ToVector, typename Hash, typename Eq>
|
||||
void fvi<T, ToVector, Hash, Eq>::non_leaf_stat_visitor::operator()(unsigned k, node * n) {
|
||||
if (n->is_leaf())
|
||||
m_owner.stats(static_cast<leaf*>(n), m_stats);
|
||||
else
|
||||
m_owner.stats(static_cast<non_leaf*>(n), m_stats);
|
||||
}
|
||||
|
||||
template<typename T, typename ToVector, typename Hash, typename Eq>
|
||||
void fvi<T, ToVector, Hash, Eq>::stats(leaf * n, statistics & result) const {
|
||||
unsigned sz = n->m_set.size();
|
||||
result.m_size += sz;
|
||||
if (sz > result.m_max_leaf_size)
|
||||
result.m_max_leaf_size = sz;
|
||||
if (sz < result.m_min_leaf_size)
|
||||
result.m_min_leaf_size = sz;
|
||||
result.m_num_leaves ++;
|
||||
result.m_num_nodes ++;
|
||||
}
|
||||
|
||||
template<typename T, typename ToVector, typename Hash, typename Eq>
|
||||
void fvi<T, ToVector, Hash, Eq>::stats(non_leaf * n, statistics & result) const {
|
||||
result.m_num_nodes++;
|
||||
// Remark: this function is recursive, but there is no risk
|
||||
// of stack overflow since the number of features is small.
|
||||
non_leaf_stat_visitor v(*this, result);
|
||||
n->m_children.visit(v);
|
||||
}
|
||||
|
||||
template<typename T, typename ToVector, typename Hash, typename Eq>
|
||||
void fvi<T, ToVector, Hash, Eq>::stats(statistics & result) const {
|
||||
result.reset();
|
||||
stats(m_root, result);
|
||||
if (m_root->m_children.empty())
|
||||
result.m_min_leaf_size = 0;
|
||||
if (result.m_num_leaves > 0)
|
||||
result.m_avg_leaf_size = result.m_size / result.m_num_leaves;
|
||||
}
|
||||
|
||||
template<typename T, typename ToVector, typename Hash, typename Eq>
|
||||
void fvi<T, ToVector, Hash, Eq>::non_leaf_collect_visitor::operator()(unsigned k, node * n) {
|
||||
if (n->is_leaf())
|
||||
m_owner.collect(static_cast<leaf*>(n), m_elems);
|
||||
else
|
||||
m_owner.collect(static_cast<non_leaf*>(n), m_elems);
|
||||
}
|
||||
|
||||
template<typename T, typename ToVector, typename Hash, typename Eq>
|
||||
void fvi<T, ToVector, Hash, Eq>::collect(leaf * n, ptr_vector<T> & result) const {
|
||||
typename set::iterator it = n->m_set.begin();
|
||||
typename set::iterator end = n->m_set.end();
|
||||
for (; it != end; ++it)
|
||||
result.push_back(*it);
|
||||
}
|
||||
|
||||
template<typename T, typename ToVector, typename Hash, typename Eq>
|
||||
void fvi<T, ToVector, Hash, Eq>::collect(non_leaf * n, ptr_vector<T> & result) const {
|
||||
// Remark: this function is recursive, but there is no risk
|
||||
// of stack overflow since the number of features is small.
|
||||
non_leaf_collect_visitor v(*this, result);
|
||||
n->m_children.visit(v);
|
||||
}
|
||||
|
||||
template<typename T, typename ToVector, typename Hash, typename Eq>
|
||||
void fvi<T, ToVector, Hash, Eq>::collect(ptr_vector<T> & result) const {
|
||||
collect(m_root, result);
|
||||
}
|
||||
|
||||
#endif /* _FVI_DEF_H_ */
|
85
src/util/hash.cpp
Normal file
85
src/util/hash.cpp
Normal file
|
@ -0,0 +1,85 @@
|
|||
/*++
|
||||
Copyright (c) 2006 Microsoft Corporation
|
||||
|
||||
Module Name:
|
||||
|
||||
hash.cpp
|
||||
|
||||
Abstract:
|
||||
|
||||
Basic hash computation support.
|
||||
|
||||
Author:
|
||||
|
||||
Leonardo de Moura (leonardo) 2006-09-11.
|
||||
|
||||
Revision History:
|
||||
|
||||
--*/
|
||||
|
||||
#include"debug.h"
|
||||
#include"hash.h"
|
||||
|
||||
// I'm using Bob Jenkin's hash function.
|
||||
// http://burtleburtle.net/bob/hash/doobs.html
|
||||
unsigned string_hash(const char * str, unsigned length, unsigned init_value) {
|
||||
register unsigned a, b, c, len;
|
||||
|
||||
/* Set up the internal state */
|
||||
len = length;
|
||||
a = b = 0x9e3779b9; /* the golden ratio; an arbitrary value */
|
||||
c = init_value; /* the previous hash value */
|
||||
|
||||
/*---------------------------------------- handle most of the key */
|
||||
while (len >= 12) {
|
||||
a += reinterpret_cast<const unsigned *>(str)[0];
|
||||
b += reinterpret_cast<const unsigned *>(str)[1];
|
||||
c += reinterpret_cast<const unsigned *>(str)[2];
|
||||
mix(a,b,c);
|
||||
str += 12; len -= 12;
|
||||
}
|
||||
|
||||
/*------------------------------------- handle the last 11 bytes */
|
||||
c += length;
|
||||
switch(len) { /* all the case statements fall through */
|
||||
case 11:
|
||||
c+=((unsigned)str[10]<<24);
|
||||
__fallthrough;
|
||||
case 10:
|
||||
c+=((unsigned)str[9]<<16);
|
||||
__fallthrough;
|
||||
case 9 :
|
||||
c+=((unsigned)str[8]<<8);
|
||||
__fallthrough;
|
||||
/* the first byte of c is reserved for the length */
|
||||
case 8 :
|
||||
b+=((unsigned)str[7]<<24);
|
||||
__fallthrough;
|
||||
case 7 :
|
||||
b+=((unsigned)str[6]<<16);
|
||||
__fallthrough;
|
||||
case 6 :
|
||||
b+=((unsigned)str[5]<<8);
|
||||
__fallthrough;
|
||||
case 5 :
|
||||
b+=str[4];
|
||||
__fallthrough;
|
||||
case 4 :
|
||||
a+=((unsigned)str[3]<<24);
|
||||
__fallthrough;
|
||||
case 3 :
|
||||
a+=((unsigned)str[2]<<16);
|
||||
__fallthrough;
|
||||
case 2 :
|
||||
a+=((unsigned)str[1]<<8);
|
||||
__fallthrough;
|
||||
case 1 :
|
||||
a+=str[0];
|
||||
__fallthrough;
|
||||
/* case 0: nothing left to add */
|
||||
}
|
||||
mix(a,b,c);
|
||||
/*-------------------------------------------- report the result */
|
||||
return c;
|
||||
}
|
||||
|
247
src/util/hash.h
Normal file
247
src/util/hash.h
Normal file
|
@ -0,0 +1,247 @@
|
|||
/*++
|
||||
Copyright (c) 2006 Microsoft Corporation
|
||||
|
||||
Module Name:
|
||||
|
||||
hash.h
|
||||
|
||||
Abstract:
|
||||
|
||||
Basic hash computation support.
|
||||
|
||||
Author:
|
||||
|
||||
Leonardo de Moura (leonardo) 2006-09-11.
|
||||
|
||||
Revision History:
|
||||
|
||||
--*/
|
||||
#ifndef _HASH_H_
|
||||
#define _HASH_H_
|
||||
|
||||
#include<algorithm>
|
||||
|
||||
#ifndef __fallthrough
|
||||
#define __fallthrough
|
||||
#endif
|
||||
|
||||
#define mix(a,b,c) \
|
||||
{ \
|
||||
a -= b; a -= c; a ^= (c>>13); \
|
||||
b -= c; b -= a; b ^= (a<<8); \
|
||||
c -= a; c -= b; c ^= (b>>13); \
|
||||
a -= b; a -= c; a ^= (c>>12); \
|
||||
b -= c; b -= a; b ^= (a<<16); \
|
||||
c -= a; c -= b; c ^= (b>>5); \
|
||||
a -= b; a -= c; a ^= (c>>3); \
|
||||
b -= c; b -= a; b ^= (a<<10); \
|
||||
c -= a; c -= b; c ^= (b>>15); \
|
||||
}
|
||||
|
||||
inline unsigned hash_u(unsigned a) {
|
||||
a = (a+0x7ed55d16) + (a<<12);
|
||||
a = (a^0xc761c23c) ^ (a>>19);
|
||||
a = (a+0x165667b1) + (a<<5);
|
||||
a = (a+0xd3a2646c) ^ (a<<9);
|
||||
a = (a+0xfd7046c5) + (a<<3);
|
||||
a = (a^0xb55a4f09) ^ (a>>16);
|
||||
return a;
|
||||
}
|
||||
|
||||
inline unsigned hash_ull(unsigned long long a) {
|
||||
a = (~a) + (a << 18);
|
||||
a ^= (a >> 31);
|
||||
a += (a << 2) + (a << 4);
|
||||
a ^= (a >> 11);
|
||||
a += (a << 6);
|
||||
a ^= (a >> 22);
|
||||
return static_cast<unsigned>(a);
|
||||
}
|
||||
|
||||
inline unsigned combine_hash(unsigned h1, unsigned h2) {
|
||||
h2 -= h1; h2 ^= (h1 << 8);
|
||||
h1 -= h2; h2 ^= (h1 << 16);
|
||||
h2 -= h1; h2 ^= (h1 << 10);
|
||||
return h2;
|
||||
}
|
||||
|
||||
inline unsigned hash_u_u(unsigned a, unsigned b) {
|
||||
return combine_hash(hash_u(a), hash_u(b));
|
||||
}
|
||||
|
||||
unsigned string_hash(const char * str, unsigned len, unsigned init_value);
|
||||
|
||||
template<typename Composite, typename GetKindHashProc, typename GetChildHashProc>
|
||||
unsigned get_composite_hash(Composite app, unsigned n, GetKindHashProc const & khasher = GetKindHashProc(), GetChildHashProc const & chasher = GetChildHashProc()) {
|
||||
unsigned a, b, c;
|
||||
SASSERT(n > 0);
|
||||
unsigned kind_hash = khasher(app);
|
||||
|
||||
a = b = 0x9e3779b9;
|
||||
c = 11;
|
||||
|
||||
switch (n) {
|
||||
case 1:
|
||||
a += kind_hash;
|
||||
b = chasher(app, 0);
|
||||
mix(a, b, c);
|
||||
return c;
|
||||
case 2:
|
||||
a += kind_hash;
|
||||
b += chasher(app, 0);
|
||||
c += chasher(app, 1);
|
||||
mix(a, b, c);
|
||||
return c;
|
||||
case 3:
|
||||
a += chasher(app, 0);
|
||||
b += chasher(app, 1);
|
||||
c += chasher(app, 2);
|
||||
mix(a, b, c);
|
||||
a += kind_hash;
|
||||
mix(a, b, c);
|
||||
return c;
|
||||
default:
|
||||
while (n >= 3) {
|
||||
n--;
|
||||
a += chasher(app, n);
|
||||
n--;
|
||||
b += chasher(app, n);
|
||||
n--;
|
||||
c += chasher(app, n);
|
||||
mix(a, b, c);
|
||||
}
|
||||
|
||||
a += kind_hash;
|
||||
switch (n) {
|
||||
case 2:
|
||||
b += chasher(app, 1);
|
||||
__fallthrough;
|
||||
case 1:
|
||||
c += chasher(app, 0);
|
||||
}
|
||||
mix(a, b, c);
|
||||
return c;
|
||||
}
|
||||
}
|
||||
|
||||
template<typename Composite>
|
||||
struct default_kind_hash_proc { unsigned operator()(Composite const & c) const { return 17; } };
|
||||
|
||||
struct int_hash {
|
||||
typedef int data;
|
||||
unsigned operator()(int x) const { return static_cast<unsigned>(x); }
|
||||
};
|
||||
|
||||
struct unsigned_hash {
|
||||
typedef unsigned data;
|
||||
unsigned operator()(unsigned x) const { return x; }
|
||||
};
|
||||
|
||||
struct size_t_hash {
|
||||
typedef size_t data;
|
||||
unsigned operator()(size_t x) const { return static_cast<unsigned>(x); }
|
||||
};
|
||||
|
||||
struct bool_hash {
|
||||
typedef bool data;
|
||||
unsigned operator()(bool x) const { return static_cast<unsigned>(x); }
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
struct obj_hash {
|
||||
typedef T data;
|
||||
unsigned operator()(const T & e) const {
|
||||
return e.hash();
|
||||
}
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
struct obj_ptr_hash {
|
||||
typedef T * data;
|
||||
unsigned operator()(T * a) const {
|
||||
return a->hash();
|
||||
}
|
||||
};
|
||||
|
||||
template<typename T1, typename T2>
|
||||
struct obj_ptr_pair_hash {
|
||||
typedef std::pair<T1*, T2*> data;
|
||||
unsigned operator()(data const & d) const {
|
||||
return combine_hash(d.first->hash(), d.second->hash());
|
||||
}
|
||||
};
|
||||
|
||||
template<typename T1, typename T2, typename T3>
|
||||
struct triple {
|
||||
T1 first;
|
||||
T2 second;
|
||||
T3 third;
|
||||
triple(): first(T1()), second(T2()), third(T3()) {}
|
||||
triple(T1 f, T2 s, T3 t): first(f), second(s), third(t) {}
|
||||
|
||||
bool operator==(triple const& other) const {
|
||||
return
|
||||
first == other.first &&
|
||||
second == other.second &&
|
||||
third == other.third;
|
||||
}
|
||||
};
|
||||
|
||||
template<typename Hash1, typename Hash2, typename Hash3>
|
||||
struct triple_hash : private Hash1 {
|
||||
Hash2 m_hash2;
|
||||
Hash3 m_hash3;
|
||||
typedef triple<typename Hash1::data, typename Hash2::data, typename Hash3::data> data;
|
||||
triple_hash(Hash1 const & h1 = Hash1(), Hash2 const & h2 = Hash2(), Hash3 const & h3 = Hash3()):
|
||||
Hash1(h1),
|
||||
m_hash2(h2),
|
||||
m_hash3(h3) {
|
||||
}
|
||||
|
||||
unsigned operator()(std::pair<typename Hash1::data, typename Hash2::data> const & p) const {
|
||||
return combine_hash(combine_hash(Hash1::operator()(p.first), m_hash2.operator()(p.second)), m_hash3.operator()(p.third));
|
||||
}
|
||||
};
|
||||
|
||||
template<typename T1, typename T2, typename T3>
|
||||
struct obj_ptr_triple_hash {
|
||||
typedef triple<T1*, T2*, T3*> data;
|
||||
unsigned operator()(data const & d) const {
|
||||
return combine_hash(combine_hash(d.first->hash(), d.second->hash()), d.third->hash());
|
||||
}
|
||||
};
|
||||
|
||||
template<typename Hash1, typename Hash2>
|
||||
struct pair_hash : private Hash1 {
|
||||
Hash2 m_hash2;
|
||||
typedef std::pair<typename Hash1::data, typename Hash2::data> data;
|
||||
pair_hash(Hash1 const & h1 = Hash1(), Hash2 const & h2 = Hash2()):
|
||||
Hash1(h1),
|
||||
m_hash2(h2) {
|
||||
}
|
||||
|
||||
unsigned operator()(std::pair<typename Hash1::data, typename Hash2::data> const & p) const {
|
||||
return combine_hash(Hash1::operator()(p.first), m_hash2.operator()(p.second));
|
||||
}
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
inline unsigned get_ptr_hash(T * ptr) {
|
||||
return static_cast<unsigned>(reinterpret_cast<size_t>(ptr));
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
struct ptr_hash {
|
||||
typedef T * data;
|
||||
unsigned operator()(T * ptr) const {
|
||||
return get_ptr_hash(ptr);
|
||||
}
|
||||
};
|
||||
|
||||
inline unsigned mk_mix(unsigned a, unsigned b, unsigned c) {
|
||||
mix(a, b, c);
|
||||
return c;
|
||||
}
|
||||
|
||||
#endif /* _HASH_H_ */
|
||||
|
643
src/util/hashtable.h
Normal file
643
src/util/hashtable.h
Normal file
|
@ -0,0 +1,643 @@
|
|||
/*++
|
||||
Copyright (c) 2006 Microsoft Corporation
|
||||
|
||||
Module Name:
|
||||
|
||||
hashtable.h
|
||||
|
||||
Abstract:
|
||||
|
||||
Hashtable without buckets.
|
||||
|
||||
Author:
|
||||
|
||||
Leonardo de Moura (leonardo) 2006-09-11.
|
||||
|
||||
Revision History:
|
||||
|
||||
--*/
|
||||
#ifndef _HASHTABLE_H_
|
||||
#define _HASHTABLE_H_
|
||||
#include"debug.h"
|
||||
#include<ostream>
|
||||
#include"util.h"
|
||||
#include"limits.h"
|
||||
#include"memory_manager.h"
|
||||
#include"hash.h"
|
||||
|
||||
#define DEFAULT_HASHTABLE_INITIAL_CAPACITY 8
|
||||
#define SMALL_TABLE_CAPACITY 64
|
||||
|
||||
// #define HASHTABLE_STATISTICS
|
||||
|
||||
#ifdef HASHTABLE_STATISTICS
|
||||
#define HS_CODE(CODE) { CODE }
|
||||
#else
|
||||
#define HS_CODE(CODE)
|
||||
#endif
|
||||
|
||||
typedef enum { HT_FREE,
|
||||
HT_DELETED,
|
||||
HT_USED } hash_entry_state;
|
||||
|
||||
template<typename T>
|
||||
class default_hash_entry {
|
||||
unsigned m_hash; //!< cached hash code
|
||||
hash_entry_state m_state;
|
||||
T m_data;
|
||||
public:
|
||||
typedef T data;
|
||||
default_hash_entry():m_state(HT_FREE) {}
|
||||
unsigned get_hash() const { return m_hash; }
|
||||
bool is_free() const { return m_state == HT_FREE; }
|
||||
bool is_deleted() const { return m_state == HT_DELETED; }
|
||||
bool is_used() const { return m_state == HT_USED; }
|
||||
T & get_data() { return m_data; }
|
||||
const T & get_data() const { return m_data; }
|
||||
void set_data(const T & d) { m_data = d; m_state = HT_USED; }
|
||||
void set_hash(unsigned h) { m_hash = h; }
|
||||
void mark_as_deleted() { m_state = HT_DELETED; }
|
||||
void mark_as_free() { m_state = HT_FREE; }
|
||||
};
|
||||
|
||||
/**
|
||||
\brief Special entry for a hashtable of integers. This entry "steals" two values for representing HT_FREE and HT_DELETED.
|
||||
*/
|
||||
template<int Free, int Deleted>
|
||||
class int_hash_entry {
|
||||
unsigned m_hash; //!< cached hash code
|
||||
int m_data;
|
||||
public:
|
||||
typedef int data;
|
||||
int_hash_entry():m_data(Free) {}
|
||||
unsigned get_hash() const { return m_hash; }
|
||||
bool is_free() const { return m_data == Free; }
|
||||
bool is_deleted() const { return m_data == Deleted; }
|
||||
bool is_used() const { return m_data != Free && m_data != Deleted; }
|
||||
int get_data() const { return m_data; }
|
||||
int & get_data() { return m_data; }
|
||||
void set_data(int d) { m_data = d; }
|
||||
void set_hash(unsigned h) { m_hash = h; }
|
||||
void mark_as_deleted() { m_data = Deleted; }
|
||||
void mark_as_free() { m_data = Free; }
|
||||
};
|
||||
|
||||
/**
|
||||
\brief Special entry for a hashtable of pointers. This entry uses 0x0 and 0x1 to represent HT_FREE and HT_DELETED.
|
||||
*/
|
||||
template<typename T>
|
||||
class ptr_hash_entry {
|
||||
unsigned m_hash; //!< cached hash code
|
||||
T * m_ptr;
|
||||
public:
|
||||
typedef T * data;
|
||||
ptr_hash_entry():m_ptr(0) {}
|
||||
unsigned get_hash() const { return m_hash; }
|
||||
bool is_free() const { return m_ptr == 0; }
|
||||
bool is_deleted() const { return m_ptr == reinterpret_cast<T *>(1); }
|
||||
bool is_used() const { return m_ptr != reinterpret_cast<T *>(0) && m_ptr != reinterpret_cast<T *>(1); }
|
||||
T * get_data() const { return m_ptr; }
|
||||
T * & get_data() { return m_ptr; }
|
||||
void set_data(T * d) { m_ptr = d; }
|
||||
void set_hash(unsigned h) { m_hash = h; }
|
||||
void mark_as_deleted() { m_ptr = reinterpret_cast<T *>(1); }
|
||||
void mark_as_free() { m_ptr = 0; }
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
\brief Special entry for a hashtable of pointers which uses the pointer itself as the hashcode.
|
||||
This entry uses 0x0 and 0x1 to represent HT_FREE and HT_DELETED.
|
||||
*/
|
||||
template<typename T>
|
||||
class ptr_addr_hash_entry : public ptr_hash_entry<T> {
|
||||
T * m_ptr;
|
||||
public:
|
||||
typedef T * data;
|
||||
ptr_addr_hash_entry():m_ptr(0) {}
|
||||
unsigned get_hash() const { return get_ptr_hash(m_ptr); }
|
||||
bool is_free() const { return m_ptr == 0; }
|
||||
bool is_deleted() const { return m_ptr == reinterpret_cast<T *>(1); }
|
||||
bool is_used() const { return m_ptr != reinterpret_cast<T *>(0) && m_ptr != reinterpret_cast<T *>(1); }
|
||||
T * get_data() const { return m_ptr; }
|
||||
T * & get_data() { return m_ptr; }
|
||||
void set_data(T * d) { m_ptr = d; }
|
||||
void set_hash(unsigned h) { SASSERT(h == get_ptr_hash(m_ptr)); /* do nothing */ }
|
||||
void mark_as_deleted() { m_ptr = reinterpret_cast<T *>(1); }
|
||||
void mark_as_free() { m_ptr = 0; }
|
||||
};
|
||||
|
||||
template<typename Entry, typename HashProc, typename EqProc>
|
||||
class core_hashtable : private HashProc, private EqProc {
|
||||
protected:
|
||||
Entry * m_table;
|
||||
unsigned m_capacity;
|
||||
unsigned m_size;
|
||||
unsigned m_num_deleted;
|
||||
#ifdef HASHTABLE_STATISTICS
|
||||
unsigned long long m_st_collision;
|
||||
#endif
|
||||
|
||||
Entry* alloc_table(unsigned size) {
|
||||
Entry* entries = alloc_vect<Entry>(size);
|
||||
return entries;
|
||||
}
|
||||
|
||||
void delete_table() {
|
||||
dealloc_vect(m_table, m_capacity);
|
||||
m_table = 0;
|
||||
}
|
||||
|
||||
public:
|
||||
typedef typename Entry::data data;
|
||||
typedef Entry entry;
|
||||
protected:
|
||||
unsigned get_hash(data const & e) const { return HashProc::operator()(e); }
|
||||
bool equals(data const & e1, data const & e2) const { return EqProc::operator()(e1, e2); }
|
||||
|
||||
static void copy_table(entry * source, unsigned source_capacity, entry * target, unsigned target_capacity) {
|
||||
SASSERT(target_capacity >= source_capacity);
|
||||
unsigned target_mask = target_capacity - 1;
|
||||
entry * source_end = source + source_capacity;
|
||||
entry * target_end = target + target_capacity;
|
||||
for (entry * source_curr = source; source_curr != source_end; ++source_curr) {
|
||||
if (source_curr->is_used()) {
|
||||
unsigned hash = source_curr->get_hash();
|
||||
unsigned idx = hash & target_mask;
|
||||
entry * target_begin = target + idx;
|
||||
entry * target_curr = target_begin;
|
||||
for (; target_curr != target_end; ++target_curr) {
|
||||
SASSERT(!target_curr->is_deleted());
|
||||
if (target_curr->is_free()) {
|
||||
*target_curr = *source_curr;
|
||||
goto end;
|
||||
}
|
||||
}
|
||||
for (target_curr = target; target_curr != target_begin; ++target_curr) {
|
||||
SASSERT(!target_curr->is_deleted());
|
||||
if (target_curr->is_free()) {
|
||||
*target_curr = *source_curr;
|
||||
goto end;
|
||||
}
|
||||
}
|
||||
UNREACHABLE();
|
||||
end:
|
||||
;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void expand_table() {
|
||||
unsigned new_capacity = m_capacity << 1;
|
||||
entry * new_table = alloc_table(new_capacity);
|
||||
copy_table(m_table, m_capacity, new_table, new_capacity);
|
||||
delete_table();
|
||||
m_table = new_table;
|
||||
m_capacity = new_capacity;
|
||||
m_num_deleted = 0;
|
||||
}
|
||||
|
||||
|
||||
void remove_deleted_entries() {
|
||||
if (memory::is_out_of_memory())
|
||||
return;
|
||||
entry * new_table = alloc_table(m_capacity);
|
||||
copy_table(m_table, m_capacity, new_table, m_capacity);
|
||||
delete_table();
|
||||
m_table = new_table;
|
||||
m_num_deleted = 0;
|
||||
}
|
||||
|
||||
public:
|
||||
core_hashtable(unsigned initial_capacity = DEFAULT_HASHTABLE_INITIAL_CAPACITY,
|
||||
HashProc const & h = HashProc(),
|
||||
EqProc const & e = EqProc()):
|
||||
HashProc(h),
|
||||
EqProc(e) {
|
||||
SASSERT(is_power_of_two(initial_capacity));
|
||||
m_table = alloc_table(initial_capacity);
|
||||
m_capacity = initial_capacity;
|
||||
m_size = 0;
|
||||
m_num_deleted = 0;
|
||||
HS_CODE({
|
||||
m_st_collision = 0;
|
||||
});
|
||||
}
|
||||
|
||||
core_hashtable(const core_hashtable & source):
|
||||
HashProc(source),
|
||||
EqProc(source) {
|
||||
m_capacity = source.m_capacity;
|
||||
m_table = alloc_table(m_capacity);
|
||||
copy_table(source.m_table, m_capacity, m_table, m_capacity);
|
||||
m_size = source.m_size;
|
||||
m_num_deleted = 0;
|
||||
HS_CODE({
|
||||
m_st_collision = 0;
|
||||
});
|
||||
}
|
||||
|
||||
~core_hashtable() {
|
||||
delete_table();
|
||||
}
|
||||
|
||||
void swap(core_hashtable & source) {
|
||||
std::swap(m_table, source.m_table);
|
||||
std::swap(m_capacity, source.m_capacity);
|
||||
std::swap(m_size, source.m_size);
|
||||
std::swap(m_num_deleted, source.m_num_deleted);
|
||||
HS_CODE({
|
||||
std::swap(m_st_collision, source.m_st_collision);
|
||||
});
|
||||
}
|
||||
|
||||
void reset() {
|
||||
if (m_size == 0 && m_num_deleted == 0)
|
||||
return;
|
||||
unsigned overhead = 0;
|
||||
entry * curr = m_table;
|
||||
entry * end = m_table + m_capacity;
|
||||
for (; curr != end; ++curr) {
|
||||
if (!curr->is_free())
|
||||
curr->mark_as_free();
|
||||
else
|
||||
overhead++;
|
||||
}
|
||||
if (m_capacity > 16 && overhead << 2 > (m_capacity * 3)) {
|
||||
delete_table();
|
||||
SASSERT(m_capacity > 16);
|
||||
SASSERT(is_power_of_two(m_capacity));
|
||||
m_capacity = (m_capacity >> 1);
|
||||
SASSERT(is_power_of_two(m_capacity));
|
||||
m_table = alloc_table(m_capacity);
|
||||
}
|
||||
m_size = 0;
|
||||
m_num_deleted = 0;
|
||||
}
|
||||
|
||||
void finalize() {
|
||||
if (m_capacity > SMALL_TABLE_CAPACITY) {
|
||||
delete_table();
|
||||
m_table = alloc_table(SMALL_TABLE_CAPACITY);
|
||||
m_capacity = SMALL_TABLE_CAPACITY;
|
||||
m_size = 0;
|
||||
m_num_deleted = 0;
|
||||
}
|
||||
else {
|
||||
reset();
|
||||
}
|
||||
}
|
||||
|
||||
class iterator {
|
||||
entry * m_curr;
|
||||
entry * m_end;
|
||||
void move_to_used() {
|
||||
while (m_curr != m_end && !m_curr->is_used()) {
|
||||
m_curr++;
|
||||
}
|
||||
}
|
||||
public:
|
||||
iterator(entry * start, entry * end): m_curr(start), m_end(end) { move_to_used(); }
|
||||
data & operator*() { return m_curr->get_data(); }
|
||||
data const & operator*() const { return m_curr->get_data(); }
|
||||
data const * operator->() const { return &(operator*()); }
|
||||
data * operator->() { return &(operator*()); }
|
||||
iterator & operator++() { ++m_curr; move_to_used(); return *this; }
|
||||
iterator operator++(int) { iterator tmp = *this; ++*this; return tmp; }
|
||||
bool operator==(iterator const & it) const { return m_curr == it.m_curr; }
|
||||
bool operator!=(iterator const & it) const { return m_curr != it.m_curr; }
|
||||
};
|
||||
|
||||
bool empty() const { return m_size == 0; }
|
||||
|
||||
unsigned size() const { return m_size; }
|
||||
|
||||
unsigned capacity() const { return m_capacity; }
|
||||
|
||||
iterator begin() const { return iterator(m_table, m_table + m_capacity); }
|
||||
|
||||
iterator end() const { return iterator(m_table + m_capacity, m_table + m_capacity); }
|
||||
|
||||
#define INSERT_LOOP_BODY() { \
|
||||
if (curr->is_used()) { \
|
||||
if (curr->get_hash() == hash && equals(curr->get_data(), e)) { \
|
||||
curr->set_data(e); \
|
||||
return; \
|
||||
} \
|
||||
HS_CODE(m_st_collision++;); \
|
||||
} \
|
||||
else if (curr->is_free()) { \
|
||||
entry * new_entry; \
|
||||
if (del_entry) { new_entry = del_entry; m_num_deleted--; } \
|
||||
else { new_entry = curr; } \
|
||||
new_entry->set_data(e); \
|
||||
new_entry->set_hash(hash); \
|
||||
m_size++; \
|
||||
return; \
|
||||
} \
|
||||
else { \
|
||||
SASSERT(curr->is_deleted()); \
|
||||
del_entry = curr; \
|
||||
HS_CODE(m_st_collision++;); \
|
||||
} \
|
||||
} ((void) 0)
|
||||
|
||||
void insert(data const & e) {
|
||||
if ((m_size + m_num_deleted) << 2 > (m_capacity * 3)) {
|
||||
// if ((m_size + m_num_deleted) * 2 > (m_capacity)) {
|
||||
expand_table();
|
||||
}
|
||||
unsigned hash = get_hash(e);
|
||||
unsigned mask = m_capacity - 1;
|
||||
unsigned idx = hash & mask;
|
||||
entry * begin = m_table + idx;
|
||||
entry * end = m_table + m_capacity;
|
||||
entry * curr = begin;
|
||||
entry * del_entry = 0;
|
||||
for (; curr != end; ++curr) {
|
||||
INSERT_LOOP_BODY();
|
||||
}
|
||||
for (curr = m_table; curr != begin; ++curr) {
|
||||
INSERT_LOOP_BODY();
|
||||
}
|
||||
UNREACHABLE();
|
||||
}
|
||||
|
||||
#define INSERT_LOOP_CORE_BODY() { \
|
||||
if (curr->is_used()) { \
|
||||
if (curr->get_hash() == hash && equals(curr->get_data(), e)) { \
|
||||
et = curr; \
|
||||
return false; \
|
||||
} \
|
||||
HS_CODE(m_st_collision++;); \
|
||||
} \
|
||||
else if (curr->is_free()) { \
|
||||
entry * new_entry; \
|
||||
if (del_entry) { new_entry = del_entry; m_num_deleted--; } \
|
||||
else { new_entry = curr; } \
|
||||
new_entry->set_data(e); \
|
||||
new_entry->set_hash(hash); \
|
||||
m_size++; \
|
||||
et = new_entry; \
|
||||
return true; \
|
||||
} \
|
||||
else { \
|
||||
SASSERT(curr->is_deleted()); \
|
||||
del_entry = curr; \
|
||||
HS_CODE(m_st_collision++;); \
|
||||
} \
|
||||
} ((void) 0)
|
||||
|
||||
/**
|
||||
\brief Insert the element e if it is not in the table.
|
||||
Return true if it is a new element, and false otherwise.
|
||||
Store the entry/slot of the table in et.
|
||||
*/
|
||||
bool insert_if_not_there_core(data const & e, entry * & et) {
|
||||
if ((m_size + m_num_deleted) << 2 > (m_capacity * 3)) {
|
||||
// if ((m_size + m_num_deleted) * 2 > (m_capacity)) {
|
||||
expand_table();
|
||||
}
|
||||
unsigned hash = get_hash(e);
|
||||
unsigned mask = m_capacity - 1;
|
||||
unsigned idx = hash & mask;
|
||||
entry * begin = m_table + idx;
|
||||
entry * end = m_table + m_capacity;
|
||||
entry * curr = begin;
|
||||
entry * del_entry = 0;
|
||||
for (; curr != end; ++curr) {
|
||||
INSERT_LOOP_CORE_BODY();
|
||||
}
|
||||
for (curr = m_table; curr != begin; ++curr) {
|
||||
INSERT_LOOP_CORE_BODY();
|
||||
}
|
||||
UNREACHABLE();
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
\brief Insert the element e if it is not in the table.
|
||||
Return a reference to e or to an object identical to e
|
||||
that was already in the table.
|
||||
*/
|
||||
data const & insert_if_not_there(data const & e) {
|
||||
entry * et;
|
||||
insert_if_not_there_core(e, et);
|
||||
return et->get_data();
|
||||
}
|
||||
|
||||
/**
|
||||
\brief Insert the element e if it is not in the table.
|
||||
Return the entry that contains e.
|
||||
*/
|
||||
entry * insert_if_not_there2(data const & e) {
|
||||
entry * et;
|
||||
insert_if_not_there_core(e, et);
|
||||
return et;
|
||||
}
|
||||
|
||||
#define FIND_LOOP_BODY() { \
|
||||
if (curr->is_used()) { \
|
||||
if (curr->get_hash() == hash && equals(curr->get_data(), e)) { \
|
||||
return curr; \
|
||||
} \
|
||||
HS_CODE(const_cast<core_hashtable*>(this)->m_st_collision++;); \
|
||||
} \
|
||||
else if (curr->is_free()) { \
|
||||
return 0; \
|
||||
} \
|
||||
HS_CODE(const_cast<core_hashtable*>(this)->m_st_collision++;); \
|
||||
} ((void) 0)
|
||||
|
||||
entry * find_core(data const & e) const {
|
||||
unsigned hash = get_hash(e);
|
||||
unsigned mask = m_capacity - 1;
|
||||
unsigned idx = hash & mask;
|
||||
entry * begin = m_table + idx;
|
||||
entry * end = m_table + m_capacity;
|
||||
entry * curr = begin;
|
||||
for (; curr != end; ++curr) {
|
||||
FIND_LOOP_BODY();
|
||||
}
|
||||
for (curr = m_table; curr != begin; ++curr) {
|
||||
FIND_LOOP_BODY();
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
bool find(data const & k, data & r) const {
|
||||
entry * e = find_core(k);
|
||||
if (e != 0) {
|
||||
r = e->get_data();
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool contains(data const & e) const {
|
||||
return find_core(e) != 0;
|
||||
}
|
||||
|
||||
iterator find(data const & e) const {
|
||||
entry * r = find_core(e);
|
||||
if (r) {
|
||||
return iterator(r, m_table + m_capacity);
|
||||
}
|
||||
else {
|
||||
return end();
|
||||
}
|
||||
}
|
||||
|
||||
#define REMOVE_LOOP_BODY() { \
|
||||
if (curr->is_used()) { \
|
||||
if (curr->get_hash() == hash && equals(curr->get_data(), e)) { \
|
||||
goto end_remove; \
|
||||
} \
|
||||
HS_CODE(m_st_collision++;); \
|
||||
} \
|
||||
else if (curr->is_free()) { \
|
||||
return; \
|
||||
} \
|
||||
HS_CODE(m_st_collision++;); \
|
||||
} ((void) 0)
|
||||
|
||||
void remove(data const & e) {
|
||||
unsigned hash = get_hash(e);
|
||||
unsigned mask = m_capacity - 1;
|
||||
unsigned idx = hash & mask;
|
||||
entry * begin = m_table + idx;
|
||||
entry * end = m_table + m_capacity;
|
||||
entry * curr = begin;
|
||||
for (; curr != end; ++curr) {
|
||||
REMOVE_LOOP_BODY();
|
||||
}
|
||||
for (curr = m_table; curr != begin; ++curr) {
|
||||
REMOVE_LOOP_BODY();
|
||||
}
|
||||
SASSERT(!contains(e));
|
||||
return; // node is not in the table
|
||||
end_remove:
|
||||
entry * next = curr + 1;
|
||||
if (next == end) {
|
||||
next = m_table;
|
||||
}
|
||||
if (next->is_free()) {
|
||||
curr->mark_as_free();
|
||||
m_size--;
|
||||
}
|
||||
else {
|
||||
curr->mark_as_deleted();
|
||||
m_num_deleted++;
|
||||
m_size--;
|
||||
if (m_num_deleted > m_size && m_num_deleted > SMALL_TABLE_CAPACITY) {
|
||||
remove_deleted_entries();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void erase(data const & e) { remove(e); }
|
||||
|
||||
void dump(std::ostream & out) {
|
||||
entry * curr = m_table;
|
||||
entry * end = m_table + m_capacity;
|
||||
out << "[";
|
||||
bool first = true;
|
||||
for (; curr != end; ++curr) {
|
||||
if (curr->is_used()) {
|
||||
if (first) {
|
||||
first = false;
|
||||
}
|
||||
else {
|
||||
out << " ";
|
||||
}
|
||||
out << curr->get_data();
|
||||
}
|
||||
}
|
||||
out << "]";
|
||||
}
|
||||
|
||||
#ifdef Z3DEBUG
|
||||
bool check_invariant() {
|
||||
entry * curr = m_table;
|
||||
entry * end = m_table + m_capacity;
|
||||
unsigned num_deleted = 0;
|
||||
unsigned num_used = 0;
|
||||
for (; curr != end; ++curr) {
|
||||
if (curr->is_deleted()) {
|
||||
num_deleted ++;
|
||||
}
|
||||
if (curr->is_used()) {
|
||||
num_used++;
|
||||
}
|
||||
}
|
||||
SASSERT(num_deleted == m_num_deleted);
|
||||
SASSERT(num_used == m_size);
|
||||
return true;
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef HASHTABLE_STATISTICS
|
||||
unsigned long long get_num_collision() const { return m_st_collision; }
|
||||
#else
|
||||
unsigned long long get_num_collision() const { return 0; }
|
||||
#endif
|
||||
|
||||
private:
|
||||
|
||||
core_hashtable& operator=(core_hashtable const&);
|
||||
|
||||
};
|
||||
|
||||
template<typename T, typename HashProc, typename EqProc>
|
||||
class hashtable : public core_hashtable<default_hash_entry<T>, HashProc, EqProc> {
|
||||
public:
|
||||
hashtable(unsigned initial_capacity = DEFAULT_HASHTABLE_INITIAL_CAPACITY,
|
||||
HashProc const & h = HashProc(),
|
||||
EqProc const & e = EqProc()):
|
||||
core_hashtable<default_hash_entry<T>, HashProc, EqProc>(initial_capacity, h, e) {}
|
||||
};
|
||||
|
||||
template<typename T, typename HashProc, typename EqProc>
|
||||
class ptr_hashtable : public core_hashtable<ptr_hash_entry<T>, HashProc, EqProc> {
|
||||
public:
|
||||
ptr_hashtable(unsigned initial_capacity = DEFAULT_HASHTABLE_INITIAL_CAPACITY,
|
||||
HashProc const & h = HashProc(),
|
||||
EqProc const & e = EqProc()):
|
||||
core_hashtable<ptr_hash_entry<T>, HashProc, EqProc>(initial_capacity, h, e) {}
|
||||
};
|
||||
|
||||
/**
|
||||
\brief Hashtable of pointers which use the pointer as the hash-code.
|
||||
*/
|
||||
template<typename T>
|
||||
class ptr_addr_hashtable : public core_hashtable<ptr_addr_hash_entry<T>, ptr_hash<T>, ptr_eq<T> > {
|
||||
public:
|
||||
typedef typename core_hashtable<ptr_addr_hash_entry<T>, ptr_hash<T>, ptr_eq<T> >::iterator iterator;
|
||||
ptr_addr_hashtable(unsigned initial_capacity = DEFAULT_HASHTABLE_INITIAL_CAPACITY):
|
||||
core_hashtable<ptr_addr_hash_entry<T>, ptr_hash<T>, ptr_eq<T> >(initial_capacity) {}
|
||||
|
||||
// Using iterators to traverse the elements of this kind of hashtable will produce non-determinism.
|
||||
iterator begin() const {
|
||||
UNREACHABLE();
|
||||
}
|
||||
|
||||
iterator end() const {
|
||||
UNREACHABLE();
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
\brief Simple int_hashtable. The values INT_MIN and INT_MIN + 1 are used to mark
|
||||
deleted and free slots. So, these values cannot be stored in the table. Use core_hashtable
|
||||
template to avoid this limitation.
|
||||
*/
|
||||
template<typename HashProc, typename EqProc>
|
||||
class int_hashtable : public core_hashtable<int_hash_entry<INT_MIN, INT_MIN + 1>, HashProc, EqProc> {
|
||||
public:
|
||||
int_hashtable(unsigned initial_capacity = DEFAULT_HASHTABLE_INITIAL_CAPACITY,
|
||||
HashProc const & h = HashProc(),
|
||||
EqProc const & e = EqProc()):
|
||||
core_hashtable<int_hash_entry<INT_MIN, INT_MIN + 1>, HashProc, EqProc>(initial_capacity, h, e) {}
|
||||
};
|
||||
|
||||
#endif /* _HASHTABLE_H_ */
|
245
src/util/heap.h
Normal file
245
src/util/heap.h
Normal file
|
@ -0,0 +1,245 @@
|
|||
/*++
|
||||
Copyright (c) 2006 Microsoft Corporation
|
||||
|
||||
Module Name:
|
||||
|
||||
heap.h
|
||||
|
||||
Abstract:
|
||||
|
||||
A heap of integers.
|
||||
|
||||
Author:
|
||||
|
||||
Leonardo de Moura (leonardo) 2006-09-14.
|
||||
|
||||
Revision History:
|
||||
|
||||
--*/
|
||||
#ifndef _HEAP_H_
|
||||
#define _HEAP_H_
|
||||
|
||||
#include"vector.h"
|
||||
#include"debug.h"
|
||||
|
||||
template<typename LT>
|
||||
class heap : private LT {
|
||||
int_vector m_values;
|
||||
int_vector m_value2indices;
|
||||
|
||||
bool less_than(int v1, int v2) const {
|
||||
return LT::operator()(v1, v2);
|
||||
}
|
||||
|
||||
static int left(int i) {
|
||||
return i << 1;
|
||||
}
|
||||
|
||||
static int right(int i) {
|
||||
return (i << 1) + 1;
|
||||
}
|
||||
|
||||
static int parent(int i) {
|
||||
return i >> 1;
|
||||
}
|
||||
|
||||
#ifdef Z3DEBUG
|
||||
// Return true if the value can be inserted in the heap. That is, the vector m_value2indices is big enough to store this value.
|
||||
bool is_valid_value(int v) const {
|
||||
SASSERT(v >= 0 && v < static_cast<int>(m_value2indices.size()));
|
||||
return true;
|
||||
}
|
||||
|
||||
bool check_invariant_core(int idx) const {
|
||||
if (idx < static_cast<int>(m_values.size())) {
|
||||
SASSERT(m_value2indices[m_values[idx]] == idx);
|
||||
SASSERT(parent(idx) == 0 || !less_than(m_values[idx], m_values[parent(idx)]));
|
||||
SASSERT(check_invariant_core(left(idx)));
|
||||
SASSERT(check_invariant_core(right(idx)));
|
||||
}
|
||||
return true;
|
||||
}
|
||||
public:
|
||||
bool check_invariant() const {
|
||||
return check_invariant_core(1);
|
||||
}
|
||||
#endif
|
||||
private:
|
||||
|
||||
void move_up(int idx) {
|
||||
int val = m_values[idx];
|
||||
while (true) {
|
||||
int parent_idx = parent(idx);
|
||||
if (parent_idx == 0 || !less_than(val, m_values[parent_idx])) {
|
||||
break;
|
||||
}
|
||||
m_values[idx] = m_values[parent_idx];
|
||||
m_value2indices[m_values[idx]] = idx;
|
||||
idx = parent_idx;
|
||||
}
|
||||
m_values[idx] = val;
|
||||
m_value2indices[val] = idx;
|
||||
CASSERT("heap", check_invariant());
|
||||
}
|
||||
|
||||
void move_down(int idx) {
|
||||
int val = m_values[idx];
|
||||
int sz = static_cast<int>(m_values.size());
|
||||
while (true) {
|
||||
int left_idx = left(idx);
|
||||
if (left_idx >= sz) {
|
||||
break;
|
||||
}
|
||||
int right_idx = right(idx);
|
||||
int min_idx = right_idx < sz && less_than(m_values[right_idx], m_values[left_idx]) ? right_idx : left_idx;
|
||||
SASSERT(parent(min_idx) == idx);
|
||||
int min_value = m_values[min_idx];
|
||||
if (!less_than(min_value, val)) {
|
||||
break;
|
||||
}
|
||||
m_values[idx] = min_value;
|
||||
m_value2indices[min_value] = idx;
|
||||
idx = min_idx;
|
||||
}
|
||||
m_values[idx] = val;
|
||||
m_value2indices[val] = idx;
|
||||
CASSERT("heap", check_invariant());
|
||||
}
|
||||
|
||||
public:
|
||||
typedef int * iterator;
|
||||
typedef const int * const_iterator;
|
||||
|
||||
heap(int s, const LT & lt = LT()):LT(lt) {
|
||||
m_values.push_back(-1);
|
||||
set_bounds(s);
|
||||
}
|
||||
|
||||
bool empty() const {
|
||||
return m_values.size() == 1;
|
||||
}
|
||||
|
||||
bool contains(int val) const {
|
||||
return val < static_cast<int>(m_value2indices.size()) && m_value2indices[val] != 0;
|
||||
}
|
||||
|
||||
void reset() {
|
||||
if (empty()) {
|
||||
return;
|
||||
}
|
||||
memset(m_value2indices.begin(), 0, sizeof(int) * m_value2indices.size());
|
||||
m_values.reset();
|
||||
m_values.push_back(-1);
|
||||
}
|
||||
|
||||
void clear() {
|
||||
reset();
|
||||
}
|
||||
|
||||
void set_bounds(int s) {
|
||||
m_value2indices.resize(s, 0);
|
||||
}
|
||||
|
||||
unsigned get_bounds() const {
|
||||
return m_value2indices.size();
|
||||
}
|
||||
|
||||
void reserve(int s) {
|
||||
if (s > static_cast<int>(m_value2indices.size()))
|
||||
set_bounds(s);
|
||||
}
|
||||
|
||||
int min_value() const {
|
||||
SASSERT(!empty());
|
||||
return m_values[1];
|
||||
}
|
||||
|
||||
int erase_min() {
|
||||
SASSERT(!empty());
|
||||
SASSERT(m_values.size() >= 2);
|
||||
int result = m_values[1];
|
||||
if (m_values.size() == 2) {
|
||||
m_value2indices[result] = 0;
|
||||
m_values.pop_back();
|
||||
SASSERT(empty());
|
||||
}
|
||||
else {
|
||||
int last_val = m_values.back();
|
||||
m_values[1] = last_val;
|
||||
m_value2indices[last_val] = 1;
|
||||
m_value2indices[result] = 0;
|
||||
m_values.pop_back();
|
||||
move_down(1);
|
||||
}
|
||||
CASSERT("heap", check_invariant());
|
||||
return result;
|
||||
}
|
||||
|
||||
void erase(int val) {
|
||||
SASSERT(contains(val));
|
||||
int idx = m_value2indices[val];
|
||||
if (idx == static_cast<int>(m_values.size()) - 1) {
|
||||
m_value2indices[val] = 0;
|
||||
m_values.pop_back();
|
||||
}
|
||||
else {
|
||||
int last_val = m_values.back();
|
||||
m_values[idx] = last_val;
|
||||
m_value2indices[last_val] = idx;
|
||||
m_value2indices[val] = 0;
|
||||
m_values.pop_back();
|
||||
int parent_idx = parent(idx);
|
||||
if (parent_idx != 0 && less_than(last_val, m_values[parent(idx)])) {
|
||||
move_up(idx);
|
||||
}
|
||||
else {
|
||||
move_down(idx);
|
||||
}
|
||||
}
|
||||
CASSERT("heap", check_invariant());
|
||||
}
|
||||
|
||||
void decreased(int val) {
|
||||
SASSERT(contains(val));
|
||||
move_up(m_value2indices[val]);
|
||||
}
|
||||
|
||||
void increased(int val) {
|
||||
SASSERT(contains(val));
|
||||
move_down(m_value2indices[val]);
|
||||
}
|
||||
|
||||
void insert(int val) {
|
||||
SASSERT(is_valid_value(val));
|
||||
int idx = static_cast<int>(m_values.size());
|
||||
m_value2indices[val] = idx;
|
||||
m_values.push_back(val);
|
||||
SASSERT(idx == static_cast<int>(m_values.size()) - 1);
|
||||
move_up(idx);
|
||||
}
|
||||
|
||||
iterator begin() {
|
||||
return m_values.begin() + 1;
|
||||
}
|
||||
|
||||
iterator end() {
|
||||
return m_values.end();
|
||||
}
|
||||
|
||||
const_iterator begin() const {
|
||||
return m_values.begin() + 1;
|
||||
}
|
||||
|
||||
const_iterator end() const {
|
||||
return m_values.end();
|
||||
}
|
||||
|
||||
void swap(heap & other) {
|
||||
m_values.swap(other.m_values);
|
||||
m_value2indices.swap(other.m_value2indices);
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
#endif /* _HEAP_H_ */
|
||||
|
646
src/util/hwf.cpp
Normal file
646
src/util/hwf.cpp
Normal file
|
@ -0,0 +1,646 @@
|
|||
/*++
|
||||
Copyright (c) 2011 Microsoft Corporation
|
||||
|
||||
Module Name:
|
||||
|
||||
hwf.cpp
|
||||
|
||||
Abstract:
|
||||
|
||||
Hardware Floating Point Numbers
|
||||
|
||||
Author:
|
||||
|
||||
Christoph Wintersteiger (cwinter) 2012-07-30.
|
||||
|
||||
Revision History:
|
||||
|
||||
--*/
|
||||
#include<float.h>
|
||||
|
||||
#ifdef _WINDOWS
|
||||
#pragma float_control( except, on ) // exception semantics; this does _not_ mean that exceptions are enabled (we want them off!)
|
||||
#pragma float_control( precise, on ) // precise semantics (no guessing!)
|
||||
#pragma fp_contract(off) // contractions off (`contraction' means x*y+z is turned into a fused-mul-add).
|
||||
#pragma fenv_access(on) // fpu environment sensitivity (needed to be allowed to make FPU mode changes).
|
||||
#else
|
||||
#pragma STDC FENV_ACCESS ON
|
||||
#include <math.h>
|
||||
#include <fenv.h>
|
||||
#endif
|
||||
|
||||
#ifndef _M_IA64
|
||||
#define USE_INTRINSICS
|
||||
#endif
|
||||
|
||||
#include<sstream>
|
||||
|
||||
#include"hwf.h"
|
||||
|
||||
// Note:
|
||||
// Which FPU will be used is determined by compiler settings. On x64 it's always SSE2,
|
||||
// on x86 we have to chose SSE2 by enabling /arch:SSE2 (otherwise the x87 FPU will be used).
|
||||
// Christoph has decided that we don't want to use the x87; this makes everything a lot easier.
|
||||
|
||||
|
||||
// For SSE2, it is best to use compiler intrinsics because this makes it completely
|
||||
// clear to the compiler what instructions should be used. E.g., for sqrt(), the Windows compiler selects
|
||||
// the x87 FPU, even when /arch:SSE2 is on.
|
||||
// Luckily, these are kind of standardized, at least for Windows/Linux/OSX.
|
||||
#include <emmintrin.h>
|
||||
|
||||
|
||||
hwf_manager::hwf_manager() :
|
||||
m_mpz_manager(m_mpq_manager)
|
||||
{
|
||||
#ifdef _WINDOWS
|
||||
#if defined(_AMD64_) || defined(_M_IA64)
|
||||
// Precision control is not supported on x64.
|
||||
// See: http://msdn.microsoft.com/en-us/library/e9b52ceh(VS.110).aspx
|
||||
// CMW: I think this is okay though, the compiler will chose the right instructions
|
||||
// (the x64/SSE2 FPU has separate instructions for different precisions).
|
||||
#else
|
||||
// Setting the precision should only be required on the x87, but it won't hurt to do it anyways.
|
||||
// _PC_53 means double precision (53 significand bits). For extended precision use _PC_64.
|
||||
|
||||
#ifndef USE_INTRINSICS
|
||||
__control87_2(_PC_53, _MCW_PC, &x86_state, &sse2_state);
|
||||
#endif
|
||||
#endif
|
||||
#else
|
||||
// OSX/Linux: Nothing.
|
||||
#endif
|
||||
|
||||
// We only set the precision of the FPU here in the constructor. At the moment, there are no
|
||||
// other parts of the code that could overwrite this, and Windows takes care of context switches.
|
||||
|
||||
// CMW: I'm not sure what happens on CPUs with hyper-threading (since the FPU is shared).
|
||||
// I have yet to discover whether Linux and OSX save the FPU state when switching context.
|
||||
// As long as we stick to using the SSE2 FPU though, there shouldn't be any problems with respect
|
||||
// to the precision (not sure about the rounding modes though).
|
||||
}
|
||||
|
||||
hwf_manager::~hwf_manager()
|
||||
{
|
||||
}
|
||||
|
||||
#define RAW(X) (*reinterpret_cast<const uint64*>(&(X)))
|
||||
#define DBL(X) (*reinterpret_cast<const double*>(&(X)))
|
||||
|
||||
void hwf_manager::set(hwf & o, int value) {
|
||||
o.value = (double) value;
|
||||
}
|
||||
|
||||
void hwf_manager::set(hwf & o, mpf_rounding_mode rm, int n, int d) {
|
||||
set_rounding_mode(rm);
|
||||
o.value = ((double) n)/((double) d);
|
||||
}
|
||||
|
||||
void hwf_manager::set(hwf & o, double value) {
|
||||
o.value = value;
|
||||
}
|
||||
|
||||
void hwf_manager::set(hwf & o, float value) {
|
||||
o.value = (double)value;
|
||||
}
|
||||
|
||||
void hwf_manager::set(hwf & o, mpf_rounding_mode rm, mpq const & value) {
|
||||
set_rounding_mode(rm);
|
||||
o.value = m_mpq_manager.get_double(value);
|
||||
}
|
||||
|
||||
void hwf_manager::set(hwf & o, mpf_rounding_mode rm, char const * value) {
|
||||
// We expect [i].[f]P[e], where P means that the exponent is interpreted as 2^e instead of 10^e.
|
||||
|
||||
std::string v(value);
|
||||
size_t e_pos = v.find('p');
|
||||
if (e_pos == std::string::npos) e_pos = v.find('P');
|
||||
|
||||
std::string f, e;
|
||||
|
||||
f = (e_pos != std::string::npos) ? v.substr(0, e_pos) : v;
|
||||
e = (e_pos != std::string::npos) ? v.substr(e_pos+1) : "0";
|
||||
|
||||
TRACE("mpf_dbg", tout << " f = " << f << " e = " << e << std::endl;);
|
||||
|
||||
mpq q;
|
||||
m_mpq_manager.set(q, f.c_str());
|
||||
|
||||
mpz ex;
|
||||
m_mpz_manager.set(ex, e.c_str());
|
||||
|
||||
set(o, rm, q, ex);
|
||||
|
||||
TRACE("mpf_dbg", tout << "set: res = " << to_string(o) << std::endl;);
|
||||
}
|
||||
|
||||
void hwf_manager::set(hwf & o, mpf_rounding_mode rm, mpq const & significand, mpz const & exponent) {
|
||||
// Assumption: this represents significand * 2^exponent.
|
||||
set_rounding_mode(rm);
|
||||
|
||||
mpq sig;
|
||||
m_mpq_manager.set(sig, significand);
|
||||
int64 exp = m_mpz_manager.get_int64(exponent);
|
||||
|
||||
if (m_mpq_manager.is_zero(significand))
|
||||
o.value = 0.0;
|
||||
else
|
||||
{
|
||||
while (m_mpq_manager.lt(sig, 1))
|
||||
{
|
||||
m_mpq_manager.mul(sig, 2, sig);
|
||||
exp--;
|
||||
}
|
||||
|
||||
hwf s; s.value = m_mpq_manager.get_double(sig);
|
||||
uint64 r = (RAW(s.value) & 0x800FFFFFFFFFFFFFull) | ((exp + 1023) << 52);
|
||||
o.value = DBL(r);
|
||||
}
|
||||
}
|
||||
|
||||
void hwf_manager::set(hwf & o, bool sign, uint64 significand, int exponent) {
|
||||
// Assumption: this represents (sign * -1) * (significand/2^sbits) * 2^exponent.
|
||||
SASSERT(significand <= 0x000FFFFFFFFFFFFFull);
|
||||
SASSERT(-1022 <= exponent && exponent <= 1023);
|
||||
uint64 raw = (sign?0x8000000000000000ull:0);
|
||||
raw |= (((uint64)exponent) + 1023) << 52;
|
||||
raw |= significand;
|
||||
o.value = *reinterpret_cast<double*>(&raw);
|
||||
}
|
||||
|
||||
void hwf_manager::set(hwf & o, hwf const & x) {
|
||||
o.value = x.value;
|
||||
}
|
||||
|
||||
void hwf_manager::abs(hwf & o) {
|
||||
o.value = fabs(o.value);
|
||||
}
|
||||
|
||||
void hwf_manager::abs(hwf const & x, hwf & o) {
|
||||
o.value = fabs(x.value);
|
||||
}
|
||||
|
||||
void hwf_manager::neg(hwf & o) {
|
||||
o.value = -o.value;
|
||||
}
|
||||
|
||||
void hwf_manager::neg(hwf const & x, hwf & o) {
|
||||
o.value = -x.value;
|
||||
}
|
||||
|
||||
bool hwf_manager::eq(hwf const & x, hwf const & y) {
|
||||
return (x.value == y.value);
|
||||
}
|
||||
|
||||
bool hwf_manager::lt(hwf const & x, hwf const & y) {
|
||||
return (x.value < y.value);
|
||||
}
|
||||
|
||||
bool hwf_manager::lte(hwf const & x, hwf const & y) {
|
||||
return (x.value <= y.value);
|
||||
}
|
||||
|
||||
bool hwf_manager::gt(hwf const & x, hwf const & y) {
|
||||
return (x.value > y.value);
|
||||
}
|
||||
|
||||
bool hwf_manager::gte(hwf const & x, hwf const & y) {
|
||||
return (x.value >= y.value);
|
||||
}
|
||||
|
||||
void hwf_manager::add(mpf_rounding_mode rm, hwf const & x, hwf const & y, hwf & o) {
|
||||
set_rounding_mode(rm);
|
||||
#ifdef USE_INTRINSICS
|
||||
_mm_store_sd(&o.value, _mm_add_sd(_mm_set_sd(x.value), _mm_set_sd(y.value)));
|
||||
#else
|
||||
o.value = x.value + y.value;
|
||||
#endif
|
||||
}
|
||||
|
||||
void hwf_manager::sub(mpf_rounding_mode rm, hwf const & x, hwf const & y, hwf & o) {
|
||||
set_rounding_mode(rm);
|
||||
#ifdef USE_INTRINSICS
|
||||
_mm_store_sd(&o.value, _mm_sub_sd(_mm_set_sd(x.value), _mm_set_sd(y.value)));
|
||||
#else
|
||||
o.value = x.value - y.value;
|
||||
#endif
|
||||
}
|
||||
|
||||
#define DBL_SCALE 15360
|
||||
|
||||
void hwf_manager::mul(mpf_rounding_mode rm, hwf const & x, hwf const & y, hwf & o) {
|
||||
set_rounding_mode(rm);
|
||||
#ifdef USE_INTRINSICS
|
||||
_mm_store_sd(&o.value, _mm_mul_sd(_mm_set_sd(x.value), _mm_set_sd(y.value)));
|
||||
#else
|
||||
o.value = x.value * y.value;
|
||||
#endif
|
||||
|
||||
#if 0
|
||||
// On the x86 FPU (x87), we use custom assembly routines because
|
||||
// the code generated for x*y and x/y suffers from the double
|
||||
// rounding on underflow problem. The scaling trick is described
|
||||
// in Roger Golliver: `Efficiently producing default orthogonal IEEE
|
||||
// double results using extended IEEE hardware', see
|
||||
// http://www.open-std.org/JTC1/SC22/JSG/docs/m3/docs/jsgn326.pdf
|
||||
// CMW: Tthis is not really needed if we use only the SSE2 FPU,
|
||||
// it shouldn't hurt the performance too much though.
|
||||
|
||||
static const int const1 = -DBL_SCALE;
|
||||
static const int const2 = +DBL_SCALE;
|
||||
double xv = x.value;
|
||||
double yv = y.value;
|
||||
double & ov = o.value;
|
||||
|
||||
__asm {
|
||||
fild const1;
|
||||
fld xv;
|
||||
fscale;
|
||||
fstp st(1);
|
||||
fmul yv;
|
||||
fild const2;
|
||||
fxch st(1);
|
||||
fscale;
|
||||
fstp ov;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
void hwf_manager::div(mpf_rounding_mode rm, hwf const & x, hwf const & y, hwf & o) {
|
||||
set_rounding_mode(rm);
|
||||
#ifdef USE_INTRINSICS
|
||||
_mm_store_sd(&o.value, _mm_div_sd(_mm_set_sd(x.value), _mm_set_sd(y.value)));
|
||||
#else
|
||||
o.value = x.value / y.value;
|
||||
#endif
|
||||
|
||||
#if 0
|
||||
// see mul(...)
|
||||
|
||||
static const int const1 = -DBL_SCALE;
|
||||
static const int const2 = +DBL_SCALE;
|
||||
double xv = x.value;
|
||||
double yv = y.value;
|
||||
double & ov = o.value;
|
||||
|
||||
__asm {
|
||||
fild const1;
|
||||
fld xv;
|
||||
fscale;
|
||||
fstp st(1);
|
||||
fdiv yv;
|
||||
fild const2;
|
||||
fxch st(1);
|
||||
fscale;
|
||||
fstp ov;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
#ifdef _M_IA64
|
||||
#pragma fp_contract(on)
|
||||
#endif
|
||||
|
||||
void hwf_manager::fused_mul_add(mpf_rounding_mode rm, hwf const & x, hwf const & y, hwf const &z, hwf & o) {
|
||||
// CMW: fused_mul_add is not available on most CPUs. As of 2012, only Itanium,
|
||||
// Intel Sandybridge and AMD Bulldozers support that (via AVX).
|
||||
|
||||
#ifdef _M_IA64
|
||||
// IA64 (Itanium) will do it, if contractions are on.
|
||||
set_rounding_mode(rm);
|
||||
o.value = x.value * y.value + z.value;
|
||||
#else
|
||||
// NOT_IMPLEMENTED_YET();
|
||||
// Just a dummy for now:
|
||||
hwf t;
|
||||
mul(rm, x, y, t);
|
||||
add(rm, t, z, o);
|
||||
#endif
|
||||
}
|
||||
|
||||
#ifdef _M_IA64
|
||||
#pragma fp_contract(off)
|
||||
#endif
|
||||
|
||||
void hwf_manager::sqrt(mpf_rounding_mode rm, hwf const & x, hwf & o) {
|
||||
set_rounding_mode(rm);
|
||||
#ifdef USE_INTRINSICS
|
||||
_mm_store_sd(&o.value, _mm_sqrt_pd(_mm_set_sd(x.value)));
|
||||
#else
|
||||
o.value = ::sqrt(x.value);
|
||||
#endif
|
||||
}
|
||||
|
||||
void hwf_manager::round_to_integral(mpf_rounding_mode rm, hwf const & x, hwf & o) {
|
||||
set_rounding_mode(rm);
|
||||
modf(x.value, &o.value);
|
||||
// Note: on x64, this sometimes produces an SNAN instead of a QNAN?
|
||||
}
|
||||
|
||||
void hwf_manager::rem(hwf const & x, hwf const & y, hwf & o) {
|
||||
// The built-in fmod() works, except for the special numbers.
|
||||
|
||||
if (is_inf(x) && is_inf(y))
|
||||
o.value = x.value/y.value; // NaN
|
||||
else if (is_inf(y))
|
||||
o.value = x.value;
|
||||
else
|
||||
o.value = fmod(x.value, y.value);
|
||||
|
||||
// Here is an x87 alternative if the above makes problems; this may also be faster.
|
||||
#if 0
|
||||
double xv = x.value;
|
||||
double yv = y.value;
|
||||
double & ov = o.value;
|
||||
|
||||
// This is from: http://webster.cs.ucr.edu/AoA/DOS/ch14/CH14-4.html#HEADING4-173
|
||||
__asm {
|
||||
fld yv
|
||||
fld xv
|
||||
L: fprem1
|
||||
fstsw ax // Get condition bits in AX.
|
||||
test ah, 100b // See if C2 is set.
|
||||
jnz L // Repeat if not done yet.
|
||||
fstp ov // Store remainder away.
|
||||
fstp st(0) // Pop old y value.
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
void hwf_manager::maximum(hwf const & x, hwf const & y, hwf & o) {
|
||||
#ifdef USE_INTRINSICS
|
||||
_mm_store_sd(&o.value, _mm_max_sd(_mm_set_sd(x.value), _mm_set_sd(y.value)));
|
||||
#else
|
||||
// use __max ?
|
||||
if (is_nan(x))
|
||||
o.value = y.value;
|
||||
else if (is_nan(y))
|
||||
o.value = x.value;
|
||||
else if (lt(x, y))
|
||||
o.value = y.value;
|
||||
else
|
||||
o.value = x.value;
|
||||
#endif
|
||||
}
|
||||
|
||||
void hwf_manager::minimum(hwf const & x, hwf const & y, hwf & o) {
|
||||
#ifdef USE_INTRINSICS
|
||||
_mm_store_sd(&o.value, _mm_min_sd(_mm_set_sd(x.value), _mm_set_sd(y.value)));
|
||||
#else
|
||||
// use __min ?
|
||||
if (is_nan(x) || is_nan(x))
|
||||
o.value = y.value;
|
||||
else if (is_nan(y))
|
||||
o.value = x.value;
|
||||
else if (lt(x, y))
|
||||
o.value = x.value;
|
||||
else
|
||||
o.value = y.value;
|
||||
#endif
|
||||
}
|
||||
|
||||
std::string hwf_manager::to_string(hwf const & x) {
|
||||
std::stringstream ss("");
|
||||
ss << std::scientific << x.value;
|
||||
return ss.str();
|
||||
}
|
||||
|
||||
std::string hwf_manager::to_rational_string(hwf const & a) {
|
||||
// temporary hack
|
||||
unsynch_mpq_manager qm;
|
||||
scoped_mpq q(qm);
|
||||
to_rational(a, q);
|
||||
return qm.to_string(q);
|
||||
}
|
||||
|
||||
void hwf_manager::display_decimal(std::ostream & out, hwf const & a, unsigned k) {
|
||||
// temporary hack
|
||||
unsynch_mpq_manager qm;
|
||||
scoped_mpq q(qm);
|
||||
to_rational(a, q);
|
||||
qm.display_decimal(out, q, k);
|
||||
}
|
||||
|
||||
void hwf_manager::display_smt2(std::ostream & out, hwf const & a, bool decimal) {
|
||||
// temporary hack
|
||||
unsynch_mpq_manager qm;
|
||||
scoped_mpq q(qm);
|
||||
to_rational(a, q);
|
||||
qm.display_smt2(out, q, decimal);
|
||||
}
|
||||
|
||||
void hwf_manager::to_rational(hwf const & x, unsynch_mpq_manager & qm, mpq & o) {
|
||||
SASSERT(is_normal(x) || is_denormal(x) || is_zero(x));
|
||||
scoped_mpz n(qm), d(qm);
|
||||
|
||||
if (is_normal(x))
|
||||
qm.set(n, sig(x) | 0x0010000000000000ull);
|
||||
else
|
||||
qm.set(n, sig(x));
|
||||
if (sgn(x))
|
||||
qm.neg(n);
|
||||
qm.set(d, 0x0010000000000000ull);
|
||||
int e = exp(x);
|
||||
if (e >= 0)
|
||||
qm.mul2k(n, (unsigned)e);
|
||||
else
|
||||
qm.mul2k(d, (unsigned)-e);
|
||||
qm.set(o, n, d);
|
||||
}
|
||||
|
||||
bool hwf_manager::is_zero(hwf const & x) {
|
||||
uint64 t = RAW(x.value) & 0x7FFFFFFFFFFFFFFFull;
|
||||
return (t == 0x0ull);
|
||||
// CMW: I tried, and these are slower:
|
||||
// return (t != 0x0ull) ? false : true;
|
||||
// return (x.value == 0.0 || x.value == -0.0); // [uses SSE2].
|
||||
}
|
||||
|
||||
bool hwf_manager::is_neg(hwf const & x) {
|
||||
// [Leo]: I added !is_nan(x)
|
||||
return sgn(x) && !is_nan(x);
|
||||
}
|
||||
|
||||
bool hwf_manager::is_pos(hwf const & x) {
|
||||
return !sgn(x) && !is_nan(x);
|
||||
}
|
||||
|
||||
bool hwf_manager::is_nzero(hwf const & x) {
|
||||
return RAW(x.value) == 0x8000000000000000ull;
|
||||
}
|
||||
|
||||
bool hwf_manager::is_pzero(hwf const & x) {
|
||||
return RAW(x.value) == 0x0000000000000000ull;
|
||||
}
|
||||
|
||||
bool hwf_manager::is_one(hwf const & x) {
|
||||
return RAW(x.value) == 0x3FF0000000000000ull;
|
||||
}
|
||||
|
||||
bool hwf_manager::is_nan(hwf const & x) {
|
||||
bool r = ((RAW(x.value) & 0x7FF0000000000000ull) == 0x7FF0000000000000ull) &&
|
||||
((RAW(x.value) & 0x000FFFFFFFFFFFFFull) != 0x0);
|
||||
#ifdef _WINDOWS
|
||||
SASSERT( !r || (_fpclass(x.value) == _FPCLASS_SNAN || _fpclass(x.value) == _FPCLASS_QNAN));
|
||||
#endif
|
||||
return r;
|
||||
}
|
||||
|
||||
bool hwf_manager::is_inf(hwf const & x) {
|
||||
bool r = ((RAW(x.value) & 0x7FF0000000000000ull) == 0x7FF0000000000000ull) &&
|
||||
((RAW(x.value) & 0x000FFFFFFFFFFFFFull) == 0x0);
|
||||
#ifdef _WINDOWS
|
||||
SASSERT( !r || (_fpclass(x.value) == _FPCLASS_NINF || _fpclass(x.value) == _FPCLASS_PINF));
|
||||
#endif
|
||||
return r;
|
||||
}
|
||||
|
||||
bool hwf_manager::is_pinf(hwf const & x) {
|
||||
return !sgn(x) && is_inf(x);
|
||||
}
|
||||
|
||||
bool hwf_manager::is_ninf(hwf const & x) {
|
||||
return sgn(x) && is_inf(x);
|
||||
}
|
||||
|
||||
bool hwf_manager::is_normal(hwf const & x) {
|
||||
uint64 t = RAW(x.value) & 0x7FF0000000000000ull;
|
||||
return (t != 0x0ull && t != 0x7FF0000000000000ull);
|
||||
}
|
||||
|
||||
bool hwf_manager::is_denormal(hwf const & x) {
|
||||
uint64 t = RAW(x.value);
|
||||
return ((t & 0x7FF0000000000000ull) == 0x0 &&
|
||||
(t & 0x000FFFFFFFFFFFFFull) != 0x0);
|
||||
}
|
||||
|
||||
bool hwf_manager::is_regular(hwf const & x) {
|
||||
// Everything that doesn't have the top-exponent is considered regular.
|
||||
// Note that +-0.0 and denormal numbers have exponent==0; these are regular.
|
||||
// All normal numbers are also regular. What remains is +-Inf and NaN, they are
|
||||
// not regular and they are the only numbers that have exponent 7FF.
|
||||
uint64 e = RAW(x.value) & 0x7FF0000000000000ull; // the exponent
|
||||
return (e != 0x7FF0000000000000ull);
|
||||
}
|
||||
|
||||
bool hwf_manager::is_int(hwf const & x) {
|
||||
if (!is_normal(x))
|
||||
return false;
|
||||
|
||||
const int e = exp(x);
|
||||
if (e >= 52)
|
||||
return true;
|
||||
else if (e < 0)
|
||||
return false;
|
||||
else
|
||||
{
|
||||
uint64 t = sig(x);
|
||||
unsigned shift = 52 - ((unsigned)e);
|
||||
uint64 mask = (0x1ull << shift) - 1;
|
||||
return (t & mask) == 0;
|
||||
}
|
||||
}
|
||||
|
||||
void hwf_manager::mk_nzero(hwf & o) {
|
||||
uint64 raw = 0x8000000000000000ull;
|
||||
o.value = DBL(raw);
|
||||
}
|
||||
|
||||
void hwf_manager::mk_pzero(hwf & o) {
|
||||
o.value = 0;
|
||||
}
|
||||
|
||||
void hwf_manager::mk_zero(bool sign, hwf & o) {
|
||||
if (sign)
|
||||
mk_nzero(o);
|
||||
else
|
||||
mk_pzero(o);
|
||||
}
|
||||
|
||||
void hwf_manager::mk_nan(hwf & o) {
|
||||
uint64 raw = 0x7FF0000000000001ull;
|
||||
o.value = DBL(raw);
|
||||
}
|
||||
|
||||
void hwf_manager::mk_inf(bool sign, hwf & o) {
|
||||
uint64 raw = (sign) ? 0xFFF0000000000000ull : 0x7FF0000000000000ull;
|
||||
o.value = DBL(raw);
|
||||
}
|
||||
|
||||
void hwf_manager::mk_pinf(hwf & o) {
|
||||
uint64 raw = 0x7FF0000000000000ull;
|
||||
o.value = DBL(raw);
|
||||
}
|
||||
|
||||
void hwf_manager::mk_ninf(hwf & o) {
|
||||
uint64 raw = 0xFFF0000000000000ull;
|
||||
o.value = DBL(raw);
|
||||
}
|
||||
|
||||
#ifdef _WINDOWS
|
||||
#if defined(_AMD64_) || defined(_M_IA64)
|
||||
#ifdef USE_INTRINSICS
|
||||
#define SETRM(RM) _MM_SET_ROUNDING_MODE(RM)
|
||||
#else
|
||||
#define SETRM(RM) _controlfp_s(&sse2_state, RM, _MCW_RC);
|
||||
#endif
|
||||
#else
|
||||
#ifdef USE_INTRINSICS
|
||||
#define SETRM(RM) _MM_SET_ROUNDING_MODE(RM)
|
||||
#else
|
||||
#define SETRM(RM) __control87_2(RM, _MCW_RC, &x86_state, &sse2_state)
|
||||
#endif
|
||||
#endif
|
||||
#else
|
||||
#define SETRM(RM) fesetround(RM)
|
||||
#endif
|
||||
|
||||
unsigned hwf_manager::prev_power_of_two(hwf const & a) {
|
||||
SASSERT(!is_nan(a) && !is_pinf(a) && !is_ninf(a));
|
||||
if (!is_pos(a))
|
||||
return 0;
|
||||
if (exp(a) <= -52)
|
||||
return 0;
|
||||
return 51 + exp(a);
|
||||
}
|
||||
|
||||
void hwf_manager::set_rounding_mode(mpf_rounding_mode rm)
|
||||
{
|
||||
#ifdef _WINDOWS
|
||||
switch (rm) {
|
||||
case MPF_ROUND_NEAREST_TEVEN:
|
||||
SETRM(_RC_NEAR);
|
||||
break;
|
||||
case MPF_ROUND_TOWARD_POSITIVE:
|
||||
SETRM(_RC_UP);
|
||||
break;
|
||||
case MPF_ROUND_TOWARD_NEGATIVE:
|
||||
SETRM(_RC_DOWN);
|
||||
break;
|
||||
case MPF_ROUND_TOWARD_ZERO:
|
||||
SETRM(_RC_CHOP);
|
||||
break;
|
||||
case MPF_ROUND_NEAREST_TAWAY:
|
||||
default:
|
||||
UNREACHABLE(); // Note: MPF_ROUND_NEAREST_TAWAY is not supported by the hardware!
|
||||
}
|
||||
#else // OSX/Linux
|
||||
switch (rm) {
|
||||
case MPF_ROUND_NEAREST_TEVEN:
|
||||
SETRM(FE_TONEAREST);
|
||||
break;
|
||||
case MPF_ROUND_TOWARD_POSITIVE:
|
||||
SETRM(FE_UPWARD);
|
||||
break;
|
||||
case MPF_ROUND_TOWARD_NEGATIVE:
|
||||
SETRM(FE_DOWNWARD);
|
||||
break;
|
||||
case MPF_ROUND_TOWARD_ZERO:
|
||||
SETRM(FE_TOWARDZERO);
|
||||
break;
|
||||
case MPF_ROUND_NEAREST_TAWAY:
|
||||
default:
|
||||
UNREACHABLE(); // Note: MPF_ROUND_NEAREST_TAWAY is not supported by the hardware!
|
||||
}
|
||||
#endif
|
||||
}
|
174
src/util/hwf.h
Normal file
174
src/util/hwf.h
Normal file
|
@ -0,0 +1,174 @@
|
|||
/*++
|
||||
Copyright (c) 2011 Microsoft Corporation
|
||||
|
||||
Module Name:
|
||||
|
||||
hwf.h
|
||||
|
||||
Abstract:
|
||||
|
||||
Hardware Floating Point Numbers
|
||||
|
||||
Author:
|
||||
|
||||
Christoph Wintersteiger (cwinter) 2012-07-30.
|
||||
|
||||
Revision History:
|
||||
|
||||
--*/
|
||||
#ifndef _HWF_H_
|
||||
#define _HWF_H_
|
||||
|
||||
#include<string>
|
||||
#include"mpz.h"
|
||||
#include"mpq.h"
|
||||
#include"mpf.h" // we use the same rounding modes as mpf's
|
||||
|
||||
class hwf {
|
||||
friend class hwf_manager;
|
||||
double value;
|
||||
hwf & operator=(hwf const & other) { UNREACHABLE(); return *this; }
|
||||
|
||||
public:
|
||||
hwf() {}
|
||||
hwf(hwf const & other) { this->value = other.value; }
|
||||
~hwf() {}
|
||||
void swap(hwf & other) { double t = value; value = other.value; other.value = t; }
|
||||
};
|
||||
|
||||
|
||||
class hwf_manager {
|
||||
unsynch_mpq_manager m_mpq_manager;
|
||||
unsynch_mpz_manager & m_mpz_manager; // A mpq_manager is a mpz_manager, reusing it.
|
||||
|
||||
public:
|
||||
typedef hwf numeral;
|
||||
hwf_manager();
|
||||
~hwf_manager();
|
||||
|
||||
void reset(hwf & o) { set(o, 0); }
|
||||
void set(hwf & o, int value);
|
||||
void set(hwf & o, mpf_rounding_mode rm, int n, int d);
|
||||
void set(hwf & o, float value);
|
||||
void set(hwf & o, double value);
|
||||
void set(hwf & o, mpf_rounding_mode rm, mpq const & value);
|
||||
void set(hwf & o, mpf_rounding_mode rm, char const * value);
|
||||
void set(hwf & o, mpf_rounding_mode rm, mpq const & significand, mpz const & exponent);
|
||||
void set(hwf & o, bool sign, uint64 significand, int exponent);
|
||||
void set(hwf & o, hwf const & x);
|
||||
|
||||
// auxiliary methods to make the interface compatible with mpf
|
||||
void reset(hwf & o, unsigned ebits, unsigned sbits) { set(o, 0); }
|
||||
void set(hwf & o, unsigned ebits, unsigned sbits, mpf_rounding_mode rm, mpq const & value) { set(o, rm, value); }
|
||||
void set(hwf & o, unsigned ebits, unsigned sbits, int value) { set(o, value); }
|
||||
void set(hwf & o, unsigned ebits, unsigned sbits, mpf_rounding_mode rm, int n, int d) { set(o, rm, n, d); }
|
||||
void set(hwf & o, unsigned ebits, unsigned sbits, float value) { set(o, value); }
|
||||
void set(hwf & o, unsigned ebits, unsigned sbits, double value) { set(o, value); }
|
||||
|
||||
|
||||
void del(hwf & x) {}
|
||||
|
||||
void abs(hwf & o);
|
||||
void abs(hwf const & x, hwf & o);
|
||||
|
||||
void neg(hwf & o);
|
||||
void neg(hwf const & x, hwf & o);
|
||||
|
||||
bool is_zero(hwf const & x);
|
||||
bool is_neg(hwf const & x);
|
||||
bool is_pos(hwf const & x);
|
||||
|
||||
bool is_nzero(hwf const & x);
|
||||
bool is_pzero(hwf const & x);
|
||||
|
||||
bool is_one(hwf const & x);
|
||||
|
||||
// structural eq
|
||||
bool eq_core(hwf const & x, hwf const & y);
|
||||
|
||||
bool eq(hwf const & x, hwf const & y);
|
||||
bool lt(hwf const & x, hwf const & y);
|
||||
bool lte(hwf const & x, hwf const & y);
|
||||
bool le(hwf const & x, hwf const & y) { return lte(x, y); }
|
||||
bool gt(hwf const & x, hwf const & y);
|
||||
bool gte(hwf const & x, hwf const & y);
|
||||
bool ge(hwf const & x, hwf const & y) { return gte(x, y); }
|
||||
|
||||
void add(mpf_rounding_mode rm, hwf const & x, hwf const & y, hwf & o);
|
||||
void sub(mpf_rounding_mode rm, hwf const & x, hwf const & y, hwf & o);
|
||||
void mul(mpf_rounding_mode rm, hwf const & x, hwf const & y, hwf & o);
|
||||
void div(mpf_rounding_mode rm, hwf const & x, hwf const & y, hwf & o);
|
||||
|
||||
void fused_mul_add(mpf_rounding_mode rm, hwf const & x, hwf const & y, hwf const &z, hwf & o);
|
||||
|
||||
void sqrt(mpf_rounding_mode rm, hwf const & x, hwf & o);
|
||||
|
||||
void round_to_integral(mpf_rounding_mode rm, hwf const & x, hwf & o);
|
||||
|
||||
void rem(hwf const & x, hwf const & y, hwf & o);
|
||||
|
||||
void maximum(hwf const & x, hwf const & y, hwf & o);
|
||||
void minimum(hwf const & x, hwf const & y, hwf & o);
|
||||
|
||||
std::string to_string(hwf const & a);
|
||||
std::string to_rational_string(hwf const & a);
|
||||
void display_decimal(std::ostream & out, hwf const & a, unsigned k);
|
||||
void display_smt2(std::ostream & out, hwf const & a, bool decimal);
|
||||
|
||||
double to_double(hwf const & x) { return x.value; }
|
||||
float to_float(hwf const & x) { return (float) x.value; }
|
||||
void to_rational(hwf const & x, unsynch_mpq_manager & qm, mpq & o);
|
||||
void to_rational(hwf const & x, scoped_mpq & o) { to_rational(x, o.m(), o); }
|
||||
|
||||
|
||||
bool sgn(hwf const & x) const {
|
||||
uint64 raw = *reinterpret_cast<uint64 const *>(&x.value);
|
||||
return (raw & 0x8000000000000000ull) != 0;
|
||||
}
|
||||
|
||||
const uint64 sig(hwf const & x) const {
|
||||
return *reinterpret_cast<uint64 const *>(&x.value) & 0x000FFFFFFFFFFFFFull;
|
||||
}
|
||||
|
||||
const int exp(hwf const & x) const {
|
||||
return ((*reinterpret_cast<uint64 const *>(&x.value) & 0x7FF0000000000000ull) >> 52) - 1023;
|
||||
}
|
||||
|
||||
bool is_nan(hwf const & x);
|
||||
bool is_inf(hwf const & x);
|
||||
bool is_pinf(hwf const & x);
|
||||
bool is_ninf(hwf const & x);
|
||||
bool is_normal(hwf const & x);
|
||||
bool is_denormal(hwf const & x);
|
||||
bool is_regular(hwf const & x);
|
||||
bool is_int(hwf const & x);
|
||||
|
||||
void mk_zero(bool sign, hwf & o);
|
||||
void mk_nzero(hwf & o);
|
||||
void mk_pzero(hwf & o);
|
||||
void mk_nan(hwf & o);
|
||||
void mk_inf(bool sign, hwf & o);
|
||||
void mk_pinf(hwf & o);
|
||||
void mk_ninf(hwf & o);
|
||||
|
||||
unsigned hash(hwf const & a) { return hash_ull(*reinterpret_cast<const unsigned long long*>(&a.value)); }
|
||||
|
||||
inline void set_rounding_mode(mpf_rounding_mode rm);
|
||||
|
||||
/**
|
||||
\brief Return the biggest k s.t. 2^k <= a.
|
||||
|
||||
\remark Return 0 if a is not positive.
|
||||
*/
|
||||
unsigned prev_power_of_two(hwf const & a);
|
||||
|
||||
protected:
|
||||
#ifdef _WINDOWS
|
||||
unsigned x86_state, sse2_state;
|
||||
#endif
|
||||
};
|
||||
|
||||
typedef _scoped_numeral<hwf_manager> scoped_hwf;
|
||||
typedef _scoped_numeral_vector<hwf_manager> scoped_hwf_vector;
|
||||
|
||||
#endif
|
83
src/util/id_gen.h
Normal file
83
src/util/id_gen.h
Normal file
|
@ -0,0 +1,83 @@
|
|||
/*++
|
||||
Copyright (c) 2006 Microsoft Corporation
|
||||
|
||||
Module Name:
|
||||
|
||||
id_gen.h
|
||||
|
||||
Abstract:
|
||||
|
||||
Basic support for generating & recycling ids.
|
||||
|
||||
Author:
|
||||
|
||||
Leonardo de Moura (leonardo) 2008-02-02.
|
||||
|
||||
Revision History:
|
||||
|
||||
--*/
|
||||
#ifndef _ID_GEN_H_
|
||||
#define _ID_GEN_H_
|
||||
|
||||
#include"vector.h"
|
||||
#include"util.h"
|
||||
|
||||
class id_gen {
|
||||
unsigned m_next_id;
|
||||
unsigned_vector m_free_ids;
|
||||
public:
|
||||
id_gen(unsigned start = 0):m_next_id(start) {}
|
||||
|
||||
unsigned mk() {
|
||||
unsigned r;
|
||||
if (m_free_ids.empty()) {
|
||||
r = m_next_id;
|
||||
m_next_id++;
|
||||
}
|
||||
else {
|
||||
r = m_free_ids.back();
|
||||
m_free_ids.pop_back();
|
||||
}
|
||||
return r;
|
||||
}
|
||||
|
||||
void recycle(unsigned id) {
|
||||
if (memory::is_out_of_memory())
|
||||
return;
|
||||
m_free_ids.push_back(id);
|
||||
}
|
||||
|
||||
void reset(unsigned start = 0) {
|
||||
m_next_id = start;
|
||||
m_free_ids.reset();
|
||||
}
|
||||
|
||||
void cleanup(unsigned start = 0) {
|
||||
m_next_id = start;
|
||||
m_free_ids.finalize();
|
||||
}
|
||||
|
||||
/**
|
||||
\brief Return N if the range of ids generated by this module is in the set [0..N)
|
||||
*/
|
||||
unsigned get_id_range() const { return m_next_id; }
|
||||
|
||||
|
||||
/**
|
||||
\brief Debugging support method: set m_next_id to the least value id' s.t. id' >= id and id' is not in m_free_ids.
|
||||
This method is only used to create small repros that exposes bugs in Z3.
|
||||
*/
|
||||
unsigned set_next_id(unsigned id) {
|
||||
m_next_id = id;
|
||||
while (std::find(m_free_ids.begin(), m_free_ids.end(), m_next_id) != m_free_ids.end())
|
||||
m_next_id++;
|
||||
return m_next_id;
|
||||
}
|
||||
|
||||
void display_free_ids(std::ostream & out) {
|
||||
::display(out, m_free_ids.begin(), m_free_ids.end());
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
#endif /* _ID_GEN_H_ */
|
3690
src/util/imdd.cpp
Normal file
3690
src/util/imdd.cpp
Normal file
File diff suppressed because it is too large
Load diff
849
src/util/imdd.h
Normal file
849
src/util/imdd.h
Normal file
|
@ -0,0 +1,849 @@
|
|||
/*++
|
||||
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_ */
|
||||
|
41
src/util/inf_int_rational.cpp
Normal file
41
src/util/inf_int_rational.cpp
Normal file
|
@ -0,0 +1,41 @@
|
|||
/*++
|
||||
Copyright (c) 2006 Microsoft Corporation
|
||||
|
||||
Module Name:
|
||||
|
||||
inf_int_rational.cpp
|
||||
|
||||
Abstract:
|
||||
|
||||
Rational numbers with infenitesimals
|
||||
|
||||
Author:
|
||||
|
||||
Nikolaj Bjorner (nbjorner) 2006-12-05.
|
||||
|
||||
Revision History:
|
||||
|
||||
--*/
|
||||
#include<sstream>
|
||||
#include"inf_int_rational.h"
|
||||
|
||||
inf_int_rational inf_int_rational::m_zero(0);
|
||||
inf_int_rational inf_int_rational::m_one(1);
|
||||
inf_int_rational inf_int_rational::m_minus_one(-1);
|
||||
|
||||
std::string inf_int_rational::to_string() const {
|
||||
if (m_second == 0) {
|
||||
return m_first.to_string();
|
||||
}
|
||||
std::ostringstream s;
|
||||
|
||||
s << "(" << m_first.to_string();
|
||||
if (m_second < 0) {
|
||||
s << " -e*" << (-m_second) << ")";
|
||||
}
|
||||
else {
|
||||
s << " +e*" << m_second << ")";
|
||||
}
|
||||
return s.str();
|
||||
}
|
||||
|
372
src/util/inf_int_rational.h
Normal file
372
src/util/inf_int_rational.h
Normal file
|
@ -0,0 +1,372 @@
|
|||
/*++
|
||||
Copyright (c) 2006 Microsoft Corporation
|
||||
|
||||
Module Name:
|
||||
|
||||
inf_int_rational.h
|
||||
|
||||
Abstract:
|
||||
|
||||
Rational numbers with infenitesimals
|
||||
|
||||
Author:
|
||||
|
||||
Leonardo de Moura (leonardo) 2006-09-18.
|
||||
Nikolaj Bjorner (nbjorner) 2006-10-24.
|
||||
|
||||
Revision History:
|
||||
|
||||
--*/
|
||||
#ifndef _INF_INT_RATIONAL_H_
|
||||
#define _INF_INT_RATIONAL_H_
|
||||
#include<stdlib.h>
|
||||
#include<string>
|
||||
#include"debug.h"
|
||||
#include"vector.h"
|
||||
#include"rational.h"
|
||||
|
||||
|
||||
class inf_int_rational {
|
||||
static inf_int_rational m_zero;
|
||||
static inf_int_rational m_one;
|
||||
static inf_int_rational m_minus_one;
|
||||
rational m_first;
|
||||
int m_second;
|
||||
public:
|
||||
|
||||
unsigned hash() const {
|
||||
return m_first.hash() ^ (static_cast<unsigned>(m_second) + 1);
|
||||
}
|
||||
|
||||
struct hash_proc { unsigned operator()(inf_int_rational const& r) const { return r.hash(); } };
|
||||
|
||||
struct eq_proc { bool operator()(inf_int_rational const& r1, inf_int_rational const& r2) const { return r1 == r2; } };
|
||||
|
||||
void swap(inf_int_rational & n) {
|
||||
m_first.swap(n.m_first);
|
||||
std::swap(m_second, n.m_second);
|
||||
}
|
||||
|
||||
std::string to_string() const;
|
||||
|
||||
inf_int_rational():
|
||||
m_first(rational()),
|
||||
m_second(0)
|
||||
{}
|
||||
|
||||
inf_int_rational(const inf_int_rational & r):
|
||||
m_first(r.m_first),
|
||||
m_second(r.m_second)
|
||||
{}
|
||||
|
||||
explicit inf_int_rational(int n):
|
||||
m_first(rational(n)),
|
||||
m_second(0)
|
||||
{}
|
||||
|
||||
explicit inf_int_rational(int n, int d):
|
||||
m_first(rational(n,d)),
|
||||
m_second(0)
|
||||
{}
|
||||
|
||||
explicit inf_int_rational(rational const& r, bool pos_inf):
|
||||
m_first(r),
|
||||
m_second(pos_inf?1:-1)
|
||||
{}
|
||||
|
||||
explicit inf_int_rational(rational const& r):
|
||||
m_first(r),
|
||||
m_second(0) {}
|
||||
|
||||
inf_int_rational(rational const& r, int i):
|
||||
m_first(r),
|
||||
m_second(i) {
|
||||
}
|
||||
|
||||
~inf_int_rational() {}
|
||||
|
||||
/**
|
||||
\brief Set inf_int_rational to 0.
|
||||
*/
|
||||
void reset() {
|
||||
m_first.reset();
|
||||
m_second = 0;
|
||||
}
|
||||
|
||||
bool is_int() const {
|
||||
return m_first.is_int() && m_second == 0;
|
||||
}
|
||||
|
||||
bool is_int64() const {
|
||||
return m_first.is_int64() && m_second == 0;
|
||||
}
|
||||
|
||||
bool is_uint64() const {
|
||||
return m_first.is_uint64() && m_second == 0;
|
||||
}
|
||||
|
||||
bool is_rational() const { return m_second == 0; }
|
||||
|
||||
int64 get_int64() const {
|
||||
SASSERT(is_int64());
|
||||
return m_first.get_int64();
|
||||
}
|
||||
|
||||
uint64 get_uint64() const {
|
||||
SASSERT(is_uint64());
|
||||
return m_first.get_uint64();
|
||||
}
|
||||
|
||||
rational const& get_rational() const {
|
||||
return m_first;
|
||||
}
|
||||
|
||||
rational get_infinitesimal() const {
|
||||
return rational(m_second);
|
||||
}
|
||||
|
||||
rational const & get_first() const { return m_first; }
|
||||
|
||||
inf_int_rational & operator=(const inf_int_rational & r) {
|
||||
m_first = r.m_first;
|
||||
m_second = r.m_second;
|
||||
return *this;
|
||||
}
|
||||
|
||||
inf_int_rational & operator=(const rational & r) {
|
||||
m_first = r;
|
||||
m_second = 0;
|
||||
return *this;
|
||||
}
|
||||
|
||||
friend inline inf_int_rational numerator(const inf_int_rational & r) {
|
||||
SASSERT(r.m_second == 0);
|
||||
return inf_int_rational(numerator(r.m_first));
|
||||
}
|
||||
|
||||
friend inline inf_int_rational denominator(const inf_int_rational & r) {
|
||||
SASSERT(r.m_second == 0);
|
||||
return inf_int_rational(denominator(r.m_first));
|
||||
}
|
||||
|
||||
inf_int_rational & operator+=(const inf_int_rational & r) {
|
||||
m_first += r.m_first;
|
||||
m_second += r.m_second;
|
||||
return *this;
|
||||
}
|
||||
|
||||
inf_int_rational & operator-=(const inf_int_rational & r) {
|
||||
m_first -= r.m_first;
|
||||
m_second -= r.m_second;
|
||||
return *this;
|
||||
}
|
||||
|
||||
inf_int_rational & operator+=(const rational & r) {
|
||||
m_first += r;
|
||||
return *this;
|
||||
}
|
||||
|
||||
inf_int_rational & operator-=(const rational & r) {
|
||||
m_first -= r;
|
||||
return *this;
|
||||
}
|
||||
|
||||
inf_int_rational & operator++() {
|
||||
++m_first;
|
||||
return *this;
|
||||
}
|
||||
|
||||
const inf_int_rational operator++(int) { inf_int_rational tmp(*this); ++(*this); return tmp; }
|
||||
|
||||
inf_int_rational & operator--() {
|
||||
--m_first;
|
||||
return *this;
|
||||
}
|
||||
|
||||
const inf_int_rational operator--(int) { inf_int_rational tmp(*this); --(*this); return tmp; }
|
||||
|
||||
friend inline bool operator==(const inf_int_rational & r1, const inf_int_rational & r2) {
|
||||
return r1.m_first == r2.m_first && r1.m_second == r2.m_second;
|
||||
}
|
||||
|
||||
friend inline bool operator==(const rational & r1, const inf_int_rational & r2) {
|
||||
return r1 == r2.m_first && r2.m_second == 0;
|
||||
}
|
||||
|
||||
friend inline bool operator==(const inf_int_rational & r1, const rational & r2) {
|
||||
return r1.m_first == r2 && r1.m_second == 0;
|
||||
}
|
||||
|
||||
friend inline bool operator<(const inf_int_rational & r1, const inf_int_rational & r2) {
|
||||
return
|
||||
(r1.m_first < r2.m_first) ||
|
||||
(r1.m_first == r2.m_first && r1.m_second < r2.m_second);
|
||||
}
|
||||
|
||||
friend inline bool operator<(const rational & r1, const inf_int_rational & r2) {
|
||||
return
|
||||
(r1 < r2.m_first) ||
|
||||
(r1 == r2.m_first && r2.m_second > 0);
|
||||
}
|
||||
|
||||
friend inline bool operator<(const inf_int_rational & r1, const rational & r2) {
|
||||
return
|
||||
(r1.m_first < r2) ||
|
||||
(r1.m_first == r2 && r1.m_second < 0);
|
||||
}
|
||||
|
||||
void neg() {
|
||||
m_first.neg();
|
||||
m_second = -m_second;
|
||||
}
|
||||
|
||||
bool is_zero() const {
|
||||
return m_first.is_zero() && m_second == 0;
|
||||
}
|
||||
|
||||
bool is_one() const {
|
||||
return m_first.is_one() && m_second == 0;
|
||||
}
|
||||
|
||||
bool is_minus_one() const {
|
||||
return m_first.is_minus_one() && m_second == 0;
|
||||
}
|
||||
|
||||
bool is_neg() const {
|
||||
return
|
||||
m_first.is_neg() ||
|
||||
(m_first.is_zero() && m_second < 0);
|
||||
}
|
||||
|
||||
bool is_pos() const {
|
||||
return
|
||||
m_first.is_pos() ||
|
||||
(m_first.is_zero() && m_second > 0);
|
||||
}
|
||||
|
||||
bool is_nonneg() const {
|
||||
return
|
||||
m_first.is_pos() ||
|
||||
(m_first.is_zero() && m_second >= 0);
|
||||
}
|
||||
|
||||
bool is_nonpos() const {
|
||||
return
|
||||
m_first.is_neg() ||
|
||||
(m_first.is_zero() && m_second <= 0);
|
||||
}
|
||||
|
||||
friend inline rational floor(const inf_int_rational & r) {
|
||||
if (r.m_first.is_int()) {
|
||||
if (r.m_second >= 0) {
|
||||
return r.m_first;
|
||||
}
|
||||
return r.m_first - rational(1);
|
||||
}
|
||||
|
||||
return floor(r.m_first);
|
||||
}
|
||||
|
||||
friend inline rational ceil(const inf_int_rational & r) {
|
||||
if (r.m_first.is_int()) {
|
||||
if (r.m_second <= 0) {
|
||||
return r.m_first;
|
||||
}
|
||||
return r.m_first + rational(1);
|
||||
}
|
||||
|
||||
return ceil(r.m_first);
|
||||
}
|
||||
|
||||
static const inf_int_rational & zero() {
|
||||
return m_zero;
|
||||
}
|
||||
|
||||
static const inf_int_rational & one() {
|
||||
return m_one;
|
||||
}
|
||||
|
||||
static const inf_int_rational & minus_one() {
|
||||
return m_minus_one;
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
inline bool operator!=(const inf_int_rational & r1, const inf_int_rational & r2) {
|
||||
return !operator==(r1, r2);
|
||||
}
|
||||
|
||||
inline bool operator!=(const rational & r1, const inf_int_rational & r2) {
|
||||
return !operator==(r1, r2);
|
||||
}
|
||||
|
||||
inline bool operator!=(const inf_int_rational & r1, const rational & r2) {
|
||||
return !operator==(r1, r2);
|
||||
}
|
||||
|
||||
inline bool operator>(const inf_int_rational & r1, const inf_int_rational & r2) {
|
||||
return operator<(r2, r1);
|
||||
}
|
||||
|
||||
inline bool operator>(const inf_int_rational & r1, const rational & r2) {
|
||||
return operator<(r2, r1);
|
||||
}
|
||||
|
||||
inline bool operator>(const rational & r1, const inf_int_rational & r2) {
|
||||
return operator<(r2, r1);
|
||||
}
|
||||
|
||||
inline bool operator<=(const inf_int_rational & r1, const inf_int_rational & r2) {
|
||||
return !operator>(r1, r2);
|
||||
}
|
||||
|
||||
inline bool operator<=(const rational & r1, const inf_int_rational & r2) {
|
||||
return !operator>(r1, r2);
|
||||
}
|
||||
|
||||
inline bool operator<=(const inf_int_rational & r1, const rational & r2) {
|
||||
return !operator>(r1, r2);
|
||||
}
|
||||
|
||||
inline bool operator>=(const inf_int_rational & r1, const inf_int_rational & r2) {
|
||||
return !operator<(r1, r2);
|
||||
}
|
||||
|
||||
inline bool operator>=(const rational & r1, const inf_int_rational & r2) {
|
||||
return !operator<(r1, r2);
|
||||
}
|
||||
|
||||
inline bool operator>=(const inf_int_rational & r1, const rational & r2) {
|
||||
return !operator<(r1, r2);
|
||||
}
|
||||
|
||||
inline inf_int_rational operator+(const inf_int_rational & r1, const inf_int_rational & r2) {
|
||||
return inf_int_rational(r1) += r2;
|
||||
}
|
||||
|
||||
inline inf_int_rational operator-(const inf_int_rational & r1, const inf_int_rational & r2) {
|
||||
return inf_int_rational(r1) -= r2;
|
||||
}
|
||||
|
||||
inline inf_int_rational operator-(const inf_int_rational & r) {
|
||||
inf_int_rational result(r);
|
||||
result.neg();
|
||||
return result;
|
||||
}
|
||||
|
||||
inline std::ostream & operator<<(std::ostream & target, const inf_int_rational & r)
|
||||
{
|
||||
target << r.to_string();
|
||||
return target;
|
||||
}
|
||||
|
||||
|
||||
inline inf_int_rational abs(const inf_int_rational & r) {
|
||||
inf_int_rational result(r);
|
||||
if (result.is_neg()) {
|
||||
result.neg();
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
#endif /* _INF_INT_RATIONAL_H_ */
|
179
src/util/inf_rational.cpp
Normal file
179
src/util/inf_rational.cpp
Normal file
|
@ -0,0 +1,179 @@
|
|||
/*++
|
||||
Copyright (c) 2006 Microsoft Corporation
|
||||
|
||||
Module Name:
|
||||
|
||||
inf_rational.cpp
|
||||
|
||||
Abstract:
|
||||
|
||||
Rational numbers with infenitesimals
|
||||
|
||||
Author:
|
||||
|
||||
Nikolaj Bjorner (nbjorner) 2006-12-05.
|
||||
|
||||
Revision History:
|
||||
|
||||
--*/
|
||||
#include"inf_rational.h"
|
||||
|
||||
inf_rational inf_rational::m_zero(0);
|
||||
inf_rational inf_rational::m_one(1);
|
||||
inf_rational inf_rational::m_minus_one(-1);
|
||||
|
||||
inf_rational inf_mult(inf_rational const& r1, inf_rational const& r2)
|
||||
{
|
||||
inf_rational result;
|
||||
result.m_first = r1.m_first * r2.m_first;
|
||||
result.m_second = (r1.m_first * r2.m_second) + (r1.m_second * r2.m_first);
|
||||
|
||||
if (r1.m_second.is_pos() && r2.m_second.is_neg()) {
|
||||
--result.m_second;
|
||||
}
|
||||
else if (r1.m_second.is_neg() && r2.m_second.is_pos()) {
|
||||
--result.m_second;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
inf_rational sup_mult(inf_rational const& r1, inf_rational const& r2)
|
||||
{
|
||||
inf_rational result;
|
||||
result.m_first = r1.m_first * r2.m_first;
|
||||
result.m_second = (r1.m_first * r2.m_second) + (r1.m_second * r2.m_first);
|
||||
|
||||
if (r1.m_second.is_pos() && r2.m_second.is_pos()) {
|
||||
++result.m_second;
|
||||
}
|
||||
else if (r1.m_second.is_neg() && r2.m_second.is_neg()) {
|
||||
++result.m_second;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
//
|
||||
// Find rationals c, x, such that c + epsilon*x <= r1/r2
|
||||
//
|
||||
// let r1 = a + d_1
|
||||
// let r2 = b + d_2
|
||||
//
|
||||
// suppose b != 0:
|
||||
//
|
||||
// r1/b <= r1/r2
|
||||
// <=> { if b > 0, then r2 > 0, and cross multiplication does not change the sign }
|
||||
// { if b < 0, then r2 < 0, and cross multiplication changes sign twice }
|
||||
// r1 * r2 <= b * r1
|
||||
// <=>
|
||||
// r1 * (b + d_2) <= r1 * b
|
||||
// <=>
|
||||
// r1 * d_2 <= 0
|
||||
//
|
||||
// if r1 * d_2 > 0, then r1/(b + sign_of(r1)*1/2*|b|) <= r1/r2
|
||||
//
|
||||
// Not handled here:
|
||||
// if b = 0, then d_2 != 0
|
||||
// if r1 * d_2 = 0 then it's 0.
|
||||
// if r1 * d_2 > 0, then result is +oo
|
||||
// if r1 * d_2 < 0, then result is -oo
|
||||
//
|
||||
inf_rational inf_div(inf_rational const& r1, inf_rational const& r2)
|
||||
{
|
||||
SASSERT(!r2.m_first.is_zero());
|
||||
inf_rational result;
|
||||
|
||||
if (r2.m_second.is_neg() && r1.is_neg()) {
|
||||
result = r1 / (r2.m_first - (abs(r2.m_first)/rational(2)));
|
||||
}
|
||||
else if (r2.m_second.is_pos() && r1.is_pos()) {
|
||||
result = r1 / (r2.m_first + (abs(r2.m_first)/rational(2)));
|
||||
}
|
||||
else {
|
||||
result = r1 / r2.m_first;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
inf_rational sup_div(inf_rational const& r1, inf_rational const& r2)
|
||||
{
|
||||
SASSERT(!r2.m_first.is_zero());
|
||||
inf_rational result;
|
||||
|
||||
if (r2.m_second.is_pos() && r1.is_neg()) {
|
||||
result = r1 / (r2.m_first + (abs(r2.m_first)/rational(2)));
|
||||
}
|
||||
else if (r2.m_second.is_neg() && r1.is_pos()) {
|
||||
result = r1 / (r2.m_first - (abs(r2.m_first)/rational(2)));
|
||||
}
|
||||
else {
|
||||
result = r1 / r2.m_first;
|
||||
}
|
||||
return result;
|
||||
|
||||
}
|
||||
|
||||
inf_rational inf_power(inf_rational const& r, unsigned n)
|
||||
{
|
||||
bool is_even = (0 == (n & 0x1));
|
||||
inf_rational result;
|
||||
if (n == 1) {
|
||||
result = r;
|
||||
}
|
||||
else if ((r.m_second.is_zero()) ||
|
||||
(r.m_first.is_pos() && r.m_second.is_pos()) ||
|
||||
(r.m_first.is_neg() && r.m_second.is_neg() && is_even)) {
|
||||
result.m_first = r.m_first.expt(n);
|
||||
}
|
||||
else if (is_even) {
|
||||
// 0 will work.
|
||||
}
|
||||
else if (r.m_first.is_zero()) {
|
||||
result.m_first = rational(-1);
|
||||
}
|
||||
else if (r.m_first.is_pos()) {
|
||||
result.m_first = rational(r.m_first - r.m_first/rational(2)).expt(n);
|
||||
}
|
||||
else {
|
||||
result.m_first = rational(r.m_first + r.m_first/rational(2)).expt(n);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
inf_rational sup_power(inf_rational const& r, unsigned n)
|
||||
{
|
||||
bool is_even = (0 == (n & 0x1));
|
||||
inf_rational result;
|
||||
if (n == 1) {
|
||||
result = r;
|
||||
}
|
||||
else if (r.m_second.is_zero() ||
|
||||
(r.m_first.is_pos() && r.m_second.is_neg()) ||
|
||||
(r.m_first.is_neg() && r.m_second.is_pos() && is_even)) {
|
||||
result.m_first = r.m_first.expt(n);
|
||||
}
|
||||
else if (r.m_first.is_zero() || (n == 0)) {
|
||||
result.m_first = rational(1);
|
||||
}
|
||||
else if (r.m_first.is_pos() || is_even) {
|
||||
result.m_first = rational(r.m_first + r.m_first/rational(2)).expt(n);
|
||||
}
|
||||
else {
|
||||
// r (r.m_first) is negative, n is odd.
|
||||
result.m_first = rational(r.m_first - r.m_first/rational(2)).expt(n);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
inf_rational inf_root(inf_rational const& r, unsigned n)
|
||||
{
|
||||
SASSERT(!r.is_neg());
|
||||
// use 0
|
||||
return inf_rational();
|
||||
}
|
||||
|
||||
inf_rational sup_root(inf_rational const& r, unsigned n)
|
||||
{
|
||||
SASSERT(!r.is_neg());
|
||||
// use r.
|
||||
return r;
|
||||
}
|
470
src/util/inf_rational.h
Normal file
470
src/util/inf_rational.h
Normal file
|
@ -0,0 +1,470 @@
|
|||
/*++
|
||||
Copyright (c) 2006 Microsoft Corporation
|
||||
|
||||
Module Name:
|
||||
|
||||
inf_rational.h
|
||||
|
||||
Abstract:
|
||||
|
||||
Rational numbers with infenitesimals
|
||||
|
||||
Author:
|
||||
|
||||
Leonardo de Moura (leonardo) 2006-09-18.
|
||||
Nikolaj Bjorner (nbjorner) 2006-10-24.
|
||||
|
||||
Revision History:
|
||||
|
||||
--*/
|
||||
#ifndef _INF_RATIONAL_H_
|
||||
#define _INF_RATIONAL_H_
|
||||
#include<stdlib.h>
|
||||
#include<string>
|
||||
#include"debug.h"
|
||||
#include"vector.h"
|
||||
#include"rational.h"
|
||||
|
||||
|
||||
class inf_rational {
|
||||
static inf_rational m_zero;
|
||||
static inf_rational m_one;
|
||||
static inf_rational m_minus_one;
|
||||
rational m_first;
|
||||
rational m_second;
|
||||
public:
|
||||
|
||||
unsigned hash() const {
|
||||
return m_first.hash() ^ (m_second.hash()+1);
|
||||
}
|
||||
|
||||
struct hash_proc { unsigned operator()(inf_rational const& r) const { return r.hash(); } };
|
||||
|
||||
struct eq_proc { bool operator()(inf_rational const& r1, inf_rational const& r2) const { return r1 == r2; } };
|
||||
|
||||
void swap(inf_rational & n) {
|
||||
m_first.swap(n.m_first);
|
||||
m_second.swap(n.m_second);
|
||||
}
|
||||
std::string to_string() const {
|
||||
if (m_second.is_zero()) {
|
||||
return m_first.to_string();
|
||||
}
|
||||
std::string s = "(";
|
||||
s += m_first.to_string();
|
||||
if (m_second.is_neg()) {
|
||||
s += " -e*";
|
||||
}
|
||||
else {
|
||||
s += " +e*";
|
||||
}
|
||||
s += abs(m_second).to_string();
|
||||
s += ")";
|
||||
return s;
|
||||
}
|
||||
|
||||
inf_rational():
|
||||
m_first(rational()),
|
||||
m_second(rational())
|
||||
{}
|
||||
|
||||
inf_rational(const inf_rational & r):
|
||||
m_first(r.m_first),
|
||||
m_second(r.m_second)
|
||||
{}
|
||||
|
||||
explicit inf_rational(int n):
|
||||
m_first(rational(n)),
|
||||
m_second(rational())
|
||||
{}
|
||||
|
||||
explicit inf_rational(int n, int d):
|
||||
m_first(rational(n,d)),
|
||||
m_second(rational())
|
||||
{}
|
||||
|
||||
explicit inf_rational(rational const& r, bool pos_inf):
|
||||
m_first(r),
|
||||
m_second(pos_inf?rational(1):rational(-1))
|
||||
{}
|
||||
|
||||
explicit inf_rational(rational const& r):
|
||||
m_first(r)
|
||||
{
|
||||
m_second.reset();
|
||||
}
|
||||
|
||||
inf_rational(rational const& r, rational const& i):
|
||||
m_first(r),
|
||||
m_second(i) {
|
||||
}
|
||||
|
||||
~inf_rational() {}
|
||||
|
||||
/**
|
||||
\brief Set inf_rational to 0.
|
||||
*/
|
||||
void reset() {
|
||||
m_first.reset();
|
||||
m_second.reset();
|
||||
}
|
||||
|
||||
bool is_int() const {
|
||||
return m_first.is_int() && m_second.is_zero();
|
||||
}
|
||||
|
||||
bool is_int64() const {
|
||||
return m_first.is_int64() && m_second.is_zero();
|
||||
}
|
||||
|
||||
bool is_uint64() const {
|
||||
return m_first.is_uint64() && m_second.is_zero();
|
||||
}
|
||||
|
||||
bool is_rational() const { return m_second.is_zero(); }
|
||||
|
||||
int64 get_int64() const {
|
||||
SASSERT(is_int64());
|
||||
return m_first.get_int64();
|
||||
}
|
||||
|
||||
uint64 get_uint64() const {
|
||||
SASSERT(is_uint64());
|
||||
return m_first.get_uint64();
|
||||
}
|
||||
|
||||
rational const& get_rational() const {
|
||||
return m_first;
|
||||
}
|
||||
|
||||
rational const& get_infinitesimal() const {
|
||||
return m_second;
|
||||
}
|
||||
|
||||
rational const & get_first() const { return m_first; }
|
||||
|
||||
inf_rational & operator=(const inf_rational & r) {
|
||||
m_first = r.m_first;
|
||||
m_second = r.m_second;
|
||||
return *this;
|
||||
}
|
||||
|
||||
inf_rational & operator=(const rational & r) {
|
||||
m_first = r;
|
||||
m_second.reset();
|
||||
return *this;
|
||||
}
|
||||
|
||||
friend inline inf_rational numerator(const inf_rational & r) {
|
||||
SASSERT(r.m_second.is_zero());
|
||||
return inf_rational(numerator(r.m_first));
|
||||
}
|
||||
|
||||
friend inline inf_rational denominator(const inf_rational & r) {
|
||||
SASSERT(r.m_second.is_zero());
|
||||
return inf_rational(denominator(r.m_first));
|
||||
}
|
||||
|
||||
inf_rational & operator+=(const inf_rational & r) {
|
||||
m_first += r.m_first;
|
||||
m_second += r.m_second;
|
||||
return *this;
|
||||
}
|
||||
|
||||
inf_rational & operator-=(const inf_rational & r) {
|
||||
m_first -= r.m_first;
|
||||
m_second -= r.m_second;
|
||||
return *this;
|
||||
}
|
||||
|
||||
inf_rational & operator+=(const rational & r) {
|
||||
m_first += r;
|
||||
return *this;
|
||||
}
|
||||
|
||||
inf_rational & operator-=(const rational & r) {
|
||||
m_first -= r;
|
||||
return *this;
|
||||
}
|
||||
|
||||
inf_rational & operator*=(const rational & r1) {
|
||||
m_first *= r1;
|
||||
m_second *= r1;
|
||||
return *this;
|
||||
}
|
||||
|
||||
//
|
||||
// These operations get us out of the realm of inf_rational:
|
||||
// (r1 + e*k1)*(r2 + e*k2) = (r1*r2 + (r1*k2 + r2*k1)*e)
|
||||
//
|
||||
// inf_rational & operator*=(const inf_rational & r)
|
||||
// inf_rational & operator/=(const inf_rational & r)
|
||||
// inf_rational & operator%=(const inf_rational & r)
|
||||
// friend inline inf_rational div(const inf_rational & r1, const inf_rational & r2)
|
||||
// inf_rational expt(int n)
|
||||
// instead, we define operators that approximate some of these operations from above and below.
|
||||
|
||||
friend inf_rational inf_mult(inf_rational const& r1, inf_rational const& r2);
|
||||
friend inf_rational sup_mult(inf_rational const& r1, inf_rational const& r2);
|
||||
|
||||
friend inf_rational inf_div(inf_rational const& r1, inf_rational const& r2);
|
||||
friend inf_rational sup_div(inf_rational const& r1, inf_rational const& r2);
|
||||
|
||||
friend inf_rational inf_power(inf_rational const& r1, unsigned n);
|
||||
friend inf_rational sup_power(inf_rational const& r1, unsigned n);
|
||||
|
||||
friend inf_rational inf_root(inf_rational const& r1, unsigned n);
|
||||
friend inf_rational sup_root(inf_rational const& r1, unsigned n);
|
||||
|
||||
inf_rational & operator/=(const rational & r) {
|
||||
m_first /= r;
|
||||
m_second /= r;
|
||||
return *this;
|
||||
}
|
||||
|
||||
friend inline inf_rational operator*(const rational & r1, const inf_rational & r2);
|
||||
friend inline inf_rational operator/(const inf_rational & r1, const rational & r2);
|
||||
|
||||
inf_rational & operator++() {
|
||||
++m_first;
|
||||
return *this;
|
||||
}
|
||||
|
||||
const inf_rational operator++(int) { inf_rational tmp(*this); ++(*this); return tmp; }
|
||||
|
||||
inf_rational & operator--() {
|
||||
--m_first;
|
||||
return *this;
|
||||
}
|
||||
|
||||
const inf_rational operator--(int) { inf_rational tmp(*this); --(*this); return tmp; }
|
||||
|
||||
friend inline bool operator==(const inf_rational & r1, const inf_rational & r2) {
|
||||
return r1.m_first == r2.m_first && r1.m_second == r2.m_second;
|
||||
}
|
||||
|
||||
friend inline bool operator==(const rational & r1, const inf_rational & r2) {
|
||||
return r1 == r2.m_first && r2.m_second.is_zero();
|
||||
}
|
||||
|
||||
friend inline bool operator==(const inf_rational & r1, const rational & r2) {
|
||||
return r1.m_first == r2 && r1.m_second.is_zero();
|
||||
}
|
||||
|
||||
friend inline bool operator<(const inf_rational & r1, const inf_rational & r2) {
|
||||
return
|
||||
(r1.m_first < r2.m_first) ||
|
||||
(r1.m_first == r2.m_first && r1.m_second < r2.m_second);
|
||||
}
|
||||
|
||||
friend inline bool operator<(const rational & r1, const inf_rational & r2) {
|
||||
return
|
||||
(r1 < r2.m_first) ||
|
||||
(r1 == r2.m_first && r2.m_second.is_pos());
|
||||
}
|
||||
|
||||
friend inline bool operator<(const inf_rational & r1, const rational & r2) {
|
||||
return
|
||||
(r1.m_first < r2) ||
|
||||
(r1.m_first == r2 && r1.m_second.is_neg());
|
||||
}
|
||||
|
||||
void neg() {
|
||||
m_first.neg();
|
||||
m_second.neg();
|
||||
}
|
||||
|
||||
bool is_zero() const {
|
||||
return m_first.is_zero() && m_second.is_zero();
|
||||
}
|
||||
|
||||
bool is_one() const {
|
||||
return m_first.is_one() && m_second.is_zero();
|
||||
}
|
||||
|
||||
bool is_minus_one() const {
|
||||
return m_first.is_minus_one() && m_second.is_zero();
|
||||
}
|
||||
|
||||
bool is_neg() const {
|
||||
return
|
||||
m_first.is_neg() ||
|
||||
(m_first.is_zero() && m_second.is_neg());
|
||||
}
|
||||
|
||||
bool is_pos() const {
|
||||
return
|
||||
m_first.is_pos() ||
|
||||
(m_first.is_zero() && m_second.is_pos());
|
||||
}
|
||||
|
||||
bool is_nonneg() const {
|
||||
return
|
||||
m_first.is_pos() ||
|
||||
(m_first.is_zero() && m_second.is_nonneg());
|
||||
}
|
||||
|
||||
bool is_nonpos() const {
|
||||
return
|
||||
m_first.is_neg() ||
|
||||
(m_first.is_zero() && m_second.is_nonpos());
|
||||
}
|
||||
|
||||
friend inline rational floor(const inf_rational & r) {
|
||||
if (r.m_first.is_int()) {
|
||||
if (r.m_second.is_nonneg()) {
|
||||
return r.m_first;
|
||||
}
|
||||
return r.m_first - rational(1);
|
||||
}
|
||||
|
||||
return floor(r.m_first);
|
||||
}
|
||||
|
||||
friend inline rational ceil(const inf_rational & r) {
|
||||
if (r.m_first.is_int()) {
|
||||
if (r.m_second.is_nonpos()) {
|
||||
return r.m_first;
|
||||
}
|
||||
return r.m_first + rational(1);
|
||||
}
|
||||
|
||||
return ceil(r.m_first);
|
||||
}
|
||||
|
||||
static const inf_rational & zero() {
|
||||
return m_zero;
|
||||
}
|
||||
|
||||
static const inf_rational & one() {
|
||||
return m_one;
|
||||
}
|
||||
|
||||
static const inf_rational & minus_one() {
|
||||
return m_minus_one;
|
||||
}
|
||||
|
||||
// Perform: this += c * k
|
||||
void addmul(const rational & c, const inf_rational & k) {
|
||||
m_first.addmul(c, k.m_first);
|
||||
m_second.addmul(c, k.m_second);
|
||||
}
|
||||
|
||||
// Perform: this += c * k
|
||||
void submul(const rational & c, const inf_rational & k) {
|
||||
m_first.submul(c, k.m_first);
|
||||
m_second.submul(c, k.m_second);
|
||||
}
|
||||
};
|
||||
|
||||
inline bool operator!=(const inf_rational & r1, const inf_rational & r2) {
|
||||
return !operator==(r1, r2);
|
||||
}
|
||||
|
||||
inline bool operator!=(const rational & r1, const inf_rational & r2) {
|
||||
return !operator==(r1, r2);
|
||||
}
|
||||
|
||||
inline bool operator!=(const inf_rational & r1, const rational & r2) {
|
||||
return !operator==(r1, r2);
|
||||
}
|
||||
|
||||
inline bool operator>(const inf_rational & r1, const inf_rational & r2) {
|
||||
return operator<(r2, r1);
|
||||
}
|
||||
|
||||
inline bool operator>(const inf_rational & r1, const rational & r2) {
|
||||
return operator<(r2, r1);
|
||||
}
|
||||
|
||||
inline bool operator>(const rational & r1, const inf_rational & r2) {
|
||||
return operator<(r2, r1);
|
||||
}
|
||||
|
||||
inline bool operator<=(const inf_rational & r1, const inf_rational & r2) {
|
||||
return !operator>(r1, r2);
|
||||
}
|
||||
|
||||
inline bool operator<=(const rational & r1, const inf_rational & r2) {
|
||||
return !operator>(r1, r2);
|
||||
}
|
||||
|
||||
inline bool operator<=(const inf_rational & r1, const rational & r2) {
|
||||
return !operator>(r1, r2);
|
||||
}
|
||||
|
||||
inline bool operator>=(const inf_rational & r1, const inf_rational & r2) {
|
||||
return !operator<(r1, r2);
|
||||
}
|
||||
|
||||
inline bool operator>=(const rational & r1, const inf_rational & r2) {
|
||||
return !operator<(r1, r2);
|
||||
}
|
||||
|
||||
inline bool operator>=(const inf_rational & r1, const rational & r2) {
|
||||
return !operator<(r1, r2);
|
||||
}
|
||||
|
||||
inline inf_rational operator+(const inf_rational & r1, const inf_rational & r2) {
|
||||
return inf_rational(r1) += r2;
|
||||
}
|
||||
|
||||
inline inf_rational operator-(const inf_rational & r1, const inf_rational & r2) {
|
||||
return inf_rational(r1) -= r2;
|
||||
}
|
||||
|
||||
inline inf_rational operator-(const inf_rational & r) {
|
||||
inf_rational result(r);
|
||||
result.neg();
|
||||
return result;
|
||||
}
|
||||
|
||||
inline inf_rational operator*(const rational & r1, const inf_rational & r2) {
|
||||
inf_rational result(r2);
|
||||
result.m_first *= r1;
|
||||
result.m_second *= r1;
|
||||
return result;
|
||||
}
|
||||
|
||||
inline inf_rational operator/(const inf_rational & r1, const rational & r2) {
|
||||
inf_rational result(r1);
|
||||
result.m_first /= r2;
|
||||
result.m_second /= r2;
|
||||
return result;
|
||||
}
|
||||
|
||||
#if 0
|
||||
inf_rational inf_mult(inf_rational const& r1, inf_rational const& r2);
|
||||
inf_rational sup_mult(inf_rational const& r1, inf_rational const& r2);
|
||||
|
||||
inf_rational inf_div(inf_rational const& r1, inf_rational const& r2);
|
||||
inf_rational sup_div(inf_rational const& r1, inf_rational const& r2);
|
||||
|
||||
inf_rational inf_power(inf_rational const& r1, unsigned n);
|
||||
inf_rational sup_power(inf_rational const& r1, unsigned n);
|
||||
|
||||
inf_rational inf_root(inf_rational const& r1, unsigned n);
|
||||
inf_rational sup_root(inf_rational const& r1, unsigned n);
|
||||
#endif
|
||||
//
|
||||
// inline inf_rational operator/(const inf_rational & r1, const inf_rational & r2)
|
||||
// inline inf_rational operator%(const inf_rational & r1, const inf_rational & r2)
|
||||
// inf_rational gcd(const inf_rational & r1, const inf_rational & r2);
|
||||
// inf_rational lcm(const inf_rational & r1, const inf_rational & r2);
|
||||
|
||||
inline std::ostream & operator<<(std::ostream & target, const inf_rational & r)
|
||||
{
|
||||
target << r.to_string();
|
||||
return target;
|
||||
}
|
||||
|
||||
|
||||
inline inf_rational abs(const inf_rational & r) {
|
||||
inf_rational result(r);
|
||||
if (result.is_neg()) {
|
||||
result.neg();
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
#endif /* _INF_RATIONAL_H_ */
|
25
src/util/inf_s_integer.cpp
Normal file
25
src/util/inf_s_integer.cpp
Normal file
|
@ -0,0 +1,25 @@
|
|||
/*++
|
||||
Copyright (c) 2006 Microsoft Corporation
|
||||
|
||||
Module Name:
|
||||
|
||||
inf_s_integer.cpp
|
||||
|
||||
Abstract:
|
||||
|
||||
<abstract>
|
||||
|
||||
Author:
|
||||
|
||||
Leonardo de Moura (leonardo) 2007-06-16.
|
||||
|
||||
Revision History:
|
||||
|
||||
--*/
|
||||
|
||||
#include"inf_s_integer.h"
|
||||
|
||||
inf_s_integer inf_s_integer::m_zero(0);
|
||||
inf_s_integer inf_s_integer::m_one(1);
|
||||
inf_s_integer inf_s_integer::m_minus_one(-1);
|
||||
|
351
src/util/inf_s_integer.h
Normal file
351
src/util/inf_s_integer.h
Normal file
|
@ -0,0 +1,351 @@
|
|||
/*++
|
||||
Copyright (c) 2006 Microsoft Corporation
|
||||
|
||||
Module Name:
|
||||
|
||||
inf_s_integer.h
|
||||
|
||||
Abstract:
|
||||
|
||||
<abstract>
|
||||
|
||||
Author:
|
||||
|
||||
Leonardo de Moura (leonardo) 2007-06-11.
|
||||
|
||||
Revision History:
|
||||
|
||||
--*/
|
||||
#ifndef _INF_S_INTEGER_H_
|
||||
#define _INF_S_INTEGER_H_
|
||||
|
||||
#include"s_integer.h"
|
||||
#include"rational.h"
|
||||
|
||||
class inf_s_integer {
|
||||
static inf_s_integer m_zero;
|
||||
static inf_s_integer m_one;
|
||||
static inf_s_integer m_minus_one;
|
||||
int m_first;
|
||||
int m_second;
|
||||
public:
|
||||
|
||||
unsigned hash() const {
|
||||
return m_first ^ (m_second + 1);
|
||||
}
|
||||
|
||||
struct hash_proc { unsigned operator()(inf_s_integer const& r) const { return r.hash(); } };
|
||||
|
||||
struct eq_proc { bool operator()(inf_s_integer const& r1, inf_s_integer const& r2) const { return r1 == r2; } };
|
||||
|
||||
void swap(inf_s_integer & n) {
|
||||
std::swap(m_first, n.m_first);
|
||||
std::swap(m_second, n.m_second);
|
||||
}
|
||||
|
||||
std::string to_string() const;
|
||||
|
||||
inf_s_integer():m_first(0), m_second(0) {}
|
||||
|
||||
inf_s_integer(const inf_s_integer & r):m_first(r.m_first), m_second(r.m_second) {}
|
||||
|
||||
explicit inf_s_integer(int n):m_first(n), m_second(0) {}
|
||||
explicit inf_s_integer(int n, int d): m_first(n), m_second(0) { SASSERT(d == 1); }
|
||||
explicit inf_s_integer(s_integer const& r, bool pos_inf):m_first(r.get_int()), m_second(pos_inf ? 1 : -1) {}
|
||||
explicit inf_s_integer(s_integer const& r):m_first(r.get_int()), m_second(0) {}
|
||||
explicit inf_s_integer(rational const& r):m_first(static_cast<int>(r.get_int64())), m_second(0) {}
|
||||
inf_s_integer(s_integer const& r, s_integer const& i):m_first(r.get_int()), m_second(i.get_int()) {}
|
||||
void reset() { m_first = 0; m_second = 0; }
|
||||
bool is_int() const { return m_second == 0; }
|
||||
bool is_int64() const { return m_second == 0; }
|
||||
bool is_uint64() const { return m_second == 0; }
|
||||
bool is_rational() const { return m_second == 0; }
|
||||
int64 get_int64() const { return m_first; }
|
||||
uint64 get_uint64() const { return m_first; }
|
||||
s_integer get_rational() const { return s_integer(m_first); }
|
||||
s_integer get_infinitesimal() const { return s_integer(m_second); }
|
||||
inf_s_integer & operator=(const inf_s_integer & r) {
|
||||
m_first = r.m_first;
|
||||
m_second = r.m_second;
|
||||
return *this;
|
||||
}
|
||||
inf_s_integer & operator=(const rational & r) {
|
||||
m_first = static_cast<int>(r.get_int64());
|
||||
m_second = 0;
|
||||
return *this;
|
||||
}
|
||||
inf_s_integer & operator=(const s_integer & r) {
|
||||
m_first = r.get_int();
|
||||
m_second = 0;
|
||||
return *this;
|
||||
}
|
||||
friend inline inf_s_integer numerator(const inf_s_integer & r) {
|
||||
SASSERT(r.m_second == 0);
|
||||
return inf_s_integer(r.m_first);
|
||||
}
|
||||
friend inline inf_s_integer denominator(const inf_s_integer & r) {
|
||||
SASSERT(r.m_second == 0);
|
||||
return inf_s_integer(1);
|
||||
}
|
||||
inf_s_integer & operator+=(const inf_s_integer & r) {
|
||||
m_first += r.m_first;
|
||||
m_second += r.m_second;
|
||||
return *this;
|
||||
}
|
||||
inf_s_integer & operator-=(const inf_s_integer & r) {
|
||||
m_first -= r.m_first;
|
||||
m_second -= r.m_second;
|
||||
return *this;
|
||||
}
|
||||
inf_s_integer & operator+=(const s_integer & r) {
|
||||
m_first += r.get_int();
|
||||
return *this;
|
||||
}
|
||||
inf_s_integer & operator-=(const s_integer & r) {
|
||||
m_first -= r.get_int();
|
||||
return *this;
|
||||
}
|
||||
inf_s_integer & operator*=(const s_integer & r1) {
|
||||
m_first *= r1.get_int();
|
||||
m_second *= r1.get_int();
|
||||
return *this;
|
||||
}
|
||||
|
||||
// friend inf_s_integer inf_mult(inf_s_integer const& r1, inf_s_integer const& r2);
|
||||
// friend inf_s_integer sup_mult(inf_s_integer const& r1, inf_s_integer const& r2);
|
||||
|
||||
// friend inf_s_integer inf_div(inf_s_integer const& r1, inf_s_integer const& r2);
|
||||
// friend inf_s_integer sup_div(inf_s_integer const& r1, inf_s_integer const& r2);
|
||||
|
||||
// friend inf_s_integer inf_power(inf_s_integer const& r1, unsigned n);
|
||||
// friend inf_s_integer sup_power(inf_s_integer const& r1, unsigned n);
|
||||
|
||||
// friend inf_s_integer inf_root(inf_s_integer const& r1, unsigned n);
|
||||
// friend inf_s_integer sup_root(inf_s_integer const& r1, unsigned n);
|
||||
|
||||
inf_s_integer & operator/=(const s_integer & r) {
|
||||
m_first /= r.get_int();
|
||||
m_second /= r.get_int();
|
||||
return *this;
|
||||
}
|
||||
|
||||
friend inline inf_s_integer operator*(const s_integer & r1, const inf_s_integer & r2);
|
||||
friend inline inf_s_integer operator/(const inf_s_integer & r1, const s_integer & r2);
|
||||
|
||||
inf_s_integer & operator++() {
|
||||
++m_first;
|
||||
return *this;
|
||||
}
|
||||
|
||||
const inf_s_integer operator++(int) { inf_s_integer tmp(*this); ++(*this); return tmp; }
|
||||
|
||||
inf_s_integer & operator--() {
|
||||
--m_first;
|
||||
return *this;
|
||||
}
|
||||
|
||||
const inf_s_integer operator--(int) { inf_s_integer tmp(*this); --(*this); return tmp; }
|
||||
|
||||
friend inline bool operator==(const inf_s_integer & r1, const inf_s_integer & r2) {
|
||||
return r1.m_first == r2.m_first && r1.m_second == r2.m_second;
|
||||
}
|
||||
|
||||
friend inline bool operator==(const s_integer & r1, const inf_s_integer & r2) {
|
||||
return r1.get_int() == r2.m_first && r2.m_second == 0;
|
||||
}
|
||||
|
||||
friend inline bool operator==(const inf_s_integer & r1, const s_integer & r2) {
|
||||
return r1.m_first == r2.get_int() && r1.m_second == 0;
|
||||
}
|
||||
|
||||
friend inline bool operator<(const inf_s_integer & r1, const inf_s_integer & r2) {
|
||||
return
|
||||
(r1.m_first < r2.m_first) ||
|
||||
(r1.m_first == r2.m_first && r1.m_second < r2.m_second);
|
||||
}
|
||||
|
||||
friend inline bool operator<(const s_integer & r1, const inf_s_integer & r2) {
|
||||
return
|
||||
(r1.get_int() < r2.m_first) ||
|
||||
(r1.get_int() == r2.m_first && r2.m_second > 0);
|
||||
}
|
||||
|
||||
friend inline bool operator<(const inf_s_integer & r1, const s_integer & r2) {
|
||||
return
|
||||
(r1.m_first < r2.get_int()) ||
|
||||
(r1.m_first == r2.get_int() && r1.m_second < 0);
|
||||
}
|
||||
|
||||
void neg() {
|
||||
m_first = -m_first;
|
||||
m_second = -m_second;
|
||||
}
|
||||
|
||||
bool is_zero() const {
|
||||
return m_first == 0 && m_second == 0;
|
||||
}
|
||||
|
||||
bool is_one() const {
|
||||
return m_first == 1 && m_second == 0;
|
||||
}
|
||||
|
||||
bool is_minus_one() const {
|
||||
return m_first == -1 && m_second == 0;
|
||||
}
|
||||
|
||||
bool is_neg() const {
|
||||
return m_first < 0 || (m_first == 0 && m_second < 0);
|
||||
}
|
||||
|
||||
bool is_pos() const {
|
||||
return m_first > 0 || (m_first == 0 && m_second > 0);
|
||||
}
|
||||
|
||||
bool is_nonneg() const {
|
||||
return m_first > 0 || (m_first == 0 && m_second >= 0);
|
||||
}
|
||||
|
||||
bool is_nonpos() const {
|
||||
return m_first < 0 || (m_first == 0 && m_second <= 0);
|
||||
}
|
||||
|
||||
friend inline s_integer floor(const inf_s_integer & r) {
|
||||
if (r.m_second >= 0) {
|
||||
return s_integer(r.m_first);
|
||||
}
|
||||
return s_integer(r.m_first - 1);
|
||||
}
|
||||
|
||||
friend inline s_integer ceil(const inf_s_integer & r) {
|
||||
if (r.m_second <= 0) {
|
||||
return s_integer(r.m_first);
|
||||
}
|
||||
return s_integer(r.m_first + 1);
|
||||
}
|
||||
|
||||
static const inf_s_integer & zero() {
|
||||
return m_zero;
|
||||
}
|
||||
|
||||
static const inf_s_integer & one() {
|
||||
return m_one;
|
||||
}
|
||||
|
||||
static const inf_s_integer & minus_one() {
|
||||
return m_minus_one;
|
||||
}
|
||||
|
||||
// Perform: this += c * k
|
||||
void addmul(const s_integer & c, const inf_s_integer & k) {
|
||||
m_first += c.get_int() * k.m_first;
|
||||
m_second += c.get_int() * k.m_second;
|
||||
}
|
||||
|
||||
// Perform: this += c * k
|
||||
void submul(const s_integer & c, const inf_s_integer & k) {
|
||||
m_first -= c.get_int() * k.m_first;
|
||||
m_second -= c.get_int() * k.m_second;
|
||||
}
|
||||
|
||||
friend inline std::ostream & operator<<(std::ostream & target, const inf_s_integer & r) {
|
||||
if (r.m_second == 0) {
|
||||
target << r.m_first;
|
||||
}
|
||||
else if (r.m_second < 0) {
|
||||
target << "(" << r.m_first << " -e*" << r.m_second << ")";
|
||||
}
|
||||
else {
|
||||
target << "(" << r.m_first << " +e*" << r.m_second << ")";
|
||||
}
|
||||
return target;
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
inline bool operator!=(const inf_s_integer & r1, const inf_s_integer & r2) {
|
||||
return !operator==(r1, r2);
|
||||
}
|
||||
|
||||
inline bool operator!=(const s_integer & r1, const inf_s_integer & r2) {
|
||||
return !operator==(r1, r2);
|
||||
}
|
||||
|
||||
inline bool operator!=(const inf_s_integer & r1, const s_integer & r2) {
|
||||
return !operator==(r1, r2);
|
||||
}
|
||||
|
||||
inline bool operator>(const inf_s_integer & r1, const inf_s_integer & r2) {
|
||||
return operator<(r2, r1);
|
||||
}
|
||||
|
||||
inline bool operator>(const inf_s_integer & r1, const s_integer & r2) {
|
||||
return operator<(r2, r1);
|
||||
}
|
||||
|
||||
inline bool operator>(const s_integer & r1, const inf_s_integer & r2) {
|
||||
return operator<(r2, r1);
|
||||
}
|
||||
|
||||
inline bool operator<=(const inf_s_integer & r1, const inf_s_integer & r2) {
|
||||
return !operator>(r1, r2);
|
||||
}
|
||||
|
||||
inline bool operator<=(const s_integer & r1, const inf_s_integer & r2) {
|
||||
return !operator>(r1, r2);
|
||||
}
|
||||
|
||||
inline bool operator<=(const inf_s_integer & r1, const s_integer & r2) {
|
||||
return !operator>(r1, r2);
|
||||
}
|
||||
|
||||
inline bool operator>=(const inf_s_integer & r1, const inf_s_integer & r2) {
|
||||
return !operator<(r1, r2);
|
||||
}
|
||||
|
||||
inline bool operator>=(const s_integer & r1, const inf_s_integer & r2) {
|
||||
return !operator<(r1, r2);
|
||||
}
|
||||
|
||||
inline bool operator>=(const inf_s_integer & r1, const s_integer & r2) {
|
||||
return !operator<(r1, r2);
|
||||
}
|
||||
|
||||
inline inf_s_integer operator+(const inf_s_integer & r1, const inf_s_integer & r2) {
|
||||
return inf_s_integer(r1) += r2;
|
||||
}
|
||||
|
||||
inline inf_s_integer operator-(const inf_s_integer & r1, const inf_s_integer & r2) {
|
||||
return inf_s_integer(r1) -= r2;
|
||||
}
|
||||
|
||||
inline inf_s_integer operator-(const inf_s_integer & r) {
|
||||
inf_s_integer result(r);
|
||||
result.neg();
|
||||
return result;
|
||||
}
|
||||
|
||||
inline inf_s_integer operator*(const s_integer & r1, const inf_s_integer & r2) {
|
||||
inf_s_integer result(r2);
|
||||
result.m_first *= r1.get_int();
|
||||
result.m_second *= r1.get_int();
|
||||
return result;
|
||||
}
|
||||
|
||||
inline inf_s_integer operator/(const inf_s_integer & r1, const s_integer & r2) {
|
||||
inf_s_integer result(r1);
|
||||
result.m_first /= r2.get_int();
|
||||
result.m_second /= r2.get_int();
|
||||
return result;
|
||||
}
|
||||
|
||||
inline inf_s_integer abs(const inf_s_integer & r) {
|
||||
inf_s_integer result(r);
|
||||
if (result.is_neg()) {
|
||||
result.neg();
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
#endif /* _INF_S_INTEGER_H_ */
|
||||
|
1564
src/util/ini_file.cpp
Normal file
1564
src/util/ini_file.cpp
Normal file
File diff suppressed because it is too large
Load diff
117
src/util/ini_file.h
Normal file
117
src/util/ini_file.h
Normal file
|
@ -0,0 +1,117 @@
|
|||
/*++
|
||||
Copyright (c) 2006 Microsoft Corporation
|
||||
|
||||
Module Name:
|
||||
|
||||
ini_file.h
|
||||
|
||||
Abstract:
|
||||
|
||||
Configuration file support.
|
||||
|
||||
Author:
|
||||
|
||||
Leonardo de Moura (leonardo) 2007-05-10.
|
||||
|
||||
Revision History:
|
||||
|
||||
--*/
|
||||
#ifndef _INI_FILE_H_
|
||||
#define _INI_FILE_H_
|
||||
|
||||
#include<iostream>
|
||||
#include<limits.h>
|
||||
#include<string>
|
||||
|
||||
#include"symbol.h"
|
||||
#include"vector.h"
|
||||
#include"ref.h"
|
||||
|
||||
#ifdef _EXTERNAL_RELEASE
|
||||
#define PRIVATE_PARAMS(CODE) ((void) 0)
|
||||
#else
|
||||
#define PRIVATE_PARAMS(CODE) { CODE }
|
||||
#endif
|
||||
|
||||
struct param_vector_imp;
|
||||
struct ini_params_imp;
|
||||
class ini_parser;
|
||||
|
||||
typedef std::pair<symbol, unsigned> symbol_nat_pair;
|
||||
|
||||
inline std::ostream & operator<<(std::ostream & out, symbol_nat_pair const & p) {
|
||||
out << p.first << ":" << p.second;
|
||||
return out;
|
||||
}
|
||||
|
||||
/**
|
||||
\brief Support for multiple values for a parameter. The values are used to configure
|
||||
different cores.
|
||||
*/
|
||||
class param_vector {
|
||||
unsigned m_ref_count;
|
||||
param_vector_imp * m_imp;
|
||||
friend struct ini_params_imp;
|
||||
friend class ini_parser;
|
||||
public:
|
||||
// TODO: onwer is a big hack
|
||||
param_vector(void * owner);
|
||||
~param_vector();
|
||||
void inc_ref();
|
||||
void dec_ref();
|
||||
void copy_params(void * curr_owner, unsigned idx);
|
||||
unsigned size(void) const;
|
||||
};
|
||||
|
||||
class set_get_param_exception {
|
||||
std::string m_id;
|
||||
std::string m_msg;
|
||||
public:
|
||||
set_get_param_exception(char const * id, char const * msg):m_id(id), m_msg(msg) {}
|
||||
char const * get_param_id() const { return m_id.c_str(); }
|
||||
char const * get_msg() const { return m_msg.c_str(); }
|
||||
};
|
||||
|
||||
class ini_parser_exception {
|
||||
unsigned m_pos;
|
||||
std::string m_msg;
|
||||
public:
|
||||
ini_parser_exception(unsigned pos, char const * msg):m_pos(pos), m_msg(msg) {}
|
||||
unsigned get_pos() const { return m_pos; }
|
||||
char const * get_msg() const { return m_msg.c_str(); }
|
||||
};
|
||||
|
||||
class ini_params {
|
||||
ini_params_imp * m_imp;
|
||||
public:
|
||||
ini_params(bool abort_on_error = true);
|
||||
~ini_params();
|
||||
void freeze(bool f = true);
|
||||
void register_bool_param(char const * param_name, bool & value, char const * descr = 0, bool is_mutable = false);
|
||||
void register_unsigned_param(char const * param_name, unsigned min, unsigned max, unsigned & value, char const * descr = 0, bool is_mutable = false);
|
||||
void register_unsigned_param(char const * param_name, unsigned & value, char const * descr = 0, bool is_mutable = false) {
|
||||
register_unsigned_param(param_name, 0, INT_MAX, value, descr, is_mutable);
|
||||
}
|
||||
void register_int_param(char const * param_name, int min, int max, int & value, char const * descr = 0, bool is_mutable = false);
|
||||
void register_int_param(char const * param_name, int & value, char const * descr = 0, bool is_mutable = false) {
|
||||
register_int_param(param_name, INT_MIN, INT_MAX, value, descr, is_mutable);
|
||||
}
|
||||
void register_double_param(char const * param_name, double & value, char const * descr = 0,bool is_mutable = false);
|
||||
void register_percentage_param(char const * param_name, double & value, char const * descr = 0, bool is_mutable = false);
|
||||
void register_string_param(char const * param_name, std::string & value, char const * descr = 0, bool is_mutable = false);
|
||||
void register_symbol_param(char const * param_name, symbol & value, char const * descr = 0, bool is_mutable = false);
|
||||
void register_symbol_list_param(char const * param_name, svector<symbol> & value, char const * descr = 0, bool is_mutable = false);
|
||||
void register_symbol_nat_list_param(char const * param_name, svector<symbol_nat_pair> & value, char const * descr = 0, bool is_mutable = false);
|
||||
void register_param_vector(param_vector * pv);
|
||||
|
||||
void read_ini_file(std::istream & in);
|
||||
void display_params(std::ostream & out) const;
|
||||
void display_parameter_help(char const* param_id, std::ostream & out) const;
|
||||
void set_param_value(char const * param_id, char const * param_value);
|
||||
void set_param_mutable(char const * param_id);
|
||||
bool get_param_value(char const * param_id, std::string& param_value);
|
||||
void display_params_documentation(std::ostream & out) const;
|
||||
};
|
||||
|
||||
#endif /* _INI_FILE_H_ */
|
||||
|
41
src/util/instruction_count.cpp
Normal file
41
src/util/instruction_count.cpp
Normal file
|
@ -0,0 +1,41 @@
|
|||
#ifdef _WINDOWS
|
||||
#include "windows.h"
|
||||
#endif
|
||||
#include "instruction_count.h"
|
||||
|
||||
#ifdef _WINDOWS
|
||||
typedef BOOL (WINAPI *QTCP)(HANDLE, PULONG64);
|
||||
static QTCP QTCP_proc;
|
||||
BOOL WINAPI dummy_qtcp(HANDLE h, PULONG64 u)
|
||||
{
|
||||
*u = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
inline void check_handler()
|
||||
{
|
||||
if (!QTCP_proc) {
|
||||
QTCP_proc = (QTCP) GetProcAddress(GetModuleHandle(TEXT("kernel32.dll")), "QueryThreadCycleTime");
|
||||
if (!QTCP_proc)
|
||||
QTCP_proc = &dummy_qtcp;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
void instruction_count::start() {
|
||||
m_count = 0;
|
||||
#ifdef _WINDOWS
|
||||
check_handler();
|
||||
QTCP_proc(GetCurrentThread(), &m_count);
|
||||
#endif
|
||||
}
|
||||
|
||||
double instruction_count::get_num_instructions() {
|
||||
unsigned long long current = 0;
|
||||
#ifdef _WINDOWS
|
||||
check_handler();
|
||||
QTCP_proc(GetCurrentThread(), ¤t);
|
||||
#endif
|
||||
return static_cast<double>(current - m_count);
|
||||
}
|
||||
|
43
src/util/instruction_count.h
Normal file
43
src/util/instruction_count.h
Normal file
|
@ -0,0 +1,43 @@
|
|||
/*++
|
||||
Copyright (c) 2009 Microsoft Corporation
|
||||
|
||||
Module Name:
|
||||
|
||||
instruction_count.h
|
||||
|
||||
Abstract:
|
||||
|
||||
<abstract>
|
||||
|
||||
Author:
|
||||
|
||||
Nikolaj Bjorner (nbjorner) 2009-03-04.
|
||||
|
||||
Revision History:
|
||||
|
||||
--*/
|
||||
#ifndef _INSTRUCTION_COUNT_H_
|
||||
#define _INSTRUCTION_COUNT_H_
|
||||
|
||||
|
||||
/**
|
||||
\brief Wrapper for an instruction counter.
|
||||
*/
|
||||
class instruction_count {
|
||||
unsigned long long m_count;
|
||||
public:
|
||||
instruction_count() : m_count(0) {}
|
||||
|
||||
~instruction_count() {}
|
||||
|
||||
void start();
|
||||
|
||||
double get_num_instructions();
|
||||
|
||||
bool is_instruction_maxed(double max_instr) {
|
||||
return max_instr > 0.0 && get_num_instructions() > max_instr;
|
||||
}
|
||||
};
|
||||
|
||||
#endif /* _INSTRUcTION_COUNT_H_ */
|
||||
|
353
src/util/interval.h
Normal file
353
src/util/interval.h
Normal file
|
@ -0,0 +1,353 @@
|
|||
/*++
|
||||
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
|
1985
src/util/interval_def.h
Normal file
1985
src/util/interval_def.h
Normal file
File diff suppressed because it is too large
Load diff
1876
src/util/interval_skip_list.h
Normal file
1876
src/util/interval_skip_list.h
Normal file
File diff suppressed because it is too large
Load diff
36
src/util/lbool.cpp
Normal file
36
src/util/lbool.cpp
Normal file
|
@ -0,0 +1,36 @@
|
|||
/*++
|
||||
Copyright (c) 2006 Microsoft Corporation
|
||||
|
||||
Module Name:
|
||||
|
||||
lbool.cpp
|
||||
|
||||
Abstract:
|
||||
|
||||
<abstract>
|
||||
|
||||
Author:
|
||||
|
||||
Leonardo de Moura (leonardo) 2008-02-08.
|
||||
|
||||
Revision History:
|
||||
|
||||
--*/
|
||||
#include"lbool.h"
|
||||
|
||||
std::ostream & operator<<(std::ostream & out, lbool b) {
|
||||
switch(b) {
|
||||
case l_false: return out << "l_false";
|
||||
case l_true: return out << "l_true";
|
||||
default: return out << "l_undef";
|
||||
}
|
||||
}
|
||||
|
||||
char const * to_sat_str(lbool l) {
|
||||
switch (l) {
|
||||
case l_false: return "unsatisfiable";
|
||||
case l_true: return "satisfiable";
|
||||
default: return "unknown";
|
||||
}
|
||||
}
|
||||
|
42
src/util/lbool.h
Normal file
42
src/util/lbool.h
Normal file
|
@ -0,0 +1,42 @@
|
|||
/*++
|
||||
Copyright (c) 2006 Microsoft Corporation
|
||||
|
||||
Module Name:
|
||||
|
||||
lbool.h
|
||||
|
||||
Abstract:
|
||||
|
||||
Lifted boolean
|
||||
|
||||
Author:
|
||||
|
||||
Leonardo de Moura (leonardo) 2008-02-08.
|
||||
|
||||
Revision History:
|
||||
|
||||
--*/
|
||||
#ifndef _LBOOL_H_
|
||||
#define _LBOOL_H_
|
||||
|
||||
#include"util.h"
|
||||
|
||||
typedef enum { l_false = -1, l_undef, l_true } lbool;
|
||||
|
||||
inline lbool operator~(lbool lb) {
|
||||
return static_cast<lbool>(-static_cast<int>(lb));
|
||||
}
|
||||
|
||||
inline lbool to_lbool(bool b) {
|
||||
return static_cast<lbool>(static_cast<int>(b)*2-1);
|
||||
}
|
||||
|
||||
std::ostream & operator<<(std::ostream & out, lbool b);
|
||||
|
||||
/**
|
||||
\brief Convert l_true -> satisfiable, l_false -> unsatisfiable, and l_undef -> unknown.
|
||||
*/
|
||||
char const * to_sat_str(lbool l);
|
||||
|
||||
#endif /* _LBOOL_H_ */
|
||||
|
96
src/util/list.h
Normal file
96
src/util/list.h
Normal file
|
@ -0,0 +1,96 @@
|
|||
/*++
|
||||
Copyright (c) 2006 Microsoft Corporation
|
||||
|
||||
Module Name:
|
||||
|
||||
list.h
|
||||
|
||||
Abstract:
|
||||
|
||||
Simple list data structure. It is meant to be used with region allocators.
|
||||
|
||||
Author:
|
||||
|
||||
Leonardo de Moura (leonardo) 2007-07-10.
|
||||
|
||||
Revision History:
|
||||
|
||||
--*/
|
||||
#ifndef _LIST_H_
|
||||
#define _LIST_H_
|
||||
|
||||
#include"buffer.h"
|
||||
#include"region.h"
|
||||
|
||||
template<typename T>
|
||||
class list {
|
||||
T m_head;
|
||||
list * m_tail;
|
||||
|
||||
public:
|
||||
list(T const & h, list * t = 0):
|
||||
m_head(h),
|
||||
m_tail(t) {
|
||||
}
|
||||
|
||||
T const & head() const { return m_head; }
|
||||
list * tail() const { return m_tail; }
|
||||
T & head() { return m_head; }
|
||||
list * & tail() { return m_tail; }
|
||||
|
||||
class iterator {
|
||||
list const * m_curr;
|
||||
public:
|
||||
iterator(list const * c = 0):m_curr(c) {}
|
||||
T const & operator*() const { return m_curr->head(); }
|
||||
iterator & operator++() { m_curr = m_curr->tail(); return *this; }
|
||||
iterator operator++(int) { iterator tmp = *this; ++*this; return tmp; }
|
||||
bool operator==(iterator const & it) { return m_curr == it.m_curr; }
|
||||
bool operator!=(iterator const & it) { return m_curr != it.m_curr; }
|
||||
};
|
||||
|
||||
typedef iterator const_iterator;
|
||||
iterator begin() const { return iterator(this); }
|
||||
iterator end() const { return iterator(0); }
|
||||
};
|
||||
|
||||
/**
|
||||
\brief Return the list length.
|
||||
*/
|
||||
template<typename T>
|
||||
unsigned length(list<T> * l) {
|
||||
unsigned r = 0;
|
||||
while(l) {
|
||||
l = l->tail();
|
||||
r++;
|
||||
}
|
||||
return r;
|
||||
}
|
||||
|
||||
/**
|
||||
\brief Non destructive apppend operation. The new nodes are allocated
|
||||
using the given region allocator.
|
||||
*/
|
||||
template<typename T>
|
||||
list<T> * append(region & r, list<T> * l1, list<T> * l2) {
|
||||
if (l2 == 0) {
|
||||
return l1;
|
||||
}
|
||||
ptr_buffer<list<T> > buffer;
|
||||
while (l1) {
|
||||
buffer.push_back(l1);
|
||||
l1 = l1->tail();
|
||||
}
|
||||
list<T> * result = l2;
|
||||
typename ptr_buffer<list<T> >::const_iterator it = buffer.end();
|
||||
typename ptr_buffer<list<T> >::const_iterator begin = buffer.begin();
|
||||
while (it != begin) {
|
||||
--it;
|
||||
list<T> * curr = *it;
|
||||
result = new (r) list<T>(curr->head(), result);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
#endif /* _LIST_H_ */
|
||||
|
30
src/util/machine.h
Normal file
30
src/util/machine.h
Normal file
|
@ -0,0 +1,30 @@
|
|||
/*++
|
||||
Copyright (c) 2006 Microsoft Corporation
|
||||
|
||||
Module Name:
|
||||
|
||||
machine.h
|
||||
|
||||
Abstract:
|
||||
|
||||
Machine/OS dependent configuration
|
||||
|
||||
Author:
|
||||
|
||||
Leonardo de Moura (leonardo) 2006-09-13.
|
||||
|
||||
Revision History:
|
||||
|
||||
--*/
|
||||
|
||||
#ifndef _MACHINE_H_
|
||||
#define _MACHINE_H_
|
||||
|
||||
#ifdef _AMD64_
|
||||
#define PTR_ALIGNMENT 3
|
||||
#else
|
||||
#define PTR_ALIGNMENT 2
|
||||
#endif
|
||||
|
||||
#endif /* _MACHINE_H_ */
|
||||
|
286
src/util/map.h
Normal file
286
src/util/map.h
Normal file
|
@ -0,0 +1,286 @@
|
|||
/*++
|
||||
Copyright (c) 2006 Microsoft Corporation
|
||||
|
||||
Module Name:
|
||||
|
||||
map.h
|
||||
|
||||
Abstract:
|
||||
|
||||
Simple mapping based on the hashtable.
|
||||
|
||||
Author:
|
||||
|
||||
Leonardo de Moura (leonardo) 2006-10-14.
|
||||
|
||||
Revision History:
|
||||
|
||||
--*/
|
||||
#ifndef _MAP_H_
|
||||
#define _MAP_H_
|
||||
|
||||
#include"hashtable.h"
|
||||
|
||||
template<typename Key, typename Value>
|
||||
struct _key_data {
|
||||
Key m_key;
|
||||
Value m_value;
|
||||
_key_data() {
|
||||
}
|
||||
_key_data(Key const & k):
|
||||
m_key(k) {
|
||||
}
|
||||
_key_data(Key const & k, Value const & v):
|
||||
m_key(k),
|
||||
m_value(v) {
|
||||
}
|
||||
};
|
||||
|
||||
template<typename Entry, typename HashProc, typename EqProc>
|
||||
class table2map {
|
||||
public:
|
||||
typedef Entry entry;
|
||||
typedef typename Entry::key key;
|
||||
typedef typename Entry::value value;
|
||||
typedef typename Entry::key_data key_data;
|
||||
|
||||
|
||||
struct entry_hash_proc : private HashProc {
|
||||
entry_hash_proc(HashProc const & p):
|
||||
HashProc(p) {
|
||||
}
|
||||
|
||||
unsigned operator()(key_data const & d) const {
|
||||
return HashProc::operator()(d.m_key);
|
||||
}
|
||||
};
|
||||
|
||||
struct entry_eq_proc : private EqProc {
|
||||
entry_eq_proc(EqProc const & p):
|
||||
EqProc(p) {
|
||||
}
|
||||
|
||||
bool operator()(key_data const & d1, key_data const & d2) const {
|
||||
return EqProc::operator()(d1.m_key, d2.m_key);
|
||||
}
|
||||
};
|
||||
|
||||
typedef core_hashtable<entry, entry_hash_proc, entry_eq_proc> table;
|
||||
|
||||
table m_table;
|
||||
|
||||
public:
|
||||
table2map(HashProc const & h = HashProc(), EqProc const & e = EqProc()):
|
||||
m_table(DEFAULT_HASHTABLE_INITIAL_CAPACITY, entry_hash_proc(h), entry_eq_proc(e)) {
|
||||
}
|
||||
|
||||
typedef typename table::iterator iterator;
|
||||
|
||||
void reset() {
|
||||
m_table.reset();
|
||||
}
|
||||
|
||||
void finalize() {
|
||||
m_table.finalize();
|
||||
}
|
||||
|
||||
bool empty() const {
|
||||
return m_table.empty();
|
||||
}
|
||||
|
||||
unsigned size() const {
|
||||
return m_table.size();
|
||||
}
|
||||
|
||||
unsigned capacity() const {
|
||||
return m_table.capacity();
|
||||
}
|
||||
|
||||
iterator begin() const {
|
||||
return m_table.begin();
|
||||
}
|
||||
|
||||
iterator end() const {
|
||||
return m_table.end();
|
||||
}
|
||||
|
||||
void insert(key const & k, value const & v) {
|
||||
m_table.insert(key_data(k, v));
|
||||
}
|
||||
|
||||
key_data const & insert_if_not_there(key const & k, value const & v) {
|
||||
return m_table.insert_if_not_there(key_data(k, v));
|
||||
}
|
||||
|
||||
entry * insert_if_not_there2(key const & k, value const & v) {
|
||||
return m_table.insert_if_not_there2(key_data(k, v));
|
||||
}
|
||||
|
||||
entry * find_core(key const & k) const {
|
||||
return m_table.find_core(key_data(k));
|
||||
}
|
||||
|
||||
bool find(key const & k, value & v) const {
|
||||
entry * e = find_core(k);
|
||||
if (e) {
|
||||
v = e->get_data().m_value;
|
||||
}
|
||||
return (0 != e);
|
||||
}
|
||||
|
||||
value const& get(key const& k, value const& default_value) const {
|
||||
entry* e = find_core(k);
|
||||
if (e) {
|
||||
return e->m_value;
|
||||
}
|
||||
else {
|
||||
return default_value;
|
||||
}
|
||||
}
|
||||
|
||||
iterator find_iterator(key const & k) const {
|
||||
return m_table.find(key_data(k));
|
||||
}
|
||||
|
||||
value const & find(key const& k) const {
|
||||
entry * e = find_core(k);
|
||||
SASSERT(e);
|
||||
return e->get_data().m_value;
|
||||
}
|
||||
|
||||
value & find(key const& k) {
|
||||
entry * e = find_core(k);
|
||||
SASSERT(e);
|
||||
return e->get_data().m_value;
|
||||
}
|
||||
|
||||
value const& operator[](key const& k) const { return find(k); }
|
||||
|
||||
value& operator[](key const& k) { return find(k); }
|
||||
|
||||
|
||||
bool contains(key const & k) const {
|
||||
return find_core(k) != 0;
|
||||
}
|
||||
|
||||
void remove(key const & k) {
|
||||
m_table.remove(key_data(k));
|
||||
}
|
||||
|
||||
void erase(key const & k) {
|
||||
remove(k);
|
||||
}
|
||||
|
||||
unsigned long long get_num_collision() const { return m_table.get_num_collision(); }
|
||||
|
||||
void swap(table2map & other) {
|
||||
m_table.swap(other.m_table);
|
||||
}
|
||||
|
||||
#ifdef Z3DEBUG
|
||||
|
||||
bool check_invariant() {
|
||||
return m_table.check_invariant();
|
||||
}
|
||||
|
||||
#endif
|
||||
};
|
||||
|
||||
template<typename Key, typename Value>
|
||||
class default_map_entry : public default_hash_entry<_key_data<Key, Value> > {
|
||||
public:
|
||||
typedef Key key;
|
||||
typedef Value value;
|
||||
typedef _key_data<Key, Value> key_data;
|
||||
};
|
||||
|
||||
|
||||
template<typename Key, typename Value, typename HashProc, typename EqProc>
|
||||
class map : public table2map<default_map_entry<Key, Value>, HashProc, EqProc> {
|
||||
public:
|
||||
map(HashProc const & h = HashProc(), EqProc const & e = EqProc()):
|
||||
table2map<default_map_entry<Key, Value>, HashProc, EqProc>(h, e) {
|
||||
}
|
||||
};
|
||||
|
||||
template<typename Key, typename Value>
|
||||
struct _key_ptr_data {
|
||||
Key * m_key;
|
||||
Value m_value;
|
||||
_key_ptr_data():
|
||||
m_key(0) {
|
||||
}
|
||||
_key_ptr_data(Key * k):
|
||||
m_key(k) {
|
||||
}
|
||||
_key_ptr_data(Key * k, Value const & v):
|
||||
m_key(k),
|
||||
m_value(v) {
|
||||
}
|
||||
};
|
||||
|
||||
template<typename Key, typename Value>
|
||||
class ptr_map_entry {
|
||||
public:
|
||||
typedef _key_ptr_data<Key, Value> key_data;
|
||||
typedef _key_ptr_data<Key, Value> data;
|
||||
private:
|
||||
unsigned m_hash; //!< cached hash code
|
||||
data m_data;
|
||||
public:
|
||||
typedef Key * key;
|
||||
typedef Value value;
|
||||
unsigned get_hash() const { return m_hash; }
|
||||
bool is_free() const { return m_data.m_key == 0; }
|
||||
bool is_deleted() const { return m_data.m_key == reinterpret_cast<Key *>(1); }
|
||||
bool is_used() const { return m_data.m_key != reinterpret_cast<Key *>(0) && m_data.m_key != reinterpret_cast<Key *>(1); }
|
||||
key_data const & get_data() const { return m_data; }
|
||||
key_data & get_data() { return m_data; }
|
||||
void set_data(key_data const & d) { m_data = d; }
|
||||
void set_hash(unsigned h) { m_hash = h; }
|
||||
void mark_as_deleted() { m_data.m_key = reinterpret_cast<Key *>(1); }
|
||||
void mark_as_free() { m_data.m_key = 0; }
|
||||
};
|
||||
|
||||
template<typename Key, typename Value>
|
||||
class ptr_addr_map_entry {
|
||||
public:
|
||||
typedef _key_ptr_data<Key, Value> key_data;
|
||||
typedef _key_ptr_data<Key, Value> data;
|
||||
private:
|
||||
data m_data;
|
||||
public:
|
||||
typedef Key * key;
|
||||
typedef Value value;
|
||||
unsigned get_hash() const { return get_ptr_hash(m_data.m_key); }
|
||||
bool is_free() const { return m_data.m_key == 0; }
|
||||
bool is_deleted() const { return m_data.m_key == reinterpret_cast<Key *>(1); }
|
||||
bool is_used() const { return m_data.m_key != reinterpret_cast<Key *>(0) && m_data.m_key != reinterpret_cast<Key *>(1); }
|
||||
key_data const & get_data() const { return m_data; }
|
||||
key_data & get_data() { return m_data; }
|
||||
void set_data(key_data const & d) { m_data = d; }
|
||||
void set_hash(unsigned h) { SASSERT(h == get_ptr_hash(m_data.m_key)); /* do nothing */ }
|
||||
void mark_as_deleted() { m_data.m_key = reinterpret_cast<Key *>(1); }
|
||||
void mark_as_free() { m_data.m_key = 0; }
|
||||
};
|
||||
|
||||
template<typename Key, typename Value>
|
||||
class ptr_addr_map : public table2map<ptr_addr_map_entry<Key, Value>, ptr_hash<Key>, ptr_eq<Key> > {
|
||||
public:
|
||||
};
|
||||
|
||||
struct u_hash { unsigned operator()(unsigned u) const { return u; } };
|
||||
|
||||
struct u_eq { bool operator()(unsigned u1, unsigned u2) const { return u1 == u2; } };
|
||||
|
||||
struct size_t_eq { bool operator()(size_t u1, size_t u2) const { return u1 == u2; } };
|
||||
|
||||
struct int_eq { bool operator()(int u1, int u2) const { return u1 == u2; } };
|
||||
|
||||
template<typename Value>
|
||||
class u_map : public map<unsigned, Value, u_hash, u_eq> {};
|
||||
|
||||
template<typename Value>
|
||||
class size_t_map : public map<size_t, Value, size_t_hash, size_t_eq> {};
|
||||
|
||||
#endif
|
56
src/util/mem_stat.cpp
Normal file
56
src/util/mem_stat.cpp
Normal file
|
@ -0,0 +1,56 @@
|
|||
/*++
|
||||
Copyright (c) 2006 Microsoft Corporation
|
||||
|
||||
Module Name:
|
||||
|
||||
mem_stat.cpp
|
||||
|
||||
Abstract:
|
||||
|
||||
Memory usage statistics
|
||||
|
||||
Author:
|
||||
|
||||
Leonardo de Moura (leonardo) 2006-11-09.
|
||||
|
||||
Revision History:
|
||||
|
||||
--*/
|
||||
|
||||
#ifdef _WINDOWS
|
||||
#include<windows.h>
|
||||
#include<cstdio>
|
||||
#include<psapi.h>
|
||||
|
||||
double get_max_heap_size() {
|
||||
DWORD processID = GetCurrentProcessId();
|
||||
HANDLE hProcess;
|
||||
PROCESS_MEMORY_COUNTERS pmc;
|
||||
|
||||
hProcess = OpenProcess(PROCESS_QUERY_INFORMATION |
|
||||
PROCESS_VM_READ,
|
||||
FALSE, processID);
|
||||
double result = -1.0;
|
||||
|
||||
if (NULL == hProcess) {
|
||||
return -1.0;
|
||||
}
|
||||
|
||||
if (GetProcessMemoryInfo( hProcess, &pmc, sizeof(pmc))) {
|
||||
result = static_cast<double>(pmc.PeakWorkingSetSize) / static_cast<double>(1024*1024);
|
||||
}
|
||||
|
||||
CloseHandle( hProcess );
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
double get_max_heap_size() {
|
||||
// not available in this platform
|
||||
return -1.0;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
25
src/util/mem_stat.h
Normal file
25
src/util/mem_stat.h
Normal file
|
@ -0,0 +1,25 @@
|
|||
/*++
|
||||
Copyright (c) 2006 Microsoft Corporation
|
||||
|
||||
Module Name:
|
||||
|
||||
mem_stat.h
|
||||
|
||||
Abstract:
|
||||
|
||||
Memory usage statistics
|
||||
|
||||
Author:
|
||||
|
||||
Leonardo de Moura (leonardo) 2006-11-09.
|
||||
|
||||
Revision History:
|
||||
|
||||
--*/
|
||||
#ifndef _MEM_STAT_H_
|
||||
#define _MEM_STAT_H_
|
||||
|
||||
double get_max_heap_size();
|
||||
|
||||
#endif /* _MEM_STAT_H_ */
|
||||
|
260
src/util/memory_manager.cpp
Normal file
260
src/util/memory_manager.cpp
Normal file
|
@ -0,0 +1,260 @@
|
|||
#include<stdlib.h>
|
||||
#include"memory_manager.h"
|
||||
#include"rational.h"
|
||||
#include"prime_generator.h"
|
||||
#include"debug.h"
|
||||
|
||||
// If PROFILE_MEMORY is defined, Z3 will display the amount of memory used, and the number of synchronization steps during finalization
|
||||
// #define PROFILE_MEMORY
|
||||
void initialize_symbols();
|
||||
void finalize_symbols();
|
||||
|
||||
out_of_memory_error::out_of_memory_error():z3_error(ERR_MEMOUT) {
|
||||
}
|
||||
|
||||
volatile bool g_memory_out_of_memory = false;
|
||||
long long g_memory_alloc_size = 0;
|
||||
long long g_memory_max_size = 0;
|
||||
long long g_memory_max_used_size = 0;
|
||||
long long g_memory_watermark = 0;
|
||||
bool g_exit_when_out_of_memory = false;
|
||||
char const * g_out_of_memory_msg = "ERROR: out of memory";
|
||||
|
||||
void memory::exit_when_out_of_memory(bool flag, char const * msg) {
|
||||
g_exit_when_out_of_memory = flag;
|
||||
if (flag && msg)
|
||||
g_out_of_memory_msg = msg;
|
||||
}
|
||||
|
||||
static void throw_out_of_memory() {
|
||||
#pragma omp critical (z3_memory_manager)
|
||||
{
|
||||
if (!g_memory_out_of_memory) {
|
||||
g_memory_out_of_memory = true;
|
||||
}
|
||||
}
|
||||
if (g_exit_when_out_of_memory) {
|
||||
std::cerr << g_out_of_memory_msg << "\n";
|
||||
exit(ERR_MEMOUT);
|
||||
}
|
||||
else {
|
||||
throw out_of_memory_error();
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef PROFILE_MEMORY
|
||||
unsigned g_synch_counter = 0;
|
||||
class mem_usage_report {
|
||||
public:
|
||||
~mem_usage_report() {
|
||||
std::cerr << "(memory :max " << g_memory_max_used_size
|
||||
<< " :final " << g_memory_alloc_size
|
||||
<< " :synch " << g_synch_counter << ")" << std::endl;
|
||||
}
|
||||
};
|
||||
mem_usage_report g_info;
|
||||
#endif
|
||||
|
||||
void memory::initialize(size_t max_size) {
|
||||
g_memory_out_of_memory = false;
|
||||
g_memory_max_size = max_size;
|
||||
rational::initialize();
|
||||
initialize_symbols();
|
||||
}
|
||||
|
||||
bool memory::is_out_of_memory() {
|
||||
bool r = false;
|
||||
#pragma omp critical (z3_memory_manager)
|
||||
{
|
||||
r = g_memory_out_of_memory;
|
||||
}
|
||||
return r;
|
||||
}
|
||||
|
||||
void memory::set_high_watermark(size_t watermak) {
|
||||
// This method is only safe to invoke at initialization time, that is, before the threads are created.
|
||||
g_memory_watermark = watermak;
|
||||
}
|
||||
|
||||
bool memory::above_high_watermark() {
|
||||
if (g_memory_watermark == 0)
|
||||
return false;
|
||||
bool r;
|
||||
#pragma omp critical (z3_memory_manager)
|
||||
{
|
||||
r = g_memory_watermark < g_memory_alloc_size;
|
||||
}
|
||||
return r;
|
||||
}
|
||||
|
||||
void memory::set_max_size(size_t max_size) {
|
||||
// This method is only safe to invoke at initialization time, that is, before the threads are created.
|
||||
g_memory_max_size = max_size;
|
||||
}
|
||||
|
||||
static bool g_finalizing = false;
|
||||
|
||||
void memory::finalize() {
|
||||
g_finalizing = true;
|
||||
finalize_debug();
|
||||
finalize_trace();
|
||||
finalize_symbols();
|
||||
rational::finalize();
|
||||
prime_iterator::finalize();
|
||||
}
|
||||
|
||||
|
||||
unsigned long long memory::get_allocation_size() {
|
||||
long long r;
|
||||
#pragma omp critical (z3_memory_manager)
|
||||
{
|
||||
r = g_memory_alloc_size;
|
||||
}
|
||||
if (r < 0)
|
||||
r = 0;
|
||||
return r;
|
||||
}
|
||||
|
||||
unsigned long long memory::get_max_used_memory() {
|
||||
unsigned long long r;
|
||||
#pragma omp critical (z3_memory_manager)
|
||||
{
|
||||
r = g_memory_max_used_size;
|
||||
}
|
||||
return r;
|
||||
}
|
||||
|
||||
void memory::display_max_usage(std::ostream & os) {
|
||||
unsigned long long mem = get_max_used_memory();
|
||||
os << "max. heap size: "
|
||||
<< static_cast<double>(mem)/static_cast<double>(1024*1024)
|
||||
<< " Mbytes\n";
|
||||
}
|
||||
|
||||
void memory::display_i_max_usage(std::ostream & os) {
|
||||
unsigned long long mem = get_max_used_memory();
|
||||
std::cout << "MEMORY "
|
||||
<< static_cast<double>(mem)/static_cast<double>(1024*1024)
|
||||
<< "\n";
|
||||
}
|
||||
|
||||
void memory::deallocate(char const * file, int line, void * p) {
|
||||
deallocate(p);
|
||||
TRACE_CODE(if (!g_finalizing) TRACE("memory", tout << "dealloc " << std::hex << p << std::dec << " " << file << ":" << line << "\n";););
|
||||
}
|
||||
|
||||
void * memory::allocate(char const* file, int line, char const* obj, size_t s) {
|
||||
void * r = allocate(s);
|
||||
TRACE("memory", tout << "alloc " << std::hex << r << std::dec << " " << file << ":" << line << " " << obj << " " << s << "\n";);
|
||||
return r;
|
||||
}
|
||||
|
||||
#if defined(_WINDOWS) || defined(_USE_THREAD_LOCAL)
|
||||
// ==================================
|
||||
// ==================================
|
||||
// THREAD LOCAL VERSION
|
||||
// ==================================
|
||||
// ==================================
|
||||
|
||||
|
||||
// We only integrate the local thread counters with the global one
|
||||
// when the local counter > SYNCH_THRESHOLD
|
||||
#define SYNCH_THRESHOLD 100000
|
||||
|
||||
#ifdef _WINDOWS
|
||||
// Actually this is VS specific instead of Windows specific.
|
||||
__declspec(thread) long long g_memory_thread_alloc_size = 0;
|
||||
#else
|
||||
// GCC style
|
||||
__thread long long g_memory_thread_alloc_size = 0;
|
||||
#endif
|
||||
|
||||
static void synchronize_counters(bool allocating) {
|
||||
#ifdef PROFILE_MEMORY
|
||||
g_synch_counter++;
|
||||
#endif
|
||||
|
||||
bool out_of_mem = false;
|
||||
#pragma omp critical (z3_memory_manager)
|
||||
{
|
||||
g_memory_alloc_size += g_memory_thread_alloc_size;
|
||||
if (g_memory_alloc_size > g_memory_max_used_size)
|
||||
g_memory_max_used_size = g_memory_alloc_size;
|
||||
if (g_memory_max_size != 0 && g_memory_alloc_size > g_memory_max_size)
|
||||
out_of_mem = true;
|
||||
}
|
||||
g_memory_thread_alloc_size = 0;
|
||||
if (out_of_mem && allocating) {
|
||||
throw_out_of_memory();
|
||||
}
|
||||
}
|
||||
|
||||
void memory::deallocate(void * p) {
|
||||
size_t * sz_p = reinterpret_cast<size_t*>(p) - 1;
|
||||
size_t sz = *sz_p;
|
||||
void * real_p = reinterpret_cast<void*>(sz_p);
|
||||
g_memory_thread_alloc_size -= sz;
|
||||
free(real_p);
|
||||
if (g_memory_thread_alloc_size < -SYNCH_THRESHOLD) {
|
||||
synchronize_counters(false);
|
||||
}
|
||||
}
|
||||
|
||||
void * memory::allocate(size_t s) {
|
||||
if (s == 0)
|
||||
return 0;
|
||||
s = s + sizeof(size_t); // we allocate an extra field!
|
||||
void * r = malloc(s);
|
||||
if (r == 0) {
|
||||
throw_out_of_memory();
|
||||
}
|
||||
*(static_cast<size_t*>(r)) = s;
|
||||
g_memory_thread_alloc_size += s;
|
||||
if (g_memory_thread_alloc_size > SYNCH_THRESHOLD) {
|
||||
synchronize_counters(true);
|
||||
}
|
||||
return static_cast<size_t*>(r) + 1; // we return a pointer to the location after the extra field
|
||||
}
|
||||
|
||||
#else
|
||||
// ==================================
|
||||
// ==================================
|
||||
// NO THREAD LOCAL VERSION
|
||||
// ==================================
|
||||
// ==================================
|
||||
// allocate & deallocate without using thread local storage
|
||||
|
||||
void memory::deallocate(void * p) {
|
||||
size_t * sz_p = reinterpret_cast<size_t*>(p) - 1;
|
||||
size_t sz = *sz_p;
|
||||
void * real_p = reinterpret_cast<void*>(sz_p);
|
||||
#pragma omp critical (z3_memory_manager)
|
||||
{
|
||||
g_memory_alloc_size -= sz;
|
||||
}
|
||||
free(real_p);
|
||||
}
|
||||
|
||||
void * memory::allocate(size_t s) {
|
||||
if (s == 0)
|
||||
return 0;
|
||||
s = s + sizeof(size_t); // we allocate an extra field!
|
||||
bool out_of_mem = false;
|
||||
#pragma omp critical (z3_memory_manager)
|
||||
{
|
||||
g_memory_alloc_size += s;
|
||||
if (g_memory_alloc_size > g_memory_max_used_size)
|
||||
g_memory_max_used_size = g_memory_alloc_size;
|
||||
if (g_memory_max_size != 0 && g_memory_alloc_size > g_memory_max_size)
|
||||
out_of_mem = true;
|
||||
}
|
||||
if (out_of_mem)
|
||||
throw_out_of_memory();
|
||||
void * r = malloc(s);
|
||||
if (r == 0)
|
||||
throw_out_of_memory();
|
||||
*(static_cast<size_t*>(r)) = s;
|
||||
return static_cast<size_t*>(r) + 1; // we return a pointer to the location after the extra field
|
||||
}
|
||||
|
||||
#endif
|
105
src/util/memory_manager.h
Normal file
105
src/util/memory_manager.h
Normal file
|
@ -0,0 +1,105 @@
|
|||
/*++
|
||||
Copyright (c) 2006 Microsoft Corporation
|
||||
|
||||
Module Name:
|
||||
|
||||
memory_manager.h
|
||||
|
||||
Abstract:
|
||||
|
||||
Custom memory layer.
|
||||
|
||||
Author:
|
||||
|
||||
Nikolaj Bjorner (nbjorner) 2007-07-24
|
||||
|
||||
Revision History:
|
||||
|
||||
--*/
|
||||
#ifndef _MEMORY_H_
|
||||
#define _MEMORY_H_
|
||||
|
||||
#include<cstdlib>
|
||||
#include<ostream>
|
||||
#include"z3_exception.h"
|
||||
|
||||
class out_of_memory_error : public z3_error {
|
||||
public:
|
||||
out_of_memory_error();
|
||||
};
|
||||
|
||||
class memory {
|
||||
public:
|
||||
static bool is_out_of_memory();
|
||||
static void initialize(size_t max_size);
|
||||
static void set_high_watermark(size_t watermak);
|
||||
static bool above_high_watermark();
|
||||
static void set_max_size(size_t max_size);
|
||||
static void finalize();
|
||||
static void display_max_usage(std::ostream& os);
|
||||
static void display_i_max_usage(std::ostream& os);
|
||||
static void deallocate(void* p);
|
||||
static void* allocate(size_t s);
|
||||
static void deallocate(char const* file, int line, void* p);
|
||||
static void* allocate(char const* file, int line, char const* obj, size_t s);
|
||||
static unsigned long long get_allocation_size();
|
||||
static unsigned long long get_max_used_memory();
|
||||
// temporary hack to avoid out-of-memory crash in z3.exe
|
||||
static void exit_when_out_of_memory(bool flag, char const * msg);
|
||||
};
|
||||
|
||||
|
||||
#if _DEBUG
|
||||
|
||||
#define alloc(T,...) new (memory::allocate(__FILE__,__LINE__,#T, sizeof(T))) T(__VA_ARGS__)
|
||||
#define dealloc(_ptr_) deallocf(__FILE__,__LINE__,_ptr_)
|
||||
|
||||
template<typename T>
|
||||
void deallocf(char const* file, int line, T * ptr) {
|
||||
if (ptr == 0) return;
|
||||
ptr->~T();
|
||||
memory::deallocate(file, line, ptr);
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
#define alloc(T,...) new (memory::allocate(sizeof(T))) T(__VA_ARGS__)
|
||||
|
||||
template<typename T>
|
||||
void dealloc(T * ptr) {
|
||||
if (ptr == 0) return;
|
||||
ptr->~T();
|
||||
memory::deallocate(ptr);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
template<typename T>
|
||||
T * alloc_vect(unsigned sz) {
|
||||
T * r = static_cast<T*>(memory::allocate(sizeof(T) * sz));
|
||||
T * curr = r;
|
||||
for (unsigned i = 0; i < sz; i++, curr++)
|
||||
new (curr) T();
|
||||
return r;
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
void dealloc_vect(T * ptr, unsigned sz) {
|
||||
if (ptr == 0) return;
|
||||
T * curr = ptr;
|
||||
for (unsigned i = 0; i < sz; i++, curr++)
|
||||
curr->~T();
|
||||
memory::deallocate(ptr);
|
||||
}
|
||||
|
||||
#define alloc_svect(T, sz) static_cast<T*>(memory::allocate(sizeof(T) * sz))
|
||||
|
||||
template<typename T>
|
||||
void dealloc_svect(T * ptr) {
|
||||
if (ptr == 0) return;
|
||||
memory::deallocate(ptr);
|
||||
}
|
||||
|
||||
|
||||
#endif /* _MEMORY_H_ */
|
||||
|
907
src/util/mpbq.cpp
Normal file
907
src/util/mpbq.cpp
Normal file
|
@ -0,0 +1,907 @@
|
|||
/*++
|
||||
Copyright (c) 2011 Microsoft Corporation
|
||||
|
||||
Module Name:
|
||||
|
||||
mpbq.cpp
|
||||
|
||||
Abstract:
|
||||
|
||||
Binary Rational Numbers
|
||||
|
||||
A binary rational is a number of the form a/2^k.
|
||||
All integers are binary rationals.
|
||||
Binary rational numbers can be implemented more efficiently than rationals.
|
||||
Binary rationals form a Ring.
|
||||
They are not closed under division.
|
||||
In Z3, they are used to implement algebraic numbers.
|
||||
The root isolation operations only use division by 2.
|
||||
|
||||
Author:
|
||||
|
||||
Leonardo de Moura (leonardo) 2011-11-24.
|
||||
|
||||
Revision History:
|
||||
|
||||
--*/
|
||||
#include<sstream>
|
||||
#include"mpbq.h"
|
||||
|
||||
#ifdef Z3DEBUG
|
||||
#define MPBQ_DEBUG
|
||||
#endif
|
||||
|
||||
rational to_rational(mpbq const & v) {
|
||||
rational r(v.numerator());
|
||||
rational twok;
|
||||
twok = power(rational(2), v.k());
|
||||
return r/twok;
|
||||
}
|
||||
|
||||
mpbq_manager::mpbq_manager(unsynch_mpz_manager & m):
|
||||
m_manager(m) {
|
||||
}
|
||||
|
||||
mpbq_manager::~mpbq_manager() {
|
||||
del(m_addmul_tmp);
|
||||
m_manager.del(m_tmp);
|
||||
m_manager.del(m_tmp2);
|
||||
m_manager.del(m_select_int_tmp1);
|
||||
m_manager.del(m_select_int_tmp2);
|
||||
m_manager.del(m_select_small_tmp);
|
||||
del(m_select_small_tmp1);
|
||||
del(m_select_small_tmp2);
|
||||
m_manager.del(m_div_tmp1);
|
||||
m_manager.del(m_div_tmp2);
|
||||
m_manager.del(m_div_tmp3);
|
||||
}
|
||||
|
||||
void mpbq_manager::reset(mpbq_vector & v) {
|
||||
unsigned sz = v.size();
|
||||
for (unsigned i = 0; i < sz; i++)
|
||||
reset(v[i]);
|
||||
v.reset();
|
||||
}
|
||||
|
||||
void mpbq_manager::normalize(mpbq & a) {
|
||||
if (a.m_k == 0)
|
||||
return;
|
||||
if (m_manager.is_zero(a.m_num)) {
|
||||
a.m_k = 0;
|
||||
return;
|
||||
}
|
||||
#ifdef MPBQ_DEBUG
|
||||
rational r = to_rational(a);
|
||||
#endif
|
||||
unsigned k = m_manager.power_of_two_multiple(a.m_num);
|
||||
if (k > a.m_k)
|
||||
k = a.m_k;
|
||||
m_manager.machine_div2k(a.m_num, k);
|
||||
a.m_k -= k;
|
||||
#ifdef MPBQ_DEBUG
|
||||
rational new_r = to_rational(a);
|
||||
SASSERT(r == new_r);
|
||||
#endif
|
||||
}
|
||||
|
||||
int mpbq_manager::magnitude_lb(mpbq const & a) {
|
||||
if (m_manager.is_zero(a.m_num))
|
||||
return 0;
|
||||
if (m_manager.is_pos(a.m_num))
|
||||
return m_manager.log2(a.m_num) - a.m_k;
|
||||
return m_manager.mlog2(a.m_num) - a.m_k + 1;
|
||||
}
|
||||
|
||||
int mpbq_manager::magnitude_ub(mpbq const & a) {
|
||||
if (m_manager.is_zero(a.m_num))
|
||||
return 0;
|
||||
if (m_manager.is_pos(a.m_num))
|
||||
return m_manager.log2(a.m_num) - a.m_k + 1;
|
||||
return m_manager.mlog2(a.m_num) - a.m_k;
|
||||
}
|
||||
|
||||
void mpbq_manager::mul2(mpbq & a) {
|
||||
if (a.m_k == 0)
|
||||
m_manager.mul2k(a.m_num, 1);
|
||||
else
|
||||
a.m_k--;
|
||||
}
|
||||
|
||||
void mpbq_manager::mul2k(mpbq & a, unsigned k) {
|
||||
if (k == 0)
|
||||
return;
|
||||
if (a.m_k < k) {
|
||||
m_manager.mul2k(a.m_num, k - a.m_k);
|
||||
a.m_k = 0;
|
||||
}
|
||||
else {
|
||||
SASSERT(a.m_k >= k);
|
||||
a.m_k -= k;
|
||||
}
|
||||
}
|
||||
|
||||
void mpbq_manager::add(mpbq const & a, mpbq const & b, mpbq & r) {
|
||||
#ifdef MPBQ_DEBUG
|
||||
rational _a = to_rational(a);
|
||||
rational _b = to_rational(b);
|
||||
#endif
|
||||
if (a.m_k == b.m_k) {
|
||||
m_manager.add(a.m_num, b.m_num, r.m_num);
|
||||
r.m_k = a.m_k;
|
||||
}
|
||||
else if (a.m_k < b.m_k) {
|
||||
m_manager.mul2k(a.m_num, b.m_k - a.m_k, m_tmp);
|
||||
m_manager.add(b.m_num, m_tmp, r.m_num);
|
||||
r.m_k = b.m_k;
|
||||
}
|
||||
else {
|
||||
SASSERT(a.m_k > b.m_k);
|
||||
m_manager.mul2k(b.m_num, a.m_k - b.m_k, m_tmp);
|
||||
m_manager.add(a.m_num, m_tmp, r.m_num);
|
||||
r.m_k = a.m_k;
|
||||
}
|
||||
normalize(r);
|
||||
#ifdef MPBQ_DEBUG
|
||||
rational _r = to_rational(r);
|
||||
SASSERT(_a + _b == _r);
|
||||
#endif
|
||||
}
|
||||
|
||||
void mpbq_manager::add(mpbq const & a, mpz const & b, mpbq & r) {
|
||||
#ifdef MPBQ_DEBUG
|
||||
rational _a = to_rational(a);
|
||||
rational _b(b);
|
||||
#endif
|
||||
if (a.m_k == 0) {
|
||||
m_manager.add(a.m_num, b, r.m_num);
|
||||
r.m_k = a.m_k;
|
||||
}
|
||||
else {
|
||||
m_manager.mul2k(b, a.m_k, m_tmp);
|
||||
m_manager.add(a.m_num, m_tmp, r.m_num);
|
||||
r.m_k = a.m_k;
|
||||
}
|
||||
normalize(r);
|
||||
#ifdef MPBQ_DEBUG
|
||||
rational _r = to_rational(r);
|
||||
TRACE("mpbq_bug", tout << "add a: " << _a << ", b: " << _b << ", r: " << _r << ", expected: " << (_a + _b) << "\n";);
|
||||
SASSERT(_a + _b == _r);
|
||||
#endif
|
||||
}
|
||||
|
||||
void mpbq_manager::sub(mpbq const & a, mpbq const & b, mpbq & r) {
|
||||
#ifdef MPBQ_DEBUG
|
||||
rational _a = to_rational(a);
|
||||
rational _b = to_rational(b);
|
||||
#endif
|
||||
if (a.m_k == b.m_k) {
|
||||
m_manager.sub(a.m_num, b.m_num, r.m_num);
|
||||
r.m_k = a.m_k;
|
||||
}
|
||||
else if (a.m_k < b.m_k) {
|
||||
m_manager.mul2k(a.m_num, b.m_k - a.m_k, m_tmp);
|
||||
m_manager.sub(m_tmp, b.m_num, r.m_num);
|
||||
r.m_k = b.m_k;
|
||||
}
|
||||
else {
|
||||
SASSERT(a.m_k > b.m_k);
|
||||
m_manager.mul2k(b.m_num, a.m_k - b.m_k, m_tmp);
|
||||
m_manager.sub(a.m_num, m_tmp, r.m_num);
|
||||
r.m_k = a.m_k;
|
||||
}
|
||||
normalize(r);
|
||||
#ifdef MPBQ_DEBUG
|
||||
rational _r = to_rational(r);
|
||||
TRACE("mpbq_bug", tout << "sub a: " << _a << ", b: " << _b << ", r: " << _r << ", expected: " << (_a - _b) << "\n";);
|
||||
SASSERT(_a - _b == _r);
|
||||
#endif
|
||||
}
|
||||
|
||||
void mpbq_manager::sub(mpbq const & a, mpz const & b, mpbq & r) {
|
||||
#ifdef MPBQ_DEBUG
|
||||
rational _a = to_rational(a);
|
||||
rational _b(b);
|
||||
#endif
|
||||
if (a.m_k == 0) {
|
||||
m_manager.sub(a.m_num, b, r.m_num);
|
||||
r.m_k = a.m_k;
|
||||
}
|
||||
else {
|
||||
m_manager.mul2k(b, a.m_k, m_tmp);
|
||||
m_manager.sub(a.m_num, m_tmp, r.m_num);
|
||||
r.m_k = a.m_k;
|
||||
}
|
||||
normalize(r);
|
||||
#ifdef MPBQ_DEBUG
|
||||
rational _r = to_rational(r);
|
||||
SASSERT(_a - _b == _r);
|
||||
#endif
|
||||
}
|
||||
|
||||
void mpbq_manager::mul(mpbq const & a, mpbq const & b, mpbq & r) {
|
||||
#ifdef MPBQ_DEBUG
|
||||
rational _a = to_rational(a);
|
||||
rational _b = to_rational(b);
|
||||
#endif
|
||||
m_manager.mul(a.m_num, b.m_num, r.m_num);
|
||||
r.m_k = a.m_k + b.m_k;
|
||||
if (a.m_k == 0 || b.m_k == 0) {
|
||||
// if a.m_k and b.m_k are greater than 0, then there is no point in normalizing r.
|
||||
normalize(r);
|
||||
}
|
||||
#ifdef MPBQ_DEBUG
|
||||
rational _r = to_rational(r);
|
||||
SASSERT(_a * _b == _r);
|
||||
#endif
|
||||
}
|
||||
|
||||
void mpbq_manager::mul(mpbq const & a, mpz const & b, mpbq & r) {
|
||||
#ifdef MPBQ_DEBUG
|
||||
rational _a = to_rational(a);
|
||||
rational _b(b);
|
||||
#endif
|
||||
m_manager.mul(a.m_num, b, r.m_num);
|
||||
r.m_k = a.m_k;
|
||||
normalize(r);
|
||||
#ifdef MPBQ_DEBUG
|
||||
rational _r = to_rational(r);
|
||||
SASSERT(_a * _b == _r);
|
||||
#endif
|
||||
}
|
||||
|
||||
void mpbq_manager::power(mpbq & a, unsigned k) {
|
||||
SASSERT(static_cast<uint64>(k) * static_cast<uint64>(a.k()) <= static_cast<uint64>(UINT_MAX));
|
||||
// We don't need to normalize because:
|
||||
// If a.m_k == 0, then a is an integer, and the result be an integer
|
||||
// If a.m_k > 0, then a.m_num must be odd, and the (a.m_num)^k will also be odd
|
||||
a.m_k *= k;
|
||||
m_manager.power(a.m_num, k, a.m_num);
|
||||
}
|
||||
|
||||
bool mpbq_manager::root_lower(mpbq & a, unsigned n) {
|
||||
bool r = m_manager.root(a.m_num, n);
|
||||
if (!r)
|
||||
m_manager.dec(a.m_num);
|
||||
if (a.m_k % n == 0) {
|
||||
a.m_k /= n;
|
||||
normalize(a);
|
||||
return r;
|
||||
}
|
||||
else if (m_manager.is_neg(a.m_num)) {
|
||||
a.m_k /= n;
|
||||
normalize(a);
|
||||
return false;
|
||||
}
|
||||
else {
|
||||
a.m_k /= n;
|
||||
a.m_k++;
|
||||
normalize(a);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
bool mpbq_manager::root_upper(mpbq & a, unsigned n) {
|
||||
bool r = m_manager.root(a.m_num, n);
|
||||
if (a.m_k % n == 0) {
|
||||
a.m_k /= n;
|
||||
normalize(a);
|
||||
return r;
|
||||
}
|
||||
else if (m_manager.is_neg(a.m_num)) {
|
||||
a.m_k /= n;
|
||||
a.m_k++;
|
||||
normalize(a);
|
||||
return false;
|
||||
}
|
||||
else {
|
||||
a.m_k /= n;
|
||||
normalize(a);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
bool mpbq_manager::lt(mpbq const & a, mpbq const & b) {
|
||||
// TODO: try the following trick when k1 != k2
|
||||
// Given, a = n1/2^k1 b = n2/2^k2
|
||||
// Suppose n1 > 0 and n2 > 0,
|
||||
// Then, we have, n1 <= 2^{log2(n1) - k1} 2^{log2(n2) - 1 - k2} <= n2
|
||||
// Thus, log2(n1) - k1 < log2(n2) - 1 - k2 implies a < b
|
||||
// Similarly: log2(n2) - k2 < log2(n1) - 1 - k1 implies b < a
|
||||
// That is we compare the "magnitude" of the numbers before performing mul2k
|
||||
//
|
||||
// If n1 < 0 and n2 < 0, a similar trick can be implemented using mlog2 instead log2.
|
||||
//
|
||||
// It seems the trick is not useful when n1 and n2 are small
|
||||
// numbers, and k1 and k2 very small < 8. Since, no bignumber
|
||||
// computation is needed for mul2k.
|
||||
|
||||
if (a.m_k == b.m_k) {
|
||||
return m_manager.lt(a.m_num, b.m_num);
|
||||
}
|
||||
else if (a.m_k < b.m_k) {
|
||||
m_manager.mul2k(a.m_num, b.m_k - a.m_k, m_tmp);
|
||||
return m_manager.lt(m_tmp, b.m_num);
|
||||
}
|
||||
else {
|
||||
SASSERT(a.m_k > b.m_k);
|
||||
m_manager.mul2k(b.m_num, a.m_k - b.m_k, m_tmp);
|
||||
return m_manager.lt(a.m_num, m_tmp);
|
||||
}
|
||||
}
|
||||
|
||||
bool mpbq_manager::lt_1div2k(mpbq const & a, unsigned k) {
|
||||
if (m_manager.is_nonpos(a.m_num))
|
||||
return true;
|
||||
if (a.m_k <= k) {
|
||||
// since a.m_num >= 1
|
||||
return false;
|
||||
}
|
||||
else {
|
||||
SASSERT(a.m_k > k);
|
||||
m_manager.mul2k(mpz(1), a.m_k - k, m_tmp);
|
||||
return m_manager.lt(a.m_num, m_tmp);
|
||||
}
|
||||
}
|
||||
|
||||
bool mpbq_manager::eq(mpbq const & a, mpq const & b) {
|
||||
if (is_int(a) && m_manager.is_one(b.denominator()))
|
||||
return m_manager.eq(a.m_num, b.numerator());
|
||||
m_manager.mul2k(b.numerator(), a.m_k, m_tmp);
|
||||
m_manager.mul(a.m_num, b.denominator(), m_tmp2);
|
||||
return m_manager.eq(m_tmp, m_tmp2);
|
||||
}
|
||||
|
||||
bool mpbq_manager::lt(mpbq const & a, mpq const & b) {
|
||||
if (is_int(a) && m_manager.is_one(b.denominator()))
|
||||
return m_manager.lt(a.m_num, b.numerator());
|
||||
m_manager.mul(a.m_num, b.denominator(), m_tmp);
|
||||
m_manager.mul2k(b.numerator(), a.m_k, m_tmp2);
|
||||
return m_manager.lt(m_tmp, m_tmp2);
|
||||
}
|
||||
|
||||
bool mpbq_manager::le(mpbq const & a, mpq const & b) {
|
||||
if (is_int(a) && m_manager.is_one(b.denominator()))
|
||||
return m_manager.le(a.m_num, b.numerator());
|
||||
m_manager.mul(a.m_num, b.denominator(), m_tmp);
|
||||
m_manager.mul2k(b.numerator(), a.m_k, m_tmp2);
|
||||
return m_manager.le(m_tmp, m_tmp2);
|
||||
}
|
||||
|
||||
bool mpbq_manager::lt(mpbq const & a, mpz const & b) {
|
||||
if (is_int(a))
|
||||
return m_manager.lt(a.m_num, b);
|
||||
m_manager.mul2k(b, a.m_k, m_tmp);
|
||||
return m_manager.lt(a.m_num, m_tmp);
|
||||
}
|
||||
|
||||
bool mpbq_manager::le(mpbq const & a, mpz const & b) {
|
||||
if (is_int(a))
|
||||
return m_manager.le(a.m_num, b);
|
||||
m_manager.mul2k(b, a.m_k, m_tmp);
|
||||
return m_manager.le(a.m_num, m_tmp);
|
||||
}
|
||||
|
||||
std::string mpbq_manager::to_string(mpbq const & a) {
|
||||
std::ostringstream buffer;
|
||||
buffer << m_manager.to_string(a.m_num);
|
||||
if (a.m_k == 1)
|
||||
buffer << "/2";
|
||||
else if (a.m_k > 1)
|
||||
buffer << "/2^" << a.m_k;
|
||||
return buffer.str();
|
||||
}
|
||||
|
||||
void mpbq_manager::display(std::ostream & out, mpbq const & a) {
|
||||
out << m_manager.to_string(a.m_num);
|
||||
if (a.m_k > 0)
|
||||
out << "/2";
|
||||
if (a.m_k > 1)
|
||||
out << "^" << a.m_k;
|
||||
}
|
||||
|
||||
void mpbq_manager::display_smt2(std::ostream & out, mpbq const & a, bool decimal) {
|
||||
if (a.m_k == 0) {
|
||||
m_manager.display_smt2(out, a.m_num, decimal);
|
||||
}
|
||||
else {
|
||||
out << "(/ ";
|
||||
m_manager.display_smt2(out, a.m_num, decimal);
|
||||
out << " ";
|
||||
out << "(^ 2";
|
||||
if (decimal) out << ".0";
|
||||
out << " " << a.m_k;
|
||||
if (decimal) out << ".0";
|
||||
out << "))";
|
||||
}
|
||||
}
|
||||
|
||||
void mpbq_manager::display_decimal(std::ostream & out, mpbq const & a, unsigned prec) {
|
||||
if (is_int(a)) {
|
||||
out << m_manager.to_string(a.m_num);
|
||||
return;
|
||||
}
|
||||
mpz two(2);
|
||||
mpz ten(10);
|
||||
mpz two_k;
|
||||
mpz n1, v1;
|
||||
if (m_manager.is_neg(a.m_num))
|
||||
out << "-";
|
||||
m_manager.set(v1, a.m_num);
|
||||
m_manager.abs(v1);
|
||||
m_manager.power(two, a.m_k, two_k);
|
||||
m_manager.rem(v1, two_k, n1);
|
||||
m_manager.div(v1, two_k, v1);
|
||||
SASSERT(!m_manager.is_zero(n1));
|
||||
out << m_manager.to_string(v1);
|
||||
out << ".";
|
||||
for (unsigned i = 0; i < prec; i++) {
|
||||
m_manager.mul(n1, ten, n1);
|
||||
m_manager.div(n1, two_k, v1);
|
||||
m_manager.rem(n1, two_k, n1);
|
||||
out << m_manager.to_string(v1);
|
||||
if (m_manager.is_zero(n1))
|
||||
goto end;
|
||||
}
|
||||
out << "?";
|
||||
end:
|
||||
m_manager.del(n1);
|
||||
m_manager.del(v1);
|
||||
m_manager.del(two_k);
|
||||
}
|
||||
|
||||
void mpbq_manager::display_decimal(std::ostream & out, mpbq const & a, mpbq const & b, unsigned prec) {
|
||||
mpz two(2);
|
||||
mpz ten(10);
|
||||
mpz two_k1, two_k2;
|
||||
mpz n1, v1, n2, v2;
|
||||
if (m_manager.is_neg(a.m_num) != m_manager.is_neg(b.m_num)) {
|
||||
out << "?";
|
||||
return;
|
||||
}
|
||||
if (m_manager.is_neg(a.m_num))
|
||||
out << "-";
|
||||
m_manager.set(v1, a.m_num);
|
||||
m_manager.abs(v1);
|
||||
m_manager.set(v2, b.m_num);
|
||||
m_manager.abs(v2);
|
||||
m_manager.power(two, a.m_k, two_k1);
|
||||
m_manager.power(two, b.m_k, two_k2);
|
||||
m_manager.rem(v1, two_k1, n1);
|
||||
m_manager.rem(v2, two_k2, n2);
|
||||
m_manager.div(v1, two_k1, v1);
|
||||
m_manager.div(v2, two_k2, v2);
|
||||
if (!m_manager.eq(v1, v2)) {
|
||||
out << "?";
|
||||
goto end;
|
||||
}
|
||||
|
||||
out << m_manager.to_string(v1);
|
||||
if (m_manager.is_zero(n1) && m_manager.is_zero(n2))
|
||||
goto end; // number is an integer
|
||||
out << ".";
|
||||
for (unsigned i = 0; i < prec; i++) {
|
||||
m_manager.mul(n1, ten, n1);
|
||||
m_manager.mul(n2, ten, n2);
|
||||
m_manager.div(n1, two_k1, v1);
|
||||
m_manager.div(n2, two_k2, v2);
|
||||
if (m_manager.eq(v1, v2)) {
|
||||
out << m_manager.to_string(v1);
|
||||
}
|
||||
else {
|
||||
out << "?";
|
||||
goto end;
|
||||
}
|
||||
m_manager.rem(n1, two_k1, n1);
|
||||
m_manager.rem(n2, two_k2, n2);
|
||||
if (m_manager.is_zero(n1) && m_manager.is_zero(n2))
|
||||
goto end; // number is precise
|
||||
}
|
||||
out << "?";
|
||||
end:
|
||||
m_manager.del(n1);
|
||||
m_manager.del(v1);
|
||||
m_manager.del(n2);
|
||||
m_manager.del(v2);
|
||||
m_manager.del(two_k1);
|
||||
m_manager.del(two_k2);
|
||||
}
|
||||
|
||||
bool mpbq_manager::to_mpbq(mpq const & q, mpbq & bq) {
|
||||
mpz const & n = q.numerator();
|
||||
mpz const & d = q.denominator();
|
||||
unsigned shift;
|
||||
if (m_manager.is_one(d)) {
|
||||
set(bq, n);
|
||||
SASSERT(eq(bq, q));
|
||||
return true;
|
||||
}
|
||||
else if (m_manager.is_power_of_two(d, shift)) {
|
||||
SASSERT(shift>=1);
|
||||
unsigned k = shift;
|
||||
set(bq, n, k);
|
||||
SASSERT(eq(bq, q));
|
||||
return true;
|
||||
}
|
||||
else {
|
||||
unsigned k = m_manager.log2(d);
|
||||
set(bq, n, k+1);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
void mpbq_manager::refine_upper(mpq const & q, mpbq & l, mpbq & u) {
|
||||
SASSERT(lt(l, q) && gt(u, q));
|
||||
SASSERT(!m_manager.is_power_of_two(q.denominator()));
|
||||
// l < q < u
|
||||
mpbq mid;
|
||||
while (true) {
|
||||
add(l, u, mid);
|
||||
div2(mid);
|
||||
if (gt(mid, q)) {
|
||||
swap(u, mid);
|
||||
del(mid);
|
||||
SASSERT(lt(l, q) && gt(u, q));
|
||||
return;
|
||||
}
|
||||
swap(l, mid);
|
||||
}
|
||||
}
|
||||
|
||||
void mpbq_manager::refine_lower(mpq const & q, mpbq & l, mpbq & u) {
|
||||
SASSERT(lt(l, q) && gt(u, q));
|
||||
SASSERT(!m_manager.is_power_of_two(q.denominator()));
|
||||
// l < q < u
|
||||
mpbq mid;
|
||||
while (true) {
|
||||
add(l, u, mid);
|
||||
div2(mid);
|
||||
if (lt(mid, q)) {
|
||||
swap(l, mid);
|
||||
del(mid);
|
||||
SASSERT(lt(l, q) && gt(u, q));
|
||||
return;
|
||||
}
|
||||
swap(u, mid);
|
||||
}
|
||||
}
|
||||
|
||||
// sectect integer in [lower, upper]
|
||||
bool mpbq_manager::select_integer(mpbq const & lower, mpbq const & upper, mpz & r) {
|
||||
if (is_int(lower)) {
|
||||
m_manager.set(r, lower.m_num);
|
||||
return true;
|
||||
}
|
||||
if (is_int(upper)) {
|
||||
m_manager.set(r, upper.m_num);
|
||||
return true;
|
||||
}
|
||||
mpz & ceil_lower = m_select_int_tmp1;
|
||||
mpz & floor_upper = m_select_int_tmp2;
|
||||
ceil(m_manager, lower, ceil_lower);
|
||||
floor(m_manager, upper, floor_upper);
|
||||
if (m_manager.le(ceil_lower, floor_upper)) {
|
||||
m_manager.set(r, ceil_lower);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
// select integer in (lower, upper]
|
||||
bool mpbq_manager::select_integer(unsynch_mpq_manager & qm, mpq const & lower, mpbq const & upper, mpz & r) {
|
||||
if (is_int(upper)) {
|
||||
m_manager.set(r, upper.m_num);
|
||||
return true;
|
||||
}
|
||||
mpz & ceil_lower = m_select_int_tmp1;
|
||||
mpz & floor_upper = m_select_int_tmp2;
|
||||
if (qm.is_int(lower)) {
|
||||
m_manager.set(ceil_lower, lower.numerator());
|
||||
m_manager.inc(ceil_lower);
|
||||
}
|
||||
else {
|
||||
scoped_mpz tmp(qm);
|
||||
qm.ceil(lower, tmp);
|
||||
m_manager.set(ceil_lower, tmp);
|
||||
}
|
||||
floor(m_manager, upper, floor_upper);
|
||||
if (m_manager.le(ceil_lower, floor_upper)) {
|
||||
m_manager.set(r, ceil_lower);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
// sectect integer in [lower, upper)
|
||||
bool mpbq_manager::select_integer(unsynch_mpq_manager & qm, mpbq const & lower, mpq const & upper, mpz & r) {
|
||||
if (is_int(lower)) {
|
||||
m_manager.set(r, lower.m_num);
|
||||
return true;
|
||||
}
|
||||
mpz & ceil_lower = m_select_int_tmp1;
|
||||
mpz & floor_upper = m_select_int_tmp2;
|
||||
ceil(m_manager, lower, ceil_lower);
|
||||
if (qm.is_int(upper)) {
|
||||
m_manager.set(floor_upper, upper.numerator());
|
||||
m_manager.dec(floor_upper);
|
||||
}
|
||||
else {
|
||||
scoped_mpz tmp(qm);
|
||||
qm.floor(upper, tmp);
|
||||
m_manager.set(floor_upper, tmp);
|
||||
}
|
||||
if (m_manager.le(ceil_lower, floor_upper)) {
|
||||
m_manager.set(r, ceil_lower);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
// sectect integer in (lower, upper)
|
||||
bool mpbq_manager::select_integer(unsynch_mpq_manager & qm, mpq const & lower, mpq const & upper, mpz & r) {
|
||||
mpz & ceil_lower = m_select_int_tmp1;
|
||||
mpz & floor_upper = m_select_int_tmp2;
|
||||
|
||||
if (qm.is_int(lower)) {
|
||||
m_manager.set(ceil_lower, lower.numerator());
|
||||
m_manager.inc(ceil_lower);
|
||||
}
|
||||
else {
|
||||
scoped_mpz tmp(qm);
|
||||
qm.ceil(lower, tmp);
|
||||
m_manager.set(ceil_lower, tmp);
|
||||
}
|
||||
|
||||
if (qm.is_int(upper)) {
|
||||
m_manager.set(floor_upper, upper.numerator());
|
||||
m_manager.dec(floor_upper);
|
||||
}
|
||||
else {
|
||||
scoped_mpz tmp(qm);
|
||||
qm.floor(upper, tmp);
|
||||
m_manager.set(floor_upper, tmp);
|
||||
}
|
||||
|
||||
if (m_manager.le(ceil_lower, floor_upper)) {
|
||||
m_manager.set(r, ceil_lower);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
#define LINEAR_SEARCH_THRESHOLD 8
|
||||
|
||||
void mpbq_manager::select_small_core(mpbq const & lower, mpbq const & upper, mpbq & r) {
|
||||
SASSERT(le(lower, upper));
|
||||
mpz & aux = m_select_small_tmp;
|
||||
if (select_integer(lower, upper, aux)) {
|
||||
set(r, aux);
|
||||
return;
|
||||
}
|
||||
|
||||
// At this point we know that k=0 does not work, since there is no integer
|
||||
// in the interval [lower, upper]
|
||||
unsigned min_k = 0;
|
||||
unsigned max_k = std::min(lower.m_k, upper.m_k);
|
||||
|
||||
if (max_k <= LINEAR_SEARCH_THRESHOLD) {
|
||||
unsigned k = 0;
|
||||
mpbq & l2k = m_select_small_tmp1;
|
||||
mpbq & u2k = m_select_small_tmp2;
|
||||
set(l2k, lower);
|
||||
set(u2k, upper);
|
||||
while (true) {
|
||||
k++;
|
||||
mul2(l2k);
|
||||
mul2(u2k);
|
||||
if (select_integer(l2k, u2k, aux)) {
|
||||
set(r, aux, k);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
mpbq & l2k = m_select_small_tmp1;
|
||||
mpbq & u2k = m_select_small_tmp2;
|
||||
while (true) {
|
||||
unsigned mid_k = min_k + (max_k - min_k)/2;
|
||||
set(l2k, lower);
|
||||
set(u2k, upper);
|
||||
mul2k(l2k, mid_k);
|
||||
mul2k(u2k, mid_k);
|
||||
if (select_integer(l2k, u2k, aux))
|
||||
max_k = mid_k;
|
||||
else
|
||||
min_k = mid_k + 1;
|
||||
if (min_k == max_k) {
|
||||
if (max_k == mid_k) {
|
||||
set(r, aux, max_k);
|
||||
}
|
||||
else {
|
||||
set(l2k, lower);
|
||||
set(u2k, upper);
|
||||
mul2k(l2k, max_k);
|
||||
mul2k(u2k, max_k);
|
||||
VERIFY(select_integer(l2k, u2k, aux));
|
||||
set(r, aux, max_k);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
SASSERT(le(lower, r));
|
||||
SASSERT(le(r, upper));
|
||||
}
|
||||
|
||||
bool mpbq_manager::select_small(mpbq const & lower, mpbq const & upper, mpbq & r) {
|
||||
if (gt(lower, upper))
|
||||
return false;
|
||||
select_small_core(lower, upper, r);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
void mpbq_manager::select_small_core(unsynch_mpq_manager & qm, mpq const & lower, mpbq const & upper, mpbq & r) {
|
||||
TRACE("select_small", tout << "lower (q): " << qm.to_string(lower) << ", upper (bq): " << to_string(upper) << "\n";);
|
||||
SASSERT(gt(upper, lower));
|
||||
mpz & aux = m_select_small_tmp;
|
||||
if (select_integer(qm, lower, upper, aux)) {
|
||||
set(r, aux);
|
||||
return;
|
||||
}
|
||||
|
||||
// At this point we know that k=0 does not work, since there is no integer
|
||||
// in the interval [lower, upper]
|
||||
unsigned k = 0;
|
||||
scoped_mpq l2k(qm);
|
||||
mpq two(2);
|
||||
mpbq & u2k = m_select_small_tmp2;
|
||||
qm.set(l2k, lower);
|
||||
set(u2k, upper);
|
||||
while (true) {
|
||||
k++;
|
||||
qm.mul(l2k, two, l2k);
|
||||
mul2(u2k);
|
||||
if (select_integer(qm, l2k, u2k, aux)) {
|
||||
set(r, aux, k);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void mpbq_manager::select_small_core(unsynch_mpq_manager & qm, mpbq const & lower, mpq const & upper, mpbq & r) {
|
||||
SASSERT(lt(lower, upper));
|
||||
mpz & aux = m_select_small_tmp;
|
||||
if (select_integer(qm, lower, upper, aux)) {
|
||||
set(r, aux);
|
||||
return;
|
||||
}
|
||||
|
||||
// At this point we know that k=0 does not work, since there is no integer
|
||||
// in the interval [lower, upper]
|
||||
unsigned k = 0;
|
||||
mpbq & l2k = m_select_small_tmp2;
|
||||
scoped_mpq u2k(qm);
|
||||
mpq two(2);
|
||||
set(l2k, lower);
|
||||
qm.set(u2k, upper);
|
||||
while (true) {
|
||||
k++;
|
||||
mul2(l2k);
|
||||
qm.mul(u2k, two, u2k);
|
||||
if (select_integer(qm, l2k, u2k, aux)) {
|
||||
set(r, aux, k);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void mpbq_manager::select_small_core(unsynch_mpq_manager & qm, mpq const & lower, mpq const & upper, mpbq & r) {
|
||||
SASSERT(qm.lt(lower, upper));
|
||||
mpz & aux = m_select_small_tmp;
|
||||
if (select_integer(qm, lower, upper, aux)) {
|
||||
set(r, aux);
|
||||
return;
|
||||
}
|
||||
|
||||
// At this point we know that k=0 does not work, since there is no integer
|
||||
// in the interval [lower, upper]
|
||||
unsigned k = 0;
|
||||
scoped_mpq l2k(qm);
|
||||
scoped_mpq u2k(qm);
|
||||
mpq two(2);
|
||||
qm.set(l2k, lower);
|
||||
qm.set(u2k, upper);
|
||||
while (true) {
|
||||
k++;
|
||||
qm.mul(l2k, two, l2k);
|
||||
qm.mul(u2k, two, u2k);
|
||||
if (select_integer(qm, l2k, u2k, aux)) {
|
||||
set(r, aux, k);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void mpbq_manager::approx(mpbq & a, unsigned k, bool to_plus_inf) {
|
||||
if (a.m_k <= k)
|
||||
return;
|
||||
#ifdef MPBQ_DEBUG
|
||||
scoped_mpbq old_a(*this);
|
||||
old_a = a;
|
||||
#endif
|
||||
bool sgn = m_manager.is_neg(a.m_num);
|
||||
bool _inc = (sgn != to_plus_inf);
|
||||
unsigned shift = a.m_k - k;
|
||||
m_manager.abs(a.m_num);
|
||||
m_manager.machine_div2k(a.m_num, shift);
|
||||
if (_inc)
|
||||
m_manager.inc(a.m_num);
|
||||
if (sgn)
|
||||
m_manager.neg(a.m_num);
|
||||
a.m_k = k;
|
||||
normalize(a);
|
||||
#ifdef MPBQ_DEBUG
|
||||
if (to_plus_inf) {
|
||||
SASSERT(lt(old_a, a));
|
||||
}
|
||||
else {
|
||||
SASSERT(lt(a, old_a));
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
void mpbq_manager::approx_div(mpbq const & a, mpbq const & b, mpbq & c, unsigned k, bool to_plus_inf) {
|
||||
SASSERT(!is_zero(b));
|
||||
unsigned k_prime;
|
||||
if (m_manager.is_power_of_two(b.m_num, k_prime)) {
|
||||
// The division is precise, so we ignore k and to_plus_inf
|
||||
SASSERT(b.m_k == 0); // remark: b.m_num is odd when b.m_k > 0
|
||||
m_manager.set(c.m_num, a.m_num);
|
||||
if (a.m_k == 0) {
|
||||
c.m_k = k_prime;
|
||||
normalize(c);
|
||||
}
|
||||
else {
|
||||
c.m_k = a.m_k + k_prime;
|
||||
// there is not need to normalize since the least significant bit of a must be 1.
|
||||
}
|
||||
}
|
||||
else if (m_manager.divides(b.m_num, a.m_num)) {
|
||||
// result is also precise
|
||||
m_manager.div(a.m_num, b.m_num, c.m_num);
|
||||
if (a.m_k >= b.m_k) {
|
||||
c.m_k = a.m_k - b.m_k;
|
||||
}
|
||||
else {
|
||||
m_manager.mul2k(c.m_num, b.m_k - a.m_k);
|
||||
c.m_k = 0;
|
||||
}
|
||||
normalize(c);
|
||||
}
|
||||
else {
|
||||
bool sgn = is_neg(a) != is_neg(b);
|
||||
mpz & abs_a = m_div_tmp1;
|
||||
mpz & norm_a = m_div_tmp2;
|
||||
mpz & abs_b = m_div_tmp3;
|
||||
m_manager.set(abs_a, a.m_num);
|
||||
m_manager.abs(abs_a);
|
||||
m_manager.set(abs_b, b.m_num);
|
||||
m_manager.abs(abs_b);
|
||||
if (a.m_k > b.m_k) {
|
||||
if (k >= a.m_k - b.m_k)
|
||||
m_manager.mul2k(abs_a, k - (a.m_k - b.m_k), norm_a);
|
||||
else
|
||||
m_manager.machine_div2k(abs_a, (a.m_k - b.m_k) - k, norm_a);
|
||||
}
|
||||
else {
|
||||
m_manager.mul2k(abs_a, k + b.m_k - a.m_k, norm_a);
|
||||
}
|
||||
c.m_k = k;
|
||||
m_manager.div(norm_a, abs_b, c.m_num);
|
||||
if (sgn != to_plus_inf)
|
||||
m_manager.inc(c.m_num);
|
||||
if (sgn)
|
||||
m_manager.neg(c.m_num);
|
||||
normalize(c);
|
||||
}
|
||||
}
|
362
src/util/mpbq.h
Normal file
362
src/util/mpbq.h
Normal file
|
@ -0,0 +1,362 @@
|
|||
/*++
|
||||
Copyright (c) 2011 Microsoft Corporation
|
||||
|
||||
Module Name:
|
||||
|
||||
mpbq.h
|
||||
|
||||
Abstract:
|
||||
|
||||
Binary Rational Numbers
|
||||
|
||||
A binary rational is a number of the form a/2^k.
|
||||
All integers are binary rationals.
|
||||
Binary rational numbers can be implemented more efficiently than rationals.
|
||||
Binary rationals form a Ring.
|
||||
They are not closed under division.
|
||||
In Z3, they are used to implement algebraic numbers.
|
||||
The root isolation operations only use division by 2.
|
||||
|
||||
Author:
|
||||
|
||||
Leonardo de Moura (leonardo) 2011-11-24.
|
||||
|
||||
Revision History:
|
||||
|
||||
--*/
|
||||
#ifndef _MPBQ_H_
|
||||
#define _MPBQ_H_
|
||||
|
||||
#include"mpq.h"
|
||||
#include"rational.h"
|
||||
#include"vector.h"
|
||||
|
||||
class mpbq {
|
||||
mpz m_num;
|
||||
unsigned m_k; // we don't need mpz here. 2^(2^32-1) is a huge number, we will not even be able to convert the mpbq into an mpq
|
||||
friend class mpbq_manager;
|
||||
public:
|
||||
mpbq():m_num(0), m_k(0) {}
|
||||
mpbq(int v):m_num(v), m_k(0) {}
|
||||
mpbq(int v, unsigned k):m_num(v), m_k(k) {}
|
||||
mpz const & numerator() const { return m_num; }
|
||||
unsigned k() const { return m_k; }
|
||||
void swap(mpbq & other) { m_num.swap(other.m_num); std::swap(m_k, other.m_k); }
|
||||
};
|
||||
|
||||
inline void swap(mpbq & m1, mpbq & m2) { m1.swap(m2); }
|
||||
|
||||
typedef svector<mpbq> mpbq_vector;
|
||||
|
||||
class mpbq_manager {
|
||||
unsynch_mpz_manager & m_manager;
|
||||
mpz m_tmp;
|
||||
mpz m_tmp2;
|
||||
mpbq m_addmul_tmp;
|
||||
mpz m_select_int_tmp1;
|
||||
mpz m_select_int_tmp2;
|
||||
mpz m_select_small_tmp;
|
||||
mpbq m_select_small_tmp1;
|
||||
mpbq m_select_small_tmp2;
|
||||
mpz m_div_tmp1, m_div_tmp2, m_div_tmp3;
|
||||
void normalize(mpbq & a);
|
||||
bool select_integer(mpbq const & lower, mpbq const & upper, mpz & r);
|
||||
bool select_integer(unsynch_mpq_manager & qm, mpq const & lower, mpbq const & upper, mpz & r);
|
||||
bool select_integer(unsynch_mpq_manager & qm, mpbq const & lower, mpq const & upper, mpz & r);
|
||||
bool select_integer(unsynch_mpq_manager & qm, mpq const & lower, mpq const & upper, mpz & r);
|
||||
|
||||
public:
|
||||
static bool precise() { return true; }
|
||||
static bool field() { return false; }
|
||||
typedef mpbq numeral;
|
||||
|
||||
mpbq_manager(unsynch_mpz_manager & m);
|
||||
~mpbq_manager();
|
||||
|
||||
static void swap(mpbq & a, mpbq & b) { a.swap(b); }
|
||||
|
||||
void del(mpbq & a) { m_manager.del(a.m_num); }
|
||||
void reset(mpbq & a) { m_manager.reset(a.m_num); a.m_k = 0; }
|
||||
void reset(mpbq_vector & v);
|
||||
void set(mpbq & a, int n) { m_manager.set(a.m_num, n); a.m_k = 0; }
|
||||
void set(mpbq & a, unsigned n) { m_manager.set(a.m_num, n); a.m_k = 0; }
|
||||
void set(mpbq & a, int n, unsigned k) { m_manager.set(a.m_num, n); a.m_k = k; normalize(a); }
|
||||
void set(mpbq & a, mpz const & n, unsigned k) { m_manager.set(a.m_num, n); a.m_k = k; normalize(a); }
|
||||
void set(mpbq & a, mpz const & n) { m_manager.set(a.m_num, n); a.m_k = 0; }
|
||||
void set(mpbq & a, mpbq const & b) { m_manager.set(a.m_num, b.m_num); a.m_k = b.m_k; }
|
||||
void set(mpbq & a, int64 n, unsigned k) { m_manager.set(a.m_num, n); a.m_k = k; normalize(a); }
|
||||
|
||||
bool is_int(mpbq const & a) const { return a.m_k == 0; }
|
||||
void get_numerator(mpbq const & a, mpz & n) { m_manager.set(n, a.m_num); }
|
||||
unsigned get_denominator_power(mpbq const & a) { return a.m_k; }
|
||||
|
||||
bool is_zero(mpbq const & a) const { return m_manager.is_zero(a.m_num); }
|
||||
bool is_nonzero(mpbq const & a) const { return !is_zero(a); }
|
||||
bool is_one(mpbq const & a) const { return a.m_k == 0 && m_manager.is_one(a.m_num); }
|
||||
bool is_pos(mpbq const & a) const { return m_manager.is_pos(a.m_num); }
|
||||
bool is_neg(mpbq const & a) const { return m_manager.is_neg(a.m_num); }
|
||||
bool is_nonpos(mpbq const & a) const { return m_manager.is_nonpos(a.m_num); }
|
||||
bool is_nonneg(mpbq const & a) const { return m_manager.is_nonneg(a.m_num); }
|
||||
|
||||
void add(mpbq const & a, mpbq const & b, mpbq & r);
|
||||
void add(mpbq const & a, mpz const & b, mpbq & r);
|
||||
void sub(mpbq const & a, mpbq const & b, mpbq & r);
|
||||
void sub(mpbq const & a, mpz const & b, mpbq & r);
|
||||
void mul(mpbq const & a, mpbq const & b, mpbq & r);
|
||||
void mul(mpbq const & a, mpz const & b, mpbq & r);
|
||||
// r <- a + b*c
|
||||
void addmul(mpbq const & a, mpbq const & b, mpbq const & c, mpbq & r) {
|
||||
mul(b, c, m_addmul_tmp);
|
||||
add(a, m_addmul_tmp, r);
|
||||
}
|
||||
void addmul(mpbq const & a, mpz const & b, mpbq const & c, mpbq & r) {
|
||||
mul(c, b, m_addmul_tmp);
|
||||
add(a, m_addmul_tmp, r);
|
||||
}
|
||||
void neg(mpbq & a) { m_manager.neg(a.m_num); }
|
||||
// when dividing by 2, we only need to normalize if m_k was zero.
|
||||
void div2(mpbq & a) { bool old_k_zero = (a.m_k == 0); a.m_k++; if (old_k_zero) normalize(a); }
|
||||
void div2k(mpbq & a, unsigned k) { bool old_k_zero = (a.m_k == 0); a.m_k += k; if (old_k_zero) normalize(a); }
|
||||
void mul2(mpbq & a);
|
||||
void mul2k(mpbq & a, unsigned k);
|
||||
void power(mpbq & a, unsigned k);
|
||||
void power(mpbq const & a, unsigned k, mpbq & b) { set(b, a); power(b, k); }
|
||||
|
||||
/**
|
||||
\brief Return true if a^{1/n} is a binary rational, and store the result in a.
|
||||
Otherwise, return false and return an lower bound based on the integer root of the
|
||||
numerator and denominator/n
|
||||
*/
|
||||
bool root_lower(mpbq & a, unsigned n);
|
||||
bool root_lower(mpbq const & a, unsigned n, mpbq & r) { set(r, a); return root_lower(r, n); }
|
||||
|
||||
/**
|
||||
\brief Return true if a^{1/n} is a binary rational, and store the result in a.
|
||||
Otherwise, return false and return an upper bound based on the integer root of the
|
||||
numerator and denominator/n
|
||||
*/
|
||||
bool root_upper(mpbq & a, unsigned n);
|
||||
bool root_upper(mpbq const & a, unsigned n, mpbq & r) { set(r, a); return root_upper(r, n); }
|
||||
|
||||
bool eq(mpbq const & a, mpbq const & b) { return a.m_k == b.m_k && m_manager.eq(a.m_num, b.m_num); }
|
||||
bool lt(mpbq const & a, mpbq const & b);
|
||||
bool neq(mpbq const & a, mpbq const & b) { return !eq(a, b); }
|
||||
bool gt(mpbq const & a, mpbq const & b) { return lt(b, a); }
|
||||
bool ge(mpbq const & a, mpbq const & b) { return le(b, a); }
|
||||
bool le(mpbq const & a, mpbq const & b) { return !gt(a, b); }
|
||||
|
||||
bool eq(mpbq const & a, mpq const & b);
|
||||
bool lt(mpbq const & a, mpq const & b);
|
||||
bool le(mpbq const & a, mpq const & b);
|
||||
bool neq(mpbq const & a, mpq const & b) { return !eq(a, b); }
|
||||
bool gt(mpbq const & a, mpq const & b) { return !le(a, b); }
|
||||
bool ge(mpbq const & a, mpq const & b) { return !lt(a, b); }
|
||||
|
||||
bool eq(mpbq const & a, mpz const & b) { return m_manager.eq(a.m_num, b) && a.m_k == 0; }
|
||||
bool lt(mpbq const & a, mpz const & b);
|
||||
bool le(mpbq const & a, mpz const & b);
|
||||
bool neq(mpbq const & a, mpz const & b) { return !eq(a, b); }
|
||||
bool gt(mpbq const & a, mpz const & b) { return !le(a, b); }
|
||||
bool ge(mpbq const & a, mpz const & b) { return !lt(a, b); }
|
||||
|
||||
/**
|
||||
\brief Return the magnitude of a = b/2^k.
|
||||
It is defined as:
|
||||
a == 0 -> 0
|
||||
a > 0 -> log2(b) - k Note that 2^{log2(b) - k} <= a <= 2^{log2(b) - k + 1}
|
||||
a < 0 -> mlog2(b) - k + 1 Note that -2^{mlog2(b) - k + 1} <= a <= -2^{mlog2(b) - k}
|
||||
|
||||
Remark: mlog2(b) = log2(-b)
|
||||
|
||||
Examples:
|
||||
|
||||
5/2^3 log2(5) - 3 = -1
|
||||
21/2^2 log2(21) - 2 = 2
|
||||
-3/2^4 log2(3) - 4 + 1 = -2
|
||||
*/
|
||||
int magnitude_lb(mpbq const & a);
|
||||
|
||||
/**
|
||||
\brief Similar to magnitude_lb
|
||||
|
||||
a == 0 -> 0
|
||||
a > 0 -> log2(b) - k + 1 a <= 2^{log2(b) - k + 1}
|
||||
a < 0 -> mlog2(b) - k a <= -2^{mlog2(b) - k}
|
||||
*/
|
||||
int magnitude_ub(mpbq const & a);
|
||||
|
||||
/**
|
||||
\brief Return true if a < 1/2^k
|
||||
*/
|
||||
bool lt_1div2k(mpbq const & a, unsigned k);
|
||||
|
||||
std::string to_string(mpbq const & a);
|
||||
|
||||
/**
|
||||
\brief Return true if q (= c/d) is a binary rational,
|
||||
and store it in bq (as a binary rational).
|
||||
Otherwise return false, and set bq to c/2^{k+1}
|
||||
where k = log2(d)
|
||||
*/
|
||||
bool to_mpbq(mpq const & q, mpbq & bq);
|
||||
|
||||
/**
|
||||
\brief Given a rational q which cannot be represented as a binary rational,
|
||||
and an interval (l, u) s.t. l < q < u. This method stores in u, a u' s.t.
|
||||
q < u' < u.
|
||||
In the refinement process, the lower bound l may be also refined to l'
|
||||
s.t. l < l' < q
|
||||
*/
|
||||
void refine_upper(mpq const & q, mpbq & l, mpbq & u);
|
||||
|
||||
/**
|
||||
\brief Similar to refine_upper.
|
||||
*/
|
||||
void refine_lower(mpq const & q, mpbq & l, mpbq & u);
|
||||
|
||||
template<typename mpz_manager>
|
||||
void floor(mpz_manager & m, mpbq const & a, mpz & f) {
|
||||
if (is_int(a)) {
|
||||
m.set(f, a.m_num);
|
||||
return;
|
||||
}
|
||||
bool is_neg_num = is_neg(a);
|
||||
m.machine_div2k(a.m_num, a.m_k, f);
|
||||
if (is_neg_num)
|
||||
m.sub(f, mpz(1), f);
|
||||
}
|
||||
|
||||
template<typename mpz_manager>
|
||||
void ceil(mpz_manager & m, mpbq const & a, mpz & c) {
|
||||
if (is_int(a)) {
|
||||
m.set(c, a.m_num);
|
||||
return;
|
||||
}
|
||||
bool is_pos_num = is_pos(a);
|
||||
m.machine_div2k(a.m_num, a.m_k, c);
|
||||
if (is_pos_num)
|
||||
m.add(c, mpz(1), c);
|
||||
}
|
||||
|
||||
/**
|
||||
\brief Select some number in the interval [lower, upper].
|
||||
Return true if succeeded, and false if lower > upper.
|
||||
This method tries to minimize the size (in bits) of r.
|
||||
For example, it will select an integer in [lower, upper]
|
||||
if the interval contains one.
|
||||
*/
|
||||
bool select_small(mpbq const & lower, mpbq const & upper, mpbq & r);
|
||||
/**
|
||||
\brief Similar to select_small, but assumes lower <= upper
|
||||
*/
|
||||
void select_small_core(mpbq const & lower, mpbq const & upper, mpbq & r);
|
||||
|
||||
// Select some number in the interval (lower, upper]
|
||||
void select_small_core(unsynch_mpq_manager & qm, mpq const & lower, mpbq const & upper, mpbq & r);
|
||||
// Select some number in the interval [lower, upper)
|
||||
void select_small_core(unsynch_mpq_manager & qm, mpbq const & lower, mpq const & upper, mpbq & r);
|
||||
// Select some number in the interval (lower, upper)
|
||||
void select_small_core(unsynch_mpq_manager & qm, mpq const & lower, mpq const & upper, mpbq & r);
|
||||
|
||||
|
||||
void display(std::ostream & out, mpbq const & a);
|
||||
void display_decimal(std::ostream & out, mpbq const & a, unsigned prec = 8);
|
||||
/**
|
||||
\brief Display a in decimal while its digits match b digits.
|
||||
This function is useful when a and b are representing an interval [a,b] which
|
||||
contains an algebraic number
|
||||
*/
|
||||
void display_decimal(std::ostream & out, mpbq const & a, mpbq const & b, unsigned prec);
|
||||
|
||||
void display_smt2(std::ostream & out, mpbq const & a, bool decimal);
|
||||
|
||||
/**
|
||||
\brief Approximate n as b/2^k' s.t. k' <= k.
|
||||
|
||||
if get_denominator_power(n) <= k, then n is not modified.
|
||||
|
||||
if get_denominator_power(n) > k, then
|
||||
if to_plus_inf, old(n) < b/2^k'
|
||||
otherwise, b/2^k' < old(n)
|
||||
*/
|
||||
void approx(mpbq & n, unsigned k, bool to_plus_inf);
|
||||
|
||||
/**
|
||||
\brief Approximated division c <- a/b
|
||||
|
||||
The result is precise when:
|
||||
1) b is a power of two
|
||||
2) get_numerator(b) divides get_numerator(a)
|
||||
|
||||
When the result is not precise, |c - a/b| <= 1/2^k
|
||||
Actually, we have that
|
||||
to_plus_inf => c - a/b <= 1/2^k
|
||||
not to_plus_inf => a/b - c <= 1/2^k
|
||||
*/
|
||||
void approx_div(mpbq const & a, mpbq const & b, mpbq & c, unsigned k=32, bool to_plus_inf=false);
|
||||
};
|
||||
|
||||
/**
|
||||
\brief Convert a binary rational into a rational
|
||||
*/
|
||||
template<typename mpq_manager>
|
||||
void to_mpq(mpq_manager & m, mpbq const & source, mpq & target) {
|
||||
mpq two(2);
|
||||
m.power(two, source.k(), target);
|
||||
m.inv(target);
|
||||
m.mul(source.numerator(), target, target);
|
||||
}
|
||||
|
||||
/**
|
||||
\brief Convert a binary rational into a rational.
|
||||
*/
|
||||
rational to_rational(mpbq const & m);
|
||||
|
||||
typedef _scoped_numeral<mpbq_manager> scoped_mpbq;
|
||||
typedef _scoped_numeral_vector<mpbq_manager> scoped_mpbq_vector;
|
||||
|
||||
|
||||
#define MPBQ_MK_COMPARISON_CORE(EXTERNAL, INTERNAL, TYPE) \
|
||||
inline bool EXTERNAL(scoped_mpbq const & a, TYPE const & b) { \
|
||||
mpbq_manager & m = a.m(); \
|
||||
scoped_mpbq _b(m); \
|
||||
m.set(_b, b); \
|
||||
return m.INTERNAL(a, _b); \
|
||||
}
|
||||
|
||||
#define MPBQ_MK_COMPARISON(EXTERNAL, INTERNAL) \
|
||||
MPBQ_MK_COMPARISON_CORE(EXTERNAL, INTERNAL, int) \
|
||||
MPBQ_MK_COMPARISON_CORE(EXTERNAL, INTERNAL, mpz) \
|
||||
|
||||
MPBQ_MK_COMPARISON(operator==, eq);
|
||||
MPBQ_MK_COMPARISON(operator!=, neq);
|
||||
MPBQ_MK_COMPARISON(operator<, lt);
|
||||
MPBQ_MK_COMPARISON(operator<=, le);
|
||||
MPBQ_MK_COMPARISON(operator>, gt);
|
||||
MPBQ_MK_COMPARISON(operator>=, ge);
|
||||
|
||||
#undef MPBQ_MK_COMPARISON
|
||||
#undef MPBQ_MK_COMPARISON_CORE
|
||||
|
||||
#define MPBQ_MK_BINARY_CORE(EXTERNAL, INTERNAL, TYPE) \
|
||||
inline scoped_mpbq EXTERNAL(scoped_mpbq const & a, TYPE const & b) { \
|
||||
mpbq_manager & m = a.m(); \
|
||||
scoped_mpbq _b(m); \
|
||||
m.set(_b, b); \
|
||||
scoped_mpbq r(m); \
|
||||
m.INTERNAL(a, _b, r); \
|
||||
return r; \
|
||||
}
|
||||
|
||||
#define MPBQ_MK_BINARY(EXTERNAL, INTERNAL) \
|
||||
MPBQ_MK_BINARY_CORE(EXTERNAL, INTERNAL, int) \
|
||||
MPBQ_MK_BINARY_CORE(EXTERNAL, INTERNAL, mpz) \
|
||||
|
||||
MPBQ_MK_BINARY(operator+, add)
|
||||
MPBQ_MK_BINARY(operator-, sub)
|
||||
MPBQ_MK_BINARY(operator*, mul)
|
||||
|
||||
#undef MPBQ_MK_BINARY
|
||||
#undef MPBQ_MK_BINARY_CORE
|
||||
|
||||
#endif
|
50
src/util/mpbqi.h
Normal file
50
src/util/mpbqi.h
Normal file
|
@ -0,0 +1,50 @@
|
|||
/*++
|
||||
Copyright (c) 2012 Microsoft Corporation
|
||||
|
||||
Module Name:
|
||||
|
||||
mpbqi.h
|
||||
|
||||
Abstract:
|
||||
|
||||
Binary Rational Number Intervals
|
||||
|
||||
Author:
|
||||
|
||||
Leonardo de Moura (leonardo) 2012-01-04
|
||||
|
||||
Revision History:
|
||||
|
||||
--*/
|
||||
#ifndef _MPBQI_H_
|
||||
#define _MPBQI_H_
|
||||
|
||||
#include"mpbq.h"
|
||||
#include"basic_interval.h"
|
||||
|
||||
class mpbqi_manager : public basic_interval_manager<mpbq_manager, false> {
|
||||
typedef basic_interval_manager<mpbq_manager, false> super;
|
||||
public:
|
||||
mpbqi_manager(mpbq_manager & m):super(m) {}
|
||||
|
||||
void set(interval & a, interval const & b) { super::set(a, b); }
|
||||
void set(interval & a, bound const & lower, bound const & upper) { super::set(a, lower, upper); }
|
||||
void set(interval & a, bound const & n) { super::set(a, n); }
|
||||
void set(interval & a, mpz const & n) {
|
||||
m().set(a.lower(), n);
|
||||
m().set(a.upper(), n);
|
||||
}
|
||||
|
||||
void add(interval const & a, interval const & b, interval & c) { super::add(a, b, c); }
|
||||
void add(interval const & a, mpz const & b, interval & c) {
|
||||
m().add(a.lower(), b, c.lower());
|
||||
m().add(a.upper(), b, c.upper());
|
||||
}
|
||||
|
||||
|
||||
};
|
||||
|
||||
typedef mpbqi_manager::interval mpbqi;
|
||||
typedef mpbqi_manager::scoped_interval scoped_mpbqi;
|
||||
|
||||
#endif
|
1572
src/util/mpf.cpp
Normal file
1572
src/util/mpf.cpp
Normal file
File diff suppressed because it is too large
Load diff
278
src/util/mpf.h
Normal file
278
src/util/mpf.h
Normal file
|
@ -0,0 +1,278 @@
|
|||
/*++
|
||||
Copyright (c) 2011 Microsoft Corporation
|
||||
|
||||
Module Name:
|
||||
|
||||
mpf.h
|
||||
|
||||
Abstract:
|
||||
|
||||
Multi Precision Floating Point Numbers
|
||||
|
||||
Author:
|
||||
|
||||
Christoph Wintersteiger (cwinter) 2011-12-01.
|
||||
|
||||
Revision History:
|
||||
|
||||
--*/
|
||||
#ifndef _MPF_H_
|
||||
#define _MPF_H_
|
||||
|
||||
#include<string>
|
||||
#include"mpz.h"
|
||||
#include"mpq.h"
|
||||
#include"map.h"
|
||||
#include"scoped_numeral.h"
|
||||
#include"scoped_numeral_vector.h"
|
||||
#include"hash.h"
|
||||
|
||||
typedef enum {
|
||||
MPF_ROUND_NEAREST_TEVEN,
|
||||
MPF_ROUND_NEAREST_TAWAY,
|
||||
MPF_ROUND_TOWARD_POSITIVE,
|
||||
MPF_ROUND_TOWARD_NEGATIVE,
|
||||
MPF_ROUND_TOWARD_ZERO
|
||||
} mpf_rounding_mode;
|
||||
|
||||
typedef int64 mpf_exp_t;
|
||||
|
||||
class mpf {
|
||||
friend class mpf_manager;
|
||||
friend class scoped_mpf;
|
||||
unsigned ebits:15;
|
||||
unsigned sbits:16;
|
||||
unsigned sign:1; // counts as one sbit.
|
||||
mpz significand;
|
||||
mpf_exp_t exponent;
|
||||
mpf & operator=(mpf const & other) { UNREACHABLE(); return *this; }
|
||||
void set(unsigned ebits, unsigned sbits);
|
||||
public:
|
||||
mpf();
|
||||
mpf(unsigned ebits, unsigned sbits);
|
||||
mpf(mpf const & other);
|
||||
~mpf();
|
||||
unsigned get_ebits() const { return ebits; }
|
||||
unsigned get_sbits() const { return sbits; }
|
||||
void swap(mpf & other);
|
||||
};
|
||||
|
||||
class mpf_manager {
|
||||
unsynch_mpq_manager m_mpq_manager;
|
||||
unsynch_mpz_manager & m_mpz_manager; // A mpq_manager is a mpz_manager, reusing it.
|
||||
|
||||
public:
|
||||
typedef mpf numeral;
|
||||
|
||||
mpf_manager();
|
||||
~mpf_manager();
|
||||
|
||||
void reset(mpf & o, unsigned ebits, unsigned sbits) { set(o, ebits, sbits, 0); }
|
||||
void set(mpf & o, unsigned ebits, unsigned sbits, int value);
|
||||
void set(mpf & o, unsigned ebits, unsigned sbits, mpf_rounding_mode rm, int n, int d);
|
||||
void set(mpf & o, unsigned ebits, unsigned sbits, float value);
|
||||
void set(mpf & o, unsigned ebits, unsigned sbits, double value);
|
||||
void set(mpf & o, unsigned ebits, unsigned sbits, mpf_rounding_mode rm, mpq const & value);
|
||||
void set(mpf & o, unsigned ebits, unsigned sbits, mpf_rounding_mode rm, char const * value);
|
||||
void set(mpf & o, unsigned ebits, unsigned sbits, mpf_rounding_mode rm, mpq const & significand, mpz const & exponent);
|
||||
void set(mpf & o, unsigned ebits, unsigned sbits, bool sign, uint64 significand, int exponent);
|
||||
void set(mpf & o, unsigned ebits, unsigned sbits, bool sign, mpz const & significand, mpf_exp_t exponent);
|
||||
void set(mpf & o, mpf const & x);
|
||||
void set(mpf & o, unsigned ebits, unsigned sbits, mpf_rounding_mode rm, mpf const & x);
|
||||
|
||||
void del(mpf & x) {
|
||||
m_mpz_manager.del(x.significand);
|
||||
}
|
||||
|
||||
void abs(mpf & o);
|
||||
void abs(mpf const & x, mpf & o);
|
||||
|
||||
void neg(mpf & o);
|
||||
void neg(mpf const & x, mpf & o);
|
||||
|
||||
bool is_zero(mpf const & x);
|
||||
bool is_neg(mpf const & x);
|
||||
bool is_pos(mpf const & x);
|
||||
bool is_one(mpf const & x);
|
||||
|
||||
bool is_nzero(mpf const & x);
|
||||
bool is_pzero(mpf const & x);
|
||||
|
||||
// structural eq
|
||||
bool eq_core(mpf const & x, mpf const & y) {
|
||||
return
|
||||
x.ebits == y.ebits &&
|
||||
x.sbits == y.sbits &&
|
||||
x.sign == y.sign &&
|
||||
m_mpz_manager.eq(x.significand, y.significand) &&
|
||||
x.exponent == y.exponent;
|
||||
}
|
||||
|
||||
bool eq(mpf const & x, mpf const & y);
|
||||
bool lt(mpf const & x, mpf const & y);
|
||||
bool lte(mpf const & x, mpf const & y);
|
||||
bool le(mpf const & x, mpf const & y) { return lte(x, y); }
|
||||
bool gt(mpf const & x, mpf const & y);
|
||||
bool gte(mpf const & x, mpf const & y);
|
||||
bool ge(mpf const & x, mpf const & y) { return gte(x, y); }
|
||||
|
||||
void add(mpf_rounding_mode rm, mpf const & x, mpf const & y, mpf & o);
|
||||
void sub(mpf_rounding_mode rm, mpf const & x, mpf const & y, mpf & o);
|
||||
void mul(mpf_rounding_mode rm, mpf const & x, mpf const & y, mpf & o);
|
||||
void div(mpf_rounding_mode rm, mpf const & x, mpf const & y, mpf & o);
|
||||
|
||||
void fused_mul_add(mpf_rounding_mode rm, mpf const & x, mpf const & y, mpf const &z, mpf & o);
|
||||
|
||||
void sqrt(mpf_rounding_mode rm, mpf const & x, mpf & o);
|
||||
|
||||
void round_to_integral(mpf_rounding_mode rm, mpf const & x, mpf & o);
|
||||
|
||||
void rem(mpf const & x, mpf const & y, mpf & o);
|
||||
|
||||
void maximum(mpf const & x, mpf const & y, mpf & o);
|
||||
void minimum(mpf const & x, mpf const & y, mpf & o);
|
||||
|
||||
std::string to_string(mpf const & a);
|
||||
std::string to_rational_string(mpf const & a);
|
||||
void display_decimal(std::ostream & out, mpf const & a, unsigned k);
|
||||
void display_smt2(std::ostream & out, mpf const & a, bool decimal);
|
||||
|
||||
// Convert x into a mpq numeral. zm is the manager that owns o.
|
||||
void to_rational(mpf const & x, unsynch_mpq_manager & qm, mpq & o);
|
||||
void to_rational(mpf const & x, scoped_mpq & o) { to_rational(x, o.m(), o); }
|
||||
|
||||
double to_double(mpf const & x);
|
||||
float to_float(mpf const & x);
|
||||
|
||||
bool sgn(mpf const & x) const { return x.sign; }
|
||||
const mpz & sig(mpf const & x) const { return x.significand; }
|
||||
const mpf_exp_t & exp(mpf const & x) const { return x.exponent; }
|
||||
|
||||
bool is_nan(mpf const & x);
|
||||
bool is_inf(mpf const & x);
|
||||
bool is_pinf(mpf const & x);
|
||||
bool is_ninf(mpf const & x);
|
||||
bool is_normal(mpf const & x);
|
||||
bool is_denormal(mpf const & x);
|
||||
bool is_regular(mpf const & x) { return x.sbits == 0 || is_normal(x) || is_denormal(x); }
|
||||
|
||||
bool is_int(mpf const & x);
|
||||
|
||||
void mk_zero(unsigned ebits, unsigned sbits, bool sign, mpf & o);
|
||||
void mk_nzero(unsigned ebits, unsigned sbits, mpf & o);
|
||||
void mk_pzero(unsigned ebits, unsigned sbits, mpf & o);
|
||||
void mk_nan(unsigned ebits, unsigned sbits, mpf & o);
|
||||
void mk_inf(unsigned ebits, unsigned sbits, bool sign, mpf & o);
|
||||
void mk_pinf(unsigned ebits, unsigned sbits, mpf & o);
|
||||
void mk_ninf(unsigned ebits, unsigned sbits, mpf & o);
|
||||
|
||||
std::string to_string_raw(mpf const & a);
|
||||
|
||||
unsynch_mpz_manager & mpz_manager(void) { return m_mpz_manager; }
|
||||
unsynch_mpq_manager & mpq_manager(void) { return m_mpq_manager; }
|
||||
|
||||
unsigned hash(mpf const & a) {
|
||||
return hash_u_u(m_mpz_manager.hash(a.significand),
|
||||
m_mpz_manager.hash(hash_ull(a.exponent)));
|
||||
}
|
||||
|
||||
void mk_max_value(unsigned ebits, unsigned sbits, bool sign, mpf & o);
|
||||
mpf_exp_t mk_bot_exp(unsigned ebits);
|
||||
mpf_exp_t mk_top_exp(unsigned ebits);
|
||||
mpf_exp_t mk_max_exp(unsigned ebits);
|
||||
mpf_exp_t mk_min_exp(unsigned ebits);
|
||||
|
||||
/**
|
||||
\brief Return the biggest k s.t. 2^k <= a.
|
||||
|
||||
\remark Return 0 if a is not positive.
|
||||
*/
|
||||
unsigned prev_power_of_two(mpf const & a);
|
||||
|
||||
protected:
|
||||
bool has_bot_exp(mpf const & x);
|
||||
bool has_top_exp(mpf const & x);
|
||||
|
||||
void unpack(mpf & o, bool normalize);
|
||||
void add_sub(mpf_rounding_mode rm, mpf const & x, mpf const & y, mpf & o, bool sub);
|
||||
void round(mpf_rounding_mode rm, mpf & o);
|
||||
void round_sqrt(mpf_rounding_mode rm, mpf & o);
|
||||
|
||||
void mk_round_inf(mpf_rounding_mode rm, mpf & o);
|
||||
|
||||
// Convert x into a mpz numeral. zm is the manager that owns o.
|
||||
void to_mpz(mpf const & x, unsynch_mpz_manager & zm, mpz & o);
|
||||
void to_mpz(mpf const & x, scoped_mpz & o) { to_mpz(x, o.m(), o); }
|
||||
|
||||
class powers2 {
|
||||
unsynch_mpz_manager & m;
|
||||
u_map<mpz*> m_p;
|
||||
u_map<mpz*> m_pn;
|
||||
u_map<mpz*> m_pm1;
|
||||
u_map<mpz*> m_pm1n;
|
||||
public:
|
||||
powers2(unsynch_mpz_manager & m) : m(m) {}
|
||||
~powers2() {
|
||||
dispose(m_p);
|
||||
dispose(m_pn);
|
||||
dispose(m_pm1);
|
||||
dispose(m_pm1n);
|
||||
}
|
||||
|
||||
void dispose(u_map<mpz*> & map) {
|
||||
for (u_map<mpz*>::iterator it = map.begin(); it != map.end(); it++) {
|
||||
m.del(*it->m_value);
|
||||
dealloc(it->m_value);
|
||||
}
|
||||
}
|
||||
|
||||
const mpz & operator()(unsigned n, bool negated = false) {
|
||||
u_map<mpz*> & map = (negated) ? m_pn : m_p;
|
||||
u_map<mpz*>::iterator it = map.find_iterator(n);
|
||||
if (it != map.end())
|
||||
return *it->m_value;
|
||||
else {
|
||||
mpz * new_obj = alloc(mpz);
|
||||
map.insert(n, new_obj);
|
||||
m.power(unsynch_mpz_manager::mk_z(2), n, *new_obj);
|
||||
if (negated) m.neg(*new_obj);
|
||||
return *new_obj;
|
||||
}
|
||||
}
|
||||
|
||||
const mpz & m1(unsigned n, bool negated=false) { // (2 ^ n) - 1
|
||||
u_map<mpz*> & map = (negated) ? m_pm1n : m_pm1;
|
||||
u_map<mpz*>::iterator it = map.find_iterator(n);
|
||||
if (it != map.end())
|
||||
return *it->m_value;
|
||||
else {
|
||||
mpz * new_obj = alloc(mpz);
|
||||
map.insert(n, new_obj);
|
||||
m.power(unsynch_mpz_manager::mk_z(2), n, *new_obj);
|
||||
m.dec(*new_obj);
|
||||
if (negated) m.neg(*new_obj);
|
||||
return *new_obj;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
public:
|
||||
powers2 m_powers2;
|
||||
};
|
||||
|
||||
class scoped_mpf : public _scoped_numeral<mpf_manager> {
|
||||
friend class mpf_manager;
|
||||
mpz & significand() { return get().significand; }
|
||||
bool sign() const { return get().sign; }
|
||||
mpf_exp_t exponent() const { return get().exponent; }
|
||||
unsigned sbits() const { return get().sbits; }
|
||||
void set(unsigned ebits, unsigned sbits) { get().set(ebits, sbits); }
|
||||
public:
|
||||
scoped_mpf(mpf_manager & m):_scoped_numeral<mpf_manager>(m) {}
|
||||
scoped_mpf(scoped_mpf const & n):_scoped_numeral<mpf_manager>(n) {}
|
||||
scoped_mpf(mpf_manager & m, unsigned ebits, unsigned sbits):_scoped_numeral<mpf_manager>(m) { set(ebits, sbits); }
|
||||
};
|
||||
|
||||
typedef _scoped_numeral_vector<mpf_manager> scoped_mpf_vector;
|
||||
|
||||
#endif
|
1413
src/util/mpff.cpp
Normal file
1413
src/util/mpff.cpp
Normal file
File diff suppressed because it is too large
Load diff
479
src/util/mpff.h
Normal file
479
src/util/mpff.h
Normal file
|
@ -0,0 +1,479 @@
|
|||
/*++
|
||||
Copyright (c) 2012 Microsoft Corporation
|
||||
|
||||
Module Name:
|
||||
|
||||
mpff.h
|
||||
|
||||
Abstract:
|
||||
|
||||
Multi precision fast floating point numbers.
|
||||
The implementation is not compliant with the IEEE standard.
|
||||
For an IEEE compliant implementation, see mpf.h
|
||||
|
||||
There are only two rounding modes: towards plus or minus inf.
|
||||
|
||||
Author:
|
||||
|
||||
Leonardo de Moura (leonardo) 2012-09-12
|
||||
|
||||
Revision History:
|
||||
|
||||
--*/
|
||||
#ifndef _MPFF_H_
|
||||
#define _MPFF_H_
|
||||
|
||||
#include"id_gen.h"
|
||||
#include"util.h"
|
||||
#include"vector.h"
|
||||
#include"z3_exception.h"
|
||||
#include"scoped_numeral.h"
|
||||
#include"scoped_numeral_vector.h"
|
||||
|
||||
class mpff_manager;
|
||||
|
||||
class mpff {
|
||||
friend class mpff_manager;
|
||||
unsigned m_sign:1;
|
||||
unsigned m_sig_idx:31; // position where the significand is stored in the mpff_manager.
|
||||
int m_exponent;
|
||||
public:
|
||||
mpff():
|
||||
m_sign(0),
|
||||
m_sig_idx(0),
|
||||
m_exponent(0) {
|
||||
}
|
||||
|
||||
void swap(mpff & other) {
|
||||
unsigned sign = m_sign; m_sign = other.m_sign; other.m_sign = sign;
|
||||
unsigned sig_idx = m_sig_idx; m_sig_idx = other.m_sig_idx; other.m_sig_idx = sig_idx;
|
||||
std::swap(m_exponent, other.m_exponent);
|
||||
}
|
||||
};
|
||||
|
||||
inline void swap(mpff & m1, mpff & m2) { m1.swap(m2); }
|
||||
|
||||
class mpz;
|
||||
class mpq;
|
||||
template<bool SYNCH> class mpz_manager;
|
||||
template<bool SYNCH> class mpq_manager;
|
||||
typedef mpz_manager<true> synch_mpz_manager;
|
||||
typedef mpz_manager<false> unsynch_mpz_manager;
|
||||
typedef mpq_manager<true> synch_mpq_manager;
|
||||
typedef mpq_manager<false> unsynch_mpq_manager;
|
||||
|
||||
class mpff_manager {
|
||||
// Some restrictions on mpff numbers
|
||||
//
|
||||
// - The exponent is always a machine integer. The main point is that 2^(2^31) is a huge number,
|
||||
// we will not even be able to convert the mpff into mpq. Formulas that need this kind of huge number
|
||||
// are usually out-of-reach for Z3.
|
||||
//
|
||||
// - The significand size is measured in words of 32-bit. The number of words is always even.
|
||||
// This decision makes sure that the size (in bits) of mpff numbers is always a multiple of 64.
|
||||
// Thus mpff objs can be easily packed in 64-bit machines.
|
||||
//
|
||||
// - The smallest mpff numeral has 128-bits total. mpff structure has always 64-bits.
|
||||
// The minimal size for the significand is 64-bits.
|
||||
//
|
||||
// - All mpff numerals in a given manager use the same number of words for storing the significand.
|
||||
// This is different from the mpf_manager where the same manager can be used to manipulate floating point numbers
|
||||
// of different precision.
|
||||
//
|
||||
// - In the encoding used for mpff numbers, the most significand bit of the most significand word is always 1.
|
||||
// The only exception is the number zero.
|
||||
// For example, assuming we are using 64-bits for the significand, the number 1 is encoded as
|
||||
// (sign = 0, significand = 0x800..0, exponent = -63)
|
||||
// Note that, in this representation, the smallest positive integer is:
|
||||
// (sign = 0, significand = 0x800..0, exponent = INT_MIN)
|
||||
// instead of
|
||||
// (sign = 0, significand = 0x000..1, exponent = INT_MIN)
|
||||
//
|
||||
// Remarks:
|
||||
//
|
||||
// - All values of type int, unsigned, int64 and uint64 can be precisely represented as mpff numerals.
|
||||
//
|
||||
// - Hardware float and double values (corresponding to rationals) can also be precisely represented as mpff numberals.
|
||||
// That is, NaN, +oo and -oo are not supported by this module.
|
||||
//
|
||||
// - An exception (mpff_manager::exception) is thrown if overflow occurs. This can happen because the exponent is
|
||||
// represented as a machine integer.
|
||||
//
|
||||
// - There are only two rounding modes: towards plus infinity and towards minus infinity.
|
||||
// The rounding mode can be dynamically modified.
|
||||
//
|
||||
// - The mpff numerals are stored in a dynamic array.
|
||||
// Type mpff is just an index (unsigned) into this array.
|
||||
|
||||
unsigned m_precision; //!< Number of words in the significand. Must be an even number.
|
||||
unsigned m_precision_bits; //!< Number of bits in the significand. Must be 32*m_precision.
|
||||
vector<unsigned> m_significands; //!< Array containing all significands.
|
||||
unsigned m_capacity; //!< Number of significands that can be stored in m_significands.
|
||||
bool m_to_plus_inf; //!< If True, then round to plus infinity, otherwise to minus infinity
|
||||
id_gen m_id_gen;
|
||||
static const unsigned MPFF_NUM_BUFFERS = 4;
|
||||
svector<unsigned> m_buffers[MPFF_NUM_BUFFERS];
|
||||
svector<unsigned> m_set_buffer;
|
||||
mpff m_one;
|
||||
|
||||
unsigned * sig(mpff const & n) const { return m_significands.c_ptr() + (n.m_sig_idx * m_precision); }
|
||||
|
||||
void ensure_capacity(unsigned sig_idx) {
|
||||
while (sig_idx >= m_capacity)
|
||||
expand();
|
||||
}
|
||||
|
||||
void expand();
|
||||
|
||||
void allocate_if_needed(mpff & n) {
|
||||
if (n.m_sig_idx == 0)
|
||||
allocate(n);
|
||||
}
|
||||
|
||||
void allocate(mpff & n);
|
||||
|
||||
// copy n to buffer idx.
|
||||
void to_buffer(unsigned idx, mpff const & n) const;
|
||||
// copy n to buffer idx and add m_precision zeros.
|
||||
void to_buffer_ext(unsigned idx, mpff const & n) const;
|
||||
// copy (and shift by m_precision_bits) n to buffer idx
|
||||
void to_buffer_shifting(unsigned idx, mpff const & n) const;
|
||||
|
||||
void inc_significand(unsigned * s, int64 & exp);
|
||||
void inc_significand(mpff & a);
|
||||
void dec_significand(mpff & a);
|
||||
bool min_significand(mpff const & a) const;
|
||||
void set_min_significand(mpff & a);
|
||||
void set_max_significand(mpff & a);
|
||||
void set_big_exponent(mpff & a, int64 e);
|
||||
void set_exponent(mpff & a, int64 e) {
|
||||
if (e > INT_MAX || e < INT_MIN)
|
||||
set_big_exponent(a, e);
|
||||
else
|
||||
a.m_exponent = static_cast<int>(e);
|
||||
}
|
||||
|
||||
template<bool SYNCH>
|
||||
void set_core(mpff & n, mpz_manager<SYNCH> & m, mpz const & v);
|
||||
|
||||
template<bool SYNCH>
|
||||
void set_core(mpff & n, mpq_manager<SYNCH> & m, mpq const & v);
|
||||
|
||||
template<bool SYNCH>
|
||||
void to_mpz_core(mpff const & n, mpz_manager<SYNCH> & m, mpz & t);
|
||||
|
||||
template<bool SYNCH>
|
||||
void to_mpq_core(mpff const & n, mpq_manager<SYNCH> & m, mpq & t);
|
||||
|
||||
template<bool SYNCH>
|
||||
void significand_core(mpff const & n, mpz_manager<SYNCH> & m, mpz & r);
|
||||
|
||||
void add_sub(bool is_sub, mpff const & a, mpff const & b, mpff & c);
|
||||
|
||||
public:
|
||||
typedef mpff numeral;
|
||||
static bool precise() { return false; }
|
||||
static bool field() { return true; }
|
||||
|
||||
class exception : public z3_exception {
|
||||
virtual char const * msg() const { return "multi-precision floating point (mpff) exception"; }
|
||||
};
|
||||
|
||||
class overflow_exception : public exception {
|
||||
virtual char const * msg() const { return "multi-precision floating point (mpff) overflow"; }
|
||||
};
|
||||
|
||||
class div0_exception : public exception {
|
||||
virtual char const * msg() const { return "multi-precision floating point (mpff) division by zero"; }
|
||||
};
|
||||
|
||||
mpff_manager(unsigned prec = 2, unsigned initial_capacity = 1024);
|
||||
~mpff_manager();
|
||||
|
||||
void round_to_plus_inf() { m_to_plus_inf = true; }
|
||||
void round_to_minus_inf() { m_to_plus_inf = false; }
|
||||
void set_rounding(bool to_plus_inf) { m_to_plus_inf = to_plus_inf; }
|
||||
bool rounding_to_plus_inf() const { return m_to_plus_inf; }
|
||||
|
||||
/**
|
||||
\brief Return the exponent of n.
|
||||
*/
|
||||
static int exponent(mpff const & n) { return n.m_exponent; }
|
||||
|
||||
/**
|
||||
\brief Update the exponent of n.
|
||||
|
||||
\remark It is a NOOP if n is zero.
|
||||
*/
|
||||
void set_exponent(mpff & n, int exp) { if (is_zero(n)) return; n.m_exponent = exp; SASSERT(check(n)); }
|
||||
|
||||
/**
|
||||
\brief Return the significand as a mpz numeral.
|
||||
*/
|
||||
void significand(mpff const & n, unsynch_mpz_manager & m, mpz & r);
|
||||
void significand(mpff const & n, synch_mpz_manager & m, mpz & r);
|
||||
|
||||
/**
|
||||
\brief Return true if n is negative
|
||||
*/
|
||||
static bool sign(mpff const & n) { return is_neg(n); }
|
||||
|
||||
/**
|
||||
\brief Set n to zero.
|
||||
*/
|
||||
void reset(mpff & n);
|
||||
|
||||
/**
|
||||
\brief Return true if n is an integer.
|
||||
*/
|
||||
bool is_int(mpff const & n) const;
|
||||
|
||||
/**
|
||||
\brief Return true if n is zero.
|
||||
*/
|
||||
static bool is_zero(mpff const & n) { return n.m_sig_idx == 0; }
|
||||
|
||||
/**
|
||||
\brief Return true if n is positive.
|
||||
*/
|
||||
static bool is_pos(mpff const & n) { return n.m_sign == 0 && !is_zero(n); }
|
||||
|
||||
/**
|
||||
\brief Return true if n is negative.
|
||||
*/
|
||||
static bool is_neg(mpff const & n) { return n.m_sign != 0; }
|
||||
|
||||
/**
|
||||
\brief Return true if n is non positive.
|
||||
*/
|
||||
static bool is_nonpos(mpff const & n) { return !is_pos(n); }
|
||||
|
||||
/**
|
||||
\brief Return true if n is non negative.
|
||||
*/
|
||||
static bool is_nonneg(mpff const & n) { return !is_neg(n); }
|
||||
|
||||
/**
|
||||
\brief Return true if the absolute value of n is 1.
|
||||
*/
|
||||
bool is_abs_one(mpff const & n) const;
|
||||
|
||||
/**
|
||||
\brief Return true if n is one.
|
||||
*/
|
||||
bool is_one(mpff const & n) const { return is_pos(n) && is_abs_one(n); }
|
||||
|
||||
/**
|
||||
\brief Return true if n is minus one.
|
||||
*/
|
||||
bool is_minus_one(mpff const & n) const { return is_neg(n) && is_abs_one(n); }
|
||||
|
||||
/**
|
||||
\brief Return true if n is two.
|
||||
*/
|
||||
bool is_two(mpff const & n) const;
|
||||
|
||||
/**
|
||||
\brief Return true if \c a is the smallest representable negative number.
|
||||
*/
|
||||
bool is_minus_epsilon(mpff const & a) const;
|
||||
|
||||
/**
|
||||
\brief Return true if \c a is the smallest representable positive number.
|
||||
*/
|
||||
bool is_plus_epsilon(mpff const & a) const;
|
||||
|
||||
/**
|
||||
\brief Return true if \c a is an integer and fits in an int64 machine integer.
|
||||
*/
|
||||
bool is_int64(mpff const & a) const;
|
||||
|
||||
/**
|
||||
\brief Return true if \c a is a non-negative integer and fits in an int64 machine integer.
|
||||
*/
|
||||
bool is_uint64(mpff const & a) const;
|
||||
|
||||
/**
|
||||
\brief Delete the resources associated with n.
|
||||
*/
|
||||
void del(mpff & n);
|
||||
|
||||
/**
|
||||
\brief a <- -a
|
||||
*/
|
||||
static void neg(mpff & a) { if (!is_zero(a)) a.m_sign = !a.m_sign; }
|
||||
|
||||
/**
|
||||
\brief a <- |a|
|
||||
*/
|
||||
static void abs(mpff & a) { a.m_sign = 0; }
|
||||
|
||||
static void swap(mpff & a, mpff & b) { a.swap(b); }
|
||||
|
||||
/**
|
||||
\brief c <- a + b
|
||||
*/
|
||||
void add(mpff const & a, mpff const & b, mpff & c);
|
||||
|
||||
/**
|
||||
\brief c <- a - b
|
||||
*/
|
||||
void sub(mpff const & a, mpff const & b, mpff & c);
|
||||
|
||||
/**
|
||||
\brief a <- a + 1
|
||||
*/
|
||||
void inc(mpff & a) { add(a, m_one, a); }
|
||||
|
||||
/**
|
||||
\brief a <- a - 1
|
||||
*/
|
||||
void dec(mpff & a) { sub(a, m_one, a); }
|
||||
|
||||
/**
|
||||
\brief c <- a * b
|
||||
*/
|
||||
void mul(mpff const & a, mpff const & b, mpff & c);
|
||||
|
||||
/**
|
||||
\brief c <- a / b
|
||||
|
||||
\pre !is_zero(b)
|
||||
*/
|
||||
void div(mpff const & a, mpff const & b, mpff & c);
|
||||
|
||||
/**
|
||||
\brief a <- 1/a
|
||||
|
||||
\pre !is_zero(a);
|
||||
*/
|
||||
void inv(mpff & a) { div(m_one, a, a); }
|
||||
void inv(mpff const & a, mpff & b) { set(b, a); inv(b); }
|
||||
|
||||
/**
|
||||
\brief b <- a^k
|
||||
*/
|
||||
void power(mpff const & a, unsigned k, mpff & b);
|
||||
|
||||
/**
|
||||
\brief Return true if \c a is a power of 2. That is, a is equal to 2^k for some k >= 0.
|
||||
*/
|
||||
bool is_power_of_two(mpff const & a, unsigned & k) const;
|
||||
bool is_power_of_two(mpff const & a) const;
|
||||
|
||||
bool eq(mpff const & a, mpff const & b) const;
|
||||
bool neq(mpff const & a, mpff const & b) const { return !eq(a, b); }
|
||||
bool lt(mpff const & a, mpff const & b) const;
|
||||
bool gt(mpff const & a, mpff const & b) const { return lt(b, a); }
|
||||
bool le(mpff const & a, mpff const & b) const { return !lt(b, a); }
|
||||
bool ge(mpff const & a, mpff const & b) const { return !lt(a, b); }
|
||||
|
||||
void set(mpff & n, int v);
|
||||
void set(mpff & n, unsigned v);
|
||||
void set(mpff & n, int64 v);
|
||||
void set(mpff & n, uint64 v);
|
||||
void set(mpff & n, int num, unsigned den);
|
||||
void set(mpff & n, int64 num, uint64 den);
|
||||
void set(mpff & n, mpff const & v);
|
||||
void set(mpff & n, unsynch_mpz_manager & m, mpz const & v);
|
||||
void set(mpff & n, synch_mpz_manager & m, mpz const & v);
|
||||
void set(mpff & n, unsynch_mpq_manager & m, mpq const & v);
|
||||
void set(mpff & n, synch_mpq_manager & m, mpq const & v);
|
||||
void set_plus_epsilon(mpff & n);
|
||||
void set_minus_epsilon(mpff & n);
|
||||
void set_max(mpff & n);
|
||||
void set_min(mpff & n);
|
||||
|
||||
/**
|
||||
\brief n <- floor(n)
|
||||
*/
|
||||
void floor(mpff & n);
|
||||
void floor(mpff const & n, mpff & o) { set(o, n); floor(o); }
|
||||
|
||||
/**
|
||||
\brief n <- ceil(n)
|
||||
*/
|
||||
void ceil(mpff & n);
|
||||
void ceil(mpff const & n, mpff & o) { set(o, n); ceil(o); }
|
||||
|
||||
/**
|
||||
\brief Update \c a to the next representable float.
|
||||
|
||||
Throws an exception if \c a is the maximal representable float.
|
||||
*/
|
||||
void next(mpff & a);
|
||||
/**
|
||||
\brief Update \c a to the previous representable float.
|
||||
|
||||
Throws an exception if \c a is the minimal representable float.
|
||||
*/
|
||||
void prev(mpff & a);
|
||||
|
||||
/**
|
||||
\brief Convert n into a mpz numeral.
|
||||
|
||||
\pre is_int(n)
|
||||
|
||||
\remark if exponent(n) is too big, we may run out of memory.
|
||||
*/
|
||||
void to_mpz(mpff const & n, unsynch_mpz_manager & m, mpz & t);
|
||||
|
||||
/**
|
||||
\brief Convert n into a mpz numeral.
|
||||
|
||||
\pre is_int(n)
|
||||
|
||||
\remark if exponent(n) is too big, we may run out of memory.
|
||||
*/
|
||||
void to_mpz(mpff const & n, synch_mpz_manager & m, mpz & t);
|
||||
|
||||
/**
|
||||
\brief Convert n into a mpq numeral.
|
||||
|
||||
\remark if exponent(n) is too big, we may run out of memory.
|
||||
*/
|
||||
void to_mpq(mpff const & n, unsynch_mpq_manager & m, mpq & t);
|
||||
|
||||
/**
|
||||
\brief Convert n into a mpq numeral.
|
||||
|
||||
\remark if exponent(n) is too big, we may run out of memory.
|
||||
*/
|
||||
void to_mpq(mpff const & n, synch_mpq_manager & m, mpq & t);
|
||||
|
||||
/**
|
||||
\brief Return n as an int64.
|
||||
|
||||
\pre is_int64(n)
|
||||
*/
|
||||
int64 get_int64(mpff const & n) const;
|
||||
|
||||
/**
|
||||
\brief Return n as an uint64.
|
||||
|
||||
\pre is_uint64(n)
|
||||
*/
|
||||
uint64 get_uint64(mpff const & n) const;
|
||||
|
||||
/**
|
||||
\brief Return the biggest k s.t. 2^k <= a.
|
||||
|
||||
\remark Return 0 if a is not positive.
|
||||
*/
|
||||
unsigned prev_power_of_two(mpff const & a);
|
||||
|
||||
void display_raw(std::ostream & out, mpff const & n) const;
|
||||
void display(std::ostream & out, mpff const & n) const;
|
||||
void display_decimal(std::ostream & out, mpff const & n, unsigned prec=32, unsigned max_power=128) const;
|
||||
void display_smt2(std::ostream & out, mpff const & n, bool decimal=true) const;
|
||||
|
||||
std::string to_string(mpff const & a) const;
|
||||
std::string to_rational_string(mpff const & a) const;
|
||||
|
||||
bool check(mpff const & n) const;
|
||||
};
|
||||
|
||||
typedef _scoped_numeral<mpff_manager> scoped_mpff;
|
||||
typedef _scoped_numeral_vector<mpff_manager> scoped_mpff_vector;
|
||||
|
||||
#endif
|
866
src/util/mpfx.cpp
Normal file
866
src/util/mpfx.cpp
Normal file
|
@ -0,0 +1,866 @@
|
|||
/*++
|
||||
Copyright (c) 2012 Microsoft Corporation
|
||||
|
||||
Module Name:
|
||||
|
||||
mpfx.h
|
||||
|
||||
Abstract:
|
||||
|
||||
Multi precision fixed point numbers.
|
||||
|
||||
Author:
|
||||
|
||||
Leonardo de Moura (leonardo) 2012-09-19
|
||||
|
||||
Revision History:
|
||||
|
||||
--*/
|
||||
#include<sstream>
|
||||
#include<iomanip>
|
||||
#include"mpfx.h"
|
||||
#include"mpn.h"
|
||||
#include"mpz.h"
|
||||
#include"mpq.h"
|
||||
#include"bit_util.h"
|
||||
#include"trace.h"
|
||||
|
||||
mpfx_manager::mpfx_manager(unsigned int_sz, unsigned frac_sz, unsigned initial_capacity) {
|
||||
SASSERT(initial_capacity > 0);
|
||||
SASSERT(int_sz > 0);
|
||||
SASSERT(frac_sz > 0);
|
||||
m_int_part_sz = int_sz;
|
||||
m_frac_part_sz = frac_sz;
|
||||
m_total_sz = m_int_part_sz + m_frac_part_sz;
|
||||
m_words.resize(initial_capacity * m_total_sz, 0);
|
||||
m_capacity = initial_capacity;
|
||||
m_to_plus_inf = false;
|
||||
m_buffer0.resize(2*m_total_sz, 0);
|
||||
m_buffer1.resize(2*m_total_sz, 0);
|
||||
m_buffer2.resize(2*m_total_sz, 0);
|
||||
unsigned zero_sig_idx = m_id_gen.mk();
|
||||
SASSERT(zero_sig_idx == 0);
|
||||
set(m_one, 1);
|
||||
}
|
||||
|
||||
mpfx_manager::~mpfx_manager() {
|
||||
del(m_one);
|
||||
}
|
||||
|
||||
void mpfx_manager::expand() {
|
||||
m_capacity = 2*m_capacity;
|
||||
m_words.resize(m_capacity * m_total_sz, 0);
|
||||
}
|
||||
|
||||
void mpfx_manager::allocate(mpfx & n) {
|
||||
SASSERT(n.m_sig_idx == 0);
|
||||
unsigned sig_idx = m_id_gen.mk();
|
||||
ensure_capacity(sig_idx);
|
||||
n.m_sig_idx = sig_idx;
|
||||
SASSERT(::is_zero(m_total_sz, words(n)));
|
||||
}
|
||||
|
||||
unsigned mpfx_manager::sz(unsigned * ws) const {
|
||||
SASSERT(!::is_zero(m_total_sz, ws));
|
||||
unsigned r = m_total_sz;
|
||||
while (true) {
|
||||
SASSERT(r > 0);
|
||||
--r;
|
||||
if (ws[r] != 0)
|
||||
return r + 1;
|
||||
}
|
||||
}
|
||||
|
||||
void mpfx_manager::del(mpfx & n) {
|
||||
unsigned sig_idx = n.m_sig_idx;
|
||||
if (sig_idx != 0) {
|
||||
m_id_gen.recycle(sig_idx);
|
||||
unsigned * w = words(n);
|
||||
for (unsigned i = 0; i < m_total_sz; i++)
|
||||
w[i] = 0;
|
||||
}
|
||||
}
|
||||
|
||||
void mpfx_manager::reset(mpfx & n) {
|
||||
del(n);
|
||||
n.m_sign = false;
|
||||
n.m_sig_idx = 0;
|
||||
SASSERT(check(n));
|
||||
}
|
||||
|
||||
bool mpfx_manager::is_int(mpfx const & n) const {
|
||||
unsigned * w = words(n);
|
||||
for (unsigned i = 0; i < m_frac_part_sz; i++)
|
||||
if (w[i] != 0)
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool mpfx_manager::is_abs_one(mpfx const & n) const {
|
||||
unsigned * w = words(n);
|
||||
return is_int(n) && w[m_frac_part_sz] == 1 && ::is_zero(m_int_part_sz - 1, w + m_frac_part_sz + 1);
|
||||
}
|
||||
|
||||
bool mpfx_manager::is_int64(mpfx const & a) const {
|
||||
if (!is_int(a))
|
||||
return false;
|
||||
if (is_zero(a) || m_int_part_sz <= 1)
|
||||
return true;
|
||||
unsigned * w = words(a);
|
||||
w += m_frac_part_sz;
|
||||
if (w[1] < 0x80000000u || (w[1] == 0x80000000u && is_neg(a))) {
|
||||
for (unsigned i = 2; i < m_int_part_sz; i++)
|
||||
if (w[i] != 0)
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
bool mpfx_manager::is_uint64(mpfx const & a) const {
|
||||
if (!is_int(a) || is_neg(a))
|
||||
return false;
|
||||
if (is_zero(a) || m_int_part_sz <= 2)
|
||||
return true;
|
||||
unsigned * w = words(a);
|
||||
for (unsigned i = m_frac_part_sz + 2; i < m_total_sz; i++)
|
||||
if (w[i] != 0)
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
void mpfx_manager::set(mpfx & n, int v) {
|
||||
if (v == 0) {
|
||||
reset(n);
|
||||
}
|
||||
else {
|
||||
if (v < 0) {
|
||||
set(n, static_cast<unsigned>(-v));
|
||||
n.m_sign = 1;
|
||||
}
|
||||
else {
|
||||
set(n, static_cast<unsigned>(v));
|
||||
}
|
||||
}
|
||||
SASSERT(get_int64(n) == v);
|
||||
SASSERT(check(n));
|
||||
}
|
||||
|
||||
void mpfx_manager::set(mpfx & n, unsigned v) {
|
||||
if (v == 0) {
|
||||
reset(n);
|
||||
}
|
||||
else {
|
||||
allocate_if_needed(n);
|
||||
n.m_sign = 0;
|
||||
unsigned * w = words(n);
|
||||
for (unsigned i = 0; i < m_total_sz; i++)
|
||||
w[i] = 0;
|
||||
w[m_frac_part_sz] = v;
|
||||
}
|
||||
SASSERT(is_int(n));
|
||||
SASSERT(get_uint64(n) == v);
|
||||
SASSERT(check(n));
|
||||
}
|
||||
|
||||
void mpfx_manager::set(mpfx & n, int64 v) {
|
||||
if (m_int_part_sz == 1) {
|
||||
if (v < -static_cast<int64>(static_cast<uint64>(UINT_MAX)) ||
|
||||
v > static_cast<int64>(static_cast<uint64>(UINT_MAX)))
|
||||
throw overflow_exception();
|
||||
}
|
||||
if (v == 0) {
|
||||
reset(n);
|
||||
}
|
||||
else {
|
||||
if (v < 0) {
|
||||
set(n, static_cast<uint64>(-v));
|
||||
n.m_sign = 1;
|
||||
}
|
||||
else {
|
||||
set(n, static_cast<uint64>(v));
|
||||
}
|
||||
}
|
||||
SASSERT(is_int(n));
|
||||
SASSERT(get_int64(n) == v);
|
||||
SASSERT(check(n));
|
||||
}
|
||||
|
||||
void mpfx_manager::set(mpfx & n, uint64 v) {
|
||||
if (m_int_part_sz == 1) {
|
||||
if (v > static_cast<uint64>(UINT_MAX))
|
||||
throw overflow_exception();
|
||||
}
|
||||
|
||||
if (v == 0) {
|
||||
reset(n);
|
||||
}
|
||||
else {
|
||||
allocate_if_needed(n);
|
||||
n.m_sign = 0;
|
||||
unsigned * _v = reinterpret_cast<unsigned*>(&v);
|
||||
unsigned * w = words(n);
|
||||
for (unsigned i = 0; i < m_total_sz; i++)
|
||||
w[i] = 0;
|
||||
w[m_frac_part_sz] = _v[0];
|
||||
if (m_int_part_sz == 1) {
|
||||
SASSERT(_v[1] == 0);
|
||||
}
|
||||
else {
|
||||
w[m_frac_part_sz+1] = _v[1];
|
||||
}
|
||||
}
|
||||
SASSERT(is_int(n));
|
||||
SASSERT(get_uint64(n) == v);
|
||||
SASSERT(check(n));
|
||||
}
|
||||
|
||||
void mpfx_manager::set(mpfx & n, int num, unsigned den) {
|
||||
scoped_mpfx a(*this), b(*this);
|
||||
set(a, num);
|
||||
set(b, den);
|
||||
div(a, b, n);
|
||||
SASSERT(check(n));
|
||||
}
|
||||
|
||||
void mpfx_manager::set(mpfx & n, int64 num, uint64 den) {
|
||||
scoped_mpfx a(*this), b(*this);
|
||||
set(a, num);
|
||||
set(b, den);
|
||||
div(a, b, n);
|
||||
SASSERT(check(n));
|
||||
}
|
||||
|
||||
void mpfx_manager::set(mpfx & n, mpfx const & v) {
|
||||
if (is_zero(v)) {
|
||||
reset(n);
|
||||
return;
|
||||
}
|
||||
allocate_if_needed(n);
|
||||
n.m_sign = v.m_sign;
|
||||
unsigned * w1 = words(n);
|
||||
unsigned * w2 = words(v);
|
||||
for (unsigned i = 0; i < m_total_sz; i++)
|
||||
w1[i] = w2[i];
|
||||
SASSERT(check(n));
|
||||
}
|
||||
|
||||
template<bool SYNCH>
|
||||
void mpfx_manager::set_core(mpfx & n, mpz_manager<SYNCH> & m, mpz const & v) {
|
||||
if (m.is_zero(v)) {
|
||||
reset(n);
|
||||
}
|
||||
else {
|
||||
m_tmp_digits.reset();
|
||||
allocate_if_needed(n);
|
||||
n.m_sign = m.decompose(v, m_tmp_digits);
|
||||
unsigned sz = m_tmp_digits.size();
|
||||
if (sz > m_int_part_sz)
|
||||
throw overflow_exception();
|
||||
unsigned * w = words(n);
|
||||
for (unsigned i = 0; i < m_frac_part_sz; i++)
|
||||
w[i] = 0;
|
||||
::copy(sz, m_tmp_digits.c_ptr(), m_int_part_sz, w + m_frac_part_sz);
|
||||
}
|
||||
SASSERT(check(n));
|
||||
}
|
||||
|
||||
void mpfx_manager::set(mpfx & n, unsynch_mpz_manager & m, mpz const & v) {
|
||||
set_core(n, m, v);
|
||||
}
|
||||
|
||||
void mpfx_manager::set(mpfx & n, synch_mpz_manager & m, mpz const & v) {
|
||||
set_core(n, m, v);
|
||||
}
|
||||
|
||||
template<bool SYNCH>
|
||||
void mpfx_manager::set_core(mpfx & n, mpq_manager<SYNCH> & m, mpq const & v) {
|
||||
if (m.is_int(v)) {
|
||||
set_core(n, m, v.numerator());
|
||||
}
|
||||
else {
|
||||
allocate_if_needed(n);
|
||||
_scoped_numeral<mpz_manager<SYNCH> > tmp(m);
|
||||
n.m_sign = is_neg(n);
|
||||
m.mul2k(v.numerator(), 8 * sizeof(unsigned) * m_frac_part_sz, tmp);
|
||||
m.abs(tmp);
|
||||
if ((n.m_sign == 1) != m_to_plus_inf && !m.divides(v.denominator(), tmp)) {
|
||||
m.div(tmp, v.denominator(), tmp);
|
||||
m.inc(tmp);
|
||||
}
|
||||
else {
|
||||
m.div(tmp, v.denominator(), tmp);
|
||||
}
|
||||
m_tmp_digits.reset();
|
||||
m.decompose(tmp, m_tmp_digits);
|
||||
unsigned sz = m_tmp_digits.size();
|
||||
if (sz > m_total_sz)
|
||||
throw overflow_exception();
|
||||
unsigned * w = words(n);
|
||||
::copy(sz, m_tmp_digits.c_ptr(), m_total_sz, w);
|
||||
}
|
||||
SASSERT(check(n));
|
||||
}
|
||||
|
||||
void mpfx_manager::set(mpfx & n, unsynch_mpq_manager & m, mpq const & v) {
|
||||
set_core(n, m, v);
|
||||
}
|
||||
|
||||
void mpfx_manager::set(mpfx & n, synch_mpq_manager & m, mpq const & v) {
|
||||
set_core(n, m, v);
|
||||
}
|
||||
|
||||
bool mpfx_manager::eq(mpfx const & a, mpfx const & b) const {
|
||||
if (is_zero(a) && is_zero(b))
|
||||
return true;
|
||||
if (is_zero(a) || is_zero(b))
|
||||
return false;
|
||||
if (a.m_sign != b.m_sign)
|
||||
return false;
|
||||
unsigned * w1 = words(a);
|
||||
unsigned * w2 = words(b);
|
||||
for (unsigned i = 0; i < m_total_sz; i++)
|
||||
if (w1[i] != w2[i])
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool mpfx_manager::lt(mpfx const & a, mpfx const & b) const {
|
||||
STRACE("mpfx_trace", tout << "[mpfx] ("; display(tout, a); tout << " < "; display(tout, b); tout << ") == ";);
|
||||
bool r;
|
||||
if (is_zero(a)) {
|
||||
r = !is_zero(b) && !is_neg(b);
|
||||
}
|
||||
else if (is_zero(b)) {
|
||||
r = is_neg(a);
|
||||
}
|
||||
else {
|
||||
SASSERT(!is_zero(a));
|
||||
SASSERT(!is_zero(b));
|
||||
if (is_neg(a)) {
|
||||
r = is_pos(b) || ::lt(m_total_sz, words(b), words(a));
|
||||
}
|
||||
else {
|
||||
SASSERT(is_pos(a));
|
||||
r = is_pos(b) && ::lt(m_total_sz, words(a), words(b));
|
||||
}
|
||||
}
|
||||
STRACE("mpfx_trace", tout << "(" << r << " == 1)\n";);
|
||||
return r;
|
||||
}
|
||||
|
||||
void mpfx_manager::add_sub(bool is_sub, mpfx const & a, mpfx const & b, mpfx & c) {
|
||||
if (is_zero(a)) {
|
||||
set(c, b);
|
||||
if (is_sub)
|
||||
neg(c);
|
||||
return;
|
||||
}
|
||||
|
||||
if (is_zero(b)) {
|
||||
set(c, a);
|
||||
return;
|
||||
}
|
||||
|
||||
TRACE("mpfx", tout << (is_sub ? "sub" : "add") << "("; display(tout, a); tout << ", "; display(tout, b); tout << ")\n";);
|
||||
|
||||
allocate_if_needed(c);
|
||||
|
||||
bool sgn_a = a.m_sign;
|
||||
bool sgn_b = b.m_sign;
|
||||
unsigned * w_a = words(a);
|
||||
unsigned * w_b = words(b);
|
||||
|
||||
if (is_sub)
|
||||
sgn_b = !sgn_b;
|
||||
|
||||
// Compute c
|
||||
unsigned * w_c = words(c);
|
||||
if (sgn_a == sgn_b) {
|
||||
c.m_sign = sgn_a;
|
||||
if (!::add(m_total_sz, w_a, w_b, w_c))
|
||||
throw overflow_exception();
|
||||
}
|
||||
else {
|
||||
unsigned borrow;
|
||||
SASSERT(sgn_a != sgn_b);
|
||||
if (::lt(m_total_sz, w_a, w_b)) {
|
||||
c.m_sign = sgn_b;
|
||||
sub_diff(w_b, m_total_sz, w_a, m_total_sz, w_c, &borrow, 0);
|
||||
SASSERT(!::is_zero(m_total_sz, w_c));
|
||||
}
|
||||
else {
|
||||
c.m_sign = sgn_a;
|
||||
sub_diff(w_a, m_total_sz, w_b, m_total_sz, w_c, &borrow, 0);
|
||||
if (::is_zero(m_total_sz, w_c))
|
||||
reset(c);
|
||||
}
|
||||
SASSERT(borrow == 0);
|
||||
}
|
||||
TRACE("mpfx", tout << "result: "; display(tout, c); tout << "\n";);
|
||||
SASSERT(check(c));
|
||||
}
|
||||
|
||||
void mpfx_manager::add(mpfx const & a, mpfx const & b, mpfx & c) {
|
||||
STRACE("mpfx_trace", tout << "[mpfx] "; display(tout, a); tout << " + "; display(tout, b); tout << " == ";);
|
||||
add_sub(false, a, b, c);
|
||||
STRACE("mpfx_trace", display(tout, c); tout << "\n";);
|
||||
}
|
||||
|
||||
void mpfx_manager::sub(mpfx const & a, mpfx const & b, mpfx & c) {
|
||||
STRACE("mpfx_trace", tout << "[mpfx] "; display(tout, a); tout << " - "; display(tout, b); tout << " == ";);
|
||||
add_sub(true, a, b, c);
|
||||
STRACE("mpfx_trace", display(tout, c); tout << "\n";);
|
||||
}
|
||||
|
||||
void mpfx_manager::mul(mpfx const & a, mpfx const & b, mpfx & c) {
|
||||
STRACE("mpfx_trace", tout << "[mpfx] ("; display(tout, a); tout << ") * ("; display(tout, b); tout << ") " << (m_to_plus_inf ? "<=" : ">=") << " ";);
|
||||
if (is_zero(a) || is_zero(b)) {
|
||||
reset(c);
|
||||
}
|
||||
else {
|
||||
allocate_if_needed(c);
|
||||
c.m_sign = a.m_sign ^ b.m_sign;
|
||||
unsigned * r = m_buffer0.c_ptr();
|
||||
multiply(words(a), m_total_sz, words(b), m_total_sz, r, 0);
|
||||
// round result
|
||||
unsigned * _r = r + m_frac_part_sz;
|
||||
if ((c.m_sign == 1) != m_to_plus_inf && !::is_zero(m_frac_part_sz, r)) {
|
||||
if (!::inc(m_total_sz, _r))
|
||||
throw overflow_exception();
|
||||
}
|
||||
// check for overflows
|
||||
if (!::is_zero(m_int_part_sz, _r + m_total_sz))
|
||||
throw overflow_exception();
|
||||
// copy result to c
|
||||
unsigned * w_c = words(c);
|
||||
for (unsigned i = 0; i < m_total_sz; i++)
|
||||
w_c[i] = _r[i];
|
||||
}
|
||||
STRACE("mpfx_trace", display(tout, c); tout << "\n";);
|
||||
SASSERT(check(c));
|
||||
}
|
||||
|
||||
void mpfx_manager::div(mpfx const & a, mpfx const & b, mpfx & c) {
|
||||
if (is_zero(b))
|
||||
throw div0_exception();
|
||||
STRACE("mpfx_trace", tout << "[mpfx] ("; display(tout, a); tout << ") / ("; display(tout, b); tout << ") " << (m_to_plus_inf ? "<=" : ">=") << " ";);
|
||||
if (is_zero(a)) {
|
||||
reset(c);
|
||||
}
|
||||
else {
|
||||
allocate_if_needed(c);
|
||||
c.m_sign = a.m_sign ^ b.m_sign;
|
||||
unsigned * w_a = words(a);
|
||||
unsigned * w_a_shft = m_buffer0.c_ptr();
|
||||
unsigned a_shft_sz = sz(w_a) + m_frac_part_sz;
|
||||
// copy a to buffer 0, and shift by m_frac_part_sz
|
||||
for (unsigned i = 0; i < m_frac_part_sz; i++)
|
||||
w_a_shft[i] = 0;
|
||||
for (unsigned i = 0; i < m_total_sz; i++)
|
||||
w_a_shft[i+m_frac_part_sz] = w_a[i];
|
||||
unsigned * w_b = words(b);
|
||||
unsigned b_sz = sz(w_b);
|
||||
unsigned * w_q = m_buffer1.c_ptr();
|
||||
if (b_sz > a_shft_sz) {
|
||||
if ((c.m_sign == 1) != m_to_plus_inf)
|
||||
set_epsilon(c);
|
||||
else
|
||||
reset(c);
|
||||
}
|
||||
else {
|
||||
unsigned q_sz = a_shft_sz - b_sz + 1;
|
||||
unsigned * w_r = m_buffer2.c_ptr();
|
||||
unsigned r_sz = b_sz;
|
||||
divide(w_a_shft, a_shft_sz,
|
||||
w_b, b_sz,
|
||||
reciprocal_1_NULL,
|
||||
w_q,
|
||||
w_r,
|
||||
0);
|
||||
for (unsigned i = m_total_sz; i < q_sz; i++)
|
||||
if (w_q[i] != 0)
|
||||
throw overflow_exception();
|
||||
if (((c.m_sign == 1) != m_to_plus_inf) && !::is_zero(r_sz, w_r)) {
|
||||
// round the result
|
||||
if (!::inc(m_total_sz, w_q))
|
||||
throw overflow_exception();
|
||||
}
|
||||
unsigned * w_c = words(c);
|
||||
bool zero_q = true;
|
||||
if (m_total_sz >= q_sz) {
|
||||
unsigned i;
|
||||
for (i = 0; i < q_sz; i++) {
|
||||
if (w_q[i] != 0)
|
||||
zero_q = false;
|
||||
w_c[i] = w_q[i];
|
||||
}
|
||||
for (; i < m_total_sz; i++)
|
||||
w_c[i] = 0;
|
||||
}
|
||||
else {
|
||||
for (unsigned i = 0; i < m_total_sz; i++) {
|
||||
if (w_q[i] != 0)
|
||||
zero_q = false;
|
||||
w_c[i] = w_q[i];
|
||||
}
|
||||
}
|
||||
if (zero_q) {
|
||||
if ((c.m_sign == 1) != m_to_plus_inf)
|
||||
set_epsilon(c);
|
||||
else
|
||||
reset(c);
|
||||
}
|
||||
}
|
||||
}
|
||||
STRACE("mpfx_trace", display(tout, c); tout << "\n";);
|
||||
SASSERT(check(c));
|
||||
}
|
||||
|
||||
void mpfx_manager::div2k(mpfx & a, unsigned k) {
|
||||
STRACE("mpfx_trace", tout << "[mpfx] ("; display(tout, a); tout << ") / (2^" << k << ") " << (m_to_plus_inf ? "<=" : ">=") << " ";);
|
||||
if (!is_zero(a) && k > 0) {
|
||||
unsigned * w = words(a);
|
||||
bool _inc = ((a.m_sign == 1) != m_to_plus_inf) && has_one_at_first_k_bits(m_total_sz, w, k);
|
||||
shr(m_total_sz, w, k, m_total_sz, w);
|
||||
if (_inc) {
|
||||
VERIFY(::inc(m_total_sz, w));
|
||||
SASSERT(!::is_zero(m_total_sz, w));
|
||||
}
|
||||
else if (::is_zero(m_total_sz, w)) {
|
||||
reset(a);
|
||||
}
|
||||
}
|
||||
STRACE("mpfx_trace", display(tout, a); tout << "\n";);
|
||||
SASSERT(check(a));
|
||||
}
|
||||
|
||||
void mpfx_manager::set_epsilon(mpfx & n) {
|
||||
unsigned * w = words(n);
|
||||
w[0] = 1;
|
||||
for (unsigned i = 1; i < m_total_sz; i++)
|
||||
w[i] = 0;
|
||||
}
|
||||
|
||||
void mpfx_manager::set_minus_epsilon(mpfx & n) {
|
||||
set_epsilon(n);
|
||||
n.m_sign = true;
|
||||
SASSERT(check(n));
|
||||
}
|
||||
|
||||
void mpfx_manager::set_plus_epsilon(mpfx & n) {
|
||||
set_epsilon(n);
|
||||
n.m_sign = 0;
|
||||
SASSERT(check(n));
|
||||
}
|
||||
|
||||
void mpfx_manager::floor(mpfx & n) {
|
||||
STRACE("mpfx_trace", tout << "[mpfx] Floor["; display(tout, n); tout << "] == ";);
|
||||
unsigned * w = words(n);
|
||||
if (is_neg(n)) {
|
||||
bool is_int = true;
|
||||
for (unsigned i = 0; i < m_frac_part_sz; i++) {
|
||||
if (w[i] != 0) {
|
||||
is_int = false;
|
||||
w[i] = 0;
|
||||
}
|
||||
}
|
||||
if (!is_int && !::inc(m_int_part_sz, w + m_frac_part_sz))
|
||||
throw overflow_exception();
|
||||
}
|
||||
else {
|
||||
for (unsigned i = 0; i < m_frac_part_sz; i++)
|
||||
w[i] = 0;
|
||||
}
|
||||
if (::is_zero(m_int_part_sz, w + m_frac_part_sz))
|
||||
reset(n);
|
||||
SASSERT(check(n));
|
||||
STRACE("mpfx_trace", display(tout, n); tout << "\n";);
|
||||
}
|
||||
|
||||
void mpfx_manager::ceil(mpfx & n) {
|
||||
STRACE("mpfx_trace", tout << "[mpfx] Ceiling["; display(tout, n); tout << "] == ";);
|
||||
unsigned * w = words(n);
|
||||
if (is_pos(n)) {
|
||||
bool is_int = true;
|
||||
for (unsigned i = 0; i < m_frac_part_sz; i++) {
|
||||
if (w[i] != 0) {
|
||||
is_int = false;
|
||||
w[i] = 0;
|
||||
}
|
||||
}
|
||||
if (!is_int && !::inc(m_int_part_sz, w + m_frac_part_sz))
|
||||
throw overflow_exception();
|
||||
}
|
||||
else {
|
||||
for (unsigned i = 0; i < m_frac_part_sz; i++)
|
||||
w[i] = 0;
|
||||
}
|
||||
if (::is_zero(m_int_part_sz, w + m_frac_part_sz))
|
||||
reset(n);
|
||||
SASSERT(check(n));
|
||||
STRACE("mpfx_trace", display(tout, n); tout << "\n";);
|
||||
}
|
||||
|
||||
void mpfx_manager::power(mpfx const & a, unsigned p, mpfx & b) {
|
||||
#ifdef _TRACE
|
||||
scoped_mpfx _a(*this); _a = a;
|
||||
unsigned _p = p;
|
||||
#endif
|
||||
#define SMALL_POWER 8
|
||||
SASSERT(check(a));
|
||||
if (is_zero(a)) {
|
||||
SASSERT(p != 0);
|
||||
reset(b);
|
||||
}
|
||||
else if (p == 0) {
|
||||
set(b, 1);
|
||||
}
|
||||
else if (p == 1) {
|
||||
set(b, a);
|
||||
}
|
||||
else if (p == 2) {
|
||||
mul(a, a, b);
|
||||
}
|
||||
else if (p <= SMALL_POWER && &a != &b) {
|
||||
SASSERT(p > 2);
|
||||
--p;
|
||||
set(b, a);
|
||||
while (p > 0) {
|
||||
--p;
|
||||
mul(a, b, b);
|
||||
}
|
||||
}
|
||||
else {
|
||||
unsigned mask = 1;
|
||||
scoped_mpfx pw(*this);
|
||||
set(pw, a);
|
||||
set(b, 1);
|
||||
while (mask <= p) {
|
||||
if (mask & p)
|
||||
mul(b, pw, b);
|
||||
mul(pw, pw, pw);
|
||||
mask = mask << 1;
|
||||
}
|
||||
}
|
||||
STRACE("mpfx_trace", tout << "[mpfx] ("; display(tout, _a); tout << ") ^ " << _p << (m_to_plus_inf ? "<=" : ">="); display(tout, b); tout << "\n";);
|
||||
TRACE("mpfx_power", display_raw(tout, b); tout << "\n";);
|
||||
SASSERT(check(b));
|
||||
}
|
||||
|
||||
|
||||
bool mpfx_manager::is_power_of_two(mpfx const & a, unsigned & k) const {
|
||||
if (!is_int(a) || is_zero(a))
|
||||
return false;
|
||||
unsigned * w = words(a);
|
||||
unsigned i = m_total_sz;
|
||||
while (true) {
|
||||
SASSERT (i > m_frac_part_sz);
|
||||
--i;
|
||||
if (w[i] != 0) {
|
||||
if (!::is_power_of_two(w[i]))
|
||||
return false;
|
||||
k = (i - m_frac_part_sz) * 8 * sizeof(unsigned) + log2(w[i]);
|
||||
while (i > m_frac_part_sz) {
|
||||
--i;
|
||||
if (w[i] != 0)
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool mpfx_manager::is_power_of_two(mpfx const & a) const {
|
||||
unsigned k;
|
||||
return is_power_of_two(a, k);
|
||||
}
|
||||
|
||||
int64 mpfx_manager::get_int64(mpfx const & n) const {
|
||||
SASSERT(is_int64(n));
|
||||
unsigned * w = words(n);
|
||||
w += m_frac_part_sz;
|
||||
uint64 r = *reinterpret_cast<uint64*>(w);
|
||||
if (r == 0x8000000000000000ull) {
|
||||
SASSERT(is_neg(n));
|
||||
return INT64_MIN;
|
||||
}
|
||||
else {
|
||||
return is_neg(n) ? -static_cast<int64>(r) : r;
|
||||
}
|
||||
}
|
||||
|
||||
uint64 mpfx_manager::get_uint64(mpfx const & n) const {
|
||||
SASSERT(is_uint64(n));
|
||||
unsigned * w = words(n);
|
||||
w += m_frac_part_sz;
|
||||
return *reinterpret_cast<uint64*>(w);
|
||||
}
|
||||
|
||||
template<bool SYNCH>
|
||||
void mpfx_manager::to_mpz_core(mpfx const & n, mpz_manager<SYNCH> & m, mpz & t) {
|
||||
SASSERT(is_int(n));
|
||||
unsigned * w = words(n);
|
||||
m.set(t, m_int_part_sz, w+m_frac_part_sz);
|
||||
if (is_neg(n))
|
||||
m.neg(t);
|
||||
}
|
||||
|
||||
void mpfx_manager::to_mpz(mpfx const & n, unsynch_mpz_manager & m, mpz & t) {
|
||||
to_mpz_core(n, m, t);
|
||||
}
|
||||
|
||||
void mpfx_manager::to_mpz(mpfx const & n, synch_mpz_manager & m, mpz & t) {
|
||||
to_mpz_core(n, m, t);
|
||||
}
|
||||
|
||||
template<bool SYNCH>
|
||||
void mpfx_manager::to_mpq_core(mpfx const & n, mpq_manager<SYNCH> & m, mpq & t) {
|
||||
_scoped_numeral<mpz_manager<SYNCH> > a(m), b(m);
|
||||
|
||||
unsigned * w = words(n);
|
||||
m.set(a, m_total_sz, w);
|
||||
|
||||
m.set(b, 1);
|
||||
m.mul2k(b, sizeof(unsigned)*8*m_frac_part_sz);
|
||||
|
||||
m.rat_div(a, b, t);
|
||||
|
||||
if (is_neg(n))
|
||||
m.neg(t);
|
||||
}
|
||||
|
||||
void mpfx_manager::to_mpq(mpfx const & n, unsynch_mpq_manager & m, mpq & t) {
|
||||
to_mpq_core(n, m, t);
|
||||
}
|
||||
|
||||
void mpfx_manager::to_mpq(mpfx const & n, synch_mpq_manager & m, mpq & t) {
|
||||
to_mpq_core(n, m, t);
|
||||
}
|
||||
|
||||
void mpfx_manager::display_raw(std::ostream & out, mpfx const & n) const {
|
||||
if (is_neg(n))
|
||||
out << "-";
|
||||
unsigned * w = words(n);
|
||||
unsigned i = m_total_sz;
|
||||
while(i > 0) {
|
||||
if (i == m_frac_part_sz)
|
||||
out << ".";
|
||||
--i;
|
||||
out << std::hex << std::setfill('0') << std::setw(2 * sizeof(unsigned)) << w[i];
|
||||
}
|
||||
}
|
||||
|
||||
void mpfx_manager::display(std::ostream & out, mpfx const & n) const {
|
||||
if (is_neg(n))
|
||||
out << "-";
|
||||
unsigned * w = words(n);
|
||||
unsigned sz = m_total_sz;
|
||||
unsigned shift = UINT_MAX;
|
||||
if (is_int(n)) {
|
||||
w += m_frac_part_sz;
|
||||
sz -= m_frac_part_sz;
|
||||
}
|
||||
else {
|
||||
shift = ntz(m_total_sz, w);
|
||||
if (shift > 0)
|
||||
shr(m_total_sz, w, shift, m_total_sz, w);
|
||||
}
|
||||
|
||||
sbuffer<char, 1024> str_buffer(11*sz, 0);
|
||||
out << mp_decimal(w, sz, str_buffer.begin(), str_buffer.size(), 0);
|
||||
if (!is_int(n)) {
|
||||
SASSERT(shift != UINT_MAX);
|
||||
// reverse effect of shr
|
||||
if (shift > 0)
|
||||
shl(m_total_sz, w, shift, m_total_sz, w);
|
||||
// display denominator as a power of 2
|
||||
unsigned k = sizeof(unsigned)*8*m_frac_part_sz - shift;
|
||||
out << "/2";
|
||||
if (k > 1)
|
||||
out << "^" << k;
|
||||
}
|
||||
}
|
||||
|
||||
void mpfx_manager::display_smt2(std::ostream & out, mpfx const & n) const {
|
||||
if (is_neg(n))
|
||||
out << "(- ";
|
||||
unsigned * w = words(n);
|
||||
unsigned sz = m_total_sz;
|
||||
if (is_int(n)) {
|
||||
w += m_frac_part_sz;
|
||||
sz -= m_frac_part_sz;
|
||||
}
|
||||
else {
|
||||
out << "(/ ";
|
||||
}
|
||||
sbuffer<char, 1024> str_buffer(11*sz, 0);
|
||||
out << mp_decimal(w, sz, str_buffer.begin(), str_buffer.size(), 0);
|
||||
if (!is_int(n)) {
|
||||
out << " ";
|
||||
unsigned * w = m_buffer0.c_ptr();
|
||||
for (unsigned i = 0; i < m_frac_part_sz; i++)
|
||||
w[i] = 0;
|
||||
w[m_frac_part_sz] = 1;
|
||||
sbuffer<char, 1024> str_buffer2(11*(m_frac_part_sz+1), 0);
|
||||
out << mp_decimal(w, m_frac_part_sz+1, str_buffer2.begin(), str_buffer2.size(), 0);
|
||||
out << ")";
|
||||
}
|
||||
if (is_neg(n))
|
||||
out << ")";
|
||||
}
|
||||
|
||||
void mpfx_manager::display_decimal(std::ostream & out, mpfx const & n, unsigned prec) const {
|
||||
if (is_neg(n))
|
||||
out << "-";
|
||||
unsigned * w = words(n);
|
||||
sbuffer<char, 1024> str_buffer(11*m_int_part_sz, 0);
|
||||
out << mp_decimal(w + m_frac_part_sz, m_int_part_sz, str_buffer.begin(), str_buffer.size(), 0);
|
||||
if (!is_int(n)) {
|
||||
out << ".";
|
||||
unsigned * frac = m_buffer0.c_ptr();
|
||||
::copy(m_frac_part_sz, w, m_frac_part_sz, frac);
|
||||
unsigned ten = 10;
|
||||
unsigned * n_frac = m_buffer1.c_ptr();
|
||||
bool frac_is_zero = false;
|
||||
unsigned i = 0;
|
||||
while (!frac_is_zero) {
|
||||
if (i >= prec) {
|
||||
out << "?";
|
||||
return;
|
||||
}
|
||||
multiply(frac, m_frac_part_sz, &ten, 1, n_frac, 0);
|
||||
frac_is_zero = ::is_zero(m_frac_part_sz, n_frac);
|
||||
SASSERT(n_frac[m_frac_part_sz] <= 9);
|
||||
if (!frac_is_zero || n_frac[m_frac_part_sz] != 0)
|
||||
out << n_frac[m_frac_part_sz];
|
||||
n_frac[m_frac_part_sz] = 0;
|
||||
std::swap(frac, n_frac);
|
||||
i++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
std::string mpfx_manager::to_string(mpfx const & a) const {
|
||||
std::ostringstream buffer;
|
||||
display(buffer, a);
|
||||
return buffer.str();
|
||||
}
|
||||
|
||||
std::string mpfx_manager::to_rational_string(mpfx const & a) const {
|
||||
return to_string(a);
|
||||
}
|
||||
|
||||
bool mpfx_manager::check(mpfx const & a) const {
|
||||
SASSERT(!is_zero(a) || a.m_sign == 0);
|
||||
SASSERT(is_zero(a) == ::is_zero(m_total_sz, words(a)));
|
||||
return true;
|
||||
}
|
||||
|
||||
unsigned mpfx_manager::prev_power_of_two(mpfx const & a) {
|
||||
if (!is_pos(a))
|
||||
return 0;
|
||||
return m_int_part_sz * sizeof(unsigned) * 8 - nlz(m_int_part_sz, words(a) + m_frac_part_sz) - 1;
|
||||
}
|
398
src/util/mpfx.h
Normal file
398
src/util/mpfx.h
Normal file
|
@ -0,0 +1,398 @@
|
|||
/*++
|
||||
Copyright (c) 2012 Microsoft Corporation
|
||||
|
||||
Module Name:
|
||||
|
||||
mpfx.h
|
||||
|
||||
Abstract:
|
||||
|
||||
Multi precision fixed point numbers.
|
||||
|
||||
Author:
|
||||
|
||||
Leonardo de Moura (leonardo) 2012-09-19
|
||||
|
||||
Revision History:
|
||||
|
||||
--*/
|
||||
#ifndef _MPFX_H_
|
||||
#define _MPFX_H_
|
||||
|
||||
#include"id_gen.h"
|
||||
#include"util.h"
|
||||
#include"vector.h"
|
||||
#include"z3_exception.h"
|
||||
#include"scoped_numeral.h"
|
||||
#include"scoped_numeral_vector.h"
|
||||
|
||||
class mpfx_manager;
|
||||
|
||||
class mpfx {
|
||||
friend class mpfx_manager;
|
||||
unsigned m_sign:1;
|
||||
unsigned m_sig_idx:31; // position where the data is stored in the mpfx_manager.
|
||||
public:
|
||||
mpfx():
|
||||
m_sign(0),
|
||||
m_sig_idx(0) {
|
||||
}
|
||||
|
||||
void swap(mpfx & other) {
|
||||
unsigned sign = m_sign; m_sign = other.m_sign; other.m_sign = sign;
|
||||
unsigned sig_idx = m_sig_idx; m_sig_idx = other.m_sig_idx; other.m_sig_idx = sig_idx;
|
||||
}
|
||||
};
|
||||
|
||||
inline void swap(mpfx & m1, mpfx & m2) { m1.swap(m2); }
|
||||
|
||||
class mpz;
|
||||
class mpq;
|
||||
template<bool SYNCH> class mpz_manager;
|
||||
template<bool SYNCH> class mpq_manager;
|
||||
typedef mpz_manager<true> synch_mpz_manager;
|
||||
typedef mpz_manager<false> unsynch_mpz_manager;
|
||||
typedef mpq_manager<true> synch_mpq_manager;
|
||||
typedef mpq_manager<false> unsynch_mpq_manager;
|
||||
|
||||
class mpfx_manager {
|
||||
// Every mpfx numeral from a given mpfx_manager uses the same number of words
|
||||
// to encode the integer and fractional parts.
|
||||
//
|
||||
// The number of words used to encode the integer part may be different from the number of words
|
||||
// used to encode the fractional part.
|
||||
//
|
||||
// There are two rounding modes: towards plus infinity, and towards minus infinity.
|
||||
//
|
||||
// If the result of an operation does not fit in the integer part, then an overflow exception is thrown.
|
||||
//
|
||||
// If the fractional part uses n words, then the error of every operation is less than 1/2^(32*n).
|
||||
//
|
||||
// Machine integer values (int, unsigned, int64, uint64) can be easily converted into mpfx numerals.
|
||||
//
|
||||
// The result of addition and subtraction operations are always precise. Note that overflows will trigger
|
||||
// an exception instead of an incorrect result.
|
||||
//
|
||||
unsigned m_int_part_sz;
|
||||
unsigned m_frac_part_sz;
|
||||
unsigned m_total_sz; //!< == m_int_part_sz + m_frac_part_sz
|
||||
unsigned_vector m_words; //!< Array containing all words
|
||||
unsigned m_capacity; //!< Number of mpfx numerals that can be stored in m_words.
|
||||
bool m_to_plus_inf; //!< If True, then round to plus infinity, otherwise to minus infinity
|
||||
id_gen m_id_gen;
|
||||
unsigned_vector m_buffer0, m_buffer1, m_buffer2;
|
||||
unsigned_vector m_tmp_digits;
|
||||
mpfx m_one;
|
||||
|
||||
unsigned * words(mpfx const & n) const { return m_words.c_ptr() + (n.m_sig_idx * m_total_sz); }
|
||||
unsigned sz(unsigned * ws) const;
|
||||
|
||||
void ensure_capacity(unsigned sig_idx) {
|
||||
while (sig_idx >= m_capacity)
|
||||
expand();
|
||||
}
|
||||
|
||||
void expand();
|
||||
|
||||
void allocate_if_needed(mpfx & n) {
|
||||
if (n.m_sig_idx == 0)
|
||||
allocate(n);
|
||||
}
|
||||
|
||||
void allocate(mpfx & n);
|
||||
|
||||
void set_epsilon(mpfx & n);
|
||||
|
||||
void add_sub(bool is_sub, mpfx const & a, mpfx const & b, mpfx & c);
|
||||
|
||||
template<bool SYNCH>
|
||||
void set_core(mpfx & n, mpz_manager<SYNCH> & m, mpz const & v);
|
||||
|
||||
template<bool SYNCH>
|
||||
void set_core(mpfx & n, mpq_manager<SYNCH> & m, mpq const & v);
|
||||
|
||||
template<bool SYNCH>
|
||||
void to_mpz_core(mpfx const & n, mpz_manager<SYNCH> & m, mpz & t);
|
||||
|
||||
template<bool SYNCH>
|
||||
void to_mpq_core(mpfx const & n, mpq_manager<SYNCH> & m, mpq & t);
|
||||
|
||||
public:
|
||||
typedef mpfx numeral;
|
||||
static bool precise() { return false; }
|
||||
static bool field() { return true; }
|
||||
|
||||
class exception : public z3_exception {
|
||||
virtual char const * msg() const { return "multi-precision fixed point (mpfx) exception"; }
|
||||
};
|
||||
|
||||
class overflow_exception : public exception {
|
||||
virtual char const * msg() const { return "multi-precision fixed point (mpfx) overflow"; }
|
||||
};
|
||||
|
||||
class div0_exception : public exception {
|
||||
virtual char const * msg() const { return "multi-precision fixed point (mpfx) division by zero"; }
|
||||
};
|
||||
|
||||
mpfx_manager(unsigned int_sz = 2, unsigned frac_sz = 1, unsigned initial_capacity = 1024);
|
||||
~mpfx_manager();
|
||||
|
||||
void round_to_plus_inf() { m_to_plus_inf = true; }
|
||||
void round_to_minus_inf() { m_to_plus_inf = false; }
|
||||
void set_rounding(bool to_plus_inf) { m_to_plus_inf = to_plus_inf; }
|
||||
bool rounding_to_plus_inf() const { return m_to_plus_inf; }
|
||||
|
||||
/**
|
||||
\brief Return true if n is negative
|
||||
*/
|
||||
static bool sign(mpfx const & n) { return is_neg(n); }
|
||||
|
||||
/**
|
||||
\brief Set n to zero.
|
||||
*/
|
||||
void reset(mpfx & n);
|
||||
|
||||
/**
|
||||
\brief Return true if n is an integer.
|
||||
*/
|
||||
bool is_int(mpfx const & n) const;
|
||||
|
||||
/**
|
||||
\brief Return true if n is zero.
|
||||
*/
|
||||
static bool is_zero(mpfx const & n) { return n.m_sig_idx == 0; }
|
||||
|
||||
/**
|
||||
\brief Return true if n is positive.
|
||||
*/
|
||||
static bool is_pos(mpfx const & n) { return n.m_sign == 0 && !is_zero(n); }
|
||||
|
||||
/**
|
||||
\brief Return true if n is negative.
|
||||
*/
|
||||
static bool is_neg(mpfx const & n) { return n.m_sign != 0; }
|
||||
|
||||
/**
|
||||
\brief Return true if n is non positive.
|
||||
*/
|
||||
static bool is_nonpos(mpfx const & n) { return !is_pos(n); }
|
||||
|
||||
/**
|
||||
\brief Return true if n is non negative.
|
||||
*/
|
||||
static bool is_nonneg(mpfx const & n) { return !is_neg(n); }
|
||||
|
||||
/**
|
||||
\brief Return true if the absolute value of n is 1.
|
||||
*/
|
||||
bool is_abs_one(mpfx const & n) const;
|
||||
|
||||
/**
|
||||
\brief Return true if n is one.
|
||||
*/
|
||||
bool is_one(mpfx const & n) const { return is_pos(n) && is_abs_one(n); }
|
||||
|
||||
/**
|
||||
\brief Return true if n is minus one.
|
||||
*/
|
||||
bool is_minus_one(mpfx const & n) const { return is_neg(n) && is_abs_one(n); }
|
||||
|
||||
/**
|
||||
\brief Return true if \c a is an integer and fits in an int64 machine integer.
|
||||
*/
|
||||
bool is_int64(mpfx const & a) const;
|
||||
|
||||
/**
|
||||
\brief Return true if \c a is a non-negative integer and fits in an int64 machine integer.
|
||||
*/
|
||||
bool is_uint64(mpfx const & a) const;
|
||||
|
||||
/**
|
||||
\brief Delete the resources associated with n.
|
||||
*/
|
||||
void del(mpfx & n);
|
||||
|
||||
/**
|
||||
\brief a <- -a
|
||||
*/
|
||||
static void neg(mpfx & a) { if (!is_zero(a)) a.m_sign = !a.m_sign; }
|
||||
|
||||
/**
|
||||
\brief a <- |a|
|
||||
*/
|
||||
static void abs(mpfx & a) { a.m_sign = 0; }
|
||||
|
||||
static void swap(mpfx & a, mpfx & b) { a.swap(b); }
|
||||
|
||||
/**
|
||||
\brief c <- a + b
|
||||
*/
|
||||
void add(mpfx const & a, mpfx const & b, mpfx & c);
|
||||
|
||||
/**
|
||||
\brief c <- a - b
|
||||
*/
|
||||
void sub(mpfx const & a, mpfx const & b, mpfx & c);
|
||||
|
||||
/**
|
||||
\brief a <- a + 1
|
||||
*/
|
||||
void inc(mpfx & a) { add(a, m_one, a); }
|
||||
|
||||
/**
|
||||
\brief a <- a - 1
|
||||
*/
|
||||
void dec(mpfx & a) { sub(a, m_one, a); }
|
||||
|
||||
/**
|
||||
\brief c <- a * b
|
||||
*/
|
||||
void mul(mpfx const & a, mpfx const & b, mpfx & c);
|
||||
|
||||
/**
|
||||
\brief c <- a / b
|
||||
|
||||
\pre !is_zero(b)
|
||||
*/
|
||||
void div(mpfx const & a, mpfx const & b, mpfx & c);
|
||||
|
||||
/**
|
||||
\brief a <- 1/a
|
||||
|
||||
\pre !is_zero(a);
|
||||
*/
|
||||
void inv(mpfx & a) { div(m_one, a, a); }
|
||||
void inv(mpfx const & a, mpfx & b) { set(b, a); inv(b); }
|
||||
|
||||
/**
|
||||
\brief a <- a/2^k
|
||||
*/
|
||||
void div2k(mpfx & a, unsigned k);
|
||||
|
||||
/**
|
||||
\brief b <- a/2^k
|
||||
*/
|
||||
void div2k(mpfx const & a, unsigned k, mpfx & b) { set(b, a); div2k(b, k); }
|
||||
|
||||
/**
|
||||
\brief a <- a/2
|
||||
*/
|
||||
void div2(mpfx & a) { div2k(a, 1); }
|
||||
|
||||
/**
|
||||
\brief b <- a/2
|
||||
*/
|
||||
void div2(mpfx const & a, mpfx & b) { div2k(a, 1, b); }
|
||||
|
||||
/**
|
||||
\brief b <- a^k
|
||||
*/
|
||||
void power(mpfx const & a, unsigned k, mpfx & b);
|
||||
|
||||
/**
|
||||
\brief Return true if \c a is a power of 2. That is, a is equal to 2^k for some k >= 0.
|
||||
*/
|
||||
bool is_power_of_two(mpfx const & a, unsigned & k) const;
|
||||
bool is_power_of_two(mpfx const & a) const;
|
||||
|
||||
bool eq(mpfx const & a, mpfx const & b) const;
|
||||
bool neq(mpfx const & a, mpfx const & b) const { return !eq(a, b); }
|
||||
bool lt(mpfx const & a, mpfx const & b) const;
|
||||
bool gt(mpfx const & a, mpfx const & b) const { return lt(b, a); }
|
||||
bool le(mpfx const & a, mpfx const & b) const { return !lt(b, a); }
|
||||
bool ge(mpfx const & a, mpfx const & b) const { return !lt(a, b); }
|
||||
|
||||
void set(mpfx & n, int v);
|
||||
void set(mpfx & n, unsigned v);
|
||||
void set(mpfx & n, int64 v);
|
||||
void set(mpfx & n, uint64 v);
|
||||
void set(mpfx & n, int num, unsigned den);
|
||||
void set(mpfx & n, int64 num, uint64 den);
|
||||
void set(mpfx & n, mpfx const & v);
|
||||
void set(mpfx & n, unsynch_mpz_manager & m, mpz const & v);
|
||||
void set(mpfx & n, synch_mpz_manager & m, mpz const & v);
|
||||
void set(mpfx & n, unsynch_mpq_manager & m, mpq const & v);
|
||||
void set(mpfx & n, synch_mpq_manager & m, mpq const & v);
|
||||
|
||||
/**
|
||||
\brief Set n to the smallest representable numeral greater than zero.
|
||||
*/
|
||||
void set_plus_epsilon(mpfx & n);
|
||||
|
||||
/**
|
||||
\brief Set n to the greatest representable numeral less than zero.
|
||||
*/
|
||||
void set_minus_epsilon(mpfx & n);
|
||||
|
||||
/**
|
||||
\brief n <- floor(n)
|
||||
*/
|
||||
void floor(mpfx & n);
|
||||
void floor(mpfx const & n, mpfx & o) { set(o, n); floor(o); }
|
||||
|
||||
/**
|
||||
\brief n <- ceil(n)
|
||||
*/
|
||||
void ceil(mpfx & n);
|
||||
void ceil(mpfx const & n, mpfx & o) { set(o, n); ceil(o); }
|
||||
|
||||
/**
|
||||
\brief Return n as an int64.
|
||||
|
||||
\pre is_int64(n)
|
||||
*/
|
||||
int64 get_int64(mpfx const & n) const;
|
||||
|
||||
/**
|
||||
\brief Return n as an uint64.
|
||||
|
||||
\pre is_uint64(n)
|
||||
*/
|
||||
uint64 get_uint64(mpfx const & n) const;
|
||||
|
||||
/**
|
||||
\brief Convert n into a mpz numeral.
|
||||
|
||||
\pre is_int(n)
|
||||
*/
|
||||
void to_mpz(mpfx const & n, unsynch_mpz_manager & m, mpz & t);
|
||||
|
||||
/**
|
||||
\brief Convert n into a mpz numeral.
|
||||
|
||||
\pre is_int(n)
|
||||
*/
|
||||
void to_mpz(mpfx const & n, synch_mpz_manager & m, mpz & t);
|
||||
|
||||
/**
|
||||
\brief Convert n into a mpq numeral.
|
||||
*/
|
||||
void to_mpq(mpfx const & n, unsynch_mpq_manager & m, mpq & t);
|
||||
|
||||
/**
|
||||
\brief Convert n into a mpq numeral.
|
||||
*/
|
||||
void to_mpq(mpfx const & n, synch_mpq_manager & m, mpq & t);
|
||||
|
||||
/**
|
||||
\brief Return the biggest k s.t. 2^k <= a.
|
||||
|
||||
\remark Return 0 if a is not positive.
|
||||
*/
|
||||
unsigned prev_power_of_two(mpfx const & a);
|
||||
|
||||
void display(std::ostream & out, mpfx const & n) const;
|
||||
void display_smt2(std::ostream & out, mpfx const & n) const;
|
||||
void display_decimal(std::ostream & out, mpfx const & n, unsigned prec = UINT_MAX) const;
|
||||
void display_raw(std::ostream & out, mpfx const & n) const;
|
||||
|
||||
std::string to_string(mpfx const & a) const;
|
||||
std::string to_rational_string(mpfx const & a) const;
|
||||
|
||||
bool check(mpfx const & a) const;
|
||||
};
|
||||
|
||||
typedef _scoped_numeral<mpfx_manager> scoped_mpfx;
|
||||
typedef _scoped_numeral_vector<mpfx_manager> scoped_mpfx_vector;
|
||||
|
||||
#endif
|
439
src/util/mpn.cpp
Normal file
439
src/util/mpn.cpp
Normal file
|
@ -0,0 +1,439 @@
|
|||
/*++
|
||||
Copyright (c) 2011 Microsoft Corporation
|
||||
|
||||
Module Name:
|
||||
|
||||
mpn.cpp
|
||||
|
||||
Abstract:
|
||||
|
||||
Multi Precision Natural Numbers
|
||||
|
||||
Author:
|
||||
|
||||
Christoph Wintersteiger (cwinter) 2011-11-16.
|
||||
|
||||
Revision History:
|
||||
|
||||
--*/
|
||||
#include"debug.h"
|
||||
#include"trace.h"
|
||||
#include"buffer.h"
|
||||
#include"mpn.h"
|
||||
|
||||
#define max(a,b) (((a) > (b)) ? (a) : (b))
|
||||
|
||||
typedef uint64 mpn_double_digit;
|
||||
COMPILE_TIME_ASSERT(sizeof(mpn_double_digit) == 2 * sizeof(mpn_digit));
|
||||
|
||||
mpn_manager static_mpn_manager;
|
||||
|
||||
const mpn_digit mpn_manager::zero = 0;
|
||||
|
||||
mpn_manager::mpn_manager() {
|
||||
#ifdef _DEBUG
|
||||
trace_enabled=true;
|
||||
#endif
|
||||
}
|
||||
|
||||
mpn_manager::~mpn_manager() {
|
||||
}
|
||||
|
||||
int mpn_manager::compare(mpn_digit const * a, size_t const lnga,
|
||||
mpn_digit const * b, size_t const lngb) const {
|
||||
int res = 0;
|
||||
|
||||
#ifdef _DEBUG
|
||||
if (trace_enabled)
|
||||
STRACE("mpn", tout << "[mpn] "; );
|
||||
#endif
|
||||
|
||||
trace(a, lnga);
|
||||
|
||||
size_t j = max(lnga, lngb) - 1;
|
||||
for (; j != (size_t)-1 && res == 0; j--) {
|
||||
mpn_digit const & u_j = (j < lnga) ? a[j] : zero;
|
||||
mpn_digit const & v_j = (j < lngb) ? b[j] : zero;
|
||||
if (u_j > v_j)
|
||||
res = 1;
|
||||
else if (u_j < v_j)
|
||||
res = -1;
|
||||
}
|
||||
|
||||
#ifdef _DEBUG
|
||||
if (trace_enabled)
|
||||
STRACE("mpn", tout << ((res == 1) ? " > " : (res == -1) ? " < " : " == "); );
|
||||
#endif
|
||||
|
||||
trace_nl(b, lngb);
|
||||
return res;
|
||||
}
|
||||
|
||||
bool mpn_manager::add(mpn_digit const * a, size_t const lnga,
|
||||
mpn_digit const * b, size_t const lngb,
|
||||
mpn_digit * c, size_t const lngc_alloc,
|
||||
size_t * plngc) const {
|
||||
trace(a, lnga, b, lngb, "+");
|
||||
// Essentially Knuth's Algorithm A
|
||||
size_t len = max(lnga, lngb);
|
||||
SASSERT(lngc_alloc == len+1 && len > 0);
|
||||
mpn_digit k = 0;
|
||||
mpn_digit r;
|
||||
bool c1, c2;
|
||||
for (size_t j = 0; j < len; j++) {
|
||||
mpn_digit const & u_j = (j < lnga) ? a[j] : zero;
|
||||
mpn_digit const & v_j = (j < lngb) ? b[j] : zero;
|
||||
r = u_j + v_j; c1 = r < u_j;
|
||||
c[j] = r + k; c2 = c[j] < r;
|
||||
k = c1 | c2;
|
||||
}
|
||||
c[len] = k;
|
||||
size_t &os = *plngc;
|
||||
for (os = len+1; os > 1 && c[os-1] == 0; ) os--;
|
||||
SASSERT(os > 0 && os <= len+1);
|
||||
trace_nl(c, os);
|
||||
return true; // return k != 0? What would MSBignum return?
|
||||
}
|
||||
|
||||
bool mpn_manager::sub(mpn_digit const * a, size_t const lnga,
|
||||
mpn_digit const * b, size_t const lngb,
|
||||
mpn_digit * c, mpn_digit * pborrow) const {
|
||||
trace(a, lnga, b, lngb, "-");
|
||||
// Essentially Knuth's Algorithm S
|
||||
size_t len = max(lnga, lngb);
|
||||
mpn_digit & k = *pborrow; k = 0;
|
||||
mpn_digit r;
|
||||
bool c1, c2;
|
||||
for (size_t j = 0; j < len; j++) {
|
||||
mpn_digit const & u_j = (j < lnga) ? a[j] : zero;
|
||||
mpn_digit const & v_j = (j < lngb) ? b[j] : zero;
|
||||
r = u_j - v_j; c1 = r > u_j;
|
||||
c[j] = r - k; c2 = c[j] > r;
|
||||
k = c1 | c2;
|
||||
}
|
||||
trace_nl(c, lnga);
|
||||
return true; // return k != 0?
|
||||
}
|
||||
|
||||
bool mpn_manager::mul(mpn_digit const * a, size_t const lnga,
|
||||
mpn_digit const * b, size_t const lngb,
|
||||
mpn_digit * c) const {
|
||||
trace(a, lnga, b, lngb, "*");
|
||||
// Essentially Knuth's Algorithm M.
|
||||
// Perhaps implement a more efficient version, see e.g., Knuth, Section 4.3.3.
|
||||
size_t i;
|
||||
mpn_digit k;
|
||||
|
||||
#define DIGIT_BITS (sizeof(mpn_digit)*8)
|
||||
#define HALF_BITS (sizeof(mpn_digit)*4)
|
||||
|
||||
for (unsigned i = 0; i < lnga; i++)
|
||||
c[i] = 0;
|
||||
|
||||
for (size_t j = 0; j < lngb; j++) {
|
||||
mpn_digit const & v_j = b[j];
|
||||
if (v_j == 0) { // This branch may be omitted according to Knuth.
|
||||
c[j+lnga] = 0;
|
||||
}
|
||||
else {
|
||||
k = 0;
|
||||
for (i = 0; i < lnga; i++) {
|
||||
mpn_digit const & u_i = a[i];
|
||||
mpn_double_digit t;
|
||||
t = ((mpn_double_digit)u_i * (mpn_double_digit)v_j) +
|
||||
(mpn_double_digit) c[i+j] +
|
||||
(mpn_double_digit) k;
|
||||
|
||||
c[i+j] = (t << DIGIT_BITS) >> DIGIT_BITS;
|
||||
k = t >> DIGIT_BITS;
|
||||
}
|
||||
c[j+lnga] = k;
|
||||
}
|
||||
}
|
||||
|
||||
trace_nl(c, lnga+lngb);
|
||||
return true;
|
||||
}
|
||||
|
||||
#define MASK_FIRST (~((mpn_digit)(-1) >> 1))
|
||||
#define FIRST_BITS(N, X) ((X) >> (DIGIT_BITS-(N)))
|
||||
#define LAST_BITS(N, X) (((X) << (DIGIT_BITS-(N))) >> (DIGIT_BITS-(N)))
|
||||
#define BASE ((mpn_double_digit)0x01 << DIGIT_BITS)
|
||||
|
||||
bool mpn_manager::div(mpn_digit const * numer, size_t const lnum,
|
||||
mpn_digit const * denom, size_t const lden,
|
||||
mpn_digit * quot,
|
||||
mpn_digit * rem) {
|
||||
trace(numer, lnum, denom, lden, "/");
|
||||
bool res = false;
|
||||
|
||||
if (lnum < lden) {
|
||||
for (size_t i = 0; i < (lnum-lden+1); i++)
|
||||
quot[i] = 0;
|
||||
for (size_t i = 0; i < lden; i++)
|
||||
rem[i] = (i < lnum) ? numer[i] : 0;
|
||||
return false;
|
||||
}
|
||||
|
||||
bool all_zero = true;
|
||||
for (size_t i = 0; i < lden && all_zero; i++)
|
||||
if (denom[i] != zero) all_zero = false;
|
||||
|
||||
if (all_zero) {
|
||||
// Division by 0. What would the MSBignum divide function do?
|
||||
UNREACHABLE();
|
||||
return res;
|
||||
}
|
||||
|
||||
SASSERT(denom[lden-1] != 0);
|
||||
|
||||
if (lnum == 1 && lden == 1) {
|
||||
*quot = numer[0] / denom[0];
|
||||
*rem = numer[0] % denom[0];
|
||||
}
|
||||
else if (lnum < lden || (lnum == lden && numer[lnum-1] < denom[lden-1])) {
|
||||
*quot = 0;
|
||||
for (size_t i = 0; i < lden; i++)
|
||||
rem[i] = (i < lnum) ? numer[i] : 0;
|
||||
}
|
||||
else {
|
||||
size_t d = div_normalize(numer, lnum, denom, lden, u, v);
|
||||
if (lden == 1)
|
||||
res = div_1(u, v[0], quot);
|
||||
else
|
||||
res = div_n(u, v, quot, rem);
|
||||
div_unnormalize(u, v, d, rem);
|
||||
}
|
||||
|
||||
// STRACE("mpn_dbg", display_raw(tout, quot, lnum - lden + 1); tout << ", ";
|
||||
// display_raw(tout, rem, lden); tout << std::endl; );
|
||||
trace_nl(quot, lnum-lden+1);
|
||||
|
||||
trace(numer, lnum, denom, lden, "%");
|
||||
trace_nl(rem, lden);
|
||||
|
||||
#ifdef _DEBUG
|
||||
mpn_sbuffer temp(lnum+1, 0);
|
||||
mul(quot, lnum-lden+1, denom, lden, temp.c_ptr());
|
||||
size_t real_size;
|
||||
add(temp.c_ptr(), lnum, rem, lden, temp.c_ptr(), lnum+1, &real_size);
|
||||
bool ok = true;
|
||||
for (size_t i = 0; i < lnum && ok; i++)
|
||||
if (temp[i] != numer[i]) ok = false;
|
||||
if (temp[lnum] != 0) ok = false;
|
||||
CTRACE("mpn_dbg", !ok, tout << "DIV BUG: quot * denom + rem = "; display_raw(tout, temp.c_ptr(), lnum+1); tout << std::endl; );
|
||||
SASSERT(ok);
|
||||
#endif
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
size_t mpn_manager::div_normalize(mpn_digit const * numer, size_t const lnum,
|
||||
mpn_digit const * denom, size_t const lden,
|
||||
mpn_sbuffer & n_numer,
|
||||
mpn_sbuffer & n_denom) const
|
||||
{
|
||||
size_t d = 0;
|
||||
while (((denom[lden-1] << d) & MASK_FIRST) == 0) d++;
|
||||
SASSERT(d < DIGIT_BITS);
|
||||
|
||||
n_numer.resize(lnum+1);
|
||||
n_denom.resize(lden);
|
||||
|
||||
if (d == 0) {
|
||||
n_numer[lnum] = 0;
|
||||
for (size_t i = 0; i < lnum; i++)
|
||||
n_numer[i] = numer[i];
|
||||
for (size_t i = 0; i < lden; i++)
|
||||
n_denom[i] = denom[i];
|
||||
}
|
||||
else {
|
||||
mpn_digit q = FIRST_BITS(d, numer[lnum-1]);
|
||||
n_numer[lnum] = q;
|
||||
for (size_t i = lnum-1; i > 0; i--)
|
||||
n_numer[i] = (numer[i] << d) | FIRST_BITS(d, numer[i-1]);
|
||||
n_numer[0] = numer[0] << d;
|
||||
for (size_t i = lden-1; i > 0; i--)
|
||||
n_denom[i] = denom[i] << d | FIRST_BITS(d, denom[i-1]);
|
||||
n_denom[0] = denom[0] << d;
|
||||
}
|
||||
|
||||
STRACE("mpn_norm", tout << "Normalized: n_numer="; display_raw(tout, n_numer.c_ptr(), n_numer.size());
|
||||
tout << " n_denom="; display_raw(tout, n_denom.c_ptr(), n_denom.size()); tout << std::endl; );
|
||||
|
||||
return d;
|
||||
}
|
||||
|
||||
void mpn_manager::div_unnormalize(mpn_sbuffer & numer, mpn_sbuffer & denom,
|
||||
size_t const d, mpn_digit * rem) const {
|
||||
if (d == 0) {
|
||||
for (size_t i = 0; i < denom.size(); i++)
|
||||
rem[i] = numer[i];
|
||||
}
|
||||
else {
|
||||
for (size_t i = 0; i < denom.size()-1; i++)
|
||||
rem[i] = numer[i] >> d | (LAST_BITS(d, numer[i+1]) << (DIGIT_BITS-d));
|
||||
rem[denom.size()-1] = numer[denom.size()-1] >> d;
|
||||
}
|
||||
}
|
||||
|
||||
bool mpn_manager::div_1(mpn_sbuffer & numer, mpn_digit const denom,
|
||||
mpn_digit * quot) const
|
||||
{
|
||||
mpn_double_digit q_hat, temp, r_hat, ms;
|
||||
mpn_digit borrow;
|
||||
|
||||
for (size_t j = numer.size()-1; j > 0; j--) {
|
||||
temp = (((mpn_double_digit)numer[j]) << DIGIT_BITS) | ((mpn_double_digit)numer[j-1]);
|
||||
q_hat = temp / (mpn_double_digit) denom;
|
||||
r_hat = temp % (mpn_double_digit) denom;
|
||||
if (q_hat >= BASE) {
|
||||
UNREACHABLE(); // is this reachable with normalized v?
|
||||
}
|
||||
SASSERT(q_hat < BASE);
|
||||
ms = temp - (q_hat * (mpn_double_digit) denom);
|
||||
borrow = ms > temp;
|
||||
numer[j-1] = (mpn_digit) ms;
|
||||
numer[j] = ms >> DIGIT_BITS;
|
||||
quot[j-1] = (mpn_digit) q_hat;
|
||||
if (borrow) {
|
||||
quot[j-1]--;
|
||||
numer[j] = numer[j-1] + denom;
|
||||
}
|
||||
STRACE("mpn_div1", tout << "j=" << j << " q_hat=" << q_hat << " r_hat=" << r_hat;
|
||||
tout << " ms=" << ms;
|
||||
tout << " new numer="; display_raw(tout, numer.c_ptr(), numer.size());
|
||||
tout << " borrow=" << borrow;
|
||||
tout << std::endl; );
|
||||
}
|
||||
|
||||
return true; // return rem != 0 or something like that?
|
||||
}
|
||||
|
||||
bool mpn_manager::div_n(mpn_sbuffer & numer, mpn_sbuffer const & denom,
|
||||
mpn_digit * quot, mpn_digit * rem) {
|
||||
SASSERT(denom.size() > 1);
|
||||
|
||||
// This is essentially Knuth's Algorithm D.
|
||||
size_t m = numer.size() - denom.size();
|
||||
size_t n = denom.size();
|
||||
|
||||
SASSERT(numer.size() == m+n);
|
||||
|
||||
t_ms.resize(n+1);
|
||||
|
||||
mpn_double_digit q_hat, temp, r_hat;
|
||||
mpn_digit borrow;
|
||||
|
||||
for (size_t j = m-1; j != (size_t)-1; j--) {
|
||||
temp = (((mpn_double_digit)numer[j+n]) << DIGIT_BITS) | ((mpn_double_digit)numer[j+n-1]);
|
||||
q_hat = temp / (mpn_double_digit) denom[n-1];
|
||||
r_hat = temp % (mpn_double_digit) denom[n-1];
|
||||
recheck:
|
||||
if (q_hat >= BASE ||
|
||||
((q_hat * denom[n-2]) > ((r_hat << DIGIT_BITS) + numer[j+n-2]))) {
|
||||
q_hat--;
|
||||
r_hat += denom[n-1];
|
||||
if (r_hat < BASE) goto recheck;
|
||||
}
|
||||
SASSERT(q_hat < BASE);
|
||||
// Replace numer[j+n]...numer[j] with
|
||||
// numer[j+n]...numer[j] - q * (denom[n-1]...denom[0])
|
||||
mpn_digit q_hat_small = (mpn_digit)q_hat;
|
||||
#ifdef _DEBUG
|
||||
trace_enabled = false;
|
||||
#endif
|
||||
mul(&q_hat_small, 1, denom.c_ptr(), n, t_ms.c_ptr());
|
||||
sub(&numer[j], n+1, t_ms.c_ptr(), n+1, &numer[j], &borrow);
|
||||
quot[j] = q_hat_small;
|
||||
if (borrow) {
|
||||
quot[j]--;
|
||||
t_ab.resize(n+2);
|
||||
size_t real_size;
|
||||
add(denom.c_ptr(), n, &numer[j], n+1, t_ab.c_ptr(), n+2, &real_size);
|
||||
for (size_t i = 0; i < n+1; i++)
|
||||
numer[j+i] = t_ab[i];
|
||||
}
|
||||
#ifdef _DEBUG
|
||||
trace_enabled = true;
|
||||
#endif
|
||||
STRACE("mpn_div", tout << "q_hat=" << q_hat << " r_hat=" << r_hat;
|
||||
tout << " t_ms="; display_raw(tout, t_ms.c_ptr(), n);
|
||||
tout << " new numer="; display_raw(tout, numer.c_ptr(), m+n+1);
|
||||
tout << " borrow=" << borrow;
|
||||
tout << std::endl; );
|
||||
}
|
||||
|
||||
return true; // return rem != 0 or something like that?
|
||||
}
|
||||
|
||||
char * mpn_manager::to_string(mpn_digit const * a, size_t const lng, char * buf, size_t const lbuf) const {
|
||||
SASSERT(buf && lbuf > 0);
|
||||
STRACE("mpn_to_string", tout << "[mpn] to_string "; display_raw(tout, a, lng); tout << " == "; );
|
||||
|
||||
if (lng == 1) {
|
||||
#ifdef _WINDOWS
|
||||
sprintf_s(buf, lbuf, "%u", *a);
|
||||
#else
|
||||
snprintf(buf, lbuf, "%u", *a);
|
||||
#endif
|
||||
}
|
||||
else {
|
||||
mpn_sbuffer temp(lng, 0), t_numer(lng+1, 0), t_denom(1, 0);
|
||||
for (unsigned i = 0; i < lng; i++)
|
||||
temp[i] = a[i];
|
||||
|
||||
size_t j = 0;
|
||||
mpn_digit rem;
|
||||
mpn_digit ten = 10;
|
||||
while (!temp.empty() && (temp.size() > 1 || temp[0] != 0)) {
|
||||
size_t d = div_normalize(&temp[0], temp.size(), &ten, 1, t_numer, t_denom);
|
||||
div_1(t_numer, t_denom[0], &temp[0]);
|
||||
div_unnormalize(t_numer, t_denom, d, &rem);
|
||||
buf[j++] = '0' + rem;
|
||||
while (temp.size() > 0 && temp.back() == 0)
|
||||
temp.pop_back();
|
||||
}
|
||||
buf[j] = 0;
|
||||
|
||||
j--;
|
||||
size_t mid = (j/2) + ((j % 2) ? 1 : 0);
|
||||
for (size_t i = 0; i < mid; i++)
|
||||
std::swap(buf[i], buf[j-i]);
|
||||
}
|
||||
|
||||
STRACE("mpn_to_string", tout << buf << std::endl; );
|
||||
|
||||
return buf;
|
||||
}
|
||||
|
||||
void mpn_manager::display_raw(std::ostream & out, mpn_digit const * a, size_t const lng) const {
|
||||
out << "[";
|
||||
for (size_t i = lng-1; i != (size_t)-1; i-- ) { out << a[i]; if (i != 0) out << "|"; }
|
||||
out << "]";
|
||||
}
|
||||
|
||||
void mpn_manager::trace(mpn_digit const * a, size_t const lnga,
|
||||
mpn_digit const * b, size_t const lngb,
|
||||
const char * op) const {
|
||||
#ifdef _DEBUG
|
||||
if (trace_enabled)
|
||||
STRACE("mpn", tout << "[mpn] " << to_string(a, lnga, char_buf, sizeof(char_buf));
|
||||
tout << " " << op << " " << to_string(b, lngb, char_buf, sizeof(char_buf));
|
||||
tout << " == "; );
|
||||
#endif
|
||||
}
|
||||
|
||||
void mpn_manager::trace(mpn_digit const * a, size_t const lnga) const {
|
||||
#ifdef _DEBUG
|
||||
if (trace_enabled)
|
||||
STRACE("mpn", tout << to_string(a, lnga, char_buf, sizeof(char_buf)); );
|
||||
#endif
|
||||
}
|
||||
|
||||
void mpn_manager::trace_nl(mpn_digit const * a, size_t const lnga) const {
|
||||
#ifdef _DEBUG
|
||||
if (trace_enabled)
|
||||
STRACE("mpn", tout << to_string(a, lnga, char_buf, sizeof(char_buf)) << std::endl; );
|
||||
#endif
|
||||
}
|
196
src/util/mpn.h
Normal file
196
src/util/mpn.h
Normal file
|
@ -0,0 +1,196 @@
|
|||
/*++
|
||||
Copyright (c) 2011 Microsoft Corporation
|
||||
|
||||
Module Name:
|
||||
|
||||
mpn.h
|
||||
|
||||
Abstract:
|
||||
|
||||
Multi Precision Natural Numbers
|
||||
|
||||
Author:
|
||||
|
||||
Christoph Wintersteiger (cwinter) 2011-11-16.
|
||||
|
||||
Revision History:
|
||||
|
||||
--*/
|
||||
#ifndef _MPN_H_
|
||||
#define _MPN_H_
|
||||
|
||||
#include<ostream>
|
||||
#include"util.h"
|
||||
#include"buffer.h"
|
||||
|
||||
// we supply a definition of a basic max because mpz relies on it.
|
||||
#define max(a,b) (((a) > (b)) ? (a) : (b))
|
||||
|
||||
typedef unsigned int mpn_digit;
|
||||
|
||||
class mpn_manager {
|
||||
public:
|
||||
mpn_manager();
|
||||
~mpn_manager();
|
||||
|
||||
int compare(mpn_digit const * a, size_t const lnga,
|
||||
mpn_digit const * b, size_t const lngb) const;
|
||||
|
||||
bool add(mpn_digit const * a, size_t const lnga,
|
||||
mpn_digit const * b, size_t const lngb,
|
||||
mpn_digit *c, size_t const lngc_alloc,
|
||||
size_t * plngc) const;
|
||||
|
||||
bool sub(mpn_digit const * a, size_t const lnga,
|
||||
mpn_digit const * b, size_t const lngb,
|
||||
mpn_digit * c, mpn_digit * pborrow) const;
|
||||
|
||||
bool mul(mpn_digit const * a, size_t const lnga,
|
||||
mpn_digit const * b, size_t const lngb,
|
||||
mpn_digit * c) const;
|
||||
|
||||
bool div(mpn_digit const * numer, size_t const lnum,
|
||||
mpn_digit const * denom, size_t const lden,
|
||||
mpn_digit * quot,
|
||||
mpn_digit * rem);
|
||||
|
||||
char * to_string(mpn_digit const * a, size_t const lng,
|
||||
char * buf, size_t const lbuf) const;
|
||||
|
||||
private:
|
||||
#ifdef _AMD64_
|
||||
class mpn_sbuffer : public sbuffer<mpn_digit> {
|
||||
public:
|
||||
mpn_sbuffer() : sbuffer<mpn_digit>() {}
|
||||
|
||||
mpn_sbuffer(size_t nsz, const mpn_digit & elem = 0) :
|
||||
sbuffer<mpn_digit>(static_cast<unsigned>(nsz), elem)
|
||||
{
|
||||
}
|
||||
void resize(size_t nsz, const mpn_digit & elem = 0) {
|
||||
sbuffer<mpn_digit>::resize(static_cast<unsigned>(nsz), elem);
|
||||
}
|
||||
|
||||
mpn_digit & operator[](size_t idx) {
|
||||
return sbuffer<mpn_digit>::operator[](static_cast<unsigned>(idx));
|
||||
}
|
||||
|
||||
const mpn_digit & operator[](size_t idx) const {
|
||||
return sbuffer<mpn_digit>::operator[](static_cast<unsigned>(idx));
|
||||
}
|
||||
};
|
||||
#else
|
||||
typedef sbuffer<mpn_digit> mpn_sbuffer;
|
||||
#endif
|
||||
|
||||
static const mpn_digit zero;
|
||||
mpn_sbuffer u, v, t_ms, t_ab;
|
||||
void display_raw(std::ostream & out, mpn_digit const * a, size_t const lng) const;
|
||||
|
||||
size_t div_normalize(mpn_digit const * numer, size_t const lnum,
|
||||
mpn_digit const * denom, size_t const lden,
|
||||
mpn_sbuffer & n_numer,
|
||||
mpn_sbuffer & n_denom) const;
|
||||
|
||||
void div_unnormalize(mpn_sbuffer & numer, mpn_sbuffer & denom,
|
||||
size_t const d, mpn_digit * rem) const;
|
||||
|
||||
bool div_1(mpn_sbuffer & numer, mpn_digit const denom,
|
||||
mpn_digit * quot) const;
|
||||
|
||||
bool div_n(mpn_sbuffer & numer, mpn_sbuffer const & denom,
|
||||
mpn_digit * quot, mpn_digit * rem);
|
||||
|
||||
#ifdef _DEBUG
|
||||
mutable char char_buf[4096];
|
||||
bool trace_enabled;
|
||||
#endif
|
||||
|
||||
void trace(mpn_digit const * a, size_t const lnga,
|
||||
mpn_digit const * b, size_t const lngb,
|
||||
const char * op) const;
|
||||
|
||||
void trace(mpn_digit const * a, size_t const lnga) const;
|
||||
void trace_nl(mpn_digit const * a, size_t const lnga) const;
|
||||
|
||||
public:
|
||||
// This function is needed because of the static_mpn_manager global variable.
|
||||
// It must be invoked by the memory_manager during finalization.
|
||||
// After we remove MSBignum from the code base, the global variable will
|
||||
// not be needed anymore, and we will be able to eliminate this function.
|
||||
void finalize() {
|
||||
u.finalize();
|
||||
v.finalize();
|
||||
t_ms.finalize();
|
||||
t_ab.finalize();
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
// MSBignum compatible interface
|
||||
// Note: The `owner' parameter is ignored. We use separate mpn_manager objects for the
|
||||
// same purpose. Multiple owners are not supported in these compatibility functions,
|
||||
// instead a static mpn_manager is used.
|
||||
|
||||
extern mpn_manager static_mpn_manager;
|
||||
|
||||
typedef unsigned int digit_t;
|
||||
|
||||
typedef struct {
|
||||
mpn_digit multiplier;
|
||||
size_t shiftamt;
|
||||
} reciprocal_1_t;
|
||||
|
||||
#define reciprocal_1_NULL ((reciprocal_1_t*)0)
|
||||
|
||||
inline int compare_diff(digit_t const * a, size_t const lnga,
|
||||
digit_t const * b, size_t const lngb)
|
||||
{
|
||||
return static_mpn_manager.compare(a, lnga, b, lngb);
|
||||
}
|
||||
|
||||
inline char * mp_decimal(digit_t const * a, size_t const lng, // Number to be converted and its length
|
||||
char * buf, size_t const lbuf, // output buffer and its length
|
||||
int owner)
|
||||
{
|
||||
return static_mpn_manager.to_string(a, lng, buf, lbuf);
|
||||
}
|
||||
|
||||
inline bool add_full(digit_t const * a, size_t const lnga,
|
||||
digit_t const * b, size_t const lngb,
|
||||
digit_t *c, size_t const lngc_alloc,
|
||||
size_t * plngc,
|
||||
int owner)
|
||||
{
|
||||
return static_mpn_manager.add(a, lnga, b, lngb, c, lngc_alloc, plngc);
|
||||
}
|
||||
|
||||
inline bool sub_diff(digit_t const * a, size_t const lnga,
|
||||
digit_t const * b, size_t const lngb,
|
||||
digit_t * c, digit_t * pborrow,
|
||||
int owner)
|
||||
{
|
||||
return static_mpn_manager.sub(a, lnga, b, lngb, c, pborrow);
|
||||
}
|
||||
|
||||
inline bool multiply(digit_t const * a, size_t const lnga,
|
||||
digit_t const * b, size_t const lngb,
|
||||
digit_t * c,
|
||||
int owner)
|
||||
{
|
||||
return static_mpn_manager.mul(a, lnga, b, lngb, c);
|
||||
}
|
||||
|
||||
inline bool divide(digit_t const * numer, size_t const lnum,
|
||||
digit_t const * denom, size_t const lden,
|
||||
reciprocal_1_t const * supplied_reciprocal, /* reciprocal_t struct for this denominator,
|
||||
or reciprocal_1_NULL
|
||||
if not previously precomputed */
|
||||
digit_t * quot, /* Quotient -- length MAX(lnum - lden + 1, 0) */
|
||||
digit_t * rem, /* Remainder -- length lden */
|
||||
int owner)
|
||||
{
|
||||
return static_mpn_manager.div(numer, lnum, denom, lden, quot, rem);
|
||||
}
|
||||
|
||||
#endif
|
317
src/util/mpq.cpp
Normal file
317
src/util/mpq.cpp
Normal file
|
@ -0,0 +1,317 @@
|
|||
/*++
|
||||
Copyright (c) 2006 Microsoft Corporation
|
||||
|
||||
Module Name:
|
||||
|
||||
mpq.cpp
|
||||
|
||||
Abstract:
|
||||
|
||||
<abstract>
|
||||
|
||||
Author:
|
||||
|
||||
Leonardo de Moura (leonardo) 2010-06-21.
|
||||
|
||||
Revision History:
|
||||
|
||||
--*/
|
||||
#include"mpq.h"
|
||||
#include"warning.h"
|
||||
#include"z3_exception.h"
|
||||
|
||||
template<bool SYNCH>
|
||||
mpq_manager<SYNCH>::mpq_manager() {
|
||||
}
|
||||
|
||||
template<bool SYNCH>
|
||||
mpq_manager<SYNCH>::~mpq_manager() {
|
||||
del(m_n_tmp);
|
||||
del(m_add_tmp1);
|
||||
del(m_add_tmp2);
|
||||
del(m_lt_tmp1);
|
||||
del(m_lt_tmp2);
|
||||
del(m_addmul_tmp);
|
||||
}
|
||||
|
||||
|
||||
template<bool SYNCH>
|
||||
bool mpq_manager<SYNCH>::rat_lt(mpq const & a, mpq const & b) {
|
||||
mpz const & na = a.numerator();
|
||||
mpz const & nb = b.numerator();
|
||||
int sign_a = this->sign(na);
|
||||
int sign_b = this->sign(nb);
|
||||
if (sign_a < 0) {
|
||||
if (sign_b >= 0) return true;
|
||||
}
|
||||
else if (sign_a == 0) {
|
||||
if (sign_b > 0) return true;
|
||||
SASSERT(sign_b <= 0); return false;
|
||||
}
|
||||
else {
|
||||
SASSERT(sign_a > 0);
|
||||
if (sign_b <= 0) return false;
|
||||
}
|
||||
SASSERT((sign_a > 0 && sign_b > 0) ||
|
||||
(sign_a < 0 && sign_b < 0));
|
||||
mpz const & da = a.denominator();
|
||||
mpz const & db = b.denominator();
|
||||
|
||||
if (SYNCH) {
|
||||
mpq tmp1;
|
||||
mpq tmp2;
|
||||
mul(na, db, tmp1);
|
||||
mul(nb, da, tmp2);
|
||||
bool r = lt(tmp1, tmp2);
|
||||
del(tmp1);
|
||||
del(tmp2);
|
||||
return r;
|
||||
}
|
||||
else {
|
||||
mul(na, db, m_lt_tmp1);
|
||||
mul(nb, da, m_lt_tmp2);
|
||||
return lt(m_lt_tmp1, m_lt_tmp2);
|
||||
}
|
||||
}
|
||||
|
||||
template<bool SYNCH>
|
||||
void mpq_manager<SYNCH>::floor(mpq const & a, mpz & f) {
|
||||
if (is_int(a)) {
|
||||
set(f, a.m_num);
|
||||
return;
|
||||
}
|
||||
bool is_neg_num = is_neg(a.m_num);
|
||||
machine_div(a.m_num, a.m_den, f);
|
||||
if (is_neg_num)
|
||||
sub(f, this->mk_z(1), f);
|
||||
}
|
||||
|
||||
template<bool SYNCH>
|
||||
void mpq_manager<SYNCH>::ceil(mpq const & a, mpz & c) {
|
||||
if (is_int(a)) {
|
||||
set(c, a.m_num);
|
||||
return;
|
||||
}
|
||||
bool is_pos_num = is_pos(a.m_num);
|
||||
machine_div(a.m_num, a.m_den, c);
|
||||
if (is_pos_num)
|
||||
add(c, this->mk_z(1), c);
|
||||
}
|
||||
|
||||
template<bool SYNCH>
|
||||
void mpq_manager<SYNCH>::gcd(unsigned sz, mpq const * as, mpq & g) {
|
||||
switch (sz) {
|
||||
case 0:
|
||||
reset(g);
|
||||
return;
|
||||
case 1:
|
||||
set(g, as[0]);
|
||||
abs(g);
|
||||
return;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
gcd(as[0], as[1], g);
|
||||
for (unsigned i = 2; i < sz; i++) {
|
||||
if (is_one(g))
|
||||
return;
|
||||
gcd(g, as[i], g);
|
||||
}
|
||||
}
|
||||
|
||||
template<bool SYNCH>
|
||||
std::string mpq_manager<SYNCH>::to_string(mpq const & a) const {
|
||||
if (is_int(a))
|
||||
return to_string(a.m_num);
|
||||
return to_string(a.m_num) + "/" + to_string(a.m_den);
|
||||
}
|
||||
|
||||
template<bool SYNCH>
|
||||
void mpq_manager<SYNCH>::display(std::ostream & out, mpq const & a) const {
|
||||
if (is_int(a)) {
|
||||
display(out, a.m_num);
|
||||
}
|
||||
else {
|
||||
display(out, a.m_num);
|
||||
out << "/";
|
||||
display(out, a.m_den);
|
||||
}
|
||||
}
|
||||
|
||||
template<bool SYNCH>
|
||||
void mpq_manager<SYNCH>::display_smt2(std::ostream & out, mpq const & a, bool decimal) const {
|
||||
if (is_int(a)) {
|
||||
display_smt2(out, a.m_num, decimal);
|
||||
}
|
||||
else {
|
||||
out << "(/ ";
|
||||
display_smt2(out, a.m_num, decimal);
|
||||
out << " ";
|
||||
display_smt2(out, a.m_den, decimal);
|
||||
out << ")";
|
||||
}
|
||||
}
|
||||
|
||||
template<bool SYNCH>
|
||||
void mpq_manager<SYNCH>::display_decimal(std::ostream & out, mpq const & a, unsigned prec) {
|
||||
mpz n1, d1, v1;
|
||||
get_numerator(a, n1);
|
||||
get_denominator(a, d1);
|
||||
if (is_neg(a)) {
|
||||
out << "-";
|
||||
neg(n1);
|
||||
}
|
||||
mpz ten(10);
|
||||
div(n1, d1, v1);
|
||||
display(out, v1);
|
||||
rem(n1, d1, n1);
|
||||
if (is_zero(n1))
|
||||
goto end; // number is an integer
|
||||
out << ".";
|
||||
for (unsigned i = 0; i < prec; i++) {
|
||||
mul(n1, ten, n1);
|
||||
div(n1, d1, v1);
|
||||
SASSERT(lt(v1, ten));
|
||||
display(out, v1);
|
||||
rem(n1, d1, n1);
|
||||
if (is_zero(n1))
|
||||
goto end; // number is precise
|
||||
}
|
||||
out << "?";
|
||||
end:
|
||||
del(ten); del(n1); del(d1); del(v1);
|
||||
}
|
||||
|
||||
template<bool SYNCH>
|
||||
void mpq_manager<SYNCH>::set(mpq & a, char const * val) {
|
||||
reset(a.m_num);
|
||||
mpz ten(10);
|
||||
_scoped_numeral<mpz_manager<SYNCH> > tmp(*this);
|
||||
char const * str = val;
|
||||
bool sign = false;
|
||||
while (str[0] == ' ') ++str;
|
||||
if (str[0] == '-')
|
||||
sign = true;
|
||||
while (str[0] && (str[0] != '/') && (str[0] != '.') && (str[0] != 'e') && (str[0] != 'E')) {
|
||||
if ('0' <= str[0] && str[0] <= '9') {
|
||||
SASSERT(str[0] - '0' <= 9);
|
||||
mul(a.m_num, ten, tmp);
|
||||
add(tmp, this->mk_z(str[0] - '0'), a.m_num);
|
||||
}
|
||||
++str;
|
||||
}
|
||||
TRACE("mpq_set", tout << "[before] a: " << to_string(a) << "\n";);
|
||||
if (str[0] == '/' || str[0] == '.' || str[0] == 'e' || str[0] == 'E') {
|
||||
bool is_rat = str[0] == '/';
|
||||
_scoped_numeral<mpz_manager<SYNCH> > tmp2(*this);
|
||||
set(tmp2, 1);
|
||||
bool has_den = false;
|
||||
if (str[0] == '/' || str[0] == '.') {
|
||||
has_den = true;
|
||||
++str;
|
||||
reset(a.m_den);
|
||||
while (str[0] && (str[0] != 'e') && (str[0] != 'E')) {
|
||||
if ('0' <= str[0] && str[0] <= '9') {
|
||||
mul(a.m_den, ten, tmp);
|
||||
add(tmp, this->mk_z(str[0] - '0'), a.m_den);
|
||||
if (!is_rat)
|
||||
mul(tmp2, ten, tmp2);
|
||||
}
|
||||
++str;
|
||||
}
|
||||
}
|
||||
unsigned long long exp = 0;
|
||||
bool exp_sign = false;
|
||||
if (str[0] == 'e' || str[0] == 'E') {
|
||||
if (is_rat)
|
||||
throw default_exception("mixing rational/scientific notation");
|
||||
++str;
|
||||
if (str[0] == '-') {
|
||||
exp_sign = true;
|
||||
++str;
|
||||
}
|
||||
while (str[0]) {
|
||||
if ('0' <= str[0] && str[0] <= '9') {
|
||||
SASSERT(str[0] - '0' <= 9);
|
||||
exp = (10*exp) + (str[0] - '0');
|
||||
}
|
||||
TRACE("mpq_set", tout << "[exp]: " << exp << ", str[0]: " << (str[0] - '0') << std::endl;);
|
||||
++str;
|
||||
}
|
||||
}
|
||||
if (!is_rat) {
|
||||
// a <- a.m_num + a.m_den/tmp2
|
||||
if (exp > static_cast<unsigned long long>(UINT_MAX))
|
||||
throw default_exception("exponent is too big");
|
||||
_scoped_numeral<mpq_manager<SYNCH> > b(*this);
|
||||
if (has_den) {
|
||||
set(b, a.m_den, tmp2);
|
||||
set(a.m_den, 1);
|
||||
add(a, b, a);
|
||||
}
|
||||
if (exp > 0) {
|
||||
_scoped_numeral<mpq_manager<SYNCH> > _exp(*this);
|
||||
_scoped_numeral<mpq_manager<SYNCH> > _ten(*this);
|
||||
set(_ten, 10);
|
||||
power(_ten, static_cast<unsigned>(exp), _exp);
|
||||
TRACE("mpq_set", tout << "a: " << to_string(a) << ", exp_sign:" << exp_sign << ", exp: " << exp << " " << to_string(_exp) << std::endl;);
|
||||
if (exp_sign)
|
||||
div(a, _exp, a);
|
||||
else
|
||||
mul(a, _exp, a);
|
||||
}
|
||||
}
|
||||
else {
|
||||
// rational case
|
||||
if (is_zero(a.m_den))
|
||||
throw default_exception("division by zero");
|
||||
}
|
||||
}
|
||||
else {
|
||||
reset_denominator(a);
|
||||
}
|
||||
if (sign)
|
||||
neg(a.m_num);
|
||||
normalize(a);
|
||||
}
|
||||
|
||||
template<bool SYNCH>
|
||||
void mpq_manager<SYNCH>::power(mpq const & a, unsigned p, mpq & b) {
|
||||
unsigned mask = 1;
|
||||
mpq power;
|
||||
set(power, a);
|
||||
set(b, 1);
|
||||
while (mask <= p) {
|
||||
if (mask & p)
|
||||
mul(b, power, b);
|
||||
mul(power, power, power);
|
||||
mask = mask << 1;
|
||||
}
|
||||
del(power);
|
||||
}
|
||||
|
||||
template<bool SYNCH>
|
||||
double mpq_manager<SYNCH>::get_double(mpq const & a) const {
|
||||
double n;
|
||||
double d;
|
||||
n = get_double(a.m_num);
|
||||
d = get_double(a.m_den);
|
||||
SASSERT(d > 0.0);
|
||||
return n/d;
|
||||
}
|
||||
|
||||
template<bool SYNCH>
|
||||
bool mpq_manager<SYNCH>::root(mpq const & a, unsigned n, mpq & r) {
|
||||
return root(a.m_num, n, r.m_num) && root(a.m_den, n, r.m_den);
|
||||
}
|
||||
|
||||
template<bool SYNCH>
|
||||
unsigned mpq_manager<SYNCH>::prev_power_of_two(mpq const & a) {
|
||||
_scoped_numeral<mpz_manager<SYNCH> > _tmp(*this);
|
||||
floor(a, _tmp);
|
||||
return prev_power_of_two(_tmp);
|
||||
}
|
||||
|
||||
template class mpq_manager<true>;
|
||||
template class mpq_manager<false>;
|
||||
|
848
src/util/mpq.h
Normal file
848
src/util/mpq.h
Normal file
|
@ -0,0 +1,848 @@
|
|||
/*++
|
||||
Copyright (c) 2006 Microsoft Corporation
|
||||
|
||||
Module Name:
|
||||
|
||||
mpq.h
|
||||
|
||||
Abstract:
|
||||
|
||||
<abstract>
|
||||
|
||||
Author:
|
||||
|
||||
Leonardo de Moura (leonardo) 2010-06-21.
|
||||
|
||||
Revision History:
|
||||
|
||||
--*/
|
||||
#ifndef _MPQ_H_
|
||||
#define _MPQ_H_
|
||||
|
||||
#include"mpz.h"
|
||||
#include"trace.h"
|
||||
|
||||
class mpq {
|
||||
mpz m_num;
|
||||
mpz m_den;
|
||||
friend class mpq_manager<true>;
|
||||
friend class mpq_manager<false>;
|
||||
mpq & operator=(mpq const & other) { UNREACHABLE(); return *this; }
|
||||
public:
|
||||
mpq(int v):m_num(v), m_den(1) {}
|
||||
mpq():m_den(1) {}
|
||||
void swap(mpq & other) { m_num.swap(other.m_num); m_den.swap(other.m_den); }
|
||||
mpz const & numerator() const { return m_num; }
|
||||
mpz const & denominator() const { return m_den; }
|
||||
};
|
||||
|
||||
inline void swap(mpq & m1, mpq & m2) { m1.swap(m2); }
|
||||
|
||||
template<bool SYNCH = true>
|
||||
class mpq_manager : public mpz_manager<SYNCH> {
|
||||
mpz m_n_tmp;
|
||||
mpz m_add_tmp1;
|
||||
mpz m_add_tmp2;
|
||||
mpq m_addmul_tmp;
|
||||
mpq m_lt_tmp1;
|
||||
mpq m_lt_tmp2;
|
||||
|
||||
void reset_denominator(mpq & a) {
|
||||
del(a.m_den);
|
||||
a.m_den.m_val = 1;
|
||||
}
|
||||
|
||||
void normalize(mpq & a) {
|
||||
if (SYNCH) {
|
||||
mpz tmp;
|
||||
gcd(a.m_num, a.m_den, tmp);
|
||||
if (is_one(tmp)) {
|
||||
del(tmp);
|
||||
return;
|
||||
}
|
||||
div(a.m_num, tmp, a.m_num);
|
||||
div(a.m_den, tmp, a.m_den);
|
||||
del(tmp);
|
||||
}
|
||||
else {
|
||||
gcd(a.m_num, a.m_den, m_n_tmp);
|
||||
if (is_one(m_n_tmp))
|
||||
return;
|
||||
div(a.m_num, m_n_tmp, a.m_num);
|
||||
div(a.m_den, m_n_tmp, a.m_den);
|
||||
}
|
||||
}
|
||||
|
||||
void rat_add(mpq const & a, mpq const & b, mpq & c) {
|
||||
STRACE("rat_mpq", tout << "[mpq] " << to_string(a) << " + " << to_string(b) << " == ";);
|
||||
if (SYNCH) {
|
||||
mpz tmp1, tmp2;
|
||||
mul(a.m_num, b.m_den, tmp1);
|
||||
mul(b.m_num, a.m_den, tmp2);
|
||||
mul(a.m_den, b.m_den, c.m_den);
|
||||
add(tmp1, tmp2, c.m_num);
|
||||
normalize(c);
|
||||
del(tmp1);
|
||||
del(tmp2);
|
||||
}
|
||||
else {
|
||||
mul(a.m_num, b.m_den, m_add_tmp1);
|
||||
mul(b.m_num, a.m_den, m_add_tmp2);
|
||||
mul(a.m_den, b.m_den, c.m_den);
|
||||
add(m_add_tmp1, m_add_tmp2, c.m_num);
|
||||
normalize(c);
|
||||
}
|
||||
STRACE("rat_mpq", tout << to_string(c) << "\n";);
|
||||
}
|
||||
|
||||
void rat_add(mpq const & a, mpz const & b, mpq & c) {
|
||||
STRACE("rat_mpq", tout << "[mpq] " << to_string(a) << " + " << to_string(b) << " == ";);
|
||||
if (SYNCH) {
|
||||
mpz tmp1;
|
||||
mul(b, a.m_den, tmp1);
|
||||
set(c.m_den, a.m_den);
|
||||
add(a.m_num, tmp1, c.m_num);
|
||||
normalize(c);
|
||||
del(tmp1);
|
||||
}
|
||||
else {
|
||||
mul(b, a.m_den, m_add_tmp1);
|
||||
set(c.m_den, a.m_den);
|
||||
add(a.m_num, m_add_tmp1, c.m_num);
|
||||
normalize(c);
|
||||
}
|
||||
STRACE("rat_mpq", tout << to_string(c) << "\n";);
|
||||
}
|
||||
|
||||
void rat_sub(mpq const & a, mpq const & b, mpq & c) {
|
||||
STRACE("rat_mpq", tout << "[mpq] " << to_string(a) << " - " << to_string(b) << " == ";);
|
||||
if (SYNCH) {
|
||||
mpz tmp1, tmp2;
|
||||
mul(a.m_num, b.m_den, tmp1);
|
||||
mul(b.m_num, a.m_den, tmp2);
|
||||
mul(a.m_den, b.m_den, c.m_den);
|
||||
sub(tmp1, tmp2, c.m_num);
|
||||
normalize(c);
|
||||
del(tmp1);
|
||||
del(tmp2);
|
||||
}
|
||||
else {
|
||||
mul(a.m_num, b.m_den, m_add_tmp1);
|
||||
mul(b.m_num, a.m_den, m_add_tmp2);
|
||||
mul(a.m_den, b.m_den, c.m_den);
|
||||
sub(m_add_tmp1, m_add_tmp2, c.m_num);
|
||||
normalize(c);
|
||||
}
|
||||
STRACE("rat_mpq", tout << to_string(c) << "\n";);
|
||||
}
|
||||
|
||||
void rat_mul(mpq const & a, mpq const & b, mpq & c) {
|
||||
STRACE("rat_mpq", tout << "[mpq] " << to_string(a) << " * " << to_string(b) << " == ";);
|
||||
mul(a.m_num, b.m_num, c.m_num);
|
||||
mul(a.m_den, b.m_den, c.m_den);
|
||||
normalize(c);
|
||||
STRACE("rat_mpq", tout << to_string(c) << "\n";);
|
||||
}
|
||||
|
||||
void rat_mul(mpz const & a, mpq const & b, mpq & c) {
|
||||
STRACE("rat_mpq", tout << "[mpq] " << to_string(a) << " * " << to_string(b) << " == ";);
|
||||
mul(a, b.m_num, c.m_num);
|
||||
set(c.m_den, b.m_den);
|
||||
normalize(c);
|
||||
STRACE("rat_mpq", tout << to_string(c) << "\n";);
|
||||
}
|
||||
|
||||
bool rat_lt(mpq const & a, mpq const & b);
|
||||
|
||||
public:
|
||||
typedef mpq numeral;
|
||||
typedef mpq rational;
|
||||
typedef mpz integer;
|
||||
static bool precise() { return true; }
|
||||
static bool field() { return true; }
|
||||
|
||||
mpq_manager();
|
||||
|
||||
~mpq_manager();
|
||||
|
||||
void reset(mpz & a) { mpz_manager<SYNCH>::reset(a); }
|
||||
|
||||
void reset(mpq & a) {
|
||||
reset(a.m_num);
|
||||
reset_denominator(a);
|
||||
}
|
||||
|
||||
static bool is_small(mpz const & a) { return mpz_manager<SYNCH>::is_small(a); }
|
||||
|
||||
static bool is_small(mpq const & a) { return is_small(a.m_num) && is_small(a.m_den); }
|
||||
|
||||
static mpq mk_q(int v) { return mpq(v); }
|
||||
|
||||
mpq mk_q(int n, int d) { mpq r; set(r, n, d); return r; }
|
||||
|
||||
void del(mpz & a) { mpz_manager<SYNCH>::del(a); }
|
||||
|
||||
void del(mpq & a) {
|
||||
del(a.m_num);
|
||||
del(a.m_den);
|
||||
}
|
||||
|
||||
void get_numerator(mpq const & a, mpz & n) { set(n, a.m_num); }
|
||||
|
||||
void get_denominator(mpq const & a, mpz & d) { set(d, a.m_den); }
|
||||
|
||||
void get_numerator(mpq const & a, mpq & n) { get_numerator(a, n.m_num); reset_denominator(n); }
|
||||
|
||||
void get_denominator(mpq const & a, mpq & d) { get_denominator(a, d.m_num); reset_denominator(d); }
|
||||
|
||||
void neg(mpz & a) { mpz_manager<SYNCH>::neg(a); }
|
||||
|
||||
void neg(mpq & a) { mpz_manager<SYNCH>::neg(a.m_num); }
|
||||
|
||||
void abs(mpz & a) { mpz_manager<SYNCH>::abs(a); }
|
||||
|
||||
void abs(mpq & a) { mpz_manager<SYNCH>::abs(a.m_num); }
|
||||
|
||||
static int sign(mpz const & a) { return mpz_manager<SYNCH>::sign(a); }
|
||||
|
||||
static int sign(mpq const & a) { return mpz_manager<SYNCH>::sign(a.m_num); }
|
||||
|
||||
static bool is_pos(mpz const & a) { return mpz_manager<SYNCH>::is_pos(a); }
|
||||
|
||||
static bool is_neg(mpz const & a) { return mpz_manager<SYNCH>::is_neg(a); }
|
||||
|
||||
static bool is_zero(mpz const & a) { return mpz_manager<SYNCH>::is_zero(a); }
|
||||
|
||||
static bool is_nonpos(mpz const & a) { return mpz_manager<SYNCH>::is_nonpos(a); }
|
||||
|
||||
static bool is_nonneg(mpz const & a) { return mpz_manager<SYNCH>::is_nonneg(a); }
|
||||
|
||||
static bool is_pos(mpq const & a) { return is_pos(a.m_num); }
|
||||
|
||||
static bool is_neg(mpq const & a) { return is_neg(a.m_num); }
|
||||
|
||||
static bool is_zero(mpq const & a) { return is_zero(a.m_num); }
|
||||
|
||||
static bool is_nonpos(mpq const & a) { return is_nonpos(a.m_num); }
|
||||
|
||||
static bool is_nonneg(mpq const & a) { return is_nonneg(a.m_num); }
|
||||
|
||||
static bool is_one(mpz const & a) { return mpz_manager<SYNCH>::is_one(a); }
|
||||
|
||||
static bool is_one(mpq const & a) { return is_one(a.m_num) && is_one(a.m_den); }
|
||||
|
||||
static bool is_minus_one(mpz const & a) { return mpz_manager<SYNCH>::is_minus_one(a); }
|
||||
|
||||
static bool is_minus_one(mpq const & a) { return is_minus_one(a.m_num) && is_one(a.m_den); }
|
||||
|
||||
void floor(mpq const & a, mpz & f);
|
||||
|
||||
void floor(mpq const & a, mpq & f) {
|
||||
floor(a, f.m_num);
|
||||
reset_denominator(f);
|
||||
}
|
||||
|
||||
void ceil(mpq const & a, mpz & f);
|
||||
|
||||
void ceil(mpq const & a, mpq & f) {
|
||||
ceil(a, f.m_num);
|
||||
reset_denominator(f);
|
||||
}
|
||||
|
||||
static bool is_int(mpq const & a) { return is_one(a.m_den); }
|
||||
|
||||
std::string to_string(mpq const & a) const;
|
||||
std::string to_rational_string(numeral const & a) { return to_string(a); }
|
||||
|
||||
std::string to_string(mpz const & a) const { return mpz_manager<SYNCH>::to_string(a); }
|
||||
|
||||
void display(std::ostream & out, mpz const & a) const { return mpz_manager<SYNCH>::display(out, a); }
|
||||
|
||||
void display(std::ostream & out, mpq const & a) const;
|
||||
|
||||
void display_smt2(std::ostream & out, mpz const & a, bool decimal) const { return mpz_manager<SYNCH>::display_smt2(out, a, decimal); }
|
||||
|
||||
void display_smt2(std::ostream & out, mpq const & a, bool decimal) const;
|
||||
|
||||
void display_decimal(std::ostream & out, mpq const & a, unsigned prec);
|
||||
|
||||
void add(mpz const & a, mpz const & b, mpz & c) { mpz_manager<SYNCH>::add(a, b, c); }
|
||||
|
||||
void add(mpq const & a, mpq const & b, mpq & c) {
|
||||
STRACE("mpq", tout << "[mpq] " << to_string(a) << " + " << to_string(b) << " == ";);
|
||||
if (is_int(a) && is_int(b)) {
|
||||
mpz_manager<SYNCH>::add(a.m_num, b.m_num, c.m_num);
|
||||
reset_denominator(c);
|
||||
}
|
||||
else
|
||||
rat_add(a, b, c);
|
||||
STRACE("mpq", tout << to_string(c) << "\n";);
|
||||
}
|
||||
|
||||
void add(mpq const & a, mpz const & b, mpq & c) {
|
||||
STRACE("mpq", tout << "[mpq] " << to_string(a) << " + " << to_string(b) << " == ";);
|
||||
if (is_int(a)) {
|
||||
mpz_manager<SYNCH>::add(a.m_num, b, c.m_num);
|
||||
reset_denominator(c);
|
||||
}
|
||||
else {
|
||||
rat_add(a, b, c);
|
||||
}
|
||||
STRACE("mpq", tout << to_string(c) << "\n";);
|
||||
}
|
||||
|
||||
void sub(mpz const & a, mpz const & b, mpz & c) { mpz_manager<SYNCH>::sub(a, b, c); }
|
||||
|
||||
void sub(mpq const & a, mpq const & b, mpq & c) {
|
||||
STRACE("mpq", tout << "[mpq] " << to_string(a) << " - " << to_string(b) << " == ";);
|
||||
if (is_int(a) && is_int(b)) {
|
||||
mpz_manager<SYNCH>::sub(a.m_num, b.m_num, c.m_num);
|
||||
reset_denominator(c);
|
||||
}
|
||||
else
|
||||
rat_sub(a, b, c);
|
||||
STRACE("mpq", tout << to_string(c) << "\n";);
|
||||
}
|
||||
|
||||
void inc(mpz & a) { mpz_manager<SYNCH>::inc(a); }
|
||||
|
||||
void dec(mpz & a) { mpz_manager<SYNCH>::dec(a); }
|
||||
|
||||
void inc(mpq & a) { add(a, mpz(1), a); }
|
||||
|
||||
void dec(mpq & a) { add(a, mpz(-1), a); }
|
||||
|
||||
void mul(mpz const & a, mpz const & b, mpz & c) { mpz_manager<SYNCH>::mul(a, b, c); }
|
||||
|
||||
void mul(mpz const & a, mpz const & b, mpq & c) {
|
||||
mpz_manager<SYNCH>::mul(a, b, c.m_num);
|
||||
reset_denominator(c);
|
||||
}
|
||||
|
||||
void mul(mpq const & a, mpq const & b, mpq & c) {
|
||||
STRACE("mpq", tout << "[mpq] " << to_string(a) << " * " << to_string(b) << " == ";);
|
||||
if (is_int(a) && is_int(b)) {
|
||||
mpz_manager<SYNCH>::mul(a.m_num, b.m_num, c.m_num);
|
||||
reset_denominator(c);
|
||||
}
|
||||
else
|
||||
rat_mul(a, b, c);
|
||||
STRACE("mpq", tout << to_string(c) << "\n";);
|
||||
}
|
||||
|
||||
void mul(mpz const & a, mpq const & b, mpq & c) {
|
||||
STRACE("mpq", tout << "[mpq] " << to_string(a) << " * " << to_string(b) << " == ";);
|
||||
if (is_int(b)) {
|
||||
mpz_manager<SYNCH>::mul(a, b.m_num, c.m_num);
|
||||
reset_denominator(c);
|
||||
}
|
||||
else
|
||||
rat_mul(a, b, c);
|
||||
STRACE("mpq", tout << to_string(c) << "\n";);
|
||||
}
|
||||
|
||||
void addmul(mpz const & a, mpz const & b, mpz const & c, mpz & d) {
|
||||
return mpz_manager<SYNCH>::addmul(a, b, c, d);
|
||||
}
|
||||
|
||||
void submul(mpz const & a, mpz const & b, mpz const & c, mpz & d) {
|
||||
return mpz_manager<SYNCH>::submul(a, b, c, d);
|
||||
}
|
||||
|
||||
// d <- a + b*c
|
||||
void addmul(mpq const & a, mpq const & b, mpq const & c, mpq & d) {
|
||||
if (is_one(b)) {
|
||||
add(a, c, d);
|
||||
}
|
||||
else if (is_minus_one(b)) {
|
||||
sub(a, c, d);
|
||||
}
|
||||
else {
|
||||
if (SYNCH) {
|
||||
mpq tmp;
|
||||
mul(b,c,tmp);
|
||||
add(a,tmp,d);
|
||||
del(tmp);
|
||||
}
|
||||
else {
|
||||
mul(b,c,m_addmul_tmp);
|
||||
add(a, m_addmul_tmp, d);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// d <- a + b*c
|
||||
void addmul(mpq const & a, mpz const & b, mpq const & c, mpq & d) {
|
||||
if (is_one(b)) {
|
||||
add(a, c, d);
|
||||
}
|
||||
else if (is_minus_one(b)) {
|
||||
sub(a, c, d);
|
||||
}
|
||||
else {
|
||||
if (SYNCH) {
|
||||
mpq tmp;
|
||||
mul(b,c,tmp);
|
||||
add(a,tmp,d);
|
||||
del(tmp);
|
||||
}
|
||||
else {
|
||||
mul(b,c,m_addmul_tmp);
|
||||
add(a, m_addmul_tmp, d);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// d <- a - b*c
|
||||
void submul(mpq const & a, mpq const & b, mpq const & c, mpq & d) {
|
||||
if (is_one(b)) {
|
||||
sub(a, c, d);
|
||||
}
|
||||
else if (is_minus_one(b)) {
|
||||
add(a, c, d);
|
||||
}
|
||||
else {
|
||||
if (SYNCH) {
|
||||
mpq tmp;
|
||||
mul(b,c,tmp);
|
||||
sub(a,tmp,d);
|
||||
del(tmp);
|
||||
}
|
||||
else {
|
||||
mul(b,c,m_addmul_tmp);
|
||||
sub(a, m_addmul_tmp, d);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// d <- a - b*c
|
||||
void submul(mpq const & a, mpz const & b, mpq const & c, mpq & d) {
|
||||
if (is_one(b)) {
|
||||
sub(a, c, d);
|
||||
}
|
||||
else if (is_minus_one(b)) {
|
||||
add(a, c, d);
|
||||
}
|
||||
else {
|
||||
if (SYNCH) {
|
||||
mpq tmp;
|
||||
mul(b,c,tmp);
|
||||
sub(a,tmp,d);
|
||||
del(tmp);
|
||||
}
|
||||
else {
|
||||
mul(b,c,m_addmul_tmp);
|
||||
sub(a, m_addmul_tmp, d);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void inv(mpq & a) {
|
||||
SASSERT(!is_zero(a));
|
||||
if (is_neg(a)) {
|
||||
neg(a.m_num);
|
||||
neg(a.m_den);
|
||||
}
|
||||
mpz_manager<SYNCH>::swap(a.m_num, a.m_den);
|
||||
}
|
||||
|
||||
void inv(mpq const & a, mpq & b) {
|
||||
set(b, a);
|
||||
inv(b);
|
||||
}
|
||||
|
||||
void div(mpq const & a, mpq const & b, mpq & c) {
|
||||
STRACE("mpq", tout << "[mpq] " << to_string(a) << " / " << to_string(b) << " == ";);
|
||||
if (&b == &c) {
|
||||
mpz tmp; // it is not safe to use c.m_num at this point.
|
||||
mul(a.m_num, b.m_den, tmp);
|
||||
mul(a.m_den, b.m_num, c.m_den);
|
||||
set(c.m_num, tmp);
|
||||
del(tmp);
|
||||
}
|
||||
else {
|
||||
mul(a.m_num, b.m_den, c.m_num);
|
||||
mul(a.m_den, b.m_num, c.m_den);
|
||||
}
|
||||
|
||||
if (mpz_manager<SYNCH>::is_neg(c.m_den)) {
|
||||
neg(c.m_num);
|
||||
neg(c.m_den);
|
||||
}
|
||||
normalize(c);
|
||||
STRACE("mpq", tout << to_string(c) << "\n";);
|
||||
}
|
||||
|
||||
void div(mpq const & a, mpz const & b, mpq & c) {
|
||||
STRACE("mpq", tout << "[mpq] " << to_string(a) << " / " << to_string(b) << " == ";);
|
||||
set(c.m_num, a.m_num);
|
||||
mul(a.m_den, b, c.m_den);
|
||||
if (mpz_manager<SYNCH>::is_neg(b)) {
|
||||
neg(c.m_num);
|
||||
neg(c.m_den);
|
||||
}
|
||||
normalize(c);
|
||||
STRACE("mpq", tout << to_string(c) << "\n";);
|
||||
}
|
||||
|
||||
void acc_div(mpq & a, mpz const & b) {
|
||||
STRACE("mpq", tout << "[mpq] " << to_string(a) << " / " << to_string(b) << " == ";);
|
||||
mul(a.m_den, b, a.m_den);
|
||||
if (mpz_manager<SYNCH>::is_neg(b)) {
|
||||
neg(a.m_num);
|
||||
neg(a.m_den);
|
||||
}
|
||||
normalize(a);
|
||||
STRACE("mpq", tout << to_string(a) << "\n";);
|
||||
}
|
||||
|
||||
void machine_div(mpz const & a, mpz const & b, mpz & c) { mpz_manager<SYNCH>::machine_div(a, b, c); }
|
||||
|
||||
void div(mpz const & a, mpz const & b, mpz & c) { mpz_manager<SYNCH>::div(a, b, c); }
|
||||
|
||||
void rat_div(mpz const & a, mpz const & b, mpq & c) {
|
||||
set(c.m_num, a);
|
||||
set(c.m_den, b);
|
||||
normalize(c);
|
||||
}
|
||||
|
||||
void machine_idiv(mpq const & a, mpq const & b, mpq & c) {
|
||||
SASSERT(is_int(a) && is_int(b));
|
||||
machine_div(a.m_num, b.m_num, c.m_num);
|
||||
reset_denominator(c);
|
||||
}
|
||||
|
||||
void machine_idiv(mpq const & a, mpq const & b, mpz & c) {
|
||||
SASSERT(is_int(a) && is_int(b));
|
||||
machine_div(a.m_num, b.m_num, c);
|
||||
}
|
||||
|
||||
void idiv(mpq const & a, mpq const & b, mpq & c) {
|
||||
SASSERT(is_int(a) && is_int(b));
|
||||
div(a.m_num, b.m_num, c.m_num);
|
||||
reset_denominator(c);
|
||||
}
|
||||
|
||||
void idiv(mpq const & a, mpq const & b, mpz & c) {
|
||||
SASSERT(is_int(a) && is_int(b));
|
||||
div(a.m_num, b.m_num, c);
|
||||
}
|
||||
|
||||
void rem(mpz const & a, mpz const & b, mpz & c) { mpz_manager<SYNCH>::rem(a, b, c); }
|
||||
|
||||
void rem(mpq const & a, mpq const & b, mpq & c) {
|
||||
SASSERT(is_int(a) && is_int(b));
|
||||
rem(a.m_num, b.m_num, c.m_num);
|
||||
reset_denominator(c);
|
||||
}
|
||||
|
||||
void rem(mpq const & a, mpq const & b, mpz & c) {
|
||||
SASSERT(is_int(a) && is_int(b));
|
||||
rem(a.m_num, b.m_num, c);
|
||||
}
|
||||
|
||||
void mod(mpz const & a, mpz const & b, mpz & c) { mpz_manager<SYNCH>::mod(a, b, c); }
|
||||
|
||||
void mod(mpq const & a, mpq const & b, mpq & c) {
|
||||
SASSERT(is_int(a) && is_int(b));
|
||||
mod(a.m_num, b.m_num, c.m_num);
|
||||
reset_denominator(c);
|
||||
}
|
||||
|
||||
void mod(mpq const & a, mpq const & b, mpz & c) {
|
||||
SASSERT(is_int(a) && is_int(b));
|
||||
mod(a.m_num, b.m_num, c);
|
||||
}
|
||||
|
||||
static unsigned hash(mpz const & a) { return mpz_manager<SYNCH>::hash(a); }
|
||||
|
||||
static unsigned hash(mpq const & a) { return hash(a.m_num); }
|
||||
|
||||
bool eq(mpz const & a, mpz const & b) { return mpz_manager<SYNCH>::eq(a, b); }
|
||||
|
||||
bool eq(mpq const & a, mpq const & b) {
|
||||
return eq(a.m_num, b.m_num) && eq(a.m_den, b.m_den);
|
||||
}
|
||||
|
||||
bool lt(mpz const & a, mpz const & b) { return mpz_manager<SYNCH>::lt(a, b); }
|
||||
|
||||
bool lt(mpq const & a, mpq const & b) {
|
||||
if (is_int(a) && is_int(b))
|
||||
return lt(a.m_num, b.m_num);
|
||||
else
|
||||
return rat_lt(a, b);
|
||||
}
|
||||
|
||||
bool neq(mpz const & a, mpz const & b) { return mpz_manager<SYNCH>::neq(a, b); }
|
||||
|
||||
bool gt(mpz const & a, mpz const & b) { return mpz_manager<SYNCH>::gt(a, b); }
|
||||
|
||||
bool ge(mpz const & a, mpz const & b) { return mpz_manager<SYNCH>::ge(a, b); }
|
||||
|
||||
bool le(mpz const & a, mpz const & b) { return mpz_manager<SYNCH>::le(a, b); }
|
||||
|
||||
bool neq(mpq const & a, mpq const & b) { return !eq(a, b); }
|
||||
|
||||
bool gt(mpq const & a, mpq const & b) { return lt(b, a); }
|
||||
|
||||
bool ge(mpq const & a, mpq const & b) { return !lt(a, b); }
|
||||
|
||||
bool le(mpq const & a, mpq const & b) { return !lt(b, a); }
|
||||
|
||||
void gcd(mpz const & a, mpz const & b, mpz & c) { mpz_manager<SYNCH>::gcd(a, b, c); }
|
||||
|
||||
void gcd(unsigned sz, mpz const * as, mpz & g) { mpz_manager<SYNCH>::gcd(sz, as, g); }
|
||||
|
||||
void gcd(unsigned sz, mpq const * as, mpq & g);
|
||||
|
||||
void gcd(mpq const & a, mpq const & b, mpq & c) {
|
||||
SASSERT(is_int(a) && is_int(b));
|
||||
gcd(a.m_num, b.m_num, c.m_num);
|
||||
reset_denominator(c);
|
||||
}
|
||||
|
||||
void gcd(mpz const & r1, mpz const & r2, mpz & a, mpz & b, mpz & g) { mpz_manager<SYNCH>::gcd(r1, r2, a, b, g); }
|
||||
|
||||
void gcd(mpq const & r1, mpq const & r2, mpq & a, mpq & b, mpq & g) {
|
||||
SASSERT(is_int(r1) && is_int(r2));
|
||||
reset_denominator(a);
|
||||
reset_denominator(b);
|
||||
reset_denominator(g);
|
||||
gcd(r1.m_num, r2.m_num, a.m_num, b.m_num, g.m_num);
|
||||
}
|
||||
|
||||
void lcm(mpz const & a, mpz const & b, mpz & c) { mpz_manager<SYNCH>::lcm(a, b, c); }
|
||||
|
||||
void lcm(mpq const & a, mpq const & b, mpq & c) {
|
||||
SASSERT(is_int(a) && is_int(b));
|
||||
lcm(a.m_num, b.m_num, c.m_num);
|
||||
reset_denominator(c);
|
||||
}
|
||||
|
||||
bool divides(mpz const & a, mpz const & b) { return mpz_manager<SYNCH>::divides(a, b); }
|
||||
|
||||
bool divides(mpq const & a, mpq const & b) {
|
||||
SASSERT(is_int(a) && is_int(b));
|
||||
return divides(a.m_num, b.m_num);
|
||||
}
|
||||
|
||||
void bitwise_or(mpz const & a, mpz const & b, mpz & c) { return mpz_manager<SYNCH>::bitwise_or(a, b, c); }
|
||||
|
||||
void bitwise_or(mpq const & a, mpq const & b, mpq & c) {
|
||||
SASSERT(is_int(a) && is_int(b));
|
||||
bitwise_or(a.m_num, b.m_num, c.m_num);
|
||||
reset_denominator(c);
|
||||
}
|
||||
|
||||
void bitwise_and(mpz const & a, mpz const & b, mpz & c) { return mpz_manager<SYNCH>::bitwise_and(a, b, c); }
|
||||
|
||||
void bitwise_and(mpq const & a, mpq const & b, mpq & c) {
|
||||
SASSERT(is_int(a) && is_int(b));
|
||||
bitwise_and(a.m_num, b.m_num, c.m_num);
|
||||
reset_denominator(c);
|
||||
}
|
||||
|
||||
void bitwise_xor(mpz const & a, mpz const & b, mpz & c) { return mpz_manager<SYNCH>::bitwise_xor(a, b, c); }
|
||||
|
||||
void bitwise_xor(mpq const & a, mpq const & b, mpq & c) {
|
||||
SASSERT(is_int(a) && is_int(b));
|
||||
bitwise_xor(a.m_num, b.m_num, c.m_num);
|
||||
reset_denominator(c);
|
||||
}
|
||||
|
||||
void bitwise_not(unsigned sz, mpz const & a, mpz & c) { return mpz_manager<SYNCH>::bitwise_not(sz, a, c); }
|
||||
|
||||
void bitwise_not(unsigned sz, mpq const & a, mpq & c) {
|
||||
SASSERT(is_int(a));
|
||||
bitwise_not(sz, a.m_num, c.m_num);
|
||||
reset_denominator(c);
|
||||
}
|
||||
|
||||
void set(mpz & target, mpz const & source) { mpz_manager<SYNCH>::set(target, source); }
|
||||
|
||||
void set(mpq & target, mpq const & source) {
|
||||
set(target.m_num, source.m_num);
|
||||
set(target.m_den, source.m_den);
|
||||
}
|
||||
|
||||
void set(mpz & a, int val) { mpz_manager<SYNCH>::set(a, val); }
|
||||
|
||||
void set(mpq & a, int val) {
|
||||
set(a.m_num, val);
|
||||
reset_denominator(a);
|
||||
}
|
||||
|
||||
void set(mpq & a, int n, int d) {
|
||||
SASSERT(d != 0);
|
||||
if (d < 0) {
|
||||
n = -n;
|
||||
d = -d;
|
||||
}
|
||||
set(a.m_num, n);
|
||||
set(a.m_den, d);
|
||||
normalize(a);
|
||||
}
|
||||
|
||||
void set(mpq & a, int64 n, uint64 d) {
|
||||
SASSERT(d != 0);
|
||||
set(a.m_num, n);
|
||||
set(a.m_den, d);
|
||||
normalize(a);
|
||||
}
|
||||
|
||||
void set(mpq & a, mpz const & n, mpz const & d) {
|
||||
if (is_neg(d)) {
|
||||
set(a.m_num, n);
|
||||
set(a.m_den, d);
|
||||
neg(a.m_num);
|
||||
neg(a.m_den);
|
||||
}
|
||||
else {
|
||||
set(a.m_num, n);
|
||||
set(a.m_den, d);
|
||||
}
|
||||
normalize(a);
|
||||
}
|
||||
|
||||
void set(mpz & a, unsigned val) { mpz_manager<SYNCH>::set(a, val); }
|
||||
|
||||
void set(mpq & a, unsigned val) {
|
||||
set(a.m_num, val);
|
||||
reset_denominator(a);
|
||||
}
|
||||
|
||||
void set(mpz & a, char const * val) { mpz_manager<SYNCH>::set(a, val); }
|
||||
|
||||
void set(mpq & a, char const * val);
|
||||
|
||||
void set(mpz & a, int64 val) { mpz_manager<SYNCH>::set(a, val); }
|
||||
|
||||
void set(mpq & a, int64 val) {
|
||||
set(a.m_num, val);
|
||||
reset_denominator(a);
|
||||
}
|
||||
|
||||
void set(mpz & a, uint64 val) { mpz_manager<SYNCH>::set(a, val); }
|
||||
|
||||
void set(mpq & a, uint64 val) {
|
||||
set(a.m_num, val);
|
||||
reset_denominator(a);
|
||||
}
|
||||
|
||||
void set(mpq & a, mpz const & val) {
|
||||
mpz_manager<SYNCH>::set(a.m_num, val);
|
||||
reset_denominator(a);
|
||||
}
|
||||
|
||||
void set(mpz & a, unsigned sz, digit_t const * digits) { mpz_manager<SYNCH>::set(a, sz, digits); }
|
||||
|
||||
void set(mpq & a, unsigned sz, digit_t const * digits) {
|
||||
mpz_manager<SYNCH>::set(a.m_num, sz, digits);
|
||||
reset_denominator(a);
|
||||
}
|
||||
|
||||
void swap(mpz & a, mpz & b) { mpz_manager<SYNCH>::swap(a, b); }
|
||||
|
||||
void swap(mpq & a, mpq & b) {
|
||||
swap(a.m_num, b.m_num);
|
||||
swap(a.m_den, b.m_den);
|
||||
}
|
||||
|
||||
void swap_numerator(mpz & a, mpq & b) {
|
||||
swap(a, b.m_num);
|
||||
}
|
||||
|
||||
bool is_uint64(mpz const & a) const { return mpz_manager<SYNCH>::is_uint64(a); }
|
||||
|
||||
bool is_int64(mpz const & a) const { return mpz_manager<SYNCH>::is_int64(a); }
|
||||
|
||||
uint64 get_uint64(mpz const & a) const { return mpz_manager<SYNCH>::get_uint64(a); }
|
||||
|
||||
int64 get_int64(mpz const & a) const { return mpz_manager<SYNCH>::get_int64(a); }
|
||||
|
||||
bool is_uint64(mpq const & a) const { return is_int(a) && is_uint64(a.m_num); }
|
||||
|
||||
bool is_int64(mpq const & a) const { return is_int(a) && is_int64(a.m_num); }
|
||||
|
||||
uint64 get_uint64(mpq const & a) const { SASSERT(is_uint64(a)); return get_uint64(a.m_num); }
|
||||
|
||||
int64 get_int64(mpq const & a) const { SASSERT(is_int64(a)); return get_int64(a.m_num); }
|
||||
|
||||
double get_double(mpz const & a) const { return mpz_manager<SYNCH>::get_double(a); }
|
||||
|
||||
double get_double(mpq const & a) const;
|
||||
|
||||
void power(mpz const & a, unsigned p, mpz & b) { mpz_manager<SYNCH>::power(a, p, b); }
|
||||
|
||||
void power(mpq const & a, unsigned p, mpq & b);
|
||||
|
||||
bool is_power_of_two(mpz const & a, unsigned & shift) { return mpz_manager<SYNCH>::is_power_of_two(a, shift); }
|
||||
|
||||
bool is_power_of_two(mpq const & a, unsigned & shift) { return is_int(a) && is_power_of_two(a.m_num, shift); }
|
||||
|
||||
unsigned bitsize(mpz const & a) { return mpz_manager<SYNCH>::bitsize(a); }
|
||||
unsigned bitsize(mpq const & a) { return is_int(a) ? bitsize(a.m_num) : bitsize(a.m_num) + bitsize(a.m_den); }
|
||||
|
||||
/**
|
||||
\brief Return true if the number is a perfect square, and
|
||||
store the square root in 'root'.
|
||||
If the number n is positive and the result is false, then
|
||||
root will contain the smallest integer r such that r*r > n.
|
||||
*/
|
||||
bool is_perfect_square(mpz const & a, mpz & r) { return mpz_manager<SYNCH>::is_perfect_square(a, r); }
|
||||
|
||||
/**
|
||||
\brief Return true if the numerator and denominators are perfect squares.
|
||||
Store the square root in root.
|
||||
If the result is false, then the value of root should be ignored.
|
||||
*/
|
||||
bool is_perfect_square(mpq const & a, mpq & r) {
|
||||
if (is_int(a)) {
|
||||
reset_denominator(r);
|
||||
return is_perfect_square(a.m_num, r.m_num);
|
||||
}
|
||||
if (is_perfect_square(a.m_num, r.m_num) && is_perfect_square(a.m_den, r.m_den)) {
|
||||
normalize(r);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool root(mpz & a, unsigned n) { return mpz_manager<SYNCH>::root(a, n); }
|
||||
bool root(mpz const & a, unsigned n, mpz & r) { return mpz_manager<SYNCH>::root(a, n, r); }
|
||||
|
||||
/**
|
||||
\brief Return true if n-th root of a is rational, and store result in r.
|
||||
*/
|
||||
bool root(mpq const & a, unsigned n, mpq & r);
|
||||
|
||||
/**
|
||||
\brief Return the biggest k s.t. 2^k <= a.
|
||||
|
||||
\remark Return 0 if a is not positive.
|
||||
*/
|
||||
unsigned prev_power_of_two(mpz const & a) { return mpz_manager<SYNCH>::prev_power_of_two(a); }
|
||||
unsigned prev_power_of_two(mpq const & a);
|
||||
|
||||
bool is_int_perfect_square(mpq const & a, mpq & r) {
|
||||
SASSERT(is_int(a));
|
||||
reset_denominator(r);
|
||||
return is_perfect_square(a.m_num, r.m_num);
|
||||
}
|
||||
|
||||
bool is_even(mpz const & a) { return mpz_manager<SYNCH>::is_even(a); }
|
||||
|
||||
bool is_even(mpq const & a) { return is_int(a) && is_even(a.m_num); }
|
||||
|
||||
};
|
||||
|
||||
typedef mpq_manager<true> synch_mpq_manager;
|
||||
typedef mpq_manager<false> unsynch_mpq_manager;
|
||||
|
||||
typedef _scoped_numeral<unsynch_mpq_manager> scoped_mpq;
|
||||
typedef _scoped_numeral<synch_mpq_manager> scoped_synch_mpq;
|
||||
typedef _scoped_numeral_vector<unsynch_mpq_manager> scoped_mpq_vector;
|
||||
|
||||
#endif /* _MPQ_H_ */
|
||||
|
42
src/util/mpq_inf.cpp
Normal file
42
src/util/mpq_inf.cpp
Normal file
|
@ -0,0 +1,42 @@
|
|||
/*++
|
||||
Copyright (c) 2006 Microsoft Corporation
|
||||
|
||||
Module Name:
|
||||
|
||||
mpq_inf.cpp
|
||||
|
||||
Abstract:
|
||||
|
||||
MPQ numbers with infinitesimals
|
||||
|
||||
Author:
|
||||
|
||||
Leonardo de Moura (leonardo) 2011-06-28
|
||||
|
||||
Revision History:
|
||||
|
||||
--*/
|
||||
#include"mpq_inf.h"
|
||||
|
||||
template<bool SYNCH>
|
||||
std::string mpq_inf_manager<SYNCH>::to_string(mpq_inf const & a) const {
|
||||
if (m.is_zero(a.second))
|
||||
return m.to_string(a.first);
|
||||
|
||||
std::string s = "(";
|
||||
s += m.to_string(a.first);
|
||||
if (m.is_neg(a.second))
|
||||
s += " -e*";
|
||||
else
|
||||
s += " +e*";
|
||||
mpq tmp;
|
||||
m.set(tmp, a.second);
|
||||
m.abs(tmp);
|
||||
s += m.to_string(tmp);
|
||||
m.del(tmp);
|
||||
s += ")";
|
||||
return s;
|
||||
}
|
||||
|
||||
template class mpq_inf_manager<true>;
|
||||
template class mpq_inf_manager<false>;
|
256
src/util/mpq_inf.h
Normal file
256
src/util/mpq_inf.h
Normal file
|
@ -0,0 +1,256 @@
|
|||
/*++
|
||||
Copyright (c) 2006 Microsoft Corporation
|
||||
|
||||
Module Name:
|
||||
|
||||
mpq_inf.h
|
||||
|
||||
Abstract:
|
||||
|
||||
MPQ numbers with infinitesimals
|
||||
|
||||
Author:
|
||||
|
||||
Leonardo de Moura (leonardo) 2011-06-28
|
||||
|
||||
Revision History:
|
||||
|
||||
--*/
|
||||
#ifndef _MPQ_INF_H_
|
||||
#define _MPQ_INF_H_
|
||||
|
||||
#include"mpq.h"
|
||||
#include"hash.h"
|
||||
#include"params.h"
|
||||
|
||||
typedef std::pair<mpq, mpq> mpq_inf;
|
||||
|
||||
template<bool SYNCH = true>
|
||||
class mpq_inf_manager {
|
||||
mpq_manager<SYNCH> & m;
|
||||
double m_inf;
|
||||
public:
|
||||
typedef mpq_inf numeral;
|
||||
|
||||
mpq_inf_manager(mpq_manager<SYNCH> & _m, params_ref const & p = params_ref()):m(_m) {
|
||||
updt_params(p);
|
||||
}
|
||||
|
||||
void updt_params(params_ref const & p) {
|
||||
m_inf = p.get_double(":infinitesimal-as-double", 0.00001);
|
||||
}
|
||||
|
||||
enum inf_kind { NEG=-1, ZERO, POS };
|
||||
|
||||
void reset(mpq_inf & a) {
|
||||
m.reset(a.first);
|
||||
m.reset(a.second);
|
||||
}
|
||||
|
||||
unsigned hash(mpq_inf const & a) const { return hash_u_u(m.hash(a.first), m.hash(a.second)); }
|
||||
|
||||
void del(mpq_inf & a) {
|
||||
m.del(a.first);
|
||||
m.del(a.second);
|
||||
}
|
||||
|
||||
void swap(mpq_inf & a, mpq_inf & b) {
|
||||
m.swap(a.first, b.first);
|
||||
m.swap(a.second, b.second);
|
||||
}
|
||||
|
||||
void set(mpq_inf & a, mpq_inf const & b) {
|
||||
m.set(a.first, b.first);
|
||||
m.set(a.second, b.second);
|
||||
}
|
||||
|
||||
void set(mpq_inf & a, mpq const & r) {
|
||||
m.set(a.first, r);
|
||||
m.reset(a.second);
|
||||
}
|
||||
|
||||
void set(mpq_inf & a, mpq const & r, inf_kind k) {
|
||||
m.set(a.first, r);
|
||||
switch (k) {
|
||||
case NEG: m.set(a.second, -1); break;
|
||||
case ZERO: m.reset(a.second); break;
|
||||
case POS: m.set(a.second, 1); break;
|
||||
}
|
||||
}
|
||||
|
||||
void set(mpq_inf & a, mpq const & r, mpq const & i) {
|
||||
m.set(a.first, r);
|
||||
m.set(a.second, i);
|
||||
}
|
||||
|
||||
bool is_int(mpq_inf const & a) const { return m.is_int(a.first) && m.is_zero(a.second); }
|
||||
|
||||
bool is_rational(mpq_inf const & a) const { return m.is_zero(a.second); }
|
||||
|
||||
void get_rational(mpq_inf const & a, mpq & r) { m.set(r, a.first); }
|
||||
|
||||
void get_infinitesimal(mpq_inf const & a, mpq & r) { m.set(r, a.second); }
|
||||
|
||||
double get_double(mpq_inf const & a) {
|
||||
double r = m.get_double(a.first);
|
||||
if (m.is_pos(a.second))
|
||||
return r + m_inf;
|
||||
else if (m.is_neg(a.second))
|
||||
return r - m_inf;
|
||||
else
|
||||
return r;
|
||||
}
|
||||
|
||||
bool is_zero(mpq_inf const & a) const {
|
||||
return m.is_zero(a.first) && m.is_zero(a.second);
|
||||
}
|
||||
|
||||
bool eq(mpq_inf const & a, mpq_inf const & b) const {
|
||||
return m.eq(a.first, b.first) && m.eq(a.second, b.second);
|
||||
}
|
||||
|
||||
bool eq(mpq_inf const & a, mpq const & b) const {
|
||||
return m.eq(a.first, b) && m.is_zero(a.second);
|
||||
}
|
||||
|
||||
bool eq(mpq_inf const & a, mpq const & b, inf_kind k) const {
|
||||
if (!m.eq(a.first, b))
|
||||
return false;
|
||||
switch (k) {
|
||||
case NEG: return m.is_minus_one(a.second);
|
||||
case ZERO: return m.is_zero(a.second);
|
||||
case POS: return m.is_one(a.second);
|
||||
}
|
||||
UNREACHABLE();
|
||||
return false;
|
||||
}
|
||||
|
||||
bool lt(mpq_inf const & a, mpq_inf const & b) const {
|
||||
return m.lt(a.first, b.first) || (m.lt(a.second, b.second) && m.eq(a.first, b.first));
|
||||
}
|
||||
|
||||
bool lt(mpq_inf const & a, mpq const & b) const {
|
||||
return m.lt(a.first, b) || (m.is_neg(a.second) && m.eq(a.first, b));
|
||||
}
|
||||
|
||||
bool lt(mpq_inf const & a, mpq const & b, inf_kind k) const {
|
||||
if (m.lt(a.first, b))
|
||||
return true;
|
||||
if (m.eq(a.first, b)) {
|
||||
switch (k) {
|
||||
case NEG: return m.lt(a.second, mpq(-1));
|
||||
case ZERO: return m.is_neg(a.second);
|
||||
case POS: return m.lt(a.second, mpq(1));
|
||||
}
|
||||
UNREACHABLE();
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool gt(mpq_inf const & a, mpq_inf const & b) const { return lt(b, a); }
|
||||
|
||||
bool gt(mpq_inf const & a, mpq const & b) const {
|
||||
return m.gt(a.first, b) || (m.is_pos(a.second) && m.eq(a.first, b));
|
||||
}
|
||||
|
||||
bool gt(mpq_inf const & a, mpq const & b, inf_kind k) const {
|
||||
if (m.gt(a.first, b))
|
||||
return true;
|
||||
if (m.eq(a.first, b)) {
|
||||
switch (k) {
|
||||
case NEG: return m.gt(a.second, mpq(-1));
|
||||
case ZERO: return m.is_pos(a.second);
|
||||
case POS: return m.gt(a.second, mpq(1));
|
||||
}
|
||||
UNREACHABLE();
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool le(mpq_inf const & a, mpq_inf const & b) const { return !gt(a, b); }
|
||||
|
||||
bool le(mpq_inf const & a, mpq const & b) const { return !gt(a, b); }
|
||||
|
||||
bool le(mpq_inf const & a, mpq const & b, inf_kind k) const { return !gt(a, b, k); }
|
||||
|
||||
bool ge(mpq_inf const & a, mpq_inf const & b) const { return !lt(a, b); }
|
||||
|
||||
bool ge(mpq_inf const & a, mpq const & b) const { return !lt(a, b); }
|
||||
|
||||
bool ge(mpq_inf const & a, mpq const & b, inf_kind k) const { return !lt(a, b, k); }
|
||||
|
||||
void add(mpq_inf const & a, mpq_inf const & b, mpq_inf & c) {
|
||||
m.add(a.first, b.first, c.first);
|
||||
m.add(a.second, b.second, c.second);
|
||||
}
|
||||
|
||||
void sub(mpq_inf const & a, mpq_inf const & b, mpq_inf & c) {
|
||||
m.sub(a.first, b.first, c.first);
|
||||
m.sub(a.second, b.second, c.second);
|
||||
}
|
||||
|
||||
void add(mpq_inf const & a, mpq const & b, mpq_inf & c) {
|
||||
m.add(a.first, b, c.first);
|
||||
m.set(c.second, a.second);
|
||||
}
|
||||
|
||||
void sub(mpq_inf const & a, mpq const & b, mpq_inf & c) {
|
||||
m.sub(a.first, b, c.first);
|
||||
m.set(c.second, a.second);
|
||||
}
|
||||
|
||||
void mul(mpq_inf const & a, mpq const & b, mpq_inf & c) {
|
||||
m.mul(a.first, b, c.first);
|
||||
m.mul(a.second, b, c.second);
|
||||
}
|
||||
|
||||
void mul(mpq_inf const & a, mpz const & b, mpq_inf & c) {
|
||||
m.mul(b, a.first, c.first);
|
||||
m.mul(b, a.second, c.second);
|
||||
}
|
||||
|
||||
void inc(mpq_inf & a) {
|
||||
m.inc(a.first);
|
||||
}
|
||||
|
||||
void dec(mpq_inf & a) {
|
||||
m.dec(a.first);
|
||||
}
|
||||
|
||||
void neg(mpq_inf & a) {
|
||||
m.neg(a.first);
|
||||
m.neg(a.second);
|
||||
}
|
||||
|
||||
void ceil(mpq_inf const & a, mpq & b) {
|
||||
if (m.is_int(a.first)) {
|
||||
// special cases for k - delta*epsilon where k is an integer
|
||||
if (m.is_pos(a.first))
|
||||
m.add(a.first, mpq(1), b); // ceil(k + delta*epsilon) --> k+1
|
||||
else
|
||||
m.set(b, a.first);
|
||||
}
|
||||
else {
|
||||
m.ceil(a.first, b);
|
||||
}
|
||||
}
|
||||
|
||||
void floor(mpq_inf const & a, mpq & b) {
|
||||
if (m.is_int(a.first)) {
|
||||
if (m.is_neg(a.first))
|
||||
m.sub(a.first, mpq(1), b); // floor(k - delta*epsilon) --> k-1
|
||||
else
|
||||
m.set(b, a.first);
|
||||
}
|
||||
else {
|
||||
m.floor(a.first, b);
|
||||
}
|
||||
}
|
||||
|
||||
std::string to_string(mpq_inf const & a) const;
|
||||
};
|
||||
|
||||
typedef mpq_inf_manager<true> synch_mpq_inf_manager;
|
||||
typedef mpq_inf_manager<false> unsynch_mpq_inf_manager;
|
||||
|
||||
#endif
|
2116
src/util/mpz.cpp
Normal file
2116
src/util/mpz.cpp
Normal file
File diff suppressed because it is too large
Load diff
798
src/util/mpz.h
Normal file
798
src/util/mpz.h
Normal file
|
@ -0,0 +1,798 @@
|
|||
/*++
|
||||
Copyright (c) 2006 Microsoft Corporation
|
||||
|
||||
Module Name:
|
||||
|
||||
mpz.h
|
||||
|
||||
Abstract:
|
||||
|
||||
<abstract>
|
||||
|
||||
Author:
|
||||
|
||||
Leonardo de Moura (leonardo) 2010-06-17.
|
||||
|
||||
Revision History:
|
||||
|
||||
--*/
|
||||
#ifndef _MPZ_H_
|
||||
#define _MPZ_H_
|
||||
|
||||
#include<limits.h>
|
||||
#include<string>
|
||||
#include"util.h"
|
||||
#include"small_object_allocator.h"
|
||||
#include"trace.h"
|
||||
#include"scoped_numeral.h"
|
||||
#include"scoped_numeral_vector.h"
|
||||
#include"z3_omp.h"
|
||||
|
||||
unsigned u_gcd(unsigned u, unsigned v);
|
||||
uint64 u64_gcd(uint64 u, uint64 v);
|
||||
|
||||
#ifdef _MP_GMP
|
||||
typedef unsigned digit_t;
|
||||
#endif
|
||||
|
||||
#ifdef _MSC_VER
|
||||
#pragma warning(disable : 4200)
|
||||
#endif
|
||||
|
||||
template<bool SYNCH> class mpz_manager;
|
||||
template<bool SYNCH> class mpq_manager;
|
||||
|
||||
#if !defined(_MP_GMP) && !defined(_MP_MSBIGNUM) && !defined(_MP_INTERNAL)
|
||||
#ifdef _WINDOWS
|
||||
#define _MP_INTERNAL
|
||||
#else
|
||||
#define _MP_GMP
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#if defined(_MP_MSBIGNUM)
|
||||
typedef size_t digit_t;
|
||||
#elif defined(_MP_INTERNAL)
|
||||
typedef unsigned int digit_t;
|
||||
#endif
|
||||
|
||||
#ifndef _MP_GMP
|
||||
class mpz_cell {
|
||||
unsigned m_size;
|
||||
unsigned m_capacity;
|
||||
digit_t m_digits[0];
|
||||
friend class mpz_manager<true>;
|
||||
friend class mpz_manager<false>;
|
||||
};
|
||||
#else
|
||||
#include<gmp.h>
|
||||
#endif
|
||||
|
||||
/**
|
||||
\brief Multi-precision integer.
|
||||
|
||||
If m_ptr == 0, the it is a small number and the value is stored at m_val.
|
||||
Otherwise, m_val contains the sign (-1 negative, 1 positive), and m_ptr points to a mpz_cell that
|
||||
store the value. <<< This last statement is true only in Windows.
|
||||
*/
|
||||
class mpz {
|
||||
int m_val;
|
||||
#ifndef _MP_GMP
|
||||
mpz_cell * m_ptr;
|
||||
#else
|
||||
mpz_t * m_ptr;
|
||||
#endif
|
||||
friend class mpz_manager<true>;
|
||||
friend class mpz_manager<false>;
|
||||
friend class mpq_manager<true>;
|
||||
friend class mpq_manager<false>;
|
||||
friend class mpq;
|
||||
friend class mpbq;
|
||||
friend class mpbq_manager;
|
||||
mpz & operator=(mpz const & other) { UNREACHABLE(); return *this; }
|
||||
public:
|
||||
mpz(int v):m_val(v), m_ptr(0) {}
|
||||
mpz():m_val(0), m_ptr(0) {}
|
||||
void swap(mpz & other) {
|
||||
std::swap(m_val, other.m_val);
|
||||
std::swap(m_ptr, other.m_ptr);
|
||||
}
|
||||
};
|
||||
|
||||
inline void swap(mpz & m1, mpz & m2) { m1.swap(m2); }
|
||||
|
||||
template<bool SYNCH = true>
|
||||
class mpz_manager {
|
||||
small_object_allocator m_allocator;
|
||||
omp_nest_lock_t m_lock;
|
||||
#define MPZ_BEGIN_CRITICAL() if (SYNCH) omp_set_nest_lock(&m_lock);
|
||||
#define MPZ_END_CRITICAL() if (SYNCH) omp_unset_nest_lock(&m_lock);
|
||||
|
||||
#ifndef _MP_GMP
|
||||
unsigned m_init_cell_capacity;
|
||||
mpz_cell * m_tmp[2];
|
||||
mpz_cell * m_arg[2];
|
||||
mpz m_int_min;
|
||||
|
||||
static unsigned cell_size(unsigned capacity) { return sizeof(mpz_cell) + sizeof(digit_t) * capacity; }
|
||||
|
||||
mpz_cell * allocate(unsigned capacity) {
|
||||
SASSERT(capacity >= m_init_cell_capacity);
|
||||
mpz_cell * cell = reinterpret_cast<mpz_cell *>(m_allocator.allocate(cell_size(capacity)));
|
||||
cell->m_capacity = capacity;
|
||||
return cell;
|
||||
}
|
||||
|
||||
// make sure that n is a big number and has capacity equal to at least c.
|
||||
void allocate_if_needed(mpz & n, unsigned c) {
|
||||
if (c < m_init_cell_capacity)
|
||||
c = m_init_cell_capacity;
|
||||
if (is_small(n)) {
|
||||
n.m_val = 1;
|
||||
n.m_ptr = allocate(c);
|
||||
n.m_ptr->m_capacity = c;
|
||||
}
|
||||
else if (capacity(n) < c) {
|
||||
deallocate(n.m_ptr);
|
||||
n.m_val = 1;
|
||||
n.m_ptr = allocate(c);
|
||||
n.m_ptr->m_capacity = c;
|
||||
}
|
||||
}
|
||||
|
||||
void deallocate(mpz_cell * ptr) {
|
||||
m_allocator.deallocate(cell_size(ptr->m_capacity), ptr);
|
||||
}
|
||||
|
||||
/**
|
||||
\brief Make sure that m_tmp[IDX] can hold the given number of digits
|
||||
*/
|
||||
template<int IDX>
|
||||
void ensure_tmp_capacity(unsigned capacity) {
|
||||
if (m_tmp[IDX]->m_capacity >= capacity)
|
||||
return;
|
||||
deallocate(m_tmp[IDX]);
|
||||
unsigned new_capacity = (3 * capacity + 1) >> 1;
|
||||
m_tmp[IDX] = allocate(new_capacity);
|
||||
SASSERT(m_tmp[IDX]->m_capacity >= capacity);
|
||||
}
|
||||
|
||||
// Expand capacity of a while preserving its content.
|
||||
void ensure_capacity(mpz & a, unsigned sz);
|
||||
|
||||
void normalize(mpz & a);
|
||||
#else
|
||||
// GMP code
|
||||
mpz_t m_tmp, m_tmp2;
|
||||
mpz_t m_two32;
|
||||
mpz_t * m_arg[2];
|
||||
mpz_t m_uint64_max;
|
||||
mpz_t m_int64_max;
|
||||
|
||||
mpz_t * allocate() {
|
||||
mpz_t * cell = reinterpret_cast<mpz_t*>(m_allocator.allocate(sizeof(mpz_t)));
|
||||
mpz_init(*cell);
|
||||
return cell;
|
||||
}
|
||||
|
||||
void deallocate(mpz_t * ptr) { mpz_clear(*ptr); m_allocator.deallocate(sizeof(mpz_t), ptr); }
|
||||
#endif
|
||||
mpz m_two64;
|
||||
|
||||
/**
|
||||
\brief Set \c a with the value stored at m_tmp[IDX], and the given sign.
|
||||
\c sz is an overapproximation of the the size of the number stored at \c tmp.
|
||||
*/
|
||||
template<int IDX>
|
||||
void set(mpz & a, int sign, unsigned sz);
|
||||
|
||||
static int64 i64(mpz const & a) { return static_cast<int64>(a.m_val); }
|
||||
|
||||
void set_big_i64(mpz & c, int64 v);
|
||||
|
||||
void set_i64(mpz & c, int64 v) {
|
||||
if (v >= INT_MIN && v <= INT_MAX) {
|
||||
del(c);
|
||||
c.m_val = static_cast<int>(v);
|
||||
}
|
||||
else {
|
||||
MPZ_BEGIN_CRITICAL();
|
||||
set_big_i64(c, v);
|
||||
MPZ_END_CRITICAL();
|
||||
}
|
||||
}
|
||||
|
||||
void set_big_ui64(mpz & c, uint64 v);
|
||||
|
||||
#ifndef _MP_GMP
|
||||
static unsigned capacity(mpz const & c) { return c.m_ptr->m_capacity; }
|
||||
|
||||
static unsigned size(mpz const & c) { return c.m_ptr->m_size; }
|
||||
|
||||
static digit_t * digits(mpz const & c) { return c.m_ptr->m_digits; }
|
||||
|
||||
template<int IDX>
|
||||
void get_sign_cell(mpz const & a, int & sign, mpz_cell * & cell) {
|
||||
if (is_small(a)) {
|
||||
if (a.m_val == INT_MIN) {
|
||||
sign = -1;
|
||||
cell = m_int_min.m_ptr;
|
||||
}
|
||||
else {
|
||||
cell = m_arg[IDX];
|
||||
SASSERT(cell->m_size == 1);
|
||||
if (a.m_val < 0) {
|
||||
sign = -1;
|
||||
cell->m_digits[0] = -a.m_val;
|
||||
}
|
||||
else {
|
||||
sign = 1;
|
||||
cell->m_digits[0] = a.m_val;
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
sign = a.m_val;
|
||||
cell = a.m_ptr;
|
||||
}
|
||||
}
|
||||
#else
|
||||
// GMP code
|
||||
|
||||
template<int IDX>
|
||||
void get_arg(mpz const & a, mpz_t * & result) {
|
||||
if (is_small(a)) {
|
||||
result = m_arg[IDX];
|
||||
mpz_set_si(*result, a.m_val);
|
||||
}
|
||||
else {
|
||||
result = a.m_ptr;
|
||||
}
|
||||
}
|
||||
|
||||
void mk_big(mpz & a) {
|
||||
if (a.m_ptr == 0)
|
||||
a.m_ptr = allocate();
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifndef _MP_GMP
|
||||
template<bool SUB>
|
||||
void big_add_sub(mpz const & a, mpz const & b, mpz & c);
|
||||
#endif
|
||||
|
||||
void big_add(mpz const & a, mpz const & b, mpz & c);
|
||||
|
||||
void big_sub(mpz const & a, mpz const & b, mpz & c);
|
||||
|
||||
void big_mul(mpz const & a, mpz const & b, mpz & c);
|
||||
|
||||
void big_set(mpz & target, mpz const & source);
|
||||
|
||||
#ifndef _MP_GMP
|
||||
|
||||
#define QUOT_ONLY 0
|
||||
#define REM_ONLY 1
|
||||
#define QUOT_AND_REM 2
|
||||
#define qr_mode int
|
||||
|
||||
template<qr_mode MODE>
|
||||
void quot_rem_core(mpz const & a, mpz const & b, mpz & q, mpz & r);
|
||||
#endif
|
||||
|
||||
void big_div_rem(mpz const & a, mpz const & b, mpz & q, mpz & r);
|
||||
|
||||
void big_div(mpz const & a, mpz const & b, mpz & c);
|
||||
|
||||
void big_rem(mpz const & a, mpz const & b, mpz & c);
|
||||
|
||||
int big_compare(mpz const & a, mpz const & b);
|
||||
|
||||
unsigned size_info(mpz const & a);
|
||||
struct sz_lt;
|
||||
|
||||
public:
|
||||
static bool precise() { return true; }
|
||||
static bool field() { return false; }
|
||||
|
||||
typedef mpz numeral;
|
||||
|
||||
mpz_manager();
|
||||
|
||||
~mpz_manager();
|
||||
|
||||
static bool is_small(mpz const & a) { return a.m_ptr == 0; }
|
||||
|
||||
static mpz mk_z(int val) { return mpz(val); }
|
||||
|
||||
void del(mpz & a) {
|
||||
if (a.m_ptr != 0) {
|
||||
MPZ_BEGIN_CRITICAL();
|
||||
deallocate(a.m_ptr);
|
||||
MPZ_END_CRITICAL();
|
||||
a.m_ptr = 0;
|
||||
}
|
||||
}
|
||||
|
||||
void add(mpz const & a, mpz const & b, mpz & c) {
|
||||
STRACE("mpz", tout << "[mpz] " << to_string(a) << " + " << to_string(b) << " == ";);
|
||||
if (is_small(a) && is_small(b)) {
|
||||
set_i64(c, i64(a) + i64(b));
|
||||
}
|
||||
else {
|
||||
MPZ_BEGIN_CRITICAL();
|
||||
big_add(a, b, c);
|
||||
MPZ_END_CRITICAL();
|
||||
}
|
||||
STRACE("mpz", tout << to_string(c) << "\n";);
|
||||
}
|
||||
|
||||
void sub(mpz const & a, mpz const & b, mpz & c) {
|
||||
STRACE("mpz", tout << "[mpz] " << to_string(a) << " - " << to_string(b) << " == ";);
|
||||
if (is_small(a) && is_small(b)) {
|
||||
set_i64(c, i64(a) - i64(b));
|
||||
}
|
||||
else {
|
||||
MPZ_BEGIN_CRITICAL();
|
||||
big_sub(a, b, c);
|
||||
MPZ_END_CRITICAL();
|
||||
}
|
||||
STRACE("mpz", tout << to_string(c) << "\n";);
|
||||
}
|
||||
|
||||
void inc(mpz & a) { add(a, mpz(1), a); }
|
||||
|
||||
void dec(mpz & a) { add(a, mpz(-1), a); }
|
||||
|
||||
void mul(mpz const & a, mpz const & b, mpz & c) {
|
||||
STRACE("mpz", tout << "[mpz] " << to_string(a) << " * " << to_string(b) << " == ";);
|
||||
if (is_small(a) && is_small(b)) {
|
||||
set_i64(c, i64(a) * i64(b));
|
||||
}
|
||||
else {
|
||||
MPZ_BEGIN_CRITICAL();
|
||||
big_mul(a, b, c);
|
||||
MPZ_END_CRITICAL();
|
||||
}
|
||||
STRACE("mpz", tout << to_string(c) << "\n";);
|
||||
}
|
||||
|
||||
// d <- a + b*c
|
||||
void addmul(mpz const & a, mpz const & b, mpz const & c, mpz & d) {
|
||||
if (is_one(b)) {
|
||||
add(a, c, d);
|
||||
}
|
||||
else if (is_minus_one(b)) {
|
||||
sub(a, c, d);
|
||||
}
|
||||
else {
|
||||
mpz tmp;
|
||||
mul(b,c,tmp);
|
||||
add(a,tmp,d);
|
||||
del(tmp);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// d <- a + b*c
|
||||
void submul(mpz const & a, mpz const & b, mpz const & c, mpz & d) {
|
||||
if (is_one(b)) {
|
||||
sub(a, c, d);
|
||||
}
|
||||
else if (is_minus_one(b)) {
|
||||
add(a, c, d);
|
||||
}
|
||||
else {
|
||||
mpz tmp;
|
||||
mul(b,c,tmp);
|
||||
sub(a,tmp,d);
|
||||
del(tmp);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void machine_div_rem(mpz const & a, mpz const & b, mpz & q, mpz & r) {
|
||||
STRACE("mpz", tout << "[mpz-ext] divrem(" << to_string(a) << ", " << to_string(b) << ") == ";);
|
||||
if (is_small(a) && is_small(b)) {
|
||||
int64 _a = i64(a);
|
||||
int64 _b = i64(b);
|
||||
set_i64(q, _a / _b);
|
||||
set_i64(r, _a % _b);
|
||||
}
|
||||
else {
|
||||
MPZ_BEGIN_CRITICAL();
|
||||
big_div_rem(a, b, q, r);
|
||||
MPZ_END_CRITICAL();
|
||||
}
|
||||
STRACE("mpz", tout << "(" << to_string(q) << ", " << to_string(r) << ")\n";);
|
||||
}
|
||||
|
||||
void machine_div(mpz const & a, mpz const & b, mpz & c) {
|
||||
STRACE("mpz", tout << "[mpz-ext] machine-div(" << to_string(a) << ", " << to_string(b) << ") == ";);
|
||||
if (is_small(a) && is_small(b)) {
|
||||
set_i64(c, i64(a) / i64(b));
|
||||
}
|
||||
else {
|
||||
MPZ_BEGIN_CRITICAL();
|
||||
big_div(a, b, c);
|
||||
MPZ_END_CRITICAL();
|
||||
}
|
||||
STRACE("mpz", tout << to_string(c) << "\n";);
|
||||
}
|
||||
|
||||
void rem(mpz const & a, mpz const & b, mpz & c) {
|
||||
STRACE("mpz", tout << "[mpz-ext] rem(" << to_string(a) << ", " << to_string(b) << ") == ";);
|
||||
if (is_small(a) && is_small(b)) {
|
||||
set_i64(c, i64(a) % i64(b));
|
||||
}
|
||||
else {
|
||||
MPZ_BEGIN_CRITICAL();
|
||||
big_rem(a, b, c);
|
||||
MPZ_END_CRITICAL();
|
||||
}
|
||||
STRACE("mpz", tout << to_string(c) << "\n";);
|
||||
}
|
||||
|
||||
void div(mpz const & a, mpz const & b, mpz & c) {
|
||||
STRACE("mpz", tout << "[mpz-ext] div(" << to_string(a) << ", " << to_string(b) << ") == ";);
|
||||
if (is_neg(a)) {
|
||||
mpz tmp;
|
||||
machine_div_rem(a, b, c, tmp);
|
||||
if (!is_zero(tmp)) {
|
||||
if (is_neg(b))
|
||||
add(c, mk_z(1), c);
|
||||
else
|
||||
sub(c, mk_z(1), c);
|
||||
}
|
||||
del(tmp);
|
||||
}
|
||||
else {
|
||||
machine_div(a, b, c);
|
||||
}
|
||||
STRACE("mpz", tout << to_string(c) << "\n";);
|
||||
}
|
||||
|
||||
void mod(mpz const & a, mpz const & b, mpz & c) {
|
||||
STRACE("mpz", tout << "[mpz-ext] mod(" << to_string(a) << ", " << to_string(b) << ") == ";);
|
||||
rem(a, b, c);
|
||||
if (is_neg(c)) {
|
||||
if (is_pos(b))
|
||||
add(c, b, c);
|
||||
else
|
||||
sub(c, b, c);
|
||||
}
|
||||
STRACE("mpz", tout << to_string(c) << "\n";);
|
||||
}
|
||||
|
||||
void neg(mpz & a) {
|
||||
STRACE("mpz", tout << "[mpz] 0 - " << to_string(a) << " == ";);
|
||||
if (is_small(a) && a.m_val == INT_MIN) {
|
||||
// neg(INT_MIN) is not a small int
|
||||
set_big_i64(a, - static_cast<long long>(INT_MIN));
|
||||
return;
|
||||
}
|
||||
#ifndef _MP_GMP
|
||||
a.m_val = -a.m_val;
|
||||
#else
|
||||
if (is_small(a)) {
|
||||
a.m_val = -a.m_val;
|
||||
}
|
||||
else {
|
||||
mpz_neg(*a.m_ptr, *a.m_ptr);
|
||||
}
|
||||
#endif
|
||||
STRACE("mpz", tout << to_string(a) << "\n";);
|
||||
}
|
||||
|
||||
void abs(mpz & a) {
|
||||
if (is_small(a)) {
|
||||
if (a.m_val < 0) {
|
||||
if (a.m_val == INT_MIN) {
|
||||
// abs(INT_MIN) is not a small int
|
||||
set_big_i64(a, - static_cast<long long>(INT_MIN));
|
||||
}
|
||||
else
|
||||
a.m_val = -a.m_val;
|
||||
}
|
||||
}
|
||||
else {
|
||||
#ifndef _MP_GMP
|
||||
a.m_val = 1;
|
||||
#else
|
||||
mpz_abs(*a.m_ptr, *a.m_ptr);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
static bool is_pos(mpz const & a) {
|
||||
#ifndef _MP_GMP
|
||||
return a.m_val > 0;
|
||||
#else
|
||||
if (is_small(a))
|
||||
return a.m_val > 0;
|
||||
else
|
||||
return mpz_sgn(*a.m_ptr) > 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
static bool is_neg(mpz const & a) {
|
||||
#ifndef _MP_GMP
|
||||
return a.m_val < 0;
|
||||
#else
|
||||
if (is_small(a))
|
||||
return a.m_val < 0;
|
||||
else
|
||||
return mpz_sgn(*a.m_ptr) < 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
static bool is_zero(mpz const & a) {
|
||||
#ifndef _MP_GMP
|
||||
return a.m_val == 0;
|
||||
#else
|
||||
if (is_small(a))
|
||||
return a.m_val == 0;
|
||||
else
|
||||
return mpz_sgn(*a.m_ptr) == 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
static int sign(mpz const & a) {
|
||||
#ifndef _MP_GMP
|
||||
return a.m_val;
|
||||
#else
|
||||
if (is_small(a))
|
||||
return a.m_val;
|
||||
else
|
||||
return mpz_sgn(*a.m_ptr);
|
||||
#endif
|
||||
}
|
||||
|
||||
static bool is_nonpos(mpz const & a) { return !is_pos(a); }
|
||||
|
||||
static bool is_nonneg(mpz const & a) { return !is_neg(a); }
|
||||
|
||||
bool eq(mpz const & a, mpz const & b) {
|
||||
if (is_small(a) && is_small(b)) {
|
||||
return a.m_val == b.m_val;
|
||||
}
|
||||
else {
|
||||
MPZ_BEGIN_CRITICAL();
|
||||
bool res = big_compare(a, b) == 0;
|
||||
MPZ_END_CRITICAL();
|
||||
return res;
|
||||
}
|
||||
}
|
||||
|
||||
bool lt(mpz const & a, mpz const & b) {
|
||||
if (is_small(a) && is_small(b)) {
|
||||
return a.m_val < b.m_val;
|
||||
}
|
||||
else {
|
||||
MPZ_BEGIN_CRITICAL();
|
||||
bool res = big_compare(a, b) < 0;
|
||||
MPZ_END_CRITICAL();
|
||||
return res;
|
||||
}
|
||||
}
|
||||
|
||||
bool neq(mpz const & a, mpz const & b) { return !eq(a, b); }
|
||||
|
||||
bool gt(mpz const & a, mpz const & b) { return lt(b, a); }
|
||||
|
||||
bool ge(mpz const & a, mpz const & b) { return !lt(a, b); }
|
||||
|
||||
bool le(mpz const & a, mpz const & b) { return !lt(b, a); }
|
||||
|
||||
void gcd(mpz const & a, mpz const & b, mpz & c);
|
||||
|
||||
void gcd(unsigned sz, mpz const * as, mpz & g);
|
||||
|
||||
/**
|
||||
\brief Extended Euclid:
|
||||
r1*a + r2*b = g
|
||||
*/
|
||||
void gcd(mpz const & r1, mpz const & r2, mpz & a, mpz & b, mpz & g);
|
||||
|
||||
void lcm(mpz const & a, mpz const & b, mpz & c);
|
||||
|
||||
/**
|
||||
\brief Return true if a | b
|
||||
*/
|
||||
bool divides(mpz const & a, mpz const & b);
|
||||
|
||||
// not a field
|
||||
void inv(mpz & a) {
|
||||
SASSERT(false);
|
||||
}
|
||||
|
||||
void bitwise_or(mpz const & a, mpz const & b, mpz & c);
|
||||
|
||||
void bitwise_and(mpz const & a, mpz const & b, mpz & c);
|
||||
|
||||
void bitwise_xor(mpz const & a, mpz const & b, mpz & c);
|
||||
|
||||
void bitwise_not(unsigned sz, mpz const & a, mpz & c);
|
||||
|
||||
void set(mpz & target, mpz const & source) {
|
||||
if (is_small(source)) {
|
||||
del(target);
|
||||
target.m_val = source.m_val;
|
||||
}
|
||||
else {
|
||||
MPZ_BEGIN_CRITICAL();
|
||||
big_set(target, source);
|
||||
MPZ_END_CRITICAL();
|
||||
}
|
||||
}
|
||||
|
||||
void set(mpz & a, int val) {
|
||||
del(a);
|
||||
a.m_val = val;
|
||||
}
|
||||
|
||||
void set(mpz & a, unsigned val) {
|
||||
if (val <= INT_MAX)
|
||||
set(a, static_cast<int>(val));
|
||||
else
|
||||
set(a, static_cast<int64>(static_cast<uint64>(val)));
|
||||
}
|
||||
|
||||
void set(mpz & a, char const * val);
|
||||
|
||||
void set(mpz & a, int64 val) {
|
||||
set_i64(a, val);
|
||||
}
|
||||
|
||||
void set(mpz & a, uint64 val) {
|
||||
if (val < INT_MAX) {
|
||||
del(a);
|
||||
a.m_val = static_cast<int>(val);
|
||||
}
|
||||
else {
|
||||
MPZ_BEGIN_CRITICAL();
|
||||
set_big_ui64(a, val);
|
||||
MPZ_END_CRITICAL();
|
||||
}
|
||||
}
|
||||
|
||||
void set(mpz & target, unsigned sz, digit_t const * digits);
|
||||
|
||||
void reset(mpz & a) {
|
||||
del(a);
|
||||
a.m_val = 0;
|
||||
}
|
||||
|
||||
void swap(mpz & a, mpz & b) {
|
||||
std::swap(a.m_val, b.m_val);
|
||||
std::swap(a.m_ptr, b.m_ptr);
|
||||
}
|
||||
|
||||
bool is_uint64(mpz const & a) const;
|
||||
|
||||
bool is_int64(mpz const & a) const;
|
||||
|
||||
uint64 get_uint64(mpz const & a) const;
|
||||
|
||||
int64 get_int64(mpz const & a) const;
|
||||
|
||||
double get_double(mpz const & a) const;
|
||||
|
||||
std::string to_string(mpz const & a) const;
|
||||
|
||||
void display(std::ostream & out, mpz const & a) const;
|
||||
|
||||
/**
|
||||
\brief Display mpz number in SMT 2.0 format.
|
||||
If decimal == true, then ".0" is appended.
|
||||
*/
|
||||
void display_smt2(std::ostream & out, mpz const & a, bool decimal) const;
|
||||
|
||||
static unsigned hash(mpz const & a);
|
||||
|
||||
static bool is_one(mpz const & a) {
|
||||
#ifndef _MP_GMP
|
||||
return is_small(a) && a.m_val == 1;
|
||||
#else
|
||||
if (is_small(a))
|
||||
return a.m_val == 1;
|
||||
return mpz_cmp_si(*a.m_ptr, 1) == 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
static bool is_minus_one(mpz const & a) {
|
||||
#ifndef _MP_GMP
|
||||
return is_small(a) && a.m_val == -1;
|
||||
#else
|
||||
if (is_small(a))
|
||||
return a.m_val == -1;
|
||||
return mpz_cmp_si(*a.m_ptr, -1) == 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
void power(mpz const & a, unsigned p, mpz & b);
|
||||
|
||||
bool is_power_of_two(mpz const & a);
|
||||
|
||||
bool is_power_of_two(mpz const & a, unsigned & shift);
|
||||
|
||||
void machine_div2k(mpz & a, unsigned k);
|
||||
|
||||
void machine_div2k(mpz const & a, unsigned k, mpz & r) { set(r, a); machine_div2k(r, k); }
|
||||
|
||||
void mul2k(mpz & a, unsigned k);
|
||||
|
||||
void mul2k(mpz const & a, unsigned k, mpz & r) { set(r, a); mul2k(r, k); }
|
||||
|
||||
/**
|
||||
\brief Return largest k s.t. n is a multiple of 2^k
|
||||
*/
|
||||
unsigned power_of_two_multiple(mpz const & n);
|
||||
|
||||
/**
|
||||
\brief Return the position of the most significant bit.
|
||||
Return 0 if the number is negative
|
||||
*/
|
||||
unsigned log2(mpz const & n);
|
||||
|
||||
/**
|
||||
\brief log2(-n)
|
||||
Return 0 if the number is nonegative
|
||||
*/
|
||||
unsigned mlog2(mpz const & n);
|
||||
|
||||
/**
|
||||
\brief Return the bit-size of n. This method is mainly used for collecting statistics.
|
||||
*/
|
||||
unsigned bitsize(mpz const & n);
|
||||
|
||||
/**
|
||||
\brief Return true if the number is a perfect square, and
|
||||
store the square root in 'root'.
|
||||
If the number n is positive and the result is false, then
|
||||
root will contain the smallest integer r such that r*r > n.
|
||||
*/
|
||||
bool is_perfect_square(mpz const & a, mpz & root);
|
||||
|
||||
/**
|
||||
\brief Return the biggest k s.t. 2^k <= a.
|
||||
|
||||
\remark Return 0 if a is not positive.
|
||||
*/
|
||||
unsigned prev_power_of_two(mpz const & a) { return log2(a); }
|
||||
|
||||
/**
|
||||
\brief Return true if a^{1/n} is an integer, and store the result in a.
|
||||
Otherwise return false, and update a with the smallest
|
||||
integer r such that r*r > n.
|
||||
|
||||
\remark This method assumes that if n is even, then a is nonegative
|
||||
*/
|
||||
bool root(mpz & a, unsigned n);
|
||||
bool root(mpz const & a, unsigned n, mpz & r) { set(r, a); return root(r, n); }
|
||||
|
||||
bool is_even(mpz const & a) {
|
||||
if (is_small(a))
|
||||
return !(a.m_val & 0x1);
|
||||
#ifndef _MP_GMP
|
||||
return !(0x1 & digits(a)[0]);
|
||||
#else
|
||||
return mpz_even_p(*a.m_ptr);
|
||||
#endif
|
||||
}
|
||||
|
||||
bool is_odd(mpz const & n) { return !is_even(n); }
|
||||
|
||||
// Store the digits of n into digits, and return the sign.
|
||||
bool decompose(mpz const & n, svector<digit_t> & digits);
|
||||
};
|
||||
|
||||
typedef mpz_manager<true> synch_mpz_manager;
|
||||
typedef mpz_manager<false> unsynch_mpz_manager;
|
||||
|
||||
typedef _scoped_numeral<unsynch_mpz_manager> scoped_mpz;
|
||||
typedef _scoped_numeral<synch_mpz_manager> scoped_synch_mpz;
|
||||
typedef _scoped_numeral_vector<unsynch_mpz_manager> scoped_mpz_vector;
|
||||
|
||||
#endif /* _MPZ_H_ */
|
||||
|
285
src/util/mpzzp.h
Normal file
285
src/util/mpzzp.h
Normal file
|
@ -0,0 +1,285 @@
|
|||
/*++
|
||||
Copyright (c) 2012 Microsoft Corporation
|
||||
|
||||
Module Name:
|
||||
|
||||
mpzzp.h
|
||||
|
||||
Abstract:
|
||||
|
||||
Combines Z ring, GF(p) finite field, and Z_p ring (when p is not a prime)
|
||||
in a single manager;
|
||||
|
||||
That is, the manager may be dynamically configured
|
||||
to be Z Ring, GF(p), etc.
|
||||
|
||||
Author:
|
||||
|
||||
Leonardo 2012-01-17.
|
||||
|
||||
Revision History:
|
||||
|
||||
This code is based on mpzp.h.
|
||||
In the future, it will replace it.
|
||||
|
||||
--*/
|
||||
#ifndef _MPZZP_H_
|
||||
#define _MPZZP_H_
|
||||
|
||||
#include "mpz.h"
|
||||
|
||||
class mpzzp_manager {
|
||||
typedef unsynch_mpz_manager numeral_manager;
|
||||
numeral_manager & m_manager;
|
||||
|
||||
bool m_z;
|
||||
// instead the usual [0..p) we will keep the numbers in [lower, upper]
|
||||
mpz m_p, m_lower, m_upper;
|
||||
bool m_p_prime;
|
||||
mpz m_inv_tmp1, m_inv_tmp2, m_inv_tmp3;
|
||||
mpz m_div_tmp;
|
||||
|
||||
bool is_p_normalized_core(mpz const & x) const {
|
||||
return m().ge(x, m_lower) && m().le(x, m_upper);
|
||||
}
|
||||
|
||||
void setup_p() {
|
||||
SASSERT(m().is_pos(m_p) && !m().is_one(m_p));
|
||||
bool even = m().is_even(m_p);
|
||||
m().div(m_p, 2, m_upper);
|
||||
m().set(m_lower, m_upper);
|
||||
m().neg(m_lower);
|
||||
if (even) {
|
||||
m().inc(m_lower);
|
||||
}
|
||||
TRACE("mpzzp", tout << "lower: " << m_manager.to_string(m_lower) << ", upper: " << m_manager.to_string(m_upper) << "\n";);
|
||||
}
|
||||
|
||||
void p_normalize_core(mpz & x) {
|
||||
SASSERT(!m_z);
|
||||
m().rem(x, m_p, x);
|
||||
if (m().gt(x, m_upper)) {
|
||||
m().sub(x, m_p, x);
|
||||
} else {
|
||||
if (m().lt(x, m_lower)) {
|
||||
m().add(x, m_p, x);
|
||||
}
|
||||
}
|
||||
SASSERT(is_p_normalized(x));
|
||||
}
|
||||
|
||||
public:
|
||||
typedef mpz numeral;
|
||||
static bool precise() { return true; }
|
||||
bool field() { return !m_z && m_p_prime; }
|
||||
bool finite() const { return !m_z; }
|
||||
bool modular() const { return !m_z; }
|
||||
|
||||
mpzzp_manager(numeral_manager & _m):
|
||||
m_manager(_m),
|
||||
m_z(true) {
|
||||
}
|
||||
|
||||
mpzzp_manager(numeral_manager & _m, mpz const & p, bool prime = true):
|
||||
m_manager(_m),
|
||||
m_z(false) {
|
||||
m().set(m_p, p);
|
||||
setup_p();
|
||||
}
|
||||
|
||||
mpzzp_manager(numeral_manager & _m, uint64 p, bool prime = true):
|
||||
m_manager(_m),
|
||||
m_z(false) {
|
||||
m().set(m_p, p);
|
||||
setup_p();
|
||||
}
|
||||
|
||||
~mpzzp_manager() {
|
||||
m().del(m_p);
|
||||
m().del(m_lower);
|
||||
m().del(m_upper);
|
||||
m().del(m_inv_tmp1);
|
||||
m().del(m_inv_tmp2);
|
||||
m().del(m_inv_tmp3);
|
||||
m().del(m_div_tmp);
|
||||
}
|
||||
|
||||
bool is_p_normalized(mpz const & x) const {
|
||||
return m_z || is_p_normalized_core(x);
|
||||
}
|
||||
|
||||
void p_normalize(mpz & x) {
|
||||
if (!m_z)
|
||||
p_normalize_core(x);
|
||||
SASSERT(is_p_normalized(x));
|
||||
}
|
||||
|
||||
numeral_manager & m() const { return m_manager; }
|
||||
|
||||
mpz const & p() const { return m_p; }
|
||||
|
||||
void set_z() { m_z = true; }
|
||||
void set_zp(mpz const & new_p) { m_z = false; m_p_prime = true; m().set(m_p, new_p); setup_p(); }
|
||||
void set_zp(uint64 new_p) { m_z = false; m_p_prime = true; m().set(m_p, new_p); setup_p(); }
|
||||
// p = p^2
|
||||
void set_p_sq() { SASSERT(!m_z); m_p_prime = false; m().mul(m_p, m_p, m_p); setup_p(); }
|
||||
void set_zp_swap(mpz & new_p) { SASSERT(!m_z); m().swap(m_p, new_p); setup_p(); }
|
||||
|
||||
void reset(mpz & a) { m().reset(a); }
|
||||
bool is_small(mpz const & a) { return m().is_small(a); }
|
||||
void del(mpz & a) { m().del(a); }
|
||||
void neg(mpz & a) { m().neg(a); p_normalize(a); }
|
||||
void abs(mpz & a) { m().abs(a); p_normalize(a); }
|
||||
bool is_zero(mpz const & a) { SASSERT(is_p_normalized(a)); return numeral_manager::is_zero(a); }
|
||||
bool is_one(mpz const & a) { SASSERT(is_p_normalized(a)); return numeral_manager::is_one(a); }
|
||||
bool is_pos(mpz const & a) { SASSERT(is_p_normalized(a)); return numeral_manager::is_pos(a); }
|
||||
bool is_neg(mpz const & a) { SASSERT(is_p_normalized(a)); return numeral_manager::is_neg(a); }
|
||||
bool is_nonpos(mpz const & a) { SASSERT(is_p_normalized(a)); return numeral_manager::is_nonpos(a); }
|
||||
bool is_nonneg(mpz const & a) { SASSERT(is_p_normalized(a)); return numeral_manager::is_nonneg(a); }
|
||||
bool is_minus_one(mpz const & a) { SASSERT(is_p_normalized(a)); return numeral_manager::is_minus_one(a); }
|
||||
bool eq(mpz const & a, mpz const & b) { SASSERT(is_p_normalized(a) && is_p_normalized(b)); return m().eq(a, b); }
|
||||
bool lt(mpz const & a, mpz const & b) { SASSERT(is_p_normalized(a) && is_p_normalized(b)); return m().lt(a, b); }
|
||||
bool le(mpz const & a, mpz const & b) { SASSERT(is_p_normalized(a) && is_p_normalized(b)); return m().le(a, b); }
|
||||
bool gt(mpz const & a, mpz const & b) { SASSERT(is_p_normalized(a) && is_p_normalized(b)); return m().gt(a, b); }
|
||||
bool ge(mpz const & a, mpz const & b) { SASSERT(is_p_normalized(a) && is_p_normalized(b)); return m().ge(a, b); }
|
||||
std::string to_string(mpz const & a) const {
|
||||
SASSERT(is_p_normalized(a));
|
||||
return m().to_string(a);
|
||||
}
|
||||
void display(std::ostream & out, mpz const & a) const { m().display(out, a); }
|
||||
void add(mpz const & a, mpz const & b, mpz & c) { SASSERT(is_p_normalized(a) && is_p_normalized(b)); m().add(a, b, c); p_normalize(c); }
|
||||
void sub(mpz const & a, mpz const & b, mpz & c) { SASSERT(is_p_normalized(a) && is_p_normalized(b)); m().sub(a, b, c); p_normalize(c); }
|
||||
void inc(mpz & a) { SASSERT(is_p_normalized(a)); m().inc(a); p_normalize(a); }
|
||||
void dec(mpz & a) { SASSERT(is_p_normalized(a)); m().dec(a); p_normalize(a); }
|
||||
void mul(mpz const & a, mpz const & b, mpz & c) { SASSERT(is_p_normalized(a) && is_p_normalized(b)); m().mul(a, b, c); p_normalize(c); }
|
||||
void addmul(mpz const & a, mpz const & b, mpz const & c, mpz & d) {
|
||||
SASSERT(is_p_normalized(a) && is_p_normalized(b) && is_p_normalized(c)); m().addmul(a, b, c, d); p_normalize(d);
|
||||
}
|
||||
// d <- a - b*c
|
||||
void submul(mpz const & a, mpz const & b, mpz const & c, mpz & d) {
|
||||
SASSERT(is_p_normalized(a));
|
||||
SASSERT(is_p_normalized(b));
|
||||
SASSERT(is_p_normalized(c));
|
||||
m().submul(a, b, c, d);
|
||||
p_normalize(d);
|
||||
}
|
||||
|
||||
void inv(mpz & a) {
|
||||
if (m_z) {
|
||||
UNREACHABLE();
|
||||
}
|
||||
else {
|
||||
SASSERT(!is_zero(a));
|
||||
// eulers theorem a^(p - 2), but gcd could be more efficient
|
||||
// a*t1 + p*t2 = 1 => a*t1 = 1 (mod p) => t1 is the inverse (t3 == 1)
|
||||
TRACE("mpzp_inv_bug", tout << "a: " << m().to_string(a) << ", p: " << m().to_string(m_p) << "\n";);
|
||||
p_normalize(a);
|
||||
TRACE("mpzp_inv_bug", tout << "after normalization a: " << m().to_string(a) << "\n";);
|
||||
m().gcd(a, m_p, m_inv_tmp1, m_inv_tmp2, m_inv_tmp3);
|
||||
TRACE("mpzp_inv_bug", tout << "tmp1: " << m().to_string(m_inv_tmp1) << "\ntmp2: " << m().to_string(m_inv_tmp2)
|
||||
<< "\ntmp3: " << m().to_string(m_inv_tmp3) << "\n";);
|
||||
p_normalize(m_inv_tmp1);
|
||||
m().swap(a, m_inv_tmp1);
|
||||
SASSERT(m().is_one(m_inv_tmp3)); // otherwise p is not prime and inverse is not defined
|
||||
}
|
||||
}
|
||||
|
||||
void swap(mpz & a, mpz & b) {
|
||||
SASSERT(is_p_normalized(a) && is_p_normalized(b));
|
||||
m().swap(a, b);
|
||||
}
|
||||
|
||||
bool divides(mpz const & a, mpz const & b) { return (field() && !is_zero(a)) || m().divides(a, b); }
|
||||
|
||||
// a/b = a*inv(b)
|
||||
void div(mpz const & a, mpz const & b, mpz & c) {
|
||||
if (m_z) {
|
||||
return m().div(a, b, c);
|
||||
}
|
||||
else {
|
||||
SASSERT(m_p_prime);
|
||||
SASSERT(is_p_normalized(a));
|
||||
m().set(m_div_tmp, b);
|
||||
inv(m_div_tmp);
|
||||
mul(a, m_div_tmp, c);
|
||||
SASSERT(is_p_normalized(c));
|
||||
}
|
||||
}
|
||||
|
||||
static unsigned hash(mpz const & a) { return numeral_manager::hash(a); }
|
||||
|
||||
void gcd(mpz const & a, mpz const & b, mpz & c) {
|
||||
SASSERT(is_p_normalized(a) && is_p_normalized(b));
|
||||
m().gcd(a, b, c);
|
||||
SASSERT(is_p_normalized(c));
|
||||
}
|
||||
|
||||
void gcd(unsigned sz, mpz const * as, mpz & g) {
|
||||
m().gcd(sz, as, g);
|
||||
SASSERT(is_p_normalized(g));
|
||||
}
|
||||
|
||||
void gcd(mpz const & r1, mpz const & r2, mpz & a, mpz & b, mpz & g) {
|
||||
SASSERT(is_p_normalized(r1) && is_p_normalized(r2));
|
||||
m().gcd(r1, r2, a, b, g);
|
||||
p_normalize(a);
|
||||
p_normalize(b);
|
||||
}
|
||||
|
||||
void set(mpz & a, mpz & val) { m().set(a, val); p_normalize(a); }
|
||||
void set(mpz & a, int val) { m().set(a, val); p_normalize(a); }
|
||||
void set(mpz & a, unsigned val) { m().set(a, val); p_normalize(a); }
|
||||
void set(mpz & a, char const * val) { m().set(a, val); p_normalize(a); }
|
||||
void set(mpz & a, int64 val) { m().set(a, val); p_normalize(a); }
|
||||
void set(mpz & a, uint64 val) { m().set(a, val); p_normalize(a); }
|
||||
void set(mpz & a, mpz const & val) { m().set(a, val); p_normalize(a); }
|
||||
|
||||
bool is_uint64(mpz & a) const { const_cast<mpzzp_manager*>(this)->p_normalize(a); return m().is_uint64(a); }
|
||||
bool is_int64(mpz & a) const { const_cast<mpzzp_manager*>(this)->p_normalize(a); return m().is_int64(a); }
|
||||
uint64 get_uint64(mpz & a) const { const_cast<mpzzp_manager*>(this)->p_normalize(a); return m().get_uint64(a); }
|
||||
int64 get_int64(mpz & a) const { const_cast<mpzzp_manager*>(this)->p_normalize(a); return m().get_int64(a); }
|
||||
double get_double(mpz & a) const { const_cast<mpzzp_manager*>(this)->p_normalize(a); return m().get_double(a); }
|
||||
void power(mpz const & a, unsigned k, mpz & b) {
|
||||
SASSERT(is_p_normalized(a));
|
||||
unsigned mask = 1;
|
||||
mpz power;
|
||||
set(power, a);
|
||||
set(b, 1);
|
||||
while (mask <= k) {
|
||||
if (mask & k)
|
||||
mul(b, power, b);
|
||||
mul(power, power, power);
|
||||
mask = mask << 1;
|
||||
}
|
||||
del(power);
|
||||
}
|
||||
bool is_perfect_square(mpz const & a, mpz & root) {
|
||||
if (m_z) {
|
||||
return m().is_perfect_square(a, root);
|
||||
}
|
||||
else {
|
||||
NOT_IMPLEMENTED_YET();
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
bool is_uint64(mpz const & a) const { return m().is_uint64(a); }
|
||||
bool is_int64(mpz const & a) const { return m().is_int64(a); }
|
||||
uint64 get_uint64(mpz const & a) const { return m().get_uint64(a); }
|
||||
int64 get_int64(mpz const & a) const { return m().get_int64(a); }
|
||||
|
||||
void mul2k(mpz & a, unsigned k) { m().mul2k(a, k); p_normalize(a); }
|
||||
void mul2k(mpz const & a, unsigned k, mpz & r) { m().mul2k(a, k, r); p_normalize(r); }
|
||||
unsigned power_of_two_multiple(mpz const & n) { return m().power_of_two_multiple(n); }
|
||||
unsigned log2(mpz const & n) { return m().log2(n); }
|
||||
unsigned mlog2(mpz const & n) { return m().mlog2(n); }
|
||||
void machine_div2k(mpz & a, unsigned k) { m().machine_div2k(a, k); SASSERT(is_p_normalized(a)); }
|
||||
void machine_div2k(mpz const & a, unsigned k, mpz & r) { m().machine_div2k(a, k, r); SASSERT(is_p_normalized(r)); }
|
||||
|
||||
bool root(mpz & a, unsigned n) { SASSERT(!modular()); return m().root(a, n); }
|
||||
bool root(mpz const & a, unsigned n, mpz & r) { SASSERT(!modular()); return m().root(a, n, r); }
|
||||
|
||||
};
|
||||
|
||||
#endif
|
||||
|
88
src/util/nat_set.h
Normal file
88
src/util/nat_set.h
Normal file
|
@ -0,0 +1,88 @@
|
|||
/*++
|
||||
Copyright (c) 2006 Microsoft Corporation
|
||||
|
||||
Module Name:
|
||||
|
||||
nat_set.h
|
||||
|
||||
Abstract:
|
||||
|
||||
Set of natural number with fast reset method.
|
||||
|
||||
Author:
|
||||
|
||||
Leonardo de Moura (leonardo) 2007-03-27.
|
||||
|
||||
Revision History:
|
||||
|
||||
--*/
|
||||
#ifndef _NAT_SET_H_
|
||||
#define _NAT_SET_H_
|
||||
|
||||
#include"vector.h"
|
||||
#include"limits.h"
|
||||
|
||||
class nat_set {
|
||||
unsigned m_curr_timestamp;
|
||||
svector<unsigned> m_timestamps;
|
||||
|
||||
public:
|
||||
nat_set(unsigned s = 0):
|
||||
m_curr_timestamp(0),
|
||||
m_timestamps() {
|
||||
if (s > 0) {
|
||||
m_timestamps.resize(s, 0);
|
||||
}
|
||||
}
|
||||
|
||||
// A nat_set is a function from [0..s-1] -> boolean.
|
||||
// This method sets the domain of this function.
|
||||
void set_domain(unsigned s) {
|
||||
m_timestamps.resize(s, 0);
|
||||
}
|
||||
|
||||
unsigned get_domain() const {
|
||||
return m_timestamps.size();
|
||||
}
|
||||
|
||||
// Assure that v is in the domain of the set.
|
||||
void assure_domain(unsigned v) {
|
||||
if (v >= get_domain()) {
|
||||
set_domain(v+1);
|
||||
}
|
||||
}
|
||||
|
||||
bool contains(unsigned v) const {
|
||||
return m_timestamps[v] > m_curr_timestamp;
|
||||
}
|
||||
|
||||
void insert(unsigned v) {
|
||||
m_timestamps[v] = m_curr_timestamp + 1;
|
||||
}
|
||||
|
||||
void remove(unsigned v) {
|
||||
m_timestamps[v] = m_curr_timestamp;
|
||||
}
|
||||
|
||||
void reset() {
|
||||
m_curr_timestamp++;
|
||||
if (m_curr_timestamp == UINT_MAX) {
|
||||
m_timestamps.fill(0);
|
||||
m_curr_timestamp = 0;
|
||||
}
|
||||
}
|
||||
|
||||
bool empty() const {
|
||||
svector<unsigned>::const_iterator it = m_timestamps.begin();
|
||||
svector<unsigned>::const_iterator end = m_timestamps.end();
|
||||
for (; it != end; ++it) {
|
||||
if (*it > m_curr_timestamp) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
#endif /* _NAT_SET_H_ */
|
||||
|
91
src/util/numeral_buffer.h
Normal file
91
src/util/numeral_buffer.h
Normal file
|
@ -0,0 +1,91 @@
|
|||
/*++
|
||||
Copyright (c) 2011 Microsoft Corporation
|
||||
|
||||
Module Name:
|
||||
|
||||
numeral_buffer.h
|
||||
|
||||
Abstract:
|
||||
|
||||
Basic buffer for managing big nums.
|
||||
|
||||
Author:
|
||||
|
||||
Leonardo de Moura (leonardo) 2011-06-18.
|
||||
|
||||
Revision History:
|
||||
|
||||
--*/
|
||||
#ifndef _NUMERAL_BUFFER_H_
|
||||
#define _NUMERAL_BUFFER_H_
|
||||
|
||||
#include"vector.h"
|
||||
|
||||
template<typename Numeral, typename NumeralManager>
|
||||
class numeral_buffer {
|
||||
NumeralManager & m_manager;
|
||||
svector<Numeral> m_buffer;
|
||||
public:
|
||||
typedef Numeral numeral;
|
||||
typedef Numeral data;
|
||||
typedef NumeralManager manager;
|
||||
|
||||
numeral_buffer(NumeralManager & m):m_manager(m) {}
|
||||
|
||||
~numeral_buffer() {
|
||||
reset();
|
||||
}
|
||||
|
||||
NumeralManager & m() const { return m_manager; }
|
||||
|
||||
unsigned size() const { return m_buffer.size(); }
|
||||
|
||||
bool empty() const { return m_buffer.empty(); }
|
||||
|
||||
void push_back(Numeral const & num) {
|
||||
m_buffer.push_back(Numeral());
|
||||
m().set(m_buffer.back(), num);
|
||||
}
|
||||
|
||||
void pop_back() {
|
||||
m().del(m_buffer.back());
|
||||
m_buffer.pop_back();
|
||||
}
|
||||
|
||||
Numeral & back() {
|
||||
return m_buffer.back();
|
||||
}
|
||||
|
||||
Numeral const & back() const {
|
||||
return m_buffer.back();
|
||||
}
|
||||
|
||||
Numeral const & operator[](unsigned idx) const {
|
||||
return m_buffer[idx];
|
||||
}
|
||||
|
||||
Numeral & operator[](unsigned idx) {
|
||||
return m_buffer[idx];
|
||||
}
|
||||
|
||||
void reset() {
|
||||
typename vector<Numeral>::iterator it = m_buffer.begin();
|
||||
typename vector<Numeral>::iterator end = m_buffer.end();
|
||||
for (; it != end; ++it)
|
||||
m().del(*it);
|
||||
m_buffer.reset();
|
||||
}
|
||||
|
||||
Numeral * c_ptr() { return m_buffer.c_ptr(); }
|
||||
|
||||
void reserve(unsigned sz) {
|
||||
m_buffer.reserve(sz);
|
||||
}
|
||||
|
||||
void swap(svector<Numeral> & other) {
|
||||
m_buffer.swap(other);
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
#endif
|
219
src/util/obj_hashtable.h
Normal file
219
src/util/obj_hashtable.h
Normal file
|
@ -0,0 +1,219 @@
|
|||
/*++
|
||||
Copyright (c) 2006 Microsoft Corporation
|
||||
|
||||
Module Name:
|
||||
|
||||
obj_hashtable.h
|
||||
|
||||
Abstract:
|
||||
|
||||
<abstract>
|
||||
|
||||
Author:
|
||||
|
||||
Leonardo de Moura (leonardo) 2008-02-16.
|
||||
|
||||
Revision History:
|
||||
|
||||
--*/
|
||||
#ifndef _OBJ_HASHTABLE_H_
|
||||
#define _OBJ_HASHTABLE_H_
|
||||
|
||||
#include"hash.h"
|
||||
#include"hashtable.h"
|
||||
|
||||
|
||||
/**
|
||||
\brief Special entry for a hashtable of obj pointers (i.e.,
|
||||
objects that have a hash() method).
|
||||
This entry uses 0x0 and 0x1 to represent HT_FREE and HT_DELETED.
|
||||
*/
|
||||
template<typename T>
|
||||
class obj_hash_entry {
|
||||
T * m_ptr;
|
||||
public:
|
||||
typedef T * data;
|
||||
obj_hash_entry():m_ptr(0) {}
|
||||
unsigned get_hash() const { return m_ptr->hash(); }
|
||||
bool is_free() const { return m_ptr == 0; }
|
||||
bool is_deleted() const { return m_ptr == reinterpret_cast<T *>(1); }
|
||||
bool is_used() const { return m_ptr != reinterpret_cast<T *>(0) && m_ptr != reinterpret_cast<T *>(1); }
|
||||
T * get_data() const { return m_ptr; }
|
||||
T * & get_data() { return m_ptr; }
|
||||
void set_data(T * d) { m_ptr = d; }
|
||||
void set_hash(unsigned h) { SASSERT(h == m_ptr->hash()); }
|
||||
void mark_as_deleted() { m_ptr = reinterpret_cast<T *>(1); }
|
||||
void mark_as_free() { m_ptr = 0; }
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
class obj_hashtable : public core_hashtable<obj_hash_entry<T>, obj_ptr_hash<T>, ptr_eq<T> > {
|
||||
public:
|
||||
obj_hashtable(unsigned initial_capacity = DEFAULT_HASHTABLE_INITIAL_CAPACITY):
|
||||
core_hashtable<obj_hash_entry<T>, obj_ptr_hash<T>, ptr_eq<T> >(initial_capacity) {}
|
||||
};
|
||||
|
||||
template<typename Key, typename Value>
|
||||
class obj_map {
|
||||
public:
|
||||
struct key_data {
|
||||
Key * m_key;
|
||||
Value m_value;
|
||||
key_data():m_key(0) {
|
||||
}
|
||||
key_data(Key * k):
|
||||
m_key(k) {
|
||||
}
|
||||
key_data(Key * k, Value const & v):
|
||||
m_key(k),
|
||||
m_value(v) {
|
||||
}
|
||||
Value const & get_value() const { return m_value; }
|
||||
unsigned hash() const { return m_key->hash(); }
|
||||
bool operator==(key_data const & other) const { return m_key == other.m_key; }
|
||||
};
|
||||
|
||||
class obj_map_entry {
|
||||
key_data m_data;
|
||||
public:
|
||||
typedef key_data data;
|
||||
obj_map_entry() {}
|
||||
unsigned get_hash() const { return m_data.hash(); }
|
||||
bool is_free() const { return m_data.m_key == 0; }
|
||||
bool is_deleted() const { return m_data.m_key == reinterpret_cast<Key *>(1); }
|
||||
bool is_used() const { return m_data.m_key != reinterpret_cast<Key *>(0) && m_data.m_key != reinterpret_cast<Key *>(1); }
|
||||
key_data const & get_data() const { return m_data; }
|
||||
key_data & get_data() { return m_data; }
|
||||
void set_data(key_data const & d) { m_data = d; }
|
||||
void set_hash(unsigned h) { SASSERT(h == m_data.hash()); }
|
||||
void mark_as_deleted() { m_data.m_key = reinterpret_cast<Key *>(1); }
|
||||
void mark_as_free() { m_data.m_key = 0; }
|
||||
};
|
||||
|
||||
typedef core_hashtable<obj_map_entry, obj_hash<key_data>, default_eq<key_data> > table;
|
||||
|
||||
table m_table;
|
||||
|
||||
public:
|
||||
obj_map():
|
||||
m_table(DEFAULT_HASHTABLE_INITIAL_CAPACITY) {}
|
||||
|
||||
typedef typename table::iterator iterator;
|
||||
typedef Key key;
|
||||
typedef Value value;
|
||||
|
||||
void reset() {
|
||||
m_table.reset();
|
||||
}
|
||||
|
||||
void finalize() {
|
||||
m_table.finalize();
|
||||
}
|
||||
|
||||
bool empty() const {
|
||||
return m_table.empty();
|
||||
}
|
||||
|
||||
unsigned size() const {
|
||||
return m_table.size();
|
||||
}
|
||||
|
||||
unsigned capacity() const {
|
||||
return m_table.capacity();
|
||||
}
|
||||
|
||||
iterator begin() const {
|
||||
return m_table.begin();
|
||||
}
|
||||
|
||||
iterator end() const {
|
||||
return m_table.end();
|
||||
}
|
||||
|
||||
void insert(Key * k, Value const & v) {
|
||||
m_table.insert(key_data(k, v));
|
||||
}
|
||||
|
||||
key_data const & insert_if_not_there(Key * k, Value const & v) {
|
||||
return m_table.insert_if_not_there(key_data(k, v));
|
||||
}
|
||||
|
||||
obj_map_entry * insert_if_not_there2(Key * k, Value const & v) {
|
||||
return m_table.insert_if_not_there2(key_data(k, v));
|
||||
}
|
||||
|
||||
obj_map_entry * find_core(Key * k) const {
|
||||
return m_table.find_core(key_data(k));
|
||||
}
|
||||
|
||||
bool find(Key * k, Value & v) const {
|
||||
obj_map_entry * e = find_core(k);
|
||||
if (e) {
|
||||
v = e->get_data().m_value;
|
||||
}
|
||||
return (0 != e);
|
||||
}
|
||||
|
||||
value const & find(key * k) const {
|
||||
obj_map_entry * e = find_core(k);
|
||||
SASSERT(e);
|
||||
return e->get_data().m_value;
|
||||
}
|
||||
|
||||
value & find(key * k) {
|
||||
obj_map_entry * e = find_core(k);
|
||||
SASSERT(e);
|
||||
return e->get_data().m_value;
|
||||
}
|
||||
|
||||
iterator find_iterator(Key * k) const {
|
||||
return m_table.find(key_data(k));
|
||||
}
|
||||
|
||||
bool contains(Key * k) const {
|
||||
return find_core(k) != 0;
|
||||
}
|
||||
|
||||
void remove(Key * k) {
|
||||
m_table.remove(key_data(k));
|
||||
}
|
||||
|
||||
void erase(Key * k) {
|
||||
remove(k);
|
||||
}
|
||||
|
||||
unsigned long long get_num_collision() const { return m_table.get_num_collision(); }
|
||||
|
||||
void swap(obj_map & other) {
|
||||
m_table.swap(other.m_table);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
\brief Reset and deallocate the values stored in a mapping of the form obj_map<Key, Value*>
|
||||
*/
|
||||
template<typename Key, typename Value>
|
||||
void reset_dealloc_values(obj_map<Key, Value*> & m) {
|
||||
typename obj_map<Key, Value*>::iterator it = m.begin();
|
||||
typename obj_map<Key, Value*>::iterator end = m.end();
|
||||
for (; it != end; ++it) {
|
||||
dealloc(it->m_value);
|
||||
}
|
||||
m.reset();
|
||||
}
|
||||
|
||||
/**
|
||||
\brief Remove the key k from the mapping m, and delete the value associated with k.
|
||||
*/
|
||||
template<typename Key, typename Value>
|
||||
void erase_dealloc_value(obj_map<Key, Value*> & m, Key * k) {
|
||||
Value * v = 0;
|
||||
bool contains = m.find(k, v);
|
||||
m.erase(k);
|
||||
if (contains) {
|
||||
dealloc(v);
|
||||
}
|
||||
}
|
||||
|
||||
#endif /* _OBJ_HASHTABLE_H_ */
|
||||
|
53
src/util/obj_mark.h
Normal file
53
src/util/obj_mark.h
Normal file
|
@ -0,0 +1,53 @@
|
|||
/*++
|
||||
Copyright (c) 2006 Microsoft Corporation
|
||||
|
||||
Module Name:
|
||||
|
||||
obj_mark.h
|
||||
|
||||
Abstract:
|
||||
|
||||
A mapping from object to boolean (for objects that can be mapped to unsigned integers).
|
||||
|
||||
Author:
|
||||
|
||||
Leonardo de Moura (leonardo) 2008-01-02.
|
||||
|
||||
Revision History:
|
||||
|
||||
--*/
|
||||
#ifndef _OBJ_MARK_H_
|
||||
#define _OBJ_MARK_H_
|
||||
|
||||
#include"bit_vector.h"
|
||||
|
||||
template<typename T>
|
||||
struct default_t2uint {
|
||||
unsigned operator()(T const & obj) const { return obj.get_id(); }
|
||||
};
|
||||
|
||||
template<typename T, typename BV = bit_vector, typename T2UInt = default_t2uint<T> >
|
||||
class obj_mark {
|
||||
T2UInt m_proc;
|
||||
BV m_marks;
|
||||
public:
|
||||
obj_mark(T2UInt const & p = T2UInt()):m_proc(p) {}
|
||||
bool is_marked(T const & obj) const {
|
||||
unsigned id = m_proc(obj);
|
||||
return id < m_marks.size() && m_marks.get(id);
|
||||
}
|
||||
bool is_marked(T * obj) const { return is_marked(*obj); }
|
||||
void mark(T const & obj, bool flag) {
|
||||
unsigned id = m_proc(obj);
|
||||
if (id >= m_marks.size()) {
|
||||
m_marks.resize(id+1, 0);
|
||||
}
|
||||
m_marks.set(id, flag);
|
||||
}
|
||||
void mark(T const * obj, bool flag) { mark(*obj, flag); }
|
||||
void mark(T const & obj) { mark(obj, true); }
|
||||
void mark(T const * obj) { mark(obj, true); }
|
||||
void reset() { m_marks.reset(); }
|
||||
};
|
||||
|
||||
#endif /* _OBJ_MARK_H_ */
|
174
src/util/obj_pair_hashtable.h
Normal file
174
src/util/obj_pair_hashtable.h
Normal file
|
@ -0,0 +1,174 @@
|
|||
/*++
|
||||
Copyright (c) 2006 Microsoft Corporation
|
||||
|
||||
Module Name:
|
||||
|
||||
obj_pair_hashtable.h
|
||||
|
||||
Abstract:
|
||||
|
||||
<abstract>
|
||||
|
||||
Author:
|
||||
|
||||
Leonardo de Moura (leonardo) 2008-02-19.
|
||||
|
||||
Revision History:
|
||||
|
||||
--*/
|
||||
#ifndef _OBJ_PAIR_HASHTABLE_H_
|
||||
#define _OBJ_PAIR_HASHTABLE_H_
|
||||
|
||||
#include"hash.h"
|
||||
#include"hashtable.h"
|
||||
|
||||
/**
|
||||
\brief Special entry for a hashtable of pairs of obj pointers (i.e.,
|
||||
objects that have a hash() method).
|
||||
This entry uses 0x0 and 0x1 to represent HT_FREE and HT_DELETED.
|
||||
*/
|
||||
template<typename T1, typename T2>
|
||||
class obj_pair_hash_entry {
|
||||
unsigned m_hash; // cached hash code
|
||||
std::pair<T1*, T2*> m_data;
|
||||
|
||||
public:
|
||||
typedef std::pair<T1*, T2*> data;
|
||||
obj_pair_hash_entry():m_data(static_cast<T1*>(0),static_cast<T2*>(0)) {}
|
||||
unsigned get_hash() const { return m_hash; }
|
||||
bool is_free() const { return m_data.first == 0; }
|
||||
bool is_deleted() const { return m_data.first == reinterpret_cast<T1 *>(1); }
|
||||
bool is_used() const { return m_data.first != reinterpret_cast<T1 *>(0) && m_data.first != reinterpret_cast<T1 *>(1); }
|
||||
data const & get_data() const { return m_data; }
|
||||
data & get_data() { return m_data; }
|
||||
void set_data(data const d) { m_data = d; }
|
||||
void set_hash(unsigned h) { m_hash = h; }
|
||||
void mark_as_deleted() { m_data.first = reinterpret_cast<T1 *>(1); }
|
||||
void mark_as_free() { m_data.first = 0; }
|
||||
};
|
||||
|
||||
template<typename T1, typename T2>
|
||||
class obj_pair_hashtable : public core_hashtable<obj_pair_hash_entry<T1, T2>, obj_ptr_pair_hash<T1, T2>, default_eq<std::pair<T1*, T2*> > > {
|
||||
public:
|
||||
obj_pair_hashtable(unsigned initial_capacity = DEFAULT_HASHTABLE_INITIAL_CAPACITY):
|
||||
core_hashtable<obj_pair_hash_entry<T1, T2>, obj_ptr_pair_hash<T1, T2>, default_eq<std::pair<T1*, T2*> > >(initial_capacity) {
|
||||
}
|
||||
};
|
||||
|
||||
template<typename Key1, typename Key2, typename Value>
|
||||
class obj_pair_map {
|
||||
protected:
|
||||
class entry;
|
||||
public:
|
||||
class key_data {
|
||||
Key1 * m_key1;
|
||||
Key2 * m_key2;
|
||||
Value m_value;
|
||||
unsigned m_hash;
|
||||
friend class entry;
|
||||
public:
|
||||
key_data():
|
||||
m_key1(0),
|
||||
m_key2(0),
|
||||
m_hash(0) {
|
||||
}
|
||||
key_data(Key1 * k1, Key2 * k2):
|
||||
m_key1(k1),
|
||||
m_key2(k2) {
|
||||
m_hash = combine_hash(m_key1->hash(), m_key2->hash());
|
||||
}
|
||||
key_data(Key1 * k1, Key2 * k2, const Value & v):
|
||||
m_key1(k1),
|
||||
m_key2(k2),
|
||||
m_value(v) {
|
||||
m_hash = combine_hash(m_key1->hash(), m_key2->hash());
|
||||
}
|
||||
unsigned hash() const { return m_hash; }
|
||||
bool operator==(key_data const & other) const { return m_key1 == other.m_key1 && m_key2 == other.m_key2; }
|
||||
Key1 * get_key1() const { return m_key1; }
|
||||
Key2 * get_key2() const { return m_key2; }
|
||||
Value const & get_value() const { return m_value; }
|
||||
};
|
||||
protected:
|
||||
class entry {
|
||||
key_data m_data;
|
||||
public:
|
||||
typedef key_data data;
|
||||
entry() {}
|
||||
unsigned get_hash() const { return m_data.hash(); }
|
||||
bool is_free() const { return m_data.m_key1 == 0; }
|
||||
bool is_deleted() const { return m_data.m_key1 == reinterpret_cast<Key1 *>(1); }
|
||||
bool is_used() const { return m_data.m_key1 != reinterpret_cast<Key1 *>(0) && m_data.m_key1 != reinterpret_cast<Key1 *>(1); }
|
||||
key_data const & get_data() const { return m_data; }
|
||||
key_data & get_data() { return m_data; }
|
||||
void set_data(key_data const & d) { m_data = d; }
|
||||
void set_hash(unsigned h) { SASSERT(h == m_data.hash()); }
|
||||
void mark_as_deleted() { m_data.m_key1 = reinterpret_cast<Key1 *>(1); }
|
||||
void mark_as_free() { m_data.m_key1 = 0; }
|
||||
};
|
||||
|
||||
typedef core_hashtable<entry, obj_hash<key_data>, default_eq<key_data> > table;
|
||||
|
||||
table m_table;
|
||||
|
||||
entry * find_core(Key1 * k1, Key2 * k2) const {
|
||||
return m_table.find_core(key_data(k1, k2));
|
||||
}
|
||||
|
||||
public:
|
||||
obj_pair_map():
|
||||
m_table(DEFAULT_HASHTABLE_INITIAL_CAPACITY) {}
|
||||
|
||||
typedef typename table::iterator iterator;
|
||||
|
||||
void reset() {
|
||||
m_table.reset();
|
||||
}
|
||||
|
||||
bool empty() const {
|
||||
return m_table.empty();
|
||||
}
|
||||
|
||||
unsigned size() const {
|
||||
return m_table.size();
|
||||
}
|
||||
|
||||
unsigned capacity() const {
|
||||
return m_table.capacity();
|
||||
}
|
||||
|
||||
iterator begin() const {
|
||||
return m_table.begin();
|
||||
}
|
||||
|
||||
iterator end() const {
|
||||
return m_table.end();
|
||||
}
|
||||
|
||||
void insert(Key1 * k1, Key2 * k2, Value const & v) {
|
||||
m_table.insert(key_data(k1, k2, v));
|
||||
}
|
||||
|
||||
key_data const & insert_if_not_there(Key1 * k1, Key2 * k2, Value const & v) {
|
||||
return m_table.insert_if_not_there(key_data(k1, k2, v));
|
||||
}
|
||||
|
||||
bool find(Key1 * k1, Key2 * k2, Value & v) const {
|
||||
entry * e = find_core(k1, k2);
|
||||
if (e) {
|
||||
v = e->get_data().get_value();
|
||||
}
|
||||
return (0 != e);
|
||||
}
|
||||
|
||||
bool contains(Key1 * k1, Key2 * k2) const {
|
||||
return find_core(k1, k2) != 0;
|
||||
}
|
||||
|
||||
void erase(Key1 * k1, Key2 * k2) {
|
||||
m_table.remove(key_data(k1, k2));
|
||||
}
|
||||
};
|
||||
|
||||
#endif /* _OBJ_PAIR_HASHTABLE_H_ */
|
||||
|
50
src/util/obj_pair_set.h
Normal file
50
src/util/obj_pair_set.h
Normal file
|
@ -0,0 +1,50 @@
|
|||
/*++
|
||||
Copyright (c) 2011 Microsoft Corporation
|
||||
|
||||
Module Name:
|
||||
|
||||
obj_pair_set.h
|
||||
|
||||
Abstract:
|
||||
|
||||
<abstract>
|
||||
|
||||
Author:
|
||||
|
||||
Leonardo de Moura (leonardo) 2011-04-19
|
||||
|
||||
Revision History:
|
||||
|
||||
--*/
|
||||
#ifndef _OBJ_PAIR_SET_H_
|
||||
#define _OBJ_PAIR_SET_H_
|
||||
|
||||
#include"chashtable.h"
|
||||
|
||||
template<typename T1, typename T2>
|
||||
class obj_pair_set {
|
||||
public:
|
||||
typedef std::pair<T1*, T2*> obj_pair;
|
||||
protected:
|
||||
struct hash_proc {
|
||||
unsigned operator()(obj_pair const & p) const { return combine_hash(p.first->hash(), p.second->hash()); }
|
||||
};
|
||||
struct eq_proc {
|
||||
bool operator()(obj_pair const & p1, obj_pair const & p2) const { return p1 == p2; }
|
||||
};
|
||||
typedef chashtable<obj_pair, hash_proc, eq_proc> set;
|
||||
set m_set;
|
||||
public:
|
||||
obj_pair_set() {}
|
||||
void insert(T1 * t1, T2 * t2) { m_set.insert(obj_pair(t1, t2)); }
|
||||
void insert(obj_pair const & p) { m_set.insert(p); }
|
||||
bool insert_if_not_there(T1 * t1, T2 * t2) { return m_set.insert_if_not_there2(obj_pair(t1, t2)); }
|
||||
bool insert_if_not_there(obj_pair const & p) { return m_set.insert_if_not_there2(p); }
|
||||
void erase(T1 * t1, T2 * t2) { return m_set.erase(obj_pair(t1, t2)); }
|
||||
void erase(obj_pair const & p) { return m_set.erase(p); }
|
||||
bool contains(T1 * t1, T2 * t2) const { return m_set.contains(obj_pair(t1, t2)); }
|
||||
bool contains(obj_pair const & p) const { return m_set.contains(p); }
|
||||
void reset() { m_set.reset(); }
|
||||
};
|
||||
|
||||
#endif
|
139
src/util/obj_ref.h
Normal file
139
src/util/obj_ref.h
Normal file
|
@ -0,0 +1,139 @@
|
|||
/*++
|
||||
Copyright (c) 2006 Microsoft Corporation
|
||||
|
||||
Module Name:
|
||||
|
||||
obj_ref.h
|
||||
|
||||
Abstract:
|
||||
|
||||
Smart pointer.
|
||||
|
||||
Author:
|
||||
|
||||
Leonardo de Moura (leonardo) 2008-01-03.
|
||||
|
||||
Revision History:
|
||||
|
||||
--*/
|
||||
#ifndef _OBJ_REF_H_
|
||||
#define _OBJ_REF_H_
|
||||
|
||||
/**
|
||||
Smart pointer for T objects.
|
||||
TManager must provide the functions:
|
||||
- void dec_ref(T * obj)
|
||||
- void inc_ref(T * obj)
|
||||
*/
|
||||
template<typename T, typename TManager>
|
||||
class obj_ref {
|
||||
T * m_obj;
|
||||
TManager & m_manager;
|
||||
|
||||
void dec_ref() { if (m_obj) m_manager.dec_ref(m_obj); }
|
||||
void inc_ref() { if (m_obj) m_manager.inc_ref(m_obj); }
|
||||
|
||||
public:
|
||||
typedef TManager manager;
|
||||
|
||||
obj_ref(T * n, TManager & m):
|
||||
m_obj(n),
|
||||
m_manager(m) {
|
||||
inc_ref();
|
||||
}
|
||||
|
||||
explicit obj_ref(TManager & m):
|
||||
m_obj(0),
|
||||
m_manager(m) {
|
||||
}
|
||||
|
||||
obj_ref(obj_ref const & n):
|
||||
m_obj(n.m_obj),
|
||||
m_manager(n.m_manager) {
|
||||
inc_ref();
|
||||
}
|
||||
|
||||
~obj_ref() { dec_ref(); }
|
||||
|
||||
TManager & get_manager() const { return m_manager; }
|
||||
|
||||
TManager & m() const { return m_manager; }
|
||||
|
||||
T * operator->() const { return m_obj; }
|
||||
|
||||
T * get() const { return m_obj; }
|
||||
|
||||
operator bool() const { return m_obj != 0; }
|
||||
|
||||
bool operator!() const { return m_obj == 0; }
|
||||
|
||||
operator T*() const { return m_obj; }
|
||||
|
||||
T const & operator*() const { return *m_obj; }
|
||||
|
||||
obj_ref & operator=(T * n) {
|
||||
if (n) {
|
||||
m_manager.inc_ref(n);
|
||||
}
|
||||
dec_ref();
|
||||
m_obj = n;
|
||||
return *this;
|
||||
}
|
||||
|
||||
obj_ref & operator=(obj_ref & n) {
|
||||
SASSERT(&m_manager == &n.m_manager);
|
||||
n.inc_ref();
|
||||
dec_ref();
|
||||
m_obj = n.m_obj;
|
||||
return *this;
|
||||
}
|
||||
|
||||
void reset() {
|
||||
dec_ref();
|
||||
m_obj = 0;
|
||||
}
|
||||
|
||||
void swap(obj_ref & n) {
|
||||
std::swap(m_obj, n.m_obj);
|
||||
}
|
||||
|
||||
/**
|
||||
\brief Steal ownership without decrementing the reference counter.
|
||||
*/
|
||||
T * steal() {
|
||||
T * r = m_obj;
|
||||
m_obj = 0;
|
||||
return r;
|
||||
}
|
||||
};
|
||||
|
||||
template<typename T, typename TManager>
|
||||
inline bool operator==(obj_ref<T, TManager> const & n1, obj_ref<T, TManager> const & n2) {
|
||||
return n1.get() == n2.get();
|
||||
}
|
||||
|
||||
template<typename T1, typename T2, typename TManager>
|
||||
inline bool operator==(obj_ref<T1, TManager> const & n1, obj_ref<T2, TManager> const & n2) {
|
||||
return n1.get() == n2.get();
|
||||
}
|
||||
|
||||
template<typename T, typename TManager>
|
||||
inline bool operator!=(obj_ref<T, TManager> const & n1, obj_ref<T, TManager> const & n2) {
|
||||
return n1.get() != n2.get();
|
||||
}
|
||||
|
||||
template<typename T1, typename T2, typename TManager>
|
||||
inline bool operator!=(obj_ref<T1, TManager> const & n1, obj_ref<T2, TManager> const & n2) {
|
||||
return n1.get() != n2.get();
|
||||
}
|
||||
|
||||
template<typename IT, typename TManager>
|
||||
inline void dec_range_ref(IT const & begin, IT const & end, TManager & m) {
|
||||
for (IT it = begin; it != end; ++it) {
|
||||
if (*it) {
|
||||
m.dec_ref(*it);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endif /* _OBJ_REF_H_ */
|
180
src/util/obj_triple_hashtable.h
Normal file
180
src/util/obj_triple_hashtable.h
Normal file
|
@ -0,0 +1,180 @@
|
|||
/*++
|
||||
Copyright (c) 2006 Microsoft Corporation
|
||||
|
||||
Module Name:
|
||||
|
||||
obj_triple_hashtable.h
|
||||
|
||||
Abstract:
|
||||
|
||||
<abstract>
|
||||
|
||||
Author:
|
||||
|
||||
Leonardo de Moura (leonardo) 2008-02-19.
|
||||
|
||||
Revision History:
|
||||
|
||||
--*/
|
||||
#ifndef _OBJ_TRIPLE_HASHTABLE_H_
|
||||
#define _OBJ_TRIPLE_HASHTABLE_H_
|
||||
|
||||
#include"hashtable.h"
|
||||
|
||||
/**
|
||||
\brief Special entry for a hashtable of pairs of obj pointers (i.e.,
|
||||
objects that have a hash() method).
|
||||
This entry uses 0x0 and 0x1 to represent HT_FREE and HT_DELETED.
|
||||
*/
|
||||
|
||||
|
||||
template<typename T1, typename T2, typename T3>
|
||||
class obj_triple_hash_entry {
|
||||
unsigned m_hash; // cached hash code
|
||||
triple<T1*, T2*, T3*> m_data;
|
||||
|
||||
public:
|
||||
typedef triple<T1*, T2*, T3*> data;
|
||||
obj_triple_hash_entry():m_data(0,0,0) {}
|
||||
unsigned get_hash() const { return m_hash; }
|
||||
bool is_free() const { return m_data.first == 0; }
|
||||
bool is_deleted() const { return m_data.first == reinterpret_cast<T1 *>(1); }
|
||||
bool is_used() const { return m_data.first != reinterpret_cast<T1 *>(0) && m_data.first != reinterpret_cast<T1 *>(1); }
|
||||
data const & get_data() const { return m_data; }
|
||||
data & get_data() { return m_data; }
|
||||
void set_data(data const d) { m_data = d; }
|
||||
void set_hash(unsigned h) { m_hash = h; }
|
||||
void mark_as_deleted() { m_data.first = reinterpret_cast<T1 *>(1); }
|
||||
void mark_as_free() { m_data.first = 0; }
|
||||
};
|
||||
|
||||
template<typename T1, typename T2, typename T3>
|
||||
class obj_triple_hashtable : public core_hashtable<obj_triple_hash_entry<T1, T2, T3>, obj_ptr_triple_hash<T1, T2, T3>, default_eq<triple<T1*, T2*, T3*> > > {
|
||||
public:
|
||||
obj_triple_hashtable(unsigned initial_capacity = DEFAULT_HASHTABLE_INITIAL_CAPACITY):
|
||||
core_hashtable<obj_triple_hash_entry<T1, T2, T3>, obj_ptr_triple_hash<T1, T2, T3>, default_eq<triple<T1*, T2*, T3*> > >(initial_capacity) {
|
||||
}
|
||||
};
|
||||
|
||||
template<typename Key1, typename Key2, typename Key3, typename Value>
|
||||
class obj_triple_map {
|
||||
protected:
|
||||
class entry;
|
||||
public:
|
||||
class key_data {
|
||||
Key1 * m_key1;
|
||||
Key2 * m_key2;
|
||||
Key3 * m_key3;
|
||||
Value m_value;
|
||||
unsigned m_hash;
|
||||
friend class entry;
|
||||
public:
|
||||
key_data():
|
||||
m_key1(0),
|
||||
m_key2(0),
|
||||
m_key3(0),
|
||||
m_hash(0) {
|
||||
}
|
||||
key_data(Key1 * k1, Key2 * k2, Key3 * k3):
|
||||
m_key1(k1),
|
||||
m_key2(k2),
|
||||
m_key3(k3){
|
||||
m_hash = combine_hash(combine_hash(m_key1->hash(), m_key2->hash()), m_key3->hash());
|
||||
}
|
||||
key_data(Key1 * k1, Key2 * k2, Key3* k3, const Value & v):
|
||||
m_key1(k1),
|
||||
m_key2(k2),
|
||||
m_key3(k3),
|
||||
m_value(v) {
|
||||
m_hash = combine_hash(combine_hash(m_key1->hash(), m_key2->hash()), m_key3->hash());
|
||||
}
|
||||
unsigned hash() const { return m_hash; }
|
||||
bool operator==(key_data const & other) const { return m_key1 == other.m_key1 && m_key2 == other.m_key2 && m_key3 == other.m_key3; }
|
||||
Key1 * get_key1() const { return m_key1; }
|
||||
Key2 * get_key2() const { return m_key2; }
|
||||
Key3 * get_key3() const { return m_key3; }
|
||||
Value const & get_value() const { return m_value; }
|
||||
};
|
||||
protected:
|
||||
class entry {
|
||||
key_data m_data;
|
||||
public:
|
||||
typedef key_data data;
|
||||
entry() {}
|
||||
unsigned get_hash() const { return m_data.hash(); }
|
||||
bool is_free() const { return m_data.m_key1 == 0; }
|
||||
bool is_deleted() const { return m_data.m_key1 == reinterpret_cast<Key1 *>(1); }
|
||||
bool is_used() const { return m_data.m_key1 != reinterpret_cast<Key1 *>(0) && m_data.m_key1 != reinterpret_cast<Key1 *>(1); }
|
||||
key_data const & get_data() const { return m_data; }
|
||||
key_data & get_data() { return m_data; }
|
||||
void set_data(key_data const & d) { m_data = d; }
|
||||
void set_hash(unsigned h) { SASSERT(h == m_data.hash()); }
|
||||
void mark_as_deleted() { m_data.m_key1 = reinterpret_cast<Key1 *>(1); }
|
||||
void mark_as_free() { m_data.m_key1 = 0; }
|
||||
};
|
||||
|
||||
typedef core_hashtable<entry, obj_hash<key_data>, default_eq<key_data> > table;
|
||||
|
||||
table m_table;
|
||||
|
||||
entry * find_core(Key1 * k1, Key2 * k2, Key3 * k3) const {
|
||||
return m_table.find_core(key_data(k1, k2, k3));
|
||||
}
|
||||
|
||||
public:
|
||||
obj_triple_map():
|
||||
m_table(DEFAULT_HASHTABLE_INITIAL_CAPACITY) {}
|
||||
|
||||
typedef typename table::iterator iterator;
|
||||
|
||||
void reset() {
|
||||
m_table.reset();
|
||||
}
|
||||
|
||||
bool empty() const {
|
||||
return m_table.empty();
|
||||
}
|
||||
|
||||
unsigned size() const {
|
||||
return m_table.size();
|
||||
}
|
||||
|
||||
unsigned capacity() const {
|
||||
return m_table.capacity();
|
||||
}
|
||||
|
||||
iterator begin() const {
|
||||
return m_table.begin();
|
||||
}
|
||||
|
||||
iterator end() const {
|
||||
return m_table.end();
|
||||
}
|
||||
|
||||
void insert(Key1 * k1, Key2 * k2, Key3* k3, Value const & v) {
|
||||
m_table.insert(key_data(k1, k2, k3, v));
|
||||
}
|
||||
|
||||
key_data const & insert_if_not_there(Key1 * k1, Key2 * k2, Key3 * k3, Value const & v) {
|
||||
return m_table.insert_if_not_there(key_data(k1, k2, k3, v));
|
||||
}
|
||||
|
||||
bool find(Key1 * k1, Key2 * k2,Key3 * k3, Value & v) const {
|
||||
entry * e = find_core(k1, k2, k3);
|
||||
if (e) {
|
||||
v = e->get_data().get_value();
|
||||
}
|
||||
return (0 != e);
|
||||
}
|
||||
|
||||
bool contains(Key1 * k1, Key2 * k2, Key3 * k3) const {
|
||||
return find_core(k1, k2, k3) != 0;
|
||||
}
|
||||
|
||||
void erase(Key1 * k1, Key2 * k2, Key3 * k3) {
|
||||
m_table.remove(key_data(k1, k2, k3));
|
||||
}
|
||||
};
|
||||
|
||||
#endif /* _OBJ_TRIPLE_HASHTABLE_H_ */
|
||||
|
289
src/util/object_allocator.h
Normal file
289
src/util/object_allocator.h
Normal file
|
@ -0,0 +1,289 @@
|
|||
/*++
|
||||
Copyright (c) 2006 Microsoft Corporation
|
||||
|
||||
Module Name:
|
||||
|
||||
object_allocator.h
|
||||
|
||||
Abstract:
|
||||
|
||||
Yet another object allocator. This allocator is supposed to be efficient
|
||||
when there is a collection of worker threads accessing it.
|
||||
|
||||
Author:
|
||||
|
||||
Leonardo de Moura (leonardo) 2010-06-09.
|
||||
|
||||
Revision History:
|
||||
|
||||
--*/
|
||||
#ifndef _OBJECT_ALLOCATOR_H_
|
||||
#define _OBJECT_ALLOCATOR_H_
|
||||
|
||||
#include"util.h"
|
||||
#include"vector.h"
|
||||
|
||||
#define DEFAULT_NUM_WORKERS 8
|
||||
#define NUM_OBJECTS_PER_PAGE 1024
|
||||
|
||||
template<typename T>
|
||||
struct do_nothing_reset_proc {
|
||||
public:
|
||||
void operator()(T * obj) {}
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
struct simple_reset_proc {
|
||||
public:
|
||||
void operator()(T * obj) { obj->reset(); }
|
||||
};
|
||||
|
||||
/**
|
||||
\brief Allocator for T objects. This allocator is supposed to be efficient even
|
||||
when a collection of working threads are accessing it.
|
||||
|
||||
Assumptions:
|
||||
- T must have an empty constructor.
|
||||
|
||||
- The destructors for T objects are only invoked when the object_allocator is deleted.
|
||||
|
||||
- The destructors are not invoked if CallDestructors == false.
|
||||
|
||||
- The functor ResetProc is invoked for \c ptr when recycle(ptr) or recycle(worker_id, ptr) are invoked.
|
||||
|
||||
The default ResetProc does nothing.
|
||||
*/
|
||||
template<typename T, bool CallDestructors = true, typename ResetProc = do_nothing_reset_proc<T> >
|
||||
class object_allocator : public ResetProc {
|
||||
|
||||
/**
|
||||
\brief Auxiliary allocator for storing object into chunks of memory.
|
||||
*/
|
||||
class region {
|
||||
ptr_vector<T> m_pages;
|
||||
unsigned m_idx; //!< next position in the current page.
|
||||
|
||||
void allocate_new_page() {
|
||||
T * new_page = static_cast<T*>(memory::allocate(sizeof(T) * NUM_OBJECTS_PER_PAGE));
|
||||
m_pages.push_back(new_page);
|
||||
m_idx = 0;
|
||||
}
|
||||
|
||||
void call_destructors_for_page(T * page, unsigned end) {
|
||||
T * page_end = page + end;
|
||||
for (; page < page_end; page++)
|
||||
page->~T();
|
||||
}
|
||||
|
||||
void call_destructors() {
|
||||
if (CallDestructors) {
|
||||
SASSERT(!m_pages.empty());
|
||||
typename ptr_vector<T>::iterator it = m_pages.begin();
|
||||
typename ptr_vector<T>::iterator end = m_pages.end();
|
||||
end--;
|
||||
call_destructors_for_page(*end, m_idx);
|
||||
for (; it != end; ++it)
|
||||
call_destructors_for_page(*it, NUM_OBJECTS_PER_PAGE);
|
||||
}
|
||||
}
|
||||
|
||||
void free_memory() {
|
||||
call_destructors();
|
||||
typename ptr_vector<T>::iterator it = m_pages.begin();
|
||||
typename ptr_vector<T>::iterator end = m_pages.end();
|
||||
for (; it != end; ++it)
|
||||
memory::deallocate(*it);
|
||||
}
|
||||
|
||||
public:
|
||||
region() {
|
||||
allocate_new_page();
|
||||
}
|
||||
|
||||
~region() {
|
||||
free_memory();
|
||||
}
|
||||
|
||||
template<bool construct>
|
||||
T * allocate() {
|
||||
SASSERT(!m_pages.empty());
|
||||
T * r = m_pages.back() + m_idx;
|
||||
if (construct) new (r) T();
|
||||
m_idx++;
|
||||
if (m_idx == NUM_OBJECTS_PER_PAGE)
|
||||
allocate_new_page();
|
||||
return r;
|
||||
}
|
||||
|
||||
void reset() {
|
||||
free_memory();
|
||||
m_pages.reset();
|
||||
allocate_new_page();
|
||||
}
|
||||
|
||||
unsigned get_objects_count() {
|
||||
return (m_pages.size() - 1) * NUM_OBJECTS_PER_PAGE + m_idx;
|
||||
}
|
||||
};
|
||||
|
||||
#ifdef Z3DEBUG
|
||||
bool m_concurrent; //!< True when the allocator can be accessed concurrently.
|
||||
#endif
|
||||
ptr_vector<region> m_regions;
|
||||
vector<ptr_vector<T> > m_free_lists;
|
||||
|
||||
template <bool construct>
|
||||
T * allocate_core(unsigned idx) {
|
||||
ptr_vector<T> & free_list = m_free_lists[idx];
|
||||
if (!free_list.empty()) {
|
||||
T * r = free_list.back();
|
||||
free_list.pop_back();
|
||||
return r;
|
||||
}
|
||||
return m_regions[idx]->allocate<construct>();
|
||||
}
|
||||
|
||||
void recycle_core(unsigned idx, T * ptr) {
|
||||
ResetProc::operator()(ptr);
|
||||
m_free_lists[idx].push_back(ptr);
|
||||
}
|
||||
|
||||
public:
|
||||
object_allocator(ResetProc const & r = ResetProc()):ResetProc(r) {
|
||||
DEBUG_CODE(m_concurrent = false;);
|
||||
reserve(DEFAULT_NUM_WORKERS);
|
||||
}
|
||||
|
||||
~object_allocator() {
|
||||
std::for_each(m_regions.begin(), m_regions.end(), delete_proc<region>());
|
||||
}
|
||||
|
||||
/**
|
||||
\brief Enable/Disable concurrent access.
|
||||
*/
|
||||
void enable_concurrent(bool flag) {
|
||||
DEBUG_CODE(m_concurrent = flag;);
|
||||
}
|
||||
|
||||
/**
|
||||
\brief Make sure that \c num_workers can access this object allocator concurrently.
|
||||
This method must only be invoked if the allocator is not in concurrent mode.
|
||||
*/
|
||||
void reserve(unsigned num_workers) {
|
||||
SASSERT(!m_concurrent);
|
||||
unsigned old_capacity = capacity();
|
||||
if (num_workers > old_capacity) {
|
||||
m_regions.resize(num_workers);
|
||||
m_free_lists.resize(num_workers);
|
||||
for (unsigned i = old_capacity; i < capacity(); i++) {
|
||||
m_regions[i] = alloc(region);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
\brief Return the number of workers supported by this object allocator.
|
||||
*/
|
||||
unsigned capacity() const {
|
||||
return m_regions.size();
|
||||
}
|
||||
|
||||
/**
|
||||
\brief Free all memory allocated using this allocator.
|
||||
This method must only be invoked when the allocator is not in concurrent mode.
|
||||
*/
|
||||
void reset() {
|
||||
SASSERT(!m_concurrent);
|
||||
unsigned c = capacity();
|
||||
for (unsigned i = 0; i < c; i++) {
|
||||
m_regions[i]->reset();
|
||||
m_free_lists[i].reset();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
\brief Allocate a new object.
|
||||
This method must only be invoked when the object_allocator is not in concurrent mode.
|
||||
*/
|
||||
template<bool construct>
|
||||
T * allocate() {
|
||||
SASSERT(!m_concurrent);
|
||||
return allocate_core<construct>(0);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
\brief Recycle the given object.
|
||||
This method must only be invoked when the object_allocator is not in concurrent mode.
|
||||
|
||||
\remark It is OK to recycle an object allocated by a worker when the object_allocator was
|
||||
in concurrent mode.
|
||||
*/
|
||||
void recycle(T * ptr) {
|
||||
SASSERT(!m_concurrent);
|
||||
recycle_core(0, ptr);
|
||||
}
|
||||
|
||||
/**
|
||||
\brief Allocate a new object for the given worker.
|
||||
This method must only be invoked when the object_allocator is in concurrent mode.
|
||||
*/
|
||||
template <bool construct>
|
||||
T * allocate(unsigned worker_id) {
|
||||
SASSERT(m_concurrent);
|
||||
return allocate_core<construct>(worker_id);
|
||||
}
|
||||
|
||||
/**
|
||||
\brief Recycle the given object.
|
||||
This method must only be invoked when the object_allocator is in concurrent mode.
|
||||
|
||||
\remark It is OK to recycle an object allocated by a different worker, or allocated when the
|
||||
object_allocator was not in concurrent mode.
|
||||
*/
|
||||
void recycle(unsigned worker_id, T * ptr) {
|
||||
SASSERT(m_concurrent);
|
||||
return recycle_core(worker_id, ptr);
|
||||
}
|
||||
|
||||
/**
|
||||
\brief Wrapper for currying worker_id in allocate and recycle methods.
|
||||
*/
|
||||
class worker_object_allocator {
|
||||
object_allocator & m_owner;
|
||||
unsigned m_worker_id;
|
||||
|
||||
friend class object_allocator;
|
||||
|
||||
worker_object_allocator(object_allocator & owner, unsigned id):m_owner(owner), m_worker_id(id) {}
|
||||
public:
|
||||
template<bool construct>
|
||||
T * allocate() { return m_owner.allocate<construct>(m_worker_id); }
|
||||
|
||||
void recycle(T * ptr) { return m_owner.recycle(m_worker_id, ptr); }
|
||||
};
|
||||
|
||||
/**
|
||||
\brief Return a wrapper for allocating memory for the given worker.
|
||||
The wrapper remains valid even when the object_allocator is not in concurrent mode.
|
||||
However, the methods allocate/recycle of the wrapper must only be invoked when the object_allocator is in concurrent mode.
|
||||
*/
|
||||
worker_object_allocator get_worker_allocator(unsigned worker_id) {
|
||||
SASSERT(worker_id < capacity());
|
||||
return worker_object_allocator(*this, worker_id);
|
||||
}
|
||||
|
||||
unsigned get_objects_count() const {
|
||||
unsigned count = 0;
|
||||
unsigned n_regions = m_regions.size();
|
||||
for (unsigned i = 0; i < n_regions; i++) {
|
||||
count += m_regions[i]->get_objects_count();
|
||||
count -= m_free_lists[i].size();
|
||||
}
|
||||
return count;
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
#endif /* _OBJECT_ALLOCATOR_H_ */
|
||||
|
642
src/util/old_interval.cpp
Normal file
642
src/util/old_interval.cpp
Normal file
|
@ -0,0 +1,642 @@
|
|||
/*++
|
||||
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 << "]";
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
138
src/util/old_interval.h
Normal file
138
src/util/old_interval.h
Normal file
|
@ -0,0 +1,138 @@
|
|||
/*++
|
||||
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_ */
|
||||
|
165
src/util/optional.h
Normal file
165
src/util/optional.h
Normal file
|
@ -0,0 +1,165 @@
|
|||
/*++
|
||||
Copyright (c) 2006 Microsoft Corporation
|
||||
|
||||
Module Name:
|
||||
|
||||
optional.h
|
||||
|
||||
Abstract:
|
||||
|
||||
Discriminated union of a type T.
|
||||
It defines the notion of initialized/uninitialized objects.
|
||||
|
||||
Author:
|
||||
|
||||
Leonardo de Moura (leonardo) 2006-09-29.
|
||||
|
||||
Revision History:
|
||||
|
||||
--*/
|
||||
|
||||
#ifndef _OPTIONAL_H_
|
||||
#define _OPTIONAL_H_
|
||||
|
||||
template<typename T>
|
||||
class optional {
|
||||
char m_obj[sizeof(T)];
|
||||
char m_initialized;
|
||||
|
||||
void construct(const T & val) {
|
||||
m_initialized = 1;
|
||||
new (reinterpret_cast<void *>(m_obj)) T(val);
|
||||
}
|
||||
|
||||
void destroy() {
|
||||
if (m_initialized == 1) {
|
||||
reinterpret_cast<T *>(m_obj)->~T();
|
||||
}
|
||||
m_initialized = 0;
|
||||
}
|
||||
|
||||
public:
|
||||
optional():
|
||||
m_initialized(0) {}
|
||||
|
||||
explicit optional(const T & val) {
|
||||
construct(val);
|
||||
}
|
||||
|
||||
optional(const optional<T> & val):
|
||||
m_initialized(0) {
|
||||
if (val.m_initialized == 1) {
|
||||
construct(*val);
|
||||
}
|
||||
}
|
||||
|
||||
~optional() {
|
||||
destroy();
|
||||
}
|
||||
|
||||
static optional const & undef() { static optional u; return u; }
|
||||
|
||||
bool initialized() const { return m_initialized == 1; }
|
||||
operator bool() const { return m_initialized == 1; }
|
||||
bool operator!() const { return m_initialized == 0; }
|
||||
|
||||
T * get() const {
|
||||
if (m_initialized == 1) {
|
||||
return reinterpret_cast<T *>(m_obj);
|
||||
}
|
||||
else {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
void set_invalid() {
|
||||
if (m_initialized == 1) {
|
||||
destroy();
|
||||
}
|
||||
}
|
||||
|
||||
T * operator->() {
|
||||
SASSERT(m_initialized==1);
|
||||
return reinterpret_cast<T *>(m_obj);
|
||||
}
|
||||
|
||||
T const * operator->() const {
|
||||
SASSERT(m_initialized==1);
|
||||
return reinterpret_cast<T const *>(m_obj);
|
||||
}
|
||||
|
||||
const T & operator*() const {
|
||||
SASSERT(m_initialized==1);
|
||||
return *reinterpret_cast<T const*>(m_obj);
|
||||
}
|
||||
|
||||
T & operator*() {
|
||||
SASSERT(m_initialized==1);
|
||||
return *reinterpret_cast<T *>(m_obj);
|
||||
}
|
||||
|
||||
optional & operator=(const T & val) {
|
||||
destroy();
|
||||
construct(val);
|
||||
return * this;
|
||||
}
|
||||
|
||||
optional & operator=(const optional & val) {
|
||||
if (&val != this) {
|
||||
destroy();
|
||||
if (val.m_initialized) {
|
||||
construct(*val);
|
||||
}
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
\brief Template specialization for pointers. NULL represents uninitialized pointers.
|
||||
*/
|
||||
template<typename T>
|
||||
class optional<T*> {
|
||||
T * m_ptr;
|
||||
|
||||
static optional m_undef;
|
||||
|
||||
public:
|
||||
|
||||
optional():m_ptr(0) {}
|
||||
|
||||
explicit optional(T * val):m_ptr(val) {}
|
||||
|
||||
optional(const optional & val):m_ptr(val.m_ptr) {}
|
||||
|
||||
static optional const & undef() { return m_undef; }
|
||||
|
||||
bool initialized() const { return m_ptr != 0 ; }
|
||||
|
||||
operator bool() const { return m_ptr != 0; }
|
||||
|
||||
bool operator!() const { return m_ptr == 0; }
|
||||
|
||||
void reset() { m_ptr = 0; }
|
||||
|
||||
optional & operator=(T * val) {
|
||||
m_ptr = val;
|
||||
return *this;
|
||||
}
|
||||
|
||||
optional & operator=(const optional & val) {
|
||||
m_ptr = val.m_ptr;
|
||||
return *this;
|
||||
}
|
||||
|
||||
T ** operator->() { return &m_ptr; }
|
||||
|
||||
T * operator*() const { return m_ptr; }
|
||||
|
||||
T * & operator*() { return m_ptr; }
|
||||
};
|
||||
|
||||
|
||||
#endif /* _OPTIONAL_H_ */
|
||||
|
68
src/util/page.cpp
Normal file
68
src/util/page.cpp
Normal file
|
@ -0,0 +1,68 @@
|
|||
/*++
|
||||
Copyright (c) 2006 Microsoft Corporation
|
||||
|
||||
Module Name:
|
||||
|
||||
page.cpp
|
||||
|
||||
Abstract:
|
||||
|
||||
Goodies for manipulating pages of memory.
|
||||
|
||||
Author:
|
||||
|
||||
Leonardo de Moura (leonardo) 2011-02-27.
|
||||
|
||||
Revision History:
|
||||
|
||||
--*/
|
||||
#include"page.h"
|
||||
#include"debug.h"
|
||||
|
||||
inline void set_page_header(char * page, char * prev, bool default_page) {
|
||||
size_t header = reinterpret_cast<size_t>(prev) | static_cast<size_t>(default_page);
|
||||
reinterpret_cast<size_t *>(page)[-1] = header;
|
||||
SASSERT(is_default_page(page) == default_page);
|
||||
SASSERT(prev_page(page) == prev);
|
||||
}
|
||||
|
||||
inline char * alloc_page(size_t s) { char * r = alloc_svect(char, s+PAGE_HEADER_SZ); return r + PAGE_HEADER_SZ; }
|
||||
|
||||
inline void del_page(char * page) { dealloc_svect(page - PAGE_HEADER_SZ); }
|
||||
|
||||
void del_pages(char * page) {
|
||||
while (page != 0) {
|
||||
char * prev = prev_page(page);
|
||||
del_page(page);
|
||||
page = prev;
|
||||
}
|
||||
}
|
||||
|
||||
char * allocate_default_page(char * prev, char * & free_pages) {
|
||||
char * r;
|
||||
if (free_pages) {
|
||||
r = free_pages;
|
||||
free_pages = prev_page(free_pages);
|
||||
}
|
||||
else {
|
||||
r = alloc_page(DEFAULT_PAGE_SIZE);
|
||||
}
|
||||
set_page_header(r, prev, true);
|
||||
return r;
|
||||
}
|
||||
|
||||
char * allocate_page(char * prev, size_t sz) {
|
||||
char * r = alloc_page(sz);
|
||||
set_page_header(r, prev, false);
|
||||
return r;
|
||||
}
|
||||
|
||||
void recycle_page(char * p, char * & free_pages) {
|
||||
if (is_default_page(p)) {
|
||||
set_page_header(p, free_pages, true);
|
||||
free_pages = p;
|
||||
}
|
||||
else {
|
||||
del_page(p);
|
||||
}
|
||||
}
|
42
src/util/page.h
Normal file
42
src/util/page.h
Normal file
|
@ -0,0 +1,42 @@
|
|||
/*++
|
||||
Copyright (c) 2006 Microsoft Corporation
|
||||
|
||||
Module Name:
|
||||
|
||||
page.h
|
||||
|
||||
Abstract:
|
||||
|
||||
Goodies for manipulating pages of memory.
|
||||
|
||||
Author:
|
||||
|
||||
Leonardo de Moura (leonardo) 2011-02-27.
|
||||
|
||||
Revision History:
|
||||
|
||||
--*/
|
||||
#ifndef _PAGE_H_
|
||||
#define _PAGE_H_
|
||||
|
||||
#include"memory_manager.h"
|
||||
|
||||
#define PAGE_HEADER_SZ sizeof(size_t)
|
||||
#define DEFAULT_PAGE_SIZE (8192 - PAGE_HEADER_SZ)
|
||||
#define PAGE_HEADER_MASK (static_cast<size_t>(-1) - 1)
|
||||
|
||||
inline char * prev_page(char * page) {
|
||||
size_t tagged_ptr = reinterpret_cast<size_t *>(page)[-1];
|
||||
return reinterpret_cast<char *>(tagged_ptr & PAGE_HEADER_MASK);
|
||||
}
|
||||
inline bool is_default_page(char * page) {
|
||||
size_t tagged_ptr = reinterpret_cast<size_t *>(page)[-1];
|
||||
return static_cast<bool>(tagged_ptr & 1);
|
||||
}
|
||||
inline char * end_of_default_page(char * p) { return p + DEFAULT_PAGE_SIZE; }
|
||||
void del_pages(char * page);
|
||||
char * allocate_default_page(char * prev, char * & free_pages);
|
||||
char * allocate_page(char * prev, size_t sz);
|
||||
void recycle_page(char * p, char * & free_pages);
|
||||
|
||||
#endif
|
621
src/util/parray.h
Normal file
621
src/util/parray.h
Normal file
|
@ -0,0 +1,621 @@
|
|||
/*++
|
||||
Copyright (c) 2011 Microsoft Corporation
|
||||
|
||||
Module Name:
|
||||
|
||||
parray.h
|
||||
|
||||
Abstract:
|
||||
|
||||
Persistent Arrays.
|
||||
|
||||
Author:
|
||||
|
||||
Leonardo de Moura (leonardo) 2011-02-21.
|
||||
|
||||
Revision History:
|
||||
|
||||
--*/
|
||||
#ifndef _PARRAY_H_
|
||||
#define _PARRAY_H_
|
||||
|
||||
#include"vector.h"
|
||||
#include"trace.h"
|
||||
|
||||
template<typename C>
|
||||
class parray_manager {
|
||||
public:
|
||||
typedef typename C::value value;
|
||||
typedef typename C::value_manager value_manager;
|
||||
typedef typename C::allocator allocator;
|
||||
private:
|
||||
static size_t capacity(value * vs) {
|
||||
return vs == 0 ? 0 : (reinterpret_cast<size_t*>(vs))[-1];
|
||||
}
|
||||
|
||||
value * allocate_values(size_t c) {
|
||||
size_t * mem = static_cast<size_t*>(m_allocator.allocate(sizeof(value)*c + sizeof(size_t)));
|
||||
*mem = c;
|
||||
++mem;
|
||||
value * r = reinterpret_cast<value*>(mem);
|
||||
SASSERT(capacity(r) == c);
|
||||
TRACE("parray_mem", tout << "allocated values[" << c << "]: " << r << "\n";);
|
||||
return r;
|
||||
}
|
||||
|
||||
void deallocate_values(value * vs) {
|
||||
if (vs == 0)
|
||||
return;
|
||||
size_t c = capacity(vs);
|
||||
TRACE("parray_mem", tout << "deallocated values[" << c << "]: " << vs << "\n";);
|
||||
size_t * mem = reinterpret_cast<size_t*>(vs);
|
||||
--mem;
|
||||
m_allocator.deallocate(sizeof(value)*c + sizeof(size_t), mem);
|
||||
}
|
||||
|
||||
enum ckind { SET, PUSH_BACK, POP_BACK, ROOT };
|
||||
struct cell {
|
||||
unsigned m_ref_count:30;
|
||||
unsigned m_kind:2;
|
||||
union {
|
||||
unsigned m_idx;
|
||||
unsigned m_size;
|
||||
};
|
||||
value m_elem;
|
||||
union {
|
||||
cell * m_next;
|
||||
value * m_values;
|
||||
};
|
||||
|
||||
ckind kind() const { return static_cast<ckind>(m_kind); }
|
||||
|
||||
unsigned idx() const { SASSERT(kind() != ROOT); return m_idx; }
|
||||
unsigned size() const { SASSERT(kind() == ROOT); return m_size; }
|
||||
cell * next() const { SASSERT(kind() != ROOT); return m_next; }
|
||||
value const & elem() const { SASSERT(kind() == SET || kind() == PUSH_BACK); return m_elem; }
|
||||
cell(ckind k):m_ref_count(1), m_kind(k), m_size(0), m_values(0) {}
|
||||
};
|
||||
|
||||
value_manager & m_vmanager;
|
||||
allocator & m_allocator;
|
||||
ptr_vector<cell> m_get_values_tmp;
|
||||
ptr_vector<cell> m_reroot_tmp;
|
||||
|
||||
void inc_ref(value const & v) {
|
||||
if (C::ref_count)
|
||||
m_vmanager.inc_ref(v);
|
||||
}
|
||||
|
||||
void dec_ref(value const & v) {
|
||||
if (C::ref_count)
|
||||
m_vmanager.dec_ref(v);
|
||||
}
|
||||
|
||||
void dec_ref(unsigned sz, value * vs) {
|
||||
if (C::ref_count)
|
||||
for (unsigned i = 0; i < sz; i++)
|
||||
m_vmanager.dec_ref(vs[i]);
|
||||
}
|
||||
|
||||
cell * mk(ckind k) {
|
||||
cell * r = new (m_allocator.allocate(sizeof(cell))) cell(k);
|
||||
TRACE("parray_mem", tout << "allocated cell: " << r << "\n";);
|
||||
return r;
|
||||
}
|
||||
|
||||
void del(cell * c) {
|
||||
while (true) {
|
||||
cell * next = 0;
|
||||
switch (c->kind()) {
|
||||
case SET:
|
||||
case PUSH_BACK:
|
||||
dec_ref(c->elem());
|
||||
next = c->next();
|
||||
break;
|
||||
case POP_BACK:
|
||||
next = c->next();
|
||||
break;
|
||||
case ROOT:
|
||||
dec_ref(c->size(), c->m_values);
|
||||
deallocate_values(c->m_values);
|
||||
break;
|
||||
}
|
||||
TRACE("parray_mem", tout << "deallocated cell: " << c << "\n";);
|
||||
c->~cell();
|
||||
m_allocator.deallocate(sizeof(cell), c);
|
||||
if (next == 0)
|
||||
return;
|
||||
SASSERT(next->m_ref_count > 0);
|
||||
next->m_ref_count--;
|
||||
if (next->m_ref_count > 0)
|
||||
return;
|
||||
c = next;
|
||||
}
|
||||
}
|
||||
|
||||
void inc_ref(cell * c) {
|
||||
if (!c) return;
|
||||
c->m_ref_count++;
|
||||
}
|
||||
|
||||
void dec_ref(cell * c) {
|
||||
if (!c) return;
|
||||
TRACE("parray_mem", tout << "dec_ref(" << c << "), ref_count: " << c->m_ref_count << "\n";);
|
||||
SASSERT(c->m_ref_count > 0);
|
||||
c->m_ref_count--;
|
||||
if (c->m_ref_count == 0)
|
||||
del(c);
|
||||
}
|
||||
|
||||
void expand(value * & vs) {
|
||||
size_t curr_capacity = capacity(vs);
|
||||
size_t new_capacity = curr_capacity == 0 ? 2 : (3 * curr_capacity + 1) >> 1;
|
||||
value * new_vs = allocate_values(new_capacity);
|
||||
if (curr_capacity > 0) {
|
||||
for (size_t i = 0; i < curr_capacity; i++)
|
||||
new_vs[i] = vs[i];
|
||||
deallocate_values(vs);
|
||||
}
|
||||
vs = new_vs;
|
||||
}
|
||||
|
||||
void rset(value * vs, unsigned i, value const & v) {
|
||||
inc_ref(v);
|
||||
dec_ref(vs[i]);
|
||||
vs[i] = v;
|
||||
}
|
||||
|
||||
void rset(cell * c, unsigned i, value const & v) {
|
||||
SASSERT(c->kind() == ROOT);
|
||||
SASSERT(i < c->size());
|
||||
rset(c->m_values, i, v);
|
||||
}
|
||||
|
||||
void rpush_back(value * & vs, unsigned & sz, value const & v) {
|
||||
if (sz == capacity(vs))
|
||||
expand(vs);
|
||||
SASSERT(sz < capacity(vs));
|
||||
inc_ref(v);
|
||||
vs[sz] = v;
|
||||
sz++;
|
||||
}
|
||||
|
||||
void rpush_back(cell * c, value const & v) {
|
||||
SASSERT(c->kind() == ROOT);
|
||||
rpush_back(c->m_values, c->m_size, v);
|
||||
}
|
||||
|
||||
void rpop_back(value * vs, unsigned & sz) {
|
||||
sz--;
|
||||
dec_ref(vs[sz]);
|
||||
}
|
||||
|
||||
void rpop_back(cell * c) {
|
||||
SASSERT(c->kind() == ROOT);
|
||||
rpop_back(c->m_values, c->m_size);
|
||||
}
|
||||
|
||||
void copy_values(value * s, unsigned sz, value * & t) {
|
||||
SASSERT(t == 0);
|
||||
t = allocate_values(capacity(s));
|
||||
for (unsigned i = 0; i < sz; i++) {
|
||||
t[i] = s[i];
|
||||
inc_ref(t[i]);
|
||||
}
|
||||
}
|
||||
|
||||
unsigned get_values(cell * s, value * & vs) {
|
||||
ptr_vector<cell> & cs = m_get_values_tmp;
|
||||
cs.reset();
|
||||
cell * r = s;
|
||||
while (r->kind() != ROOT) {
|
||||
cs.push_back(r);
|
||||
r = r->next();
|
||||
}
|
||||
SASSERT(r->kind() == ROOT);
|
||||
unsigned sz = r->m_size;
|
||||
vs = 0;
|
||||
copy_values(r->m_values, sz, vs);
|
||||
unsigned i = cs.size();
|
||||
while (i > 0) {
|
||||
--i;
|
||||
cell * curr = cs[i];
|
||||
switch (curr->kind()) {
|
||||
case SET:
|
||||
rset(vs, curr->m_idx, curr->m_elem);
|
||||
break;
|
||||
case POP_BACK:
|
||||
rpop_back(vs, sz);
|
||||
break;
|
||||
case PUSH_BACK:
|
||||
rpush_back(vs, sz, curr->m_elem);
|
||||
break;
|
||||
case ROOT:
|
||||
UNREACHABLE();
|
||||
break;
|
||||
}
|
||||
}
|
||||
return sz;
|
||||
}
|
||||
|
||||
void unfold(cell * c) {
|
||||
if (c->kind() == ROOT)
|
||||
return;
|
||||
value * vs;
|
||||
unsigned sz = get_values(c, vs);
|
||||
dec_ref(c->m_next);
|
||||
if (c->kind() == SET || c->kind() == PUSH_BACK)
|
||||
dec_ref(c->m_elem);
|
||||
c->m_next = 0;
|
||||
c->m_kind = ROOT;
|
||||
c->m_size = sz;
|
||||
c->m_values = vs;
|
||||
SASSERT(c->kind() == ROOT);
|
||||
}
|
||||
|
||||
public:
|
||||
class ref {
|
||||
cell * m_ref;
|
||||
unsigned m_updt_counter; // counter for minimizing memory consumption when using preserve_roots option
|
||||
ref(cell * r):m_ref(r), m_updt_counter(0) {}
|
||||
bool root() const { return m_ref->kind() == ROOT; }
|
||||
bool unshared() const { return m_ref->m_ref_count == 1; }
|
||||
friend class parray_manager;
|
||||
public:
|
||||
ref():m_ref(0), m_updt_counter(0) {}
|
||||
};
|
||||
|
||||
public:
|
||||
parray_manager(value_manager & m, allocator & a):
|
||||
m_vmanager(m),
|
||||
m_allocator(a) {
|
||||
}
|
||||
|
||||
value_manager & manager() { return m_vmanager; }
|
||||
|
||||
void mk(ref & r) {
|
||||
dec_ref(r.m_ref);
|
||||
cell * new_c = mk(ROOT);
|
||||
r.m_ref = new_c;
|
||||
r.m_updt_counter = 0;
|
||||
SASSERT(new_c->m_ref_count == 1);
|
||||
}
|
||||
|
||||
void del(ref & r) {
|
||||
dec_ref(r.m_ref);
|
||||
r.m_ref = 0;
|
||||
r.m_updt_counter = 0;
|
||||
}
|
||||
|
||||
void copy(ref const & s, ref & t) {
|
||||
inc_ref(s.m_ref);
|
||||
dec_ref(t.m_ref);
|
||||
t.m_ref = s.m_ref;
|
||||
t.m_updt_counter = 0;
|
||||
}
|
||||
|
||||
unsigned size(ref const & r) const {
|
||||
cell * c = r.m_ref;
|
||||
if (c == 0) return 0;
|
||||
while (true) {
|
||||
switch (c->kind()) {
|
||||
case SET:
|
||||
c = c->next();
|
||||
break;
|
||||
case PUSH_BACK:
|
||||
return c->idx() + 1;
|
||||
case POP_BACK:
|
||||
return c->idx() - 1;
|
||||
case ROOT:
|
||||
return c->size();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool empty(ref const & r) const { return size(r) == 0; }
|
||||
|
||||
value const & get(ref const & r, unsigned i) const {
|
||||
SASSERT(i < size(r));
|
||||
|
||||
unsigned trail_sz = 0;
|
||||
cell * c = r.m_ref;
|
||||
|
||||
while (true) {
|
||||
if (trail_sz > C::max_trail_sz) {
|
||||
const_cast<parray_manager*>(this)->reroot(const_cast<ref&>(r));
|
||||
SASSERT(r.m_ref->kind() == ROOT);
|
||||
return r.m_ref->m_values[i];
|
||||
}
|
||||
switch (c->kind()) {
|
||||
case SET:
|
||||
case PUSH_BACK:
|
||||
if (i == c->idx())
|
||||
return c->elem();
|
||||
trail_sz++;
|
||||
c = c->next();
|
||||
break;
|
||||
case POP_BACK:
|
||||
trail_sz++;
|
||||
c = c->next();
|
||||
break;
|
||||
case ROOT:
|
||||
return c->m_values[i];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void set(ref & r, unsigned i, value const & v) {
|
||||
SASSERT(i < size(r));
|
||||
if (r.root()) {
|
||||
if (r.unshared()) {
|
||||
rset(r.m_ref, i, v);
|
||||
return;
|
||||
}
|
||||
if (C::preserve_roots) {
|
||||
if (r.m_updt_counter > size(r)) {
|
||||
unshare(r);
|
||||
SASSERT(r.unshared());
|
||||
SASSERT(r.m_updt_counter == 0);
|
||||
rset(r.m_ref, i, v);
|
||||
return;
|
||||
}
|
||||
r.m_updt_counter++;
|
||||
cell * c = r.m_ref;
|
||||
cell * new_c = mk(ROOT);
|
||||
new_c->m_size = c->m_size;
|
||||
new_c->m_values = c->m_values;
|
||||
inc_ref(new_c);
|
||||
c->m_kind = SET;
|
||||
c->m_idx = i;
|
||||
c->m_elem = c->m_values[i];
|
||||
inc_ref(c->m_elem);
|
||||
c->m_next = new_c;
|
||||
dec_ref(c);
|
||||
r.m_ref = new_c;
|
||||
rset(new_c, i, v);
|
||||
SASSERT(new_c->m_ref_count == 2);
|
||||
return;
|
||||
}
|
||||
}
|
||||
cell * new_c = mk(SET);
|
||||
new_c->m_idx = i;
|
||||
inc_ref(v);
|
||||
new_c->m_elem = v;
|
||||
new_c->m_next = r.m_ref;
|
||||
r.m_ref = new_c;
|
||||
SASSERT(new_c->m_ref_count == 1);
|
||||
}
|
||||
|
||||
void set(ref const & s, unsigned i, value const & v, ref & r) {
|
||||
SASSERT(i < size(s));
|
||||
if (&s == &r) {
|
||||
set(r, i, v);
|
||||
return;
|
||||
}
|
||||
copy(s, r);
|
||||
set(r, i, v);
|
||||
}
|
||||
|
||||
void push_back(ref & r, value const & v) {
|
||||
if (r.m_ref == 0)
|
||||
mk(r);
|
||||
if (r.root()) {
|
||||
if (r.unshared()) {
|
||||
rpush_back(r.m_ref, v);
|
||||
return;
|
||||
}
|
||||
if (C::preserve_roots) {
|
||||
if (r.m_updt_counter > size(r)) {
|
||||
unshare(r);
|
||||
SASSERT(r.unshared());
|
||||
SASSERT(r.m_updt_counter == 0);
|
||||
rpush_back(r.m_ref, v);
|
||||
return;
|
||||
}
|
||||
r.m_updt_counter++;
|
||||
cell * c = r.m_ref;
|
||||
SASSERT(c->m_ref_count > 1);
|
||||
cell * new_c = mk(ROOT);
|
||||
new_c->m_size = c->m_size;
|
||||
new_c->m_values = c->m_values;
|
||||
inc_ref(new_c);
|
||||
c->m_kind = POP_BACK;
|
||||
c->m_idx = new_c->m_size + 1;
|
||||
c->m_next = new_c;
|
||||
dec_ref(c);
|
||||
r.m_ref = new_c;
|
||||
rpush_back(new_c, v);
|
||||
SASSERT(new_c->m_ref_count == 2);
|
||||
return;
|
||||
}
|
||||
}
|
||||
cell * new_c = mk(PUSH_BACK);
|
||||
new_c->m_idx = size(r.m_ref);
|
||||
inc_ref(v);
|
||||
new_c->m_elem = v;
|
||||
new_c->m_next = r.m_ref;
|
||||
r.m_ref = new_c;
|
||||
SASSERT(new_c->m_ref_count == 1);
|
||||
}
|
||||
|
||||
void push_back(ref const & s, value const & v, ref & r) {
|
||||
if (&s == &r) {
|
||||
push_back(r, v);
|
||||
return;
|
||||
}
|
||||
copy(s, r);
|
||||
push_back(r, v);
|
||||
}
|
||||
|
||||
void pop_back(ref & r) {
|
||||
SASSERT(!empty(r));
|
||||
if (r.root()) {
|
||||
if (r.unshared()) {
|
||||
rpop_back(r.m_ref);
|
||||
return;
|
||||
}
|
||||
if (C::preserve_roots) {
|
||||
if (r.m_updt_counter > size(r)) {
|
||||
unshare(r);
|
||||
SASSERT(r.unshared());
|
||||
SASSERT(r.m_updt_counter == 0);
|
||||
rpop_back(r.m_ref);
|
||||
return;
|
||||
}
|
||||
r.m_updt_counter++;
|
||||
cell * c = r.m_ref;
|
||||
SASSERT(c->m_ref_count > 1);
|
||||
cell * new_c = mk(ROOT);
|
||||
new_c->m_size = c->m_size;
|
||||
new_c->m_values = c->m_values;
|
||||
inc_ref(new_c);
|
||||
c->m_kind = PUSH_BACK;
|
||||
c->m_idx = new_c->m_size - 1;
|
||||
c->m_elem = new_c->m_values[c->m_idx];
|
||||
inc_ref(c->m_elem);
|
||||
c->m_next = new_c;
|
||||
dec_ref(c);
|
||||
r.m_ref = new_c;
|
||||
rpop_back(new_c);
|
||||
SASSERT(new_c->m_ref_count == 2);
|
||||
return;
|
||||
}
|
||||
}
|
||||
cell * new_c = mk(POP_BACK);
|
||||
new_c->m_idx = size(r.m_ref);
|
||||
new_c->m_next = r.m_ref;
|
||||
r.m_ref = new_c;
|
||||
SASSERT(new_c->m_ref_count == 1);
|
||||
}
|
||||
|
||||
void pop_back(ref const & s, ref & r) {
|
||||
SASSERT(!empty(s));
|
||||
if (&s == &r) {
|
||||
pop_back(r);
|
||||
return;
|
||||
}
|
||||
copy(s, r);
|
||||
pop_back(r);
|
||||
}
|
||||
|
||||
void unshare(ref & r) {
|
||||
if (r.root() && r.unshared())
|
||||
return;
|
||||
cell * c = r.m_ref;
|
||||
cell * new_c = mk(ROOT);
|
||||
new_c->m_size = get_values(c, new_c->m_values);
|
||||
SASSERT(new_c->m_ref_count == 1);
|
||||
dec_ref(c);
|
||||
r.m_ref = new_c;
|
||||
r.m_updt_counter = 0;
|
||||
SASSERT(r.root());
|
||||
SASSERT(r.unshared());
|
||||
}
|
||||
|
||||
void unfold(ref & r) {
|
||||
if (r.root())
|
||||
return;
|
||||
unfold(r.m_ref);
|
||||
r.m_updt_counter = 0;
|
||||
SASSERT(r.root());
|
||||
}
|
||||
|
||||
void reroot(ref & r) {
|
||||
if (r.root())
|
||||
return;
|
||||
ptr_vector<cell> & cs = m_reroot_tmp;
|
||||
cs.reset();
|
||||
unsigned r_sz = size(r);
|
||||
unsigned trail_split_idx = r_sz / C::factor;
|
||||
unsigned i = 0;
|
||||
cell * c = r.m_ref;
|
||||
while (c->kind() != ROOT && i < trail_split_idx) {
|
||||
cs.push_back(c);
|
||||
c = c->next();
|
||||
i++;
|
||||
}
|
||||
if (c->kind() != ROOT) {
|
||||
// root is too far away.
|
||||
unfold(c);
|
||||
}
|
||||
SASSERT(c->kind() == ROOT);
|
||||
i = cs.size();
|
||||
while (i > 0) {
|
||||
--i;
|
||||
cell * p = cs[i];
|
||||
SASSERT(c->m_kind == ROOT);
|
||||
unsigned sz = c->m_size;
|
||||
value * vs = c->m_values;
|
||||
SASSERT(p->m_kind != ROOT);
|
||||
SASSERT(p->m_next == c);
|
||||
switch (p->m_kind) {
|
||||
case SET:
|
||||
c->m_kind = SET;
|
||||
c->m_idx = p->m_idx;
|
||||
c->m_elem = vs[c->m_idx];
|
||||
vs[p->m_idx] = p->m_elem;
|
||||
break;
|
||||
case PUSH_BACK:
|
||||
c->m_kind = POP_BACK;
|
||||
if (sz == capacity(vs))
|
||||
expand(vs);
|
||||
c->m_idx = sz;
|
||||
vs[sz] = p->m_elem;
|
||||
sz++;
|
||||
break;
|
||||
case POP_BACK:
|
||||
c->m_kind = PUSH_BACK;
|
||||
--sz;
|
||||
c->m_idx = sz;
|
||||
c->m_elem = vs[sz];
|
||||
break;
|
||||
case ROOT:
|
||||
UNREACHABLE();
|
||||
break;
|
||||
}
|
||||
inc_ref(p);
|
||||
c->m_next = p;
|
||||
// p does not point to c anymore
|
||||
dec_ref(c);
|
||||
p->m_kind = ROOT;
|
||||
p->m_size = sz;
|
||||
p->m_values = vs;
|
||||
c = p;
|
||||
}
|
||||
SASSERT(c == r.m_ref);
|
||||
SASSERT(c->kind() == ROOT);
|
||||
SASSERT(c->m_size == r_sz);
|
||||
r.m_updt_counter = 0;
|
||||
SASSERT(r.root());
|
||||
}
|
||||
|
||||
void display_info(std::ostream & out, ref const & r) {
|
||||
cell * c = r.m_ref;
|
||||
if (c == 0) {
|
||||
out << "<null>";
|
||||
return;
|
||||
}
|
||||
while (true) {
|
||||
out << "cell[" << c << ", ";
|
||||
switch (c->kind()) {
|
||||
case SET: out << "set, " << c->m_idx; break;
|
||||
case PUSH_BACK: out << "push, " << c->m_idx; break;
|
||||
case POP_BACK: out << "pop, " << c->m_idx; break;
|
||||
case ROOT: out << "root, " << c->m_size << ", " << capacity(c->m_values); break;
|
||||
}
|
||||
out << "]#" << c->m_ref_count;
|
||||
if (c->kind() == ROOT)
|
||||
break;
|
||||
out << " -> ";
|
||||
c = c->next();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
struct dummy_value_manager {
|
||||
void inc_ref(T const &) {}
|
||||
void dec_ref(T const &) {}
|
||||
};
|
||||
|
||||
#endif
|
76
src/util/permutation.cpp
Normal file
76
src/util/permutation.cpp
Normal file
|
@ -0,0 +1,76 @@
|
|||
/*++
|
||||
Copyright (c) 2011 Microsoft Corporation
|
||||
|
||||
Module Name:
|
||||
|
||||
permutation.cpp
|
||||
|
||||
Abstract:
|
||||
|
||||
Goodies for managing permutations.
|
||||
|
||||
Author:
|
||||
|
||||
Leonardo de Moura (leonardo) 2011-06-10.
|
||||
|
||||
Revision History:
|
||||
|
||||
--*/
|
||||
#include"permutation.h"
|
||||
|
||||
permutation::permutation(unsigned size) {
|
||||
reset(size);
|
||||
}
|
||||
|
||||
void permutation::reset(unsigned size) {
|
||||
m_p.reset();
|
||||
m_inv_p.reset();
|
||||
for (unsigned i = 0; i < size; i++) {
|
||||
m_p.push_back(i);
|
||||
m_inv_p.push_back(i);
|
||||
}
|
||||
}
|
||||
|
||||
void permutation::swap(unsigned i, unsigned j) {
|
||||
unsigned i_prime = m_p[i];
|
||||
unsigned j_prime = m_p[j];
|
||||
std::swap(m_p[i], m_p[j]);
|
||||
std::swap(m_inv_p[i_prime], m_inv_p[j_prime]);
|
||||
}
|
||||
|
||||
/**
|
||||
\brief Move i after j.
|
||||
*/
|
||||
void permutation::move_after(unsigned i, unsigned j) {
|
||||
if (i >= j)
|
||||
return;
|
||||
unsigned i_prime = m_p[i];
|
||||
for (unsigned k = i; k < j; k++) {
|
||||
m_p[k] = m_p[k+1];
|
||||
m_inv_p[m_p[k]] = k;
|
||||
}
|
||||
m_p[j] = i_prime;
|
||||
m_inv_p[i_prime] = j;
|
||||
SASSERT(check_invariant());
|
||||
}
|
||||
|
||||
void permutation::display(std::ostream & out) const {
|
||||
unsigned n = m_p.size();
|
||||
for (unsigned i = 0; i < n; i++) {
|
||||
if (i > 0)
|
||||
out << " ";
|
||||
out << i << ":" << m_p[i];
|
||||
}
|
||||
}
|
||||
|
||||
bool permutation::check_invariant() const {
|
||||
SASSERT(m_p.size() == m_inv_p.size());
|
||||
unsigned n = m_p.size();
|
||||
for (unsigned i = 0; i < n; i++) {
|
||||
SASSERT(m_p[i] < n);
|
||||
SASSERT(m_inv_p[i] < n);
|
||||
SASSERT(m_p[m_inv_p[i]] == i);
|
||||
SASSERT(m_inv_p[m_p[i]] == i);
|
||||
}
|
||||
return true;
|
||||
}
|
93
src/util/permutation.h
Normal file
93
src/util/permutation.h
Normal file
|
@ -0,0 +1,93 @@
|
|||
/*++
|
||||
Copyright (c) 2011 Microsoft Corporation
|
||||
|
||||
Module Name:
|
||||
|
||||
permutation.h
|
||||
|
||||
Abstract:
|
||||
|
||||
Simple abstraction for managing permutations.
|
||||
|
||||
Author:
|
||||
|
||||
Leonardo de Moura (leonardo) 2011-06-10.
|
||||
|
||||
Revision History:
|
||||
|
||||
--*/
|
||||
#ifndef _PERMUTATION_H_
|
||||
#define _PERMUTATION_H_
|
||||
|
||||
#include<iostream>
|
||||
#include"vector.h"
|
||||
|
||||
class permutation {
|
||||
unsigned_vector m_p;
|
||||
unsigned_vector m_inv_p;
|
||||
public:
|
||||
permutation(unsigned size = 0);
|
||||
void reset(unsigned size = 0);
|
||||
|
||||
unsigned operator()(unsigned i) const { return m_p[i]; }
|
||||
unsigned inv(unsigned i_prime) const { return m_inv_p[i_prime]; }
|
||||
|
||||
void swap(unsigned i, unsigned j);
|
||||
void move_after(unsigned i, unsigned j);
|
||||
|
||||
void display(std::ostream & out) const;
|
||||
bool check_invariant() const;
|
||||
};
|
||||
|
||||
inline std::ostream & operator<<(std::ostream & out, permutation const & p) {
|
||||
p.display(out);
|
||||
return out;
|
||||
}
|
||||
|
||||
/**
|
||||
\brief Apply permutation p to data.
|
||||
The algorithm does not use any extra memory.
|
||||
|
||||
Requirement: swap(T, T) must be available.
|
||||
|
||||
This version will perform destructive updates to p.
|
||||
Use apply_permutation if p must not be preserved
|
||||
*/
|
||||
template<typename T>
|
||||
void apply_permutation_core(unsigned sz, T * data, unsigned * p) {
|
||||
int * p1 = reinterpret_cast<int*>(p);
|
||||
for (int i = 0; i < static_cast<int>(sz); i++) {
|
||||
if (p1[i] < 0)
|
||||
continue; // already processed
|
||||
int j = i;
|
||||
while (true) {
|
||||
SASSERT(j >= 0);
|
||||
int p_j = p1[j];
|
||||
SASSERT(p_j >= 0);
|
||||
SASSERT(p_j < static_cast<int>(sz));
|
||||
p1[j] = - p1[j] - 1; // mark as done
|
||||
if (p_j == i)
|
||||
break; // cycle starting at i is done
|
||||
swap(data[j], data[p_j]);
|
||||
j = p_j;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
\brief Apply permutation p to data.
|
||||
The algorithm does not use any extra memory.
|
||||
|
||||
Requirement: swap(T, T) must be available.
|
||||
*/
|
||||
template<typename T>
|
||||
void apply_permutation(unsigned sz, T * data, unsigned const * p) {
|
||||
apply_permutation_core(sz, data, const_cast<unsigned*>(p));
|
||||
// restore p
|
||||
int * p1 = reinterpret_cast<int*>(const_cast<unsigned*>(p));
|
||||
for (unsigned i = 0; i < sz; i++) {
|
||||
p1[i] = - p1[i] - 1;
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
50
src/util/pool.h
Normal file
50
src/util/pool.h
Normal file
|
@ -0,0 +1,50 @@
|
|||
/*++
|
||||
Copyright (c) 2006 Microsoft Corporation
|
||||
|
||||
Module Name:
|
||||
|
||||
pool.h
|
||||
|
||||
Abstract:
|
||||
|
||||
Object pool.
|
||||
|
||||
Author:
|
||||
|
||||
Leonardo de Moura (leonardo) 2007-02-15.
|
||||
|
||||
Revision History:
|
||||
|
||||
--*/
|
||||
#ifndef _POOL_H_
|
||||
#define _POOL_H_
|
||||
|
||||
#include"util.h"
|
||||
#include"vector.h"
|
||||
|
||||
template<typename T>
|
||||
class pool {
|
||||
ptr_vector<T> m_objs;
|
||||
public:
|
||||
~pool() {
|
||||
std::for_each(m_objs.begin(), m_objs.end(), delete_proc<T>());
|
||||
}
|
||||
|
||||
T * mk() {
|
||||
if (m_objs.empty()) {
|
||||
return alloc(T);
|
||||
}
|
||||
else {
|
||||
T * r = m_objs.back();
|
||||
m_objs.pop_back();
|
||||
return r;
|
||||
}
|
||||
}
|
||||
|
||||
void recycle(T * obj) {
|
||||
m_objs.push_back(obj);
|
||||
}
|
||||
};
|
||||
|
||||
#endif /* _POOL_H_ */
|
||||
|
37
src/util/pop_scopes.h
Normal file
37
src/util/pop_scopes.h
Normal file
|
@ -0,0 +1,37 @@
|
|||
/*++
|
||||
Copyright (c) 2006 Microsoft Corporation
|
||||
|
||||
Module Name:
|
||||
|
||||
pop_scopes.h
|
||||
|
||||
Abstract:
|
||||
|
||||
<abstract>
|
||||
|
||||
Author:
|
||||
|
||||
Leonardo de Moura (leonardo) 2008-06-02.
|
||||
|
||||
Revision History:
|
||||
|
||||
--*/
|
||||
#ifndef _POP_SCOPES_H_
|
||||
#define _POP_SCOPES_H_
|
||||
|
||||
#define POP_SCOPES(_num_scopes, _lim, _trail, _action) \
|
||||
if (_num_scopes > 0) \
|
||||
{ \
|
||||
unsigned scope_lvl = _lim.size(); \
|
||||
unsigned new_lvl = scope_lvl - _num_scopes; \
|
||||
unsigned curr_size = _trail.size(); \
|
||||
unsigned old_size = _lim[new_lvl]; \
|
||||
for (unsigned i = curr_size-1; i >= old_size && i != static_cast<unsigned>(-1); --i) { \
|
||||
_action; \
|
||||
} \
|
||||
_trail.shrink(old_size); \
|
||||
_lim.shrink(new_lvl); \
|
||||
}
|
||||
|
||||
#endif /* _POP_SCOPES_H_ */
|
||||
|
129
src/util/prime_generator.cpp
Normal file
129
src/util/prime_generator.cpp
Normal file
|
@ -0,0 +1,129 @@
|
|||
/*++
|
||||
Copyright (c) 2011 Microsoft Corporation
|
||||
|
||||
Module Name:
|
||||
|
||||
prime_generator.cpp
|
||||
|
||||
Abstract:
|
||||
|
||||
Prime generator
|
||||
|
||||
Author:
|
||||
|
||||
Leonardo (leonardo) 2011-12-23
|
||||
|
||||
Notes:
|
||||
|
||||
--*/
|
||||
#include"prime_generator.h"
|
||||
|
||||
#define PRIME_LIST_MAX_SIZE 1<<20
|
||||
|
||||
prime_generator::prime_generator() {
|
||||
m_primes.push_back(2);
|
||||
m_primes.push_back(3);
|
||||
process_next_k_numbers(128);
|
||||
}
|
||||
|
||||
void prime_generator::process_next_k_numbers(uint64 k) {
|
||||
svector<uint64> todo;
|
||||
uint64 begin = m_primes.back() + 2;
|
||||
uint64 end = begin + k;
|
||||
for (uint64 i = begin; i < end; i+=2) {
|
||||
todo.push_back(i);
|
||||
}
|
||||
unsigned j = 1;
|
||||
SASSERT(m_primes[j] == 3);
|
||||
while (!todo.empty()) {
|
||||
unsigned sz = m_primes.size();
|
||||
for (; j < sz; j++) {
|
||||
uint64 p = m_primes[j];
|
||||
unsigned todo_sz = todo.size();
|
||||
unsigned k1 = 0;
|
||||
unsigned k2 = 0;
|
||||
for (; k1 < todo_sz; k1++) {
|
||||
if (todo[k1] % p == 0)
|
||||
continue;
|
||||
todo[k2] = todo[k1];
|
||||
k2++;
|
||||
}
|
||||
todo.shrink(k2);
|
||||
if (k2 == 0)
|
||||
return;
|
||||
if (p > (todo[k2-1] / p) + 1) {
|
||||
// all numbers in todo are primes
|
||||
for (unsigned k1 = 0; k1 < k2; k1++) {
|
||||
m_primes.push_back(todo[k1]);
|
||||
}
|
||||
return;
|
||||
}
|
||||
}
|
||||
uint64 p = m_primes.back();
|
||||
p = p*p;
|
||||
unsigned todo_sz = todo.size();
|
||||
unsigned k1 = 0;
|
||||
for (k1 = 0; k1 < todo_sz; k1++) {
|
||||
if (todo[k1] < p) {
|
||||
m_primes.push_back(todo[k1]);
|
||||
}
|
||||
break;
|
||||
}
|
||||
unsigned k2 = 0;
|
||||
for (; k1 < todo_sz; k1++, k2++) {
|
||||
todo[k2] = todo[k1];
|
||||
}
|
||||
todo.shrink(k2);
|
||||
}
|
||||
}
|
||||
|
||||
void prime_generator::finalize() {
|
||||
m_primes.finalize();
|
||||
}
|
||||
|
||||
uint64 prime_generator::operator()(unsigned idx) {
|
||||
if (idx < m_primes.size())
|
||||
return m_primes[idx];
|
||||
if (idx > PRIME_LIST_MAX_SIZE)
|
||||
throw prime_generator_exception("prime generator capacity exceeded");
|
||||
process_next_k_numbers(1024);
|
||||
if (idx < m_primes.size())
|
||||
return m_primes[idx];
|
||||
while (idx <= m_primes.size())
|
||||
process_next_k_numbers(1024*16);
|
||||
return m_primes[idx];
|
||||
}
|
||||
|
||||
prime_generator g_prime_generator;
|
||||
|
||||
prime_iterator::prime_iterator(prime_generator * g):m_idx(0) {
|
||||
if (g == 0) {
|
||||
m_generator = &g_prime_generator;
|
||||
m_global = true;
|
||||
}
|
||||
else {
|
||||
m_generator = g;
|
||||
m_global = false;
|
||||
}
|
||||
}
|
||||
|
||||
uint64 prime_iterator::next() {
|
||||
unsigned idx = m_idx;
|
||||
m_idx++;
|
||||
if (!m_global) {
|
||||
return (*m_generator)(idx);
|
||||
}
|
||||
else {
|
||||
uint64 r;
|
||||
#pragma omp critical (prime_iterator)
|
||||
{
|
||||
r = (*m_generator)(idx);
|
||||
}
|
||||
return r;
|
||||
}
|
||||
}
|
||||
|
||||
void prime_iterator::finalize() {
|
||||
g_prime_generator.finalize();
|
||||
}
|
||||
|
53
src/util/prime_generator.h
Normal file
53
src/util/prime_generator.h
Normal file
|
@ -0,0 +1,53 @@
|
|||
/*++
|
||||
Copyright (c) 2011 Microsoft Corporation
|
||||
|
||||
Module Name:
|
||||
|
||||
prime_generator.h
|
||||
|
||||
Abstract:
|
||||
|
||||
Prime generator
|
||||
|
||||
Author:
|
||||
|
||||
Leonardo (leonardo) 2011-12-23
|
||||
|
||||
Notes:
|
||||
|
||||
--*/
|
||||
#ifndef _PRIME_GENERATOR_H_
|
||||
#define _PRIME_GENERATOR_H_
|
||||
|
||||
#include"vector.h"
|
||||
#include"z3_exception.h"
|
||||
#include"util.h"
|
||||
|
||||
class prime_generator_exception : public default_exception {
|
||||
public:
|
||||
prime_generator_exception(char const * msg):default_exception(msg) {}
|
||||
};
|
||||
|
||||
/**
|
||||
\brief Prime generator
|
||||
*/
|
||||
class prime_generator {
|
||||
svector<uint64> m_primes;
|
||||
void process_next_k_numbers(uint64 k);
|
||||
public:
|
||||
prime_generator();
|
||||
uint64 operator()(unsigned idx);
|
||||
void finalize();
|
||||
};
|
||||
|
||||
class prime_iterator {
|
||||
unsigned m_idx;
|
||||
prime_generator * m_generator;
|
||||
bool m_global;
|
||||
public:
|
||||
prime_iterator(prime_generator * g = 0);
|
||||
uint64 next();
|
||||
static void finalize();
|
||||
};
|
||||
|
||||
#endif
|
56
src/util/ptr_scoped_buffer.h
Normal file
56
src/util/ptr_scoped_buffer.h
Normal file
|
@ -0,0 +1,56 @@
|
|||
/*++
|
||||
Copyright (c) 2011 Microsoft Corporation
|
||||
|
||||
Module Name:
|
||||
|
||||
ptr_scoped_buffer.h
|
||||
|
||||
Abstract:
|
||||
|
||||
<abstract>
|
||||
|
||||
Author:
|
||||
|
||||
Leonardo de Moura (leonardo) 2011-03-03.
|
||||
|
||||
Revision History:
|
||||
|
||||
--*/
|
||||
#ifndef _PTR_SCOPED_BUFFER_H_
|
||||
#define _PTR_SCOPED_BUFFER_H_
|
||||
|
||||
#include"util.h"
|
||||
#include"debug.h"
|
||||
#include"buffer.h"
|
||||
|
||||
template<typename T, unsigned INITIAL_SIZE=16, typename D = delete_proc<T> >
|
||||
class ptr_scoped_buffer : private ptr_buffer<T, INITIAL_SIZE> {
|
||||
D m_deallocator;
|
||||
void deallocate_all() {
|
||||
typename ptr_buffer<T, INITIAL_SIZE>::iterator it = ptr_buffer<T, INITIAL_SIZE>::begin();
|
||||
typename ptr_buffer<T, INITIAL_SIZE>::iterator end = ptr_buffer<T, INITIAL_SIZE>::end();
|
||||
for (; it != end; ++it)
|
||||
m_deallocator(*it);
|
||||
}
|
||||
public:
|
||||
typedef typename ptr_buffer<T, INITIAL_SIZE>::const_iterator const_iterator;
|
||||
ptr_scoped_buffer(D const & m = D()):ptr_buffer<T, INITIAL_SIZE>(), m_deallocator(m) {}
|
||||
~ptr_scoped_buffer() { deallocate_all(); }
|
||||
void reset() { deallocate_all(); ptr_buffer<T, INITIAL_SIZE>::reset(); }
|
||||
void finalize() { deallocate_all(); ptr_buffer<T, INITIAL_SIZE>::finalize(); }
|
||||
/** \brief Release ownership of the pointers stored in the buffer */
|
||||
void release() { ptr_buffer<T, INITIAL_SIZE>::reset(); }
|
||||
unsigned size() const { return ptr_buffer<T, INITIAL_SIZE>::size(); }
|
||||
bool empty() const { return ptr_buffer<T, INITIAL_SIZE>::empty(); }
|
||||
const_iterator begin() const { return ptr_buffer<T, INITIAL_SIZE>::begin(); }
|
||||
const_iterator end() const { return ptr_buffer<T, INITIAL_SIZE>::end(); }
|
||||
void push_back(T * elem) { return ptr_buffer<T, INITIAL_SIZE>::push_back(elem); }
|
||||
T * back() const { return ptr_buffer<T, INITIAL_SIZE>::back(); }
|
||||
void pop_back() { m_deallocator(back()); ptr_buffer<T, INITIAL_SIZE>::pop_back(); }
|
||||
T * get(unsigned idx) const { return ptr_buffer<T, INITIAL_SIZE>::get(idx); }
|
||||
void set(unsigned idx, T * e) { T * old_e = get(idx); if (e != old_e) m_deallocator(old_e); ptr_buffer<T, INITIAL_SIZE>::set(idx, e); }
|
||||
void append(unsigned n, T * const * elems) { ptr_buffer<T, INITIAL_SIZE>::append(n, elems); }
|
||||
};
|
||||
|
||||
#endif
|
||||
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Add a link
Reference in a new issue