/*++ 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 #include"debug.h" enum ext_numeral_kind { EN_MINUS_INFINITY, EN_NUMERAL, EN_PLUS_INFINITY }; template 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 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 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 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 void reset(numeral_manager & m, typename numeral_manager::numeral & a, ext_numeral_kind & ak) { m.reset(a); ak = EN_NUMERAL; } template 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 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 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 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 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 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 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 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 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 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 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 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 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 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