From 98c7069f75b19df1aed92087cc4fef34a76c38b7 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Mon, 18 Apr 2022 14:29:16 +0200 Subject: [PATCH] add rewrite for hoisting multipliers over modular inverses Signed-off-by: Nikolaj Bjorner --- src/ast/rewriter/arith_rewriter.cpp | 23 +++++++++++++++++++++++ src/ast/rewriter/arith_rewriter.h | 4 +++- 2 files changed, 26 insertions(+), 1 deletion(-) diff --git a/src/ast/rewriter/arith_rewriter.cpp b/src/ast/rewriter/arith_rewriter.cpp index 857ae0755..1b52e335d 100644 --- a/src/ast/rewriter/arith_rewriter.cpp +++ b/src/ast/rewriter/arith_rewriter.cpp @@ -700,9 +700,32 @@ br_status arith_rewriter::mk_eq_core(expr * arg1, expr * arg2, expr_ref & result else if (m_arith_lhs || is_arith_term(arg1) || is_arith_term(arg2)) { st = mk_le_ge_eq_core(arg1, arg2, EQ, result); } + + if (st == BR_FAILED && mk_eq_mod(arg1, arg2, result)) + st = BR_REWRITE2; return st; } +bool arith_rewriter::mk_eq_mod(expr* arg1, expr* arg2, expr_ref& result) { + expr* x = nullptr, *y = nullptr, *z = nullptr, *u = nullptr; + rational p, k, l; + // match k*u mod p = l, where k, p, l are integers + if (m_util.is_mod(arg1, x, y) && m_util.is_numeral(y, p) && + m_util.is_mul(x, z, u) && m_util.is_numeral(z, k) && + m_util.is_numeral(arg2, l) && 0 <= l && l < p) { + // a*p + k*b = g + rational a, b; + rational g = gcd(p, k, a, b); + if (g == 1) { + expr_ref nb(m_util.mk_numeral(b, true), m()); + result = m().mk_eq(m_util.mk_mod(u, y), + m_util.mk_mod(m_util.mk_mul(nb, arg2), y)); + return true; + } + } + return false; +} + expr_ref arith_rewriter::neg_monomial(expr* e) const { expr_ref_vector args(m()); rational a1; diff --git a/src/ast/rewriter/arith_rewriter.h b/src/ast/rewriter/arith_rewriter.h index d64896d3d..19a8363a0 100644 --- a/src/ast/rewriter/arith_rewriter.h +++ b/src/ast/rewriter/arith_rewriter.h @@ -104,7 +104,9 @@ class arith_rewriter : public poly_rewriter { bool divides(expr* d, expr* n, expr_ref& result); expr_ref remove_divisor(expr* arg, expr* num, expr* den); void flat_mul(expr* e, ptr_buffer& args); - void remove_divisor(expr* d, ptr_buffer& args); + void remove_divisor(expr* d, ptr_buffer& args); + + bool mk_eq_mod(expr* arg1, expr* arg2, expr_ref& result); public: arith_rewriter(ast_manager & m, params_ref const & p = params_ref()): poly_rewriter(m, p) {