3
0
Fork 0
mirror of https://github.com/Z3Prover/z3 synced 2026-08-04 05:03:30 +00:00
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
This commit is contained in:
Nikolaj Bjorner 2026-07-12 13:35:57 -07:00 committed by GitHub
parent ba7b12c18c
commit eaceded5f1
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
13 changed files with 269 additions and 11 deletions

View file

@ -6,6 +6,7 @@ z3_add_component(simplifiers
bound_propagator.cpp
bound_simplifier.cpp
bv_bounds_simplifier.cpp
bv_divrem_bounds.cpp
bv_slice.cpp
card2bv.cpp
demodulator_simplifier.cpp

View file

@ -0,0 +1,43 @@
/*++
Copyright (c) 2026 Microsoft Corporation
Module Name:
bv_divrem_bounds.cpp
Abstract:
Simplifier that adds range/bound lemmas for bit-vector division and
remainder terms with a non-constant divisor. See bv_divrem_bounds.h.
Author:
Nikolaj Bjorner (nbjorner)
--*/
#include "ast/simplifiers/bv_divrem_bounds.h"
#include "ast/for_each_expr.h"
namespace bv {
void divrem_bounds::reduce() {
expr_ref_vector targets(m), fmls(m), clause(m);
for (unsigned i : indices())
fmls.push_back(m_fmls[i].fml());
for (expr* e : subterms::ground(fmls))
if (m_util.is_bv_divrem(e))
targets.push_back(e);
for (expr* t : targets) {
m_util.mk_bv_divrem_bound(t, clause);
if (clause.empty())
continue;
expr_ref lemma(m.mk_or(clause), m);
// the lemma is a bit-vector theory axiom (valid with no premises)
proof_ref pr(m);
if (m.proofs_enabled())
pr = m.mk_th_lemma(m_util.get_fid(), lemma, 0, nullptr);
m_fmls.add(dependent_expr(m, lemma, pr, nullptr));
++m_num_lemmas;
}
}
}

View file

@ -0,0 +1,64 @@
/*++
Copyright (c) 2026 Microsoft Corporation
Module Name:
bv_divrem_bounds.h
Abstract:
Simplifier that adds range/bound lemmas for bit-vector division and
remainder terms with a non-constant divisor.
Bit-blasting a division circuit with a symbolic divisor hides the algebraic
fact that the remainder magnitude is bounded by the divisor magnitude. For a
divisor b that is not a numeral the following facts hold and are added as
(implied) lemmas so that a downstream bit-blasting + SAT solver can reason
about the magnitudes without unfolding the division circuit:
b != 0 => bvult (bvurem a b) b (unsigned remainder)
b != 0 => bvult |bvsrem a b| |b| (signed remainder)
b != 0 => bvult |bvsmod a b| |b| (signed modulo)
b != 0 => bvule (bvudiv a b) a (unsigned quotient)
b != 0 => bvule |bvsdiv a b| |a| (signed quotient)
where |x| = ite(x <s 0, -x, x). These lemmas are logically implied by the
semantics of the operators for a non-zero divisor, so the transformation
preserves satisfiability and all models. The unsigned comparison on the
absolute values keeps the bounds sound at INT_MIN: -INT_MIN overflows to
INT_MIN whose unsigned value is the maximum magnitude, so the bound only
ever loosens, never becomes unsound.
Author:
Nikolaj Bjorner (nbjorner)
--*/
#pragma once
#include "ast/bv_decl_plugin.h"
#include "ast/simplifiers/dependent_expr_state.h"
namespace bv {
class divrem_bounds : public dependent_expr_simplifier {
bv_util m_util;
unsigned m_num_lemmas = 0;
public:
divrem_bounds(ast_manager& m, dependent_expr_state& fmls) :
dependent_expr_simplifier(m, fmls), m_util(m) {}
char const* name() const override { return "bv-divrem-bounds"; }
void reduce() override;
bool supports_proofs() const override { return true; }
void collect_statistics(statistics& st) const override {
st.update("bv-divrem-bounds", m_num_lemmas);
}
void reset_statistics() override { m_num_lemmas = 0; }
};
}