3
0
Fork 0
mirror of https://github.com/Z3Prover/z3 synced 2025-08-22 11:07:51 +00:00
z3/src/qe/qe_bool_plugin.cpp
LeeYoungJoon 0a93ff515d
Centralize and document TRACE tags using X-macros (#7657)
* Introduce X-macro-based trace tag definition
- Created trace_tags.def to centralize TRACE tag definitions
- Each tag includes a symbolic name and description
- Set up enum class TraceTag for type-safe usage in TRACE macros

* Add script to generate Markdown documentation from trace_tags.def
- Python script parses trace_tags.def and outputs trace_tags.md

* Refactor TRACE_NEW to prepend TraceTag and pass enum to is_trace_enabled

* trace: improve trace tag handling system with hierarchical tagging

- Introduce hierarchical tag-class structure: enabling a tag class activates all child tags
- Unify TRACE, STRACE, SCTRACE, and CTRACE under enum TraceTag
- Implement initial version of trace_tag.def using X(tag, tag_class, description)
  (class names and descriptions to be refined in a future update)

* trace: replace all string-based TRACE tags with enum TraceTag
- Migrated all TRACE, STRACE, SCTRACE, and CTRACE macros to use enum TraceTag values instead of raw string literals

* trace : add cstring header

* trace : Add Markdown documentation generation from trace_tags.def via mk_api_doc.py

* trace : rename macro parameter 'class' to 'tag_class' and remove Unicode comment in trace_tags.h.

* trace : Add TODO comment for future implementation of tag_class activation

* trace : Disable code related to tag_class until implementation is ready (#7663).
2025-05-28 14:31:25 +01:00

174 lines
5.4 KiB
C++

/*++
Copyright (c) 2010 Microsoft Corporation
Module Name:
qe_bool_plugin.cpp
Abstract:
Eliminate Boolean variable from formula
Author:
Nikolaj Bjorner (nbjorner) 2010-02-19
Revision History:
Notes:
The procedure is a bit naive.
Consider a co-factoring approach that eliminates all Boolean
variables in scope in one shot, similar to what we do with
BDDs.
--*/
#include "qe/qe.h"
#include "ast/rewriter/expr_safe_replace.h"
#include "ast/ast_pp.h"
#include "model/model_evaluator.h"
namespace qe {
class bool_plugin : public qe_solver_plugin {
expr_safe_replace m_replace;
public:
bool_plugin(i_solver_context& ctx, ast_manager& m):
qe_solver_plugin(m, m.get_basic_family_id(), ctx),
m_replace(m)
{}
void assign(contains_app& x, expr* fml, rational const& vl) override {
SASSERT(vl.is_zero() || vl.is_one());
}
bool get_num_branches(contains_app& x, expr* fml, rational& nb) override {
nb = rational(2);
return true;
}
void subst(contains_app& x, rational const& vl, expr_ref& fml, expr_ref* def) override {
SASSERT(vl.is_one() || vl.is_zero());
expr* tf = (vl.is_one())?m.mk_true():m.mk_false();
m_replace.apply_substitution(x.x(), tf, fml);
if (def) {
*def = tf;
}
}
bool project(contains_app& x, model_ref& model, expr_ref& fml) override {
model_evaluator model_eval(*model);
expr_ref val_x(m);
rational val;
model_eval(x.x(), val_x);
CTRACE(qe, (!m.is_true(val_x) && !m.is_false(val_x)),
tout << "Boolean is a don't care: " << mk_pp(x.x(), m) << "\n";);
val = m.is_true(val_x)?rational::one():rational::zero();
subst(x, val, fml, nullptr);
return true;
}
unsigned get_weight(contains_app& contains_x, expr* fml) override {
app* x = contains_x.x();
bool p = m_ctx.pos_atoms().contains(x);
bool n = m_ctx.neg_atoms().contains(x);
if (p && n) {
return 3;
}
return 0;
}
bool solve(conj_enum& conjs,expr* fml) override {
return
solve_units(conjs, fml) ||
solve_polarized(fml);
}
bool is_uninterpreted(app* a) override {
return false;
}
private:
bool solve_units(conj_enum& conjs, expr* _fml) {
expr_ref fml(_fml, m);
unsigned idx;
for (expr * e : conjs) {
if (!is_app(e)) {
continue;
}
app* a = to_app(e);
expr* e1;
if (m_ctx.is_var(a, idx)) {
m_replace.apply_substitution(a, m.mk_true(), fml);
m_ctx.elim_var(idx, fml, m.mk_true());
return true;
}
else if (m.is_not(e, e1) && m_ctx.is_var(e1, idx)) {
m_replace.apply_substitution(to_app(e1), m.mk_false(), fml);
m_ctx.elim_var(idx, fml, m.mk_false());
return true;
}
}
return false;
}
bool solve_polarized(expr* _fml) {
unsigned num_vars = m_ctx.get_num_vars();
expr_ref fml(_fml, m), def(m);
for (unsigned i = 0; i < num_vars; ++i) {
if (m.is_bool(m_ctx.get_var(i)) &&
solve_polarized(m_ctx.contains(i), fml, def)) {
m_ctx.elim_var(i, fml, def);
return true;
}
}
return false;
}
bool solve_polarized( contains_app& contains_x, expr_ref& fml, expr_ref& def) {
app* x = contains_x.x();
bool p = m_ctx.pos_atoms().contains(x);
bool n = m_ctx.neg_atoms().contains(x);
TRACE(quant_elim, tout << mk_pp(x, m) << " " << mk_pp(fml, m) << "\n";);
if (p && n) {
return false;
}
else if (p && !n) {
for (expr* y : m_ctx.pos_atoms()) {
if (x != y && contains_x(y)) return false;
}
for (expr* y : m_ctx.neg_atoms()) {
if (contains_x(y)) return false;
}
// only occurrences of 'x' must be in positive atoms
def = m.mk_true();
m_replace.apply_substitution(x, def, fml);
return true;
}
else if (!p && n) {
for (expr* y : m_ctx.pos_atoms()) {
if (contains_x(y)) return false;
}
for (expr* y : m_ctx.neg_atoms()) {
if (x != y && contains_x(y)) return false;
}
def = m.mk_false();
m_replace.apply_substitution(x, def, fml);
return true;
}
else if (contains_x(fml)) {
return false;
}
else {
def = m.mk_false();
return true;
}
}
};
qe_solver_plugin* mk_bool_plugin(i_solver_context& ctx) {
return alloc(bool_plugin, ctx, ctx.get_manager());
}
}