mirror of
https://github.com/Z3Prover/z3
synced 2025-04-14 21:08:46 +00:00
* introduce int_solver.h Signed-off-by: Lev Nachmanson <levnach@hotmail.com> * add int_solver class Signed-off-by: Lev Nachmanson <levnach@hotmail.com> * track which var is an integer Signed-off-by: Lev Nachmanson <levnach@microsoft.com> * add queries for integrality of vars Signed-off-by: Lev Nachmanson <levnach@microsoft.com> * resurrect lp_tst in its own director lp Signed-off-by: Lev Nachmanson <levnach@microsoft.com> * add file Signed-off-by: Lev Nachmanson <levnach@microsoft.com> * add_constraint has got a body Signed-off-by: Lev Nachmanson <levnach@microsoft.com> * fix add_constraint and substitute_terms_in_linear_expression Signed-off-by: Lev Nachmanson <levnach@microsoft.com> * after merge with Z3Prover Signed-off-by: Lev Nachmanson <levnach@hotmail.com> * adding stub check_int_feasibility() Signed-off-by: Lev Nachmanson <levnach@hotmail.com> * Dev (#50) * initial skeletons for nra solver Signed-off-by: Nikolaj Bjorner <nbjorner@microsoft.com> * initial skeletons for nra solver Signed-off-by: Nikolaj Bjorner <nbjorner@microsoft.com> * small fix in lar_solver.cpp Signed-off-by: Lev Nachmanson <levnach@hotmail.com> * adding some content to the new check_int_feasibility() Signed-off-by: Lev Nachmanson <levnach@hotmail.com> * Dev (#51) * initial skeletons for nra solver Signed-off-by: Nikolaj Bjorner <nbjorner@microsoft.com> * initial skeletons for nra solver Signed-off-by: Nikolaj Bjorner <nbjorner@microsoft.com> * adding more nlsat Signed-off-by: Nikolaj Bjorner <nbjorner@microsoft.com> * nlsat integration Signed-off-by: Nikolaj Bjorner <nbjorner@microsoft.com> * adding constraints Signed-off-by: Nikolaj Bjorner <nbjorner@microsoft.com> * adding nra solver Signed-off-by: Nikolaj Bjorner <nbjorner@microsoft.com> * add missing initialization Signed-off-by: Nikolaj Bjorner <nbjorner@microsoft.com> * adding nra solver Signed-off-by: Nikolaj Bjorner <nbjorner@microsoft.com> * test Signed-off-by: Lev Nachmanson <levnach@microsoft.com> * Dev (#53) * change in a comment Signed-off-by: Lev Nachmanson <levnach@hotmail.com> * Disabled debug output * removing FOCI2 interface from interp * remove foci reference from cmakelist.txt Signed-off-by: Nikolaj Bjorner <nbjorner@microsoft.com> * initial skeletons for nra solver Signed-off-by: Nikolaj Bjorner <nbjorner@microsoft.com> * initial skeletons for nra solver Signed-off-by: Nikolaj Bjorner <nbjorner@microsoft.com> * adding more nlsat Signed-off-by: Nikolaj Bjorner <nbjorner@microsoft.com> * nlsat integration Signed-off-by: Nikolaj Bjorner <nbjorner@microsoft.com> * adding constraints Signed-off-by: Nikolaj Bjorner <nbjorner@microsoft.com> * adding nra solver Signed-off-by: Nikolaj Bjorner <nbjorner@microsoft.com> * add missing initialization Signed-off-by: Nikolaj Bjorner <nbjorner@microsoft.com> * adding nra solver Signed-off-by: Nikolaj Bjorner <nbjorner@microsoft.com> * adding nra Signed-off-by: Nikolaj Bjorner <nbjorner@microsoft.com> * debugging nra Signed-off-by: Nikolaj Bjorner <nbjorner@microsoft.com> * updates to nra_solver integration to call it directly from theory_lra instead of over lar_solver Signed-off-by: Nikolaj Bjorner <nbjorner@microsoft.com> * n/a Signed-off-by: Nikolaj Bjorner <nbjorner@microsoft.com> * integrate nlsat Signed-off-by: Nikolaj Bjorner <nbjorner@microsoft.com> * tidy Signed-off-by: Nikolaj Bjorner <nbjorner@microsoft.com> * preserve is_int flag Signed-off-by: Lev Nachmanson <levnach@hotmail.com> * remove a debug printout Signed-off-by: Lev Nachmanson <levnach@hotmail.com> * Dev (#54) * change in a comment Signed-off-by: Lev Nachmanson <levnach@hotmail.com> * Disabled debug output * removing FOCI2 interface from interp * remove foci reference from cmakelist.txt Signed-off-by: Nikolaj Bjorner <nbjorner@microsoft.com> * initial skeletons for nra solver Signed-off-by: Nikolaj Bjorner <nbjorner@microsoft.com> * initial skeletons for nra solver Signed-off-by: Nikolaj Bjorner <nbjorner@microsoft.com> * adding more nlsat Signed-off-by: Nikolaj Bjorner <nbjorner@microsoft.com> * nlsat integration Signed-off-by: Nikolaj Bjorner <nbjorner@microsoft.com> * adding constraints Signed-off-by: Nikolaj Bjorner <nbjorner@microsoft.com> * adding nra solver Signed-off-by: Nikolaj Bjorner <nbjorner@microsoft.com> * add missing initialization Signed-off-by: Nikolaj Bjorner <nbjorner@microsoft.com> * adding nra solver Signed-off-by: Nikolaj Bjorner <nbjorner@microsoft.com> * adding nra Signed-off-by: Nikolaj Bjorner <nbjorner@microsoft.com> * debugging nra Signed-off-by: Nikolaj Bjorner <nbjorner@microsoft.com> * updates to nra_solver integration to call it directly from theory_lra instead of over lar_solver Signed-off-by: Nikolaj Bjorner <nbjorner@microsoft.com> * n/a Signed-off-by: Nikolaj Bjorner <nbjorner@microsoft.com> * integrate nlsat Signed-off-by: Nikolaj Bjorner <nbjorner@microsoft.com> * tidy Signed-off-by: Nikolaj Bjorner <nbjorner@microsoft.com> * use integer test from lra solver, updated it to work on term variables Signed-off-by: Nikolaj Bjorner <nbjorner@microsoft.com> * fix equality check in assume-eq Signed-off-by: Nikolaj Bjorner <nbjorner@microsoft.com> * fix model_is_int_feasible Signed-off-by: Lev Nachmanson <levnach@hotmail.com> * untested gcd_test() Signed-off-by: Lev Nachmanson <levnach@hotmail.com> * call fill_explanation_from_fixed_columns() Signed-off-by: Lev Nachmanson <levnach@microsoft.com> * add the call to pivot_fixed_vars_from_basis() to int_solver.cpp::check() Signed-off-by: Lev Nachmanson <levnach@microsoft.com> * port more of theory_arith_int.h Signed-off-by: Lev Nachmanson <levnach@microsoft.com> * use statistics of lar_solver by theory_lra.cpp Signed-off-by: Lev Nachmanson <levnach@hotmail.com> * port more code to int_solver.cpp Signed-off-by: Lev Nachmanson <levnach@microsoft.com> * add an assert Signed-off-by: Lev Nachmanson <levnach@microsoft.com> * more int porting Signed-off-by: Lev Nachmanson <levnach@hotmail.com> * fix a bug in pivot_fixed_vars_from_basis Signed-off-by: Lev Nachmanson <levnach@microsoft.com> * small change Signed-off-by: Lev Nachmanson <levnach@hotmail.com> * implement find_inf_int_base_column() Signed-off-by: Lev Nachmanson <levnach@microsoft.com> * catch unregistered vars in add_var_bound Signed-off-by: Lev Nachmanson <levnach@microsoft.com> * add a file Signed-off-by: Lev Nachmanson <levnach@microsoft.com> * compile for vs2012 Signed-off-by: Lev Nachmanson <levnach@microsoft.com> * fix asserts in add_var_bound Signed-off-by: Lev Nachmanson <levnach@microsoft.com> * fix the lp_solver init when workig on an mps file Signed-off-by: Lev Nachmanson <levnach@microsoft.com> * towards int_solver::check() Signed-off-by: Lev Nachmanson <levnach@microsoft.com> * change in int_solver::check() signature Signed-off-by: Lev Nachmanson <levnach@microsoft.com> * add handlers for lia moves Signed-off-by: Nikolaj Bjorner <nbjorner@microsoft.com> * spacing Signed-off-by: Nikolaj Bjorner <nbjorner@microsoft.com>
497 lines
16 KiB
C++
497 lines
16 KiB
C++
/*++
|
|
Copyright (c) 2007 Microsoft Corporation
|
|
|
|
Module Name:
|
|
|
|
arith_simplifier_plugin.cpp
|
|
|
|
Abstract:
|
|
|
|
Simplifier for the arithmetic family.
|
|
|
|
Author:
|
|
|
|
Leonardo (leonardo) 2008-01-08
|
|
|
|
--*/
|
|
#include"arith_simplifier_plugin.h"
|
|
#include"ast_pp.h"
|
|
#include"ast_ll_pp.h"
|
|
#include"ast_smt2_pp.h"
|
|
|
|
arith_simplifier_plugin::~arith_simplifier_plugin() {
|
|
}
|
|
|
|
arith_simplifier_plugin::arith_simplifier_plugin(ast_manager & m, basic_simplifier_plugin & b, arith_simplifier_params & p):
|
|
poly_simplifier_plugin(symbol("arith"), m, OP_ADD, OP_MUL, OP_UMINUS, OP_SUB, OP_NUM),
|
|
m_params(p),
|
|
m_util(m),
|
|
m_bsimp(b),
|
|
m_int_zero(m),
|
|
m_real_zero(m) {
|
|
m_int_zero = m_util.mk_numeral(rational(0), true);
|
|
m_real_zero = m_util.mk_numeral(rational(0), false);
|
|
}
|
|
|
|
/**
|
|
\brief Return true if the first monomial of t is negative.
|
|
*/
|
|
bool arith_simplifier_plugin::is_neg_poly(expr * t) const {
|
|
if (m_util.is_add(t)) {
|
|
t = to_app(t)->get_arg(0);
|
|
}
|
|
if (m_util.is_mul(t)) {
|
|
t = to_app(t)->get_arg(0);
|
|
rational r;
|
|
if (is_numeral(t, r))
|
|
return r.is_neg();
|
|
}
|
|
return false;
|
|
}
|
|
|
|
void arith_simplifier_plugin::get_monomial_gcd(expr_ref_vector& monomials, numeral& g) {
|
|
g = numeral::zero();
|
|
numeral n;
|
|
for (unsigned i = 0; !g.is_one() && i < monomials.size(); ++i) {
|
|
expr* e = monomials[i].get();
|
|
if (is_numeral(e, n)) {
|
|
g = gcd(abs(n), g);
|
|
}
|
|
else if (is_mul(e) && is_numeral(to_app(e)->get_arg(0), n)) {
|
|
g = gcd(abs(n), g);
|
|
}
|
|
else {
|
|
g = numeral::one();
|
|
return;
|
|
}
|
|
}
|
|
if (g.is_zero()) {
|
|
g = numeral::one();
|
|
}
|
|
}
|
|
|
|
void arith_simplifier_plugin::div_monomial(expr_ref_vector& monomials, numeral const& g) {
|
|
numeral n;
|
|
for (unsigned i = 0; i < monomials.size(); ++i) {
|
|
expr* e = monomials[i].get();
|
|
if (is_numeral(e, n)) {
|
|
SASSERT((n/g).is_int());
|
|
monomials[i] = mk_numeral(n/g);
|
|
}
|
|
else if (is_mul(e) && is_numeral(to_app(e)->get_arg(0), n)) {
|
|
SASSERT((n/g).is_int());
|
|
monomials[i] = mk_mul(n/g, to_app(e)->get_arg(1));
|
|
}
|
|
else {
|
|
UNREACHABLE();
|
|
}
|
|
}
|
|
}
|
|
|
|
void arith_simplifier_plugin::gcd_reduce_monomial(expr_ref_vector& monomials, numeral& k) {
|
|
numeral g, n;
|
|
|
|
get_monomial_gcd(monomials, g);
|
|
g = gcd(abs(k), g);
|
|
|
|
if (g.is_one()) {
|
|
return;
|
|
}
|
|
SASSERT(g.is_pos());
|
|
|
|
k = k / g;
|
|
div_monomial(monomials, g);
|
|
|
|
}
|
|
|
|
template<arith_simplifier_plugin::op_kind Kind>
|
|
void arith_simplifier_plugin::mk_le_ge_eq_core(expr * arg1, expr * arg2, expr_ref & result) {
|
|
set_curr_sort(arg1);
|
|
bool is_int = m_curr_sort->get_decl_kind() == INT_SORT;
|
|
expr_ref_vector monomials(m_manager);
|
|
rational k;
|
|
TRACE("arith_eq_bug", tout << mk_ismt2_pp(arg1, m_manager) << "\n" << mk_ismt2_pp(arg2, m_manager) << "\n";);
|
|
process_sum_of_monomials(false, arg1, monomials, k);
|
|
process_sum_of_monomials(true, arg2, monomials, k);
|
|
k.neg();
|
|
if (is_int) {
|
|
numeral g;
|
|
get_monomial_gcd(monomials, g);
|
|
if (!g.is_one()) {
|
|
div_monomial(monomials, g);
|
|
switch(Kind) {
|
|
case LE:
|
|
//
|
|
// g*monmials' <= k
|
|
// <=>
|
|
// monomials' <= floor(k/g)
|
|
//
|
|
k = floor(k/g);
|
|
break;
|
|
case GE:
|
|
//
|
|
// g*monmials' >= k
|
|
// <=>
|
|
// monomials' >= ceil(k/g)
|
|
//
|
|
k = ceil(k/g);
|
|
break;
|
|
case EQ:
|
|
k = k/g;
|
|
if (!k.is_int()) {
|
|
result = m_manager.mk_false();
|
|
return;
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
expr_ref lhs(m_manager);
|
|
mk_sum_of_monomials(monomials, lhs);
|
|
if (m_util.is_numeral(lhs)) {
|
|
SASSERT(lhs == mk_zero());
|
|
if (( Kind == LE && numeral::zero() <= k) ||
|
|
( Kind == GE && numeral::zero() >= k) ||
|
|
( Kind == EQ && numeral::zero() == k))
|
|
result = m_manager.mk_true();
|
|
else
|
|
result = m_manager.mk_false();
|
|
}
|
|
else {
|
|
|
|
if (is_neg_poly(lhs)) {
|
|
expr_ref neg_lhs(m_manager);
|
|
mk_uminus(lhs, neg_lhs);
|
|
lhs = neg_lhs;
|
|
k.neg();
|
|
expr * rhs = m_util.mk_numeral(k, is_int);
|
|
switch (Kind) {
|
|
case LE:
|
|
result = m_util.mk_ge(lhs, rhs);
|
|
break;
|
|
case GE:
|
|
result = m_util.mk_le(lhs, rhs);
|
|
break;
|
|
case EQ:
|
|
result = m_manager.mk_eq(lhs, rhs);
|
|
break;
|
|
}
|
|
}
|
|
else {
|
|
expr * rhs = m_util.mk_numeral(k, is_int);
|
|
switch (Kind) {
|
|
case LE:
|
|
result = m_util.mk_le(lhs, rhs);
|
|
break;
|
|
case GE:
|
|
result = m_util.mk_ge(lhs, rhs);
|
|
break;
|
|
case EQ:
|
|
result = m_manager.mk_eq(lhs, rhs);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
void arith_simplifier_plugin::mk_arith_eq(expr * arg1, expr * arg2, expr_ref & result) {
|
|
mk_le_ge_eq_core<EQ>(arg1, arg2, result);
|
|
}
|
|
|
|
void arith_simplifier_plugin::mk_le(expr * arg1, expr * arg2, expr_ref & result) {
|
|
mk_le_ge_eq_core<LE>(arg1, arg2, result);
|
|
}
|
|
|
|
void arith_simplifier_plugin::mk_ge(expr * arg1, expr * arg2, expr_ref & result) {
|
|
mk_le_ge_eq_core<GE>(arg1, arg2, result);
|
|
}
|
|
|
|
void arith_simplifier_plugin::mk_lt(expr * arg1, expr * arg2, expr_ref & result) {
|
|
expr_ref tmp(m_manager);
|
|
mk_le(arg2, arg1, tmp);
|
|
m_bsimp.mk_not(tmp, result);
|
|
}
|
|
|
|
void arith_simplifier_plugin::mk_gt(expr * arg1, expr * arg2, expr_ref & result) {
|
|
expr_ref tmp(m_manager);
|
|
mk_le(arg1, arg2, tmp);
|
|
m_bsimp.mk_not(tmp, result);
|
|
}
|
|
|
|
void arith_simplifier_plugin::gcd_normalize(numeral & coeff, expr_ref& term) {
|
|
if (!abs(coeff).is_one()) {
|
|
set_curr_sort(term);
|
|
SASSERT(m_curr_sort->get_decl_kind() == INT_SORT);
|
|
expr_ref_vector monomials(m_manager);
|
|
rational k;
|
|
monomials.push_back(mk_numeral(numeral(coeff), true));
|
|
process_sum_of_monomials(false, term, monomials, k);
|
|
gcd_reduce_monomial(monomials, k);
|
|
numeral coeff1;
|
|
if (!is_numeral(monomials[0].get(), coeff1)) {
|
|
UNREACHABLE();
|
|
}
|
|
if (coeff1 == coeff) {
|
|
return;
|
|
}
|
|
monomials[0] = mk_numeral(k, true);
|
|
coeff = coeff1;
|
|
mk_sum_of_monomials(monomials, term);
|
|
}
|
|
}
|
|
|
|
|
|
void arith_simplifier_plugin::mk_div(expr * arg1, expr * arg2, expr_ref & result) {
|
|
set_curr_sort(arg1);
|
|
numeral v1, v2;
|
|
bool is_int;
|
|
if (m_util.is_numeral(arg2, v2, is_int) && !v2.is_zero()) {
|
|
SASSERT(!is_int);
|
|
if (m_util.is_numeral(arg1, v1, is_int))
|
|
result = m_util.mk_numeral(v1/v2, false);
|
|
else {
|
|
numeral k(1);
|
|
k /= v2;
|
|
|
|
expr_ref inv_arg2(m_util.mk_numeral(k, false), m_manager);
|
|
mk_mul(inv_arg2, arg1, result);
|
|
}
|
|
}
|
|
else
|
|
result = m_util.mk_div(arg1, arg2);
|
|
}
|
|
|
|
void arith_simplifier_plugin::mk_idiv(expr * arg1, expr * arg2, expr_ref & result) {
|
|
set_curr_sort(arg1);
|
|
numeral v1, v2;
|
|
bool is_int;
|
|
if (m_util.is_numeral(arg1, v1, is_int) && m_util.is_numeral(arg2, v2, is_int) && !v2.is_zero())
|
|
result = m_util.mk_numeral(div(v1, v2), is_int);
|
|
else if (divides(arg2, arg1, result)) {
|
|
result = m_util.mk_mul(result, m_util.mk_idiv(arg2, arg2));
|
|
}
|
|
else
|
|
result = m_util.mk_idiv(arg1, arg2);
|
|
}
|
|
|
|
bool arith_simplifier_plugin::divides(expr* d, expr* n, expr_ref& quot) {
|
|
ast_manager& m = m_manager;
|
|
if (d == n) {
|
|
quot = m_util.mk_numeral(rational(1), m_util.is_int(d));
|
|
return true;
|
|
}
|
|
if (m_util.is_mul(n)) {
|
|
expr_ref_vector muls(m);
|
|
muls.push_back(n);
|
|
expr* n1, *n2;
|
|
rational r1, r2;
|
|
for (unsigned i = 0; i < muls.size(); ++i) {
|
|
if (m_util.is_mul(muls[i].get(), n1, n2)) {
|
|
muls[i] = n1;
|
|
muls.push_back(n2);
|
|
--i;
|
|
}
|
|
}
|
|
if (m_util.is_numeral(d, r1) && !r1.is_zero()) {
|
|
for (unsigned i = 0; i < muls.size(); ++i) {
|
|
if (m_util.is_numeral(muls[i].get(), r2) && (r2 / r1).is_int()) {
|
|
muls[i] = m_util.mk_numeral(r2 / r1, m_util.is_int(d));
|
|
quot = m_util.mk_mul(muls.size(), muls.c_ptr());
|
|
return true;
|
|
}
|
|
}
|
|
}
|
|
else {
|
|
for (unsigned i = 0; i < muls.size(); ++i) {
|
|
if (d == muls[i].get()) {
|
|
muls[i] = muls.back();
|
|
muls.pop_back();
|
|
quot = m_util.mk_mul(muls.size(), muls.c_ptr());
|
|
return true;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
|
|
|
|
void arith_simplifier_plugin::prop_mod_const(expr * e, unsigned depth, numeral const& k, expr_ref& result) {
|
|
SASSERT(m_util.is_int(e));
|
|
SASSERT(k.is_int() && k.is_pos());
|
|
numeral n;
|
|
bool is_int;
|
|
|
|
if (depth == 0) {
|
|
result = e;
|
|
}
|
|
else if (is_add(e) || is_mul(e)) {
|
|
expr_ref_vector args(m_manager);
|
|
expr_ref tmp(m_manager);
|
|
app* a = to_app(e);
|
|
for (unsigned i = 0; i < a->get_num_args(); ++i) {
|
|
prop_mod_const(a->get_arg(i), depth - 1, k, tmp);
|
|
args.push_back(tmp);
|
|
}
|
|
reduce(a->get_decl(), args.size(), args.c_ptr(), result);
|
|
}
|
|
else if (m_util.is_numeral(e, n, is_int) && is_int) {
|
|
result = mk_numeral(mod(n, k), true);
|
|
}
|
|
else {
|
|
result = e;
|
|
}
|
|
}
|
|
|
|
void arith_simplifier_plugin::mk_mod(expr * arg1, expr * arg2, expr_ref & result) {
|
|
set_curr_sort(arg1);
|
|
numeral v1, v2;
|
|
bool is_int;
|
|
if (m_util.is_numeral(arg1, v1, is_int) && m_util.is_numeral(arg2, v2, is_int) && !v2.is_zero()) {
|
|
result = m_util.mk_numeral(mod(v1, v2), is_int);
|
|
}
|
|
else if (m_util.is_numeral(arg2, v2, is_int) && is_int && v2.is_one()) {
|
|
result = m_util.mk_numeral(numeral(0), true);
|
|
}
|
|
else if (m_util.is_numeral(arg2, v2, is_int) && is_int && v2.is_pos()) {
|
|
expr_ref tmp(m_manager);
|
|
prop_mod_const(arg1, 5, v2, tmp);
|
|
result = m_util.mk_mod(tmp, arg2);
|
|
}
|
|
else {
|
|
result = m_util.mk_mod(arg1, arg2);
|
|
}
|
|
}
|
|
|
|
void arith_simplifier_plugin::mk_rem(expr * arg1, expr * arg2, expr_ref & result) {
|
|
set_curr_sort(arg1);
|
|
numeral v1, v2;
|
|
bool is_int;
|
|
if (m_util.is_numeral(arg1, v1, is_int) && m_util.is_numeral(arg2, v2, is_int) && !v2.is_zero()) {
|
|
numeral m = mod(v1, v2);
|
|
//
|
|
// rem(v1,v2) = if v2 >= 0 then mod(v1,v2) else -mod(v1,v2)
|
|
//
|
|
if (v2.is_neg()) {
|
|
m.neg();
|
|
}
|
|
result = m_util.mk_numeral(m, is_int);
|
|
}
|
|
else if (m_util.is_numeral(arg2, v2, is_int) && is_int && v2.is_one()) {
|
|
result = m_util.mk_numeral(numeral(0), true);
|
|
}
|
|
else if (m_util.is_numeral(arg2, v2, is_int) && is_int && !v2.is_zero()) {
|
|
expr_ref tmp(m_manager);
|
|
prop_mod_const(arg1, 5, v2, tmp);
|
|
result = m_util.mk_mod(tmp, arg2);
|
|
if (v2.is_neg()) {
|
|
result = m_util.mk_uminus(result);
|
|
}
|
|
}
|
|
else {
|
|
result = m_util.mk_rem(arg1, arg2);
|
|
}
|
|
}
|
|
|
|
void arith_simplifier_plugin::mk_to_real(expr * arg, expr_ref & result) {
|
|
numeral v;
|
|
if (m_util.is_numeral(arg, v))
|
|
result = m_util.mk_numeral(v, false);
|
|
else
|
|
result = m_util.mk_to_real(arg);
|
|
}
|
|
|
|
void arith_simplifier_plugin::mk_to_int(expr * arg, expr_ref & result) {
|
|
numeral v;
|
|
if (m_util.is_numeral(arg, v))
|
|
result = m_util.mk_numeral(floor(v), true);
|
|
else if (m_util.is_to_real(arg))
|
|
result = to_app(arg)->get_arg(0);
|
|
else
|
|
result = m_util.mk_to_int(arg);
|
|
}
|
|
|
|
void arith_simplifier_plugin::mk_is_int(expr * arg, expr_ref & result) {
|
|
numeral v;
|
|
if (m_util.is_numeral(arg, v))
|
|
result = v.is_int()?m_manager.mk_true():m_manager.mk_false();
|
|
else if (m_util.is_to_real(arg))
|
|
result = m_manager.mk_true();
|
|
else
|
|
result = m_util.mk_is_int(arg);
|
|
}
|
|
|
|
bool arith_simplifier_plugin::reduce(func_decl * f, unsigned num_args, expr * const * args, expr_ref & result) {
|
|
set_reduce_invoked();
|
|
SASSERT(f->get_family_id() == m_fid);
|
|
TRACE("arith_simplifier_plugin", tout << mk_pp(f, m_manager) << "\n";
|
|
for (unsigned i = 0; i < num_args; i++) tout << mk_pp(args[i], m_manager) << "\n";);
|
|
arith_op_kind k = static_cast<arith_op_kind>(f->get_decl_kind());
|
|
switch (k) {
|
|
case OP_NUM: return false;
|
|
case OP_LE: if (m_presimp) return false; SASSERT(num_args == 2); mk_le(args[0], args[1], result); break;
|
|
case OP_GE: if (m_presimp) return false; SASSERT(num_args == 2); mk_ge(args[0], args[1], result); break;
|
|
case OP_LT: if (m_presimp) return false; SASSERT(num_args == 2); mk_lt(args[0], args[1], result); break;
|
|
case OP_GT: if (m_presimp) return false; SASSERT(num_args == 2); mk_gt(args[0], args[1], result); break;
|
|
case OP_ADD: mk_add(num_args, args, result); break;
|
|
case OP_SUB: mk_sub(num_args, args, result); break;
|
|
case OP_UMINUS: SASSERT(num_args == 1); mk_uminus(args[0], result); break;
|
|
case OP_MUL:
|
|
mk_mul(num_args, args, result);
|
|
TRACE("arith_simplifier_plugin", tout << mk_pp(result, m_manager) << "\n";);
|
|
break;
|
|
case OP_DIV: SASSERT(num_args == 2); mk_div(args[0], args[1], result); break;
|
|
case OP_IDIV: SASSERT(num_args == 2); mk_idiv(args[0], args[1], result); break;
|
|
case OP_REM: SASSERT(num_args == 2); mk_rem(args[0], args[1], result); break;
|
|
case OP_MOD: SASSERT(num_args == 2); mk_mod(args[0], args[1], result); break;
|
|
case OP_TO_REAL: SASSERT(num_args == 1); mk_to_real(args[0], result); break;
|
|
case OP_TO_INT: SASSERT(num_args == 1); mk_to_int(args[0], result); break;
|
|
case OP_IS_INT: SASSERT(num_args == 1); mk_is_int(args[0], result); break;
|
|
case OP_POWER: return false;
|
|
case OP_ABS: SASSERT(num_args == 1); mk_abs(args[0], result); break;
|
|
case OP_IRRATIONAL_ALGEBRAIC_NUM: return false;
|
|
case OP_DIV_0: return false;
|
|
case OP_IDIV_0: return false;
|
|
default:
|
|
return false;
|
|
}
|
|
TRACE("arith_simplifier_plugin", tout << mk_pp(result.get(), m_manager) << "\n";);
|
|
return true;
|
|
}
|
|
|
|
void arith_simplifier_plugin::mk_abs(expr * arg, expr_ref & result) {
|
|
expr_ref c(m_manager);
|
|
expr_ref m_arg(m_manager);
|
|
mk_uminus(arg, m_arg);
|
|
mk_ge(arg, m_util.mk_numeral(rational(0), m_util.is_int(arg)), c);
|
|
m_bsimp.mk_ite(c, arg, m_arg, result);
|
|
}
|
|
|
|
bool arith_simplifier_plugin::is_arith_term(expr * n) const {
|
|
return n->get_kind() == AST_APP && to_app(n)->get_family_id() == m_fid;
|
|
}
|
|
|
|
bool arith_simplifier_plugin::reduce_eq(expr * lhs, expr * rhs, expr_ref & result) {
|
|
TRACE("reduce_eq_bug", tout << mk_ismt2_pp(lhs, m_manager) << "\n" << mk_ismt2_pp(rhs, m_manager) << "\n";);
|
|
set_reduce_invoked();
|
|
if (m_presimp) {
|
|
return false;
|
|
}
|
|
if (m_params.m_arith_expand_eqs) {
|
|
expr_ref le(m_manager), ge(m_manager);
|
|
mk_le_ge_eq_core<LE>(lhs, rhs, le);
|
|
mk_le_ge_eq_core<GE>(lhs, rhs, ge);
|
|
m_bsimp.mk_and(le, ge, result);
|
|
return true;
|
|
}
|
|
|
|
if (m_params.m_arith_process_all_eqs || is_arith_term(lhs) || is_arith_term(rhs)) {
|
|
mk_arith_eq(lhs, rhs, result);
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
|
|
|