z3-z3-4.13.0.src.api.api_numeral.cpp Maven / Gradle / Ivy
The newest version!
/*++
Copyright (c) 2012 Microsoft Corporation
Module Name:
api_numeral.cpp
Abstract:
API for handling numerals in Z3
Author:
Leonardo de Moura (leonardo) 2012-02-29.
Revision History:
--*/
#include
#include "api/z3.h"
#include "api/api_log_macros.h"
#include "api/api_context.h"
#include "api/api_util.h"
#include "ast/arith_decl_plugin.h"
#include "ast/bv_decl_plugin.h"
#include "math/polynomial/algebraic_numbers.h"
#include "ast/fpa_decl_plugin.h"
bool is_numeral_sort(Z3_context c, Z3_sort ty) {
if (!ty) return false;
sort * _ty = to_sort(ty);
family_id fid = _ty->get_family_id();
return
fid == mk_c(c)->get_arith_fid() ||
fid == mk_c(c)->get_bv_fid() ||
fid == mk_c(c)->get_datalog_fid() ||
fid == mk_c(c)->get_fpa_fid();
}
static bool check_numeral_sort(Z3_context c, Z3_sort ty) {
bool is_num = is_numeral_sort(c, ty);
if (!is_num) {
SET_ERROR_CODE(Z3_INVALID_ARG, nullptr);
}
return is_num;
}
extern "C" {
Z3_ast Z3_API Z3_mk_numeral(Z3_context c, const char* n, Z3_sort ty) {
Z3_TRY;
LOG_Z3_mk_numeral(c, n, ty);
RESET_ERROR_CODE();
if (!check_numeral_sort(c, ty)) {
RETURN_Z3(nullptr);
}
if (!n) {
SET_ERROR_CODE(Z3_INVALID_ARG, nullptr);
RETURN_Z3(nullptr);
}
sort * _ty = to_sort(ty);
bool is_float = mk_c(c)->fpautil().is_float(_ty);
char const* m = n;
while (*m) {
if (!(('0' <= *m && *m <= '9') ||
('/' == *m) || ('-' == *m) ||
(' ' == *m) || ('\n' == *m) ||
('.' == *m) || ('e' == *m) ||
('E' == *m) || ('+' == *m) ||
(is_float &&
(('p' == *m) ||
('P' == *m))))) {
SET_ERROR_CODE(Z3_PARSER_ERROR, nullptr);
RETURN_Z3(nullptr);
}
++m;
}
ast * a = nullptr;
if (_ty->get_family_id() == mk_c(c)->get_fpa_fid()) {
// avoid expanding floats into huge rationals.
fpa_util & fu = mk_c(c)->fpautil();
scoped_mpf t(fu.fm());
fu.fm().set(t, fu.get_ebits(_ty), fu.get_sbits(_ty), MPF_ROUND_NEAREST_TEVEN, n);
a = fu.mk_value(t);
mk_c(c)->save_ast_trail(a);
}
else
a = mk_c(c)->mk_numeral_core(rational(n), _ty);
RETURN_Z3(of_ast(a));
Z3_CATCH_RETURN(nullptr);
}
Z3_ast Z3_API Z3_mk_int(Z3_context c, int value, Z3_sort ty) {
Z3_TRY;
LOG_Z3_mk_int(c, value, ty);
RESET_ERROR_CODE();
if (!check_numeral_sort(c, ty)) {
RETURN_Z3(nullptr);
}
ast * a = mk_c(c)->mk_numeral_core(rational(value), to_sort(ty));
RETURN_Z3(of_ast(a));
Z3_CATCH_RETURN(nullptr);
}
Z3_ast Z3_API Z3_mk_unsigned_int(Z3_context c, unsigned value, Z3_sort ty) {
Z3_TRY;
LOG_Z3_mk_unsigned_int(c, value, ty);
RESET_ERROR_CODE();
if (!check_numeral_sort(c, ty)) {
RETURN_Z3(nullptr);
}
ast * a = mk_c(c)->mk_numeral_core(rational(value), to_sort(ty));
RETURN_Z3(of_ast(a));
Z3_CATCH_RETURN(nullptr);
}
Z3_ast Z3_API Z3_mk_int64(Z3_context c, int64_t value, Z3_sort ty) {
Z3_TRY;
LOG_Z3_mk_int64(c, value, ty);
RESET_ERROR_CODE();
if (!check_numeral_sort(c, ty)) {
RETURN_Z3(nullptr);
}
rational n(value, rational::i64());
ast* a = mk_c(c)->mk_numeral_core(n, to_sort(ty));
RETURN_Z3(of_ast(a));
Z3_CATCH_RETURN(nullptr);
}
Z3_ast Z3_API Z3_mk_unsigned_int64(Z3_context c, uint64_t value, Z3_sort ty) {
Z3_TRY;
LOG_Z3_mk_unsigned_int64(c, value, ty);
RESET_ERROR_CODE();
if (!check_numeral_sort(c, ty)) {
RETURN_Z3(nullptr);
}
rational n(value, rational::ui64());
ast * a = mk_c(c)->mk_numeral_core(n, to_sort(ty));
RETURN_Z3(of_ast(a));
Z3_CATCH_RETURN(nullptr);
}
bool Z3_API Z3_is_numeral_ast(Z3_context c, Z3_ast a) {
Z3_TRY;
LOG_Z3_is_numeral_ast(c, a);
RESET_ERROR_CODE();
CHECK_IS_EXPR(a, false);
expr* e = to_expr(a);
return
mk_c(c)->autil().is_numeral(e) ||
mk_c(c)->bvutil().is_numeral(e) ||
mk_c(c)->fpautil().is_numeral(e) ||
mk_c(c)->fpautil().is_rm_numeral(e) ||
mk_c(c)->datalog_util().is_numeral(e);
Z3_CATCH_RETURN(false);
}
bool Z3_API Z3_get_numeral_rational(Z3_context c, Z3_ast a, rational& r) {
Z3_TRY;
// This function is not part of the public API
RESET_ERROR_CODE();
CHECK_IS_EXPR(a, false);
expr* e = to_expr(a);
if (mk_c(c)->autil().is_numeral(e, r)) {
return true;
}
unsigned bv_size;
if (mk_c(c)->bvutil().is_numeral(e, r, bv_size)) {
return true;
}
uint64_t v;
if (mk_c(c)->datalog_util().is_numeral(e, v)) {
r = rational(v, rational::ui64());
return true;
}
return false;
Z3_CATCH_RETURN(false);
}
Z3_string Z3_API Z3_get_numeral_binary_string(Z3_context c, Z3_ast a) {
Z3_TRY;
// This function invokes Z3_get_numeral_rational, but it is still ok to add LOG command here because it does not return a Z3 object.
LOG_Z3_get_numeral_binary_string(c, a);
RESET_ERROR_CODE();
CHECK_IS_EXPR(a, "");
rational r;
bool ok = Z3_get_numeral_rational(c, a, r);
if (ok && r.is_int() && !r.is_neg()) {
std::stringstream strm;
strm << r.as_bin(r.get_num_bits());
return mk_c(c)->mk_external_string(std::move(strm).str());
}
else {
SET_ERROR_CODE(Z3_INVALID_ARG, nullptr);
return "";
}
Z3_CATCH_RETURN("");
}
Z3_string Z3_API Z3_get_numeral_string(Z3_context c, Z3_ast a) {
Z3_TRY;
// This function invokes Z3_get_numeral_rational, but it is still ok to add LOG command here because it does not return a Z3 object.
LOG_Z3_get_numeral_string(c, a);
RESET_ERROR_CODE();
CHECK_IS_EXPR(a, "");
rational r;
bool ok = Z3_get_numeral_rational(c, a, r);
if (ok) {
return mk_c(c)->mk_external_string(r.to_string());
}
else {
fpa_util & fu = mk_c(c)->fpautil();
scoped_mpf tmp(fu.fm());
mpf_rounding_mode rm;
if (mk_c(c)->fpautil().is_rm_numeral(to_expr(a), rm)) {
switch (rm) {
case MPF_ROUND_NEAREST_TEVEN:
return mk_c(c)->mk_external_string("roundNearestTiesToEven");
break;
case MPF_ROUND_NEAREST_TAWAY:
return mk_c(c)->mk_external_string("roundNearestTiesToAway");
break;
case MPF_ROUND_TOWARD_POSITIVE:
return mk_c(c)->mk_external_string("roundTowardPositive");
break;
case MPF_ROUND_TOWARD_NEGATIVE:
return mk_c(c)->mk_external_string("roundTowardNegative");
break;
case MPF_ROUND_TOWARD_ZERO:
default:
return mk_c(c)->mk_external_string("roundTowardZero");
break;
}
}
else if (mk_c(c)->fpautil().is_numeral(to_expr(a), tmp)) {
std::ostringstream buffer;
fu.fm().display_smt2(buffer, tmp, false);
return mk_c(c)->mk_external_string(std::move(buffer).str());
}
else {
SET_ERROR_CODE(Z3_INVALID_ARG, nullptr);
return "";
}
}
Z3_CATCH_RETURN("");
}
double Z3_API Z3_get_numeral_double(Z3_context c, Z3_ast a) {
LOG_Z3_get_numeral_double(c, a);
RESET_ERROR_CODE();
if (!is_expr(a)) {
SET_ERROR_CODE(Z3_INVALID_ARG, nullptr);
return NAN;
}
expr* e = to_expr(a);
fpa_util & fu = mk_c(c)->fpautil();
scoped_mpf tmp(fu.fm());
if (mk_c(c)->fpautil().is_numeral(e, tmp)) {
if (tmp.get().get_ebits() > 11 ||
tmp.get().get_sbits() > 53) {
SET_ERROR_CODE(Z3_INVALID_ARG, nullptr);
return NAN;
}
return fu.fm().to_double(tmp);
}
rational r;
arith_util & u = mk_c(c)->autil();
if (u.is_numeral(e, r)) {
return r.get_double();
}
SET_ERROR_CODE(Z3_INVALID_ARG, nullptr);
return 0.0;
}
Z3_string Z3_API Z3_get_numeral_decimal_string(Z3_context c, Z3_ast a, unsigned precision) {
Z3_TRY;
LOG_Z3_get_numeral_decimal_string(c, a, precision);
RESET_ERROR_CODE();
CHECK_IS_EXPR(a, "");
expr* e = to_expr(a);
rational r;
arith_util & u = mk_c(c)->autil();
fpa_util & fu = mk_c(c)->fpautil();
scoped_mpf ftmp(fu.fm());
mpf_rounding_mode rm;
if (u.is_numeral(e, r) && !r.is_int()) {
std::ostringstream buffer;
r.display_decimal(buffer, precision);
return mk_c(c)->mk_external_string(std::move(buffer).str());
}
if (u.is_irrational_algebraic_numeral(e)) {
algebraic_numbers::anum const & n = u.to_irrational_algebraic_numeral(e);
algebraic_numbers::manager & am = u.am();
std::ostringstream buffer;
am.display_decimal(buffer, n, precision);
return mk_c(c)->mk_external_string(std::move(buffer).str());
}
else if (mk_c(c)->fpautil().is_rm_numeral(to_expr(a), rm))
return Z3_get_numeral_string(c, a);
else if (mk_c(c)->fpautil().is_numeral(to_expr(a), ftmp)) {
std::ostringstream buffer;
fu.fm().display_decimal(buffer, ftmp, 12);
return mk_c(c)->mk_external_string(std::move(buffer).str());
}
else if (Z3_get_numeral_rational(c, a, r)) {
return mk_c(c)->mk_external_string(r.to_string());
}
else {
SET_ERROR_CODE(Z3_INVALID_ARG, nullptr);
return "";
}
Z3_CATCH_RETURN("");
}
bool Z3_API Z3_get_numeral_small(Z3_context c, Z3_ast a, int64_t* num, int64_t* den) {
Z3_TRY;
// This function invokes Z3_get_numeral_rational, but it is still ok to add LOG command here because it does not return a Z3 object.
LOG_Z3_get_numeral_small(c, a, num, den);
RESET_ERROR_CODE();
CHECK_IS_EXPR(a, false);
rational r;
bool ok = Z3_get_numeral_rational(c, a, r);
if (ok) {
rational n = numerator(r);
rational d = denominator(r);
if (n.is_int64() && d.is_int64()) {
*num = n.get_int64();
*den = d.get_int64();
return true;
}
else {
return false;
}
}
SET_ERROR_CODE(Z3_INVALID_ARG, nullptr);
return false;
Z3_CATCH_RETURN(false);
}
bool Z3_API Z3_get_numeral_int(Z3_context c, Z3_ast v, int* i) {
Z3_TRY;
// This function invokes Z3_get_numeral_int64, but it is still ok to add LOG command here because it does not return a Z3 object.
LOG_Z3_get_numeral_int(c, v, i);
RESET_ERROR_CODE();
CHECK_IS_EXPR(v, false);
if (!i) {
SET_ERROR_CODE(Z3_INVALID_ARG, nullptr);
return false;
}
int64_t l;
if (Z3_get_numeral_int64(c, v, &l) && l >= INT_MIN && l <= INT_MAX) {
*i = static_cast(l);
return true;
}
return false;
Z3_CATCH_RETURN(false);
}
bool Z3_API Z3_get_numeral_uint(Z3_context c, Z3_ast v, unsigned* u) {
Z3_TRY;
// This function invokes Z3_get_numeral_uint64, but it is still ok to add LOG command here because it does not return a Z3 object.
LOG_Z3_get_numeral_uint(c, v, u);
RESET_ERROR_CODE();
CHECK_IS_EXPR(v, false);
if (!u) {
SET_ERROR_CODE(Z3_INVALID_ARG, nullptr);
return false;
}
uint64_t l;
if (Z3_get_numeral_uint64(c, v, &l) && (l <= 0xFFFFFFFF)) {
*u = static_cast(l);
return true;
}
return false;
Z3_CATCH_RETURN(false);
}
bool Z3_API Z3_get_numeral_uint64(Z3_context c, Z3_ast v, uint64_t* u) {
Z3_TRY;
// This function invokes Z3_get_numeral_rational, but it is still ok to add LOG command here because it does not return a Z3 object.
LOG_Z3_get_numeral_uint64(c, v, u);
RESET_ERROR_CODE();
CHECK_IS_EXPR(v, false);
if (!u) {
SET_ERROR_CODE(Z3_INVALID_ARG, nullptr);
return false;
}
rational r;
bool ok = Z3_get_numeral_rational(c, v, r);
SASSERT(u);
if (ok && r.is_uint64()) {
*u = r.get_uint64();
return ok;
}
return false;
Z3_CATCH_RETURN(false);
}
bool Z3_API Z3_get_numeral_int64(Z3_context c, Z3_ast v, int64_t* i) {
Z3_TRY;
// This function invokes Z3_get_numeral_rational, but it is still ok to add LOG command here because it does not return a Z3 object.
LOG_Z3_get_numeral_int64(c, v, i);
RESET_ERROR_CODE();
CHECK_IS_EXPR(v, false);
if (!i) {
SET_ERROR_CODE(Z3_INVALID_ARG, nullptr);
return false;
}
rational r;
bool ok = Z3_get_numeral_rational(c, v, r);
if (ok && r.is_int64()) {
*i = r.get_int64();
return ok;
}
return false;
Z3_CATCH_RETURN(false);
}
bool Z3_API Z3_get_numeral_rational_int64(Z3_context c, Z3_ast v, int64_t* num, int64_t* den) {
Z3_TRY;
// This function invokes Z3_get_numeral_rational, but it is still ok to add LOG command here because it does not return a Z3 object.
LOG_Z3_get_numeral_rational_int64(c, v, num, den);
RESET_ERROR_CODE();
CHECK_IS_EXPR(v, false);
if (!num || !den) {
SET_ERROR_CODE(Z3_INVALID_ARG, nullptr);
return false;
}
rational r;
bool ok = Z3_get_numeral_rational(c, v, r);
if (ok != true) {
return ok;
}
rational n = numerator(r);
rational d = denominator(r);
if (n.is_int64() && d.is_int64()) {
*num = n.get_int64();
*den = d.get_int64();
return ok;
}
return false;
Z3_CATCH_RETURN(false);
}
Z3_ast Z3_API Z3_mk_bv_numeral(Z3_context c, unsigned sz, bool const* bits) {
Z3_TRY;
LOG_Z3_mk_bv_numeral(c, sz, bits);
RESET_ERROR_CODE();
rational r(0);
for (unsigned i = 0; i < sz; ++i) {
if (bits[i]) r += rational::power_of_two(i);
}
ast * a = mk_c(c)->mk_numeral_core(r, mk_c(c)->bvutil().mk_sort(sz));
RETURN_Z3(of_ast(a));
Z3_CATCH_RETURN(nullptr);
}
#if 0
Z3_ast Z3_API Z3_mk_mpz_numeral(Z3_context c, bool sign, unsigned n, unsigned const nums[], Z3_sort* srt) {
LOG_TRY;
LOG_Z3_mk_mpz_numeral(c, sign, n, nums, srt);
RESET_ERROR_CODE();
rational z;
// todo fill in z
if (!z.size())
z.neg();
arith_util & a = mk_c(c)->autil();
auto* a = mk_c(c)->mk_numeral_core(r, a.mk_int_sort());
Z3_CATCH_RETURN(nullptr);
}
Z3_ast Z3_API Z3_mk_mpq_numeral1(Z3_context c, bool sign, unsigned n, unsigned const nums[], unsigned d, unsigned const dens[]) {
LOG_TRY;
LOG_Z3_mk_mpq_numeral(c, sign, n, nums, d, dens);
RESET_ERROR_CODE();
rational q;
if (!sign)
q.neg();
Z3_CATCH_RETURN(nullptr);
}
#endif
};