3
0
Fork 0
mirror of https://github.com/Z3Prover/z3 synced 2025-09-30 13:19:04 +00:00
z3/src/opt/maxlex.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

217 lines
6.4 KiB
C++

/*++
Copyright (c) 2019 Microsoft Corporation
Module Name:
maxlex.cpp
Abstract:
MaxLex solves weighted max-sat problems where weights impose lexicographic order.
MaxSAT is particularly easy for this class:
In order of highest weight, check if soft constraint can be satisfied.
If so, assert it, otherwise assert the negation and record whether the soft
constraint is true or false in the solution.
Author:
Nikolaj Bjorner (nbjorner) 2019-25-1
--*/
#include "ast/ast_pp.h"
#include "opt/opt_context.h"
#include "opt/maxsmt.h"
#include "opt/maxlex.h"
namespace opt {
bool is_maxlex(vector<soft> const & _ws) {
vector<soft> ws(_ws);
std::sort(ws.begin(), ws.end(), [&](soft const& s1, soft const& s2) { return s1.weight < s2.weight; });
ws.reverse();
rational sum(0);
for (auto const& [e, w, t] : ws) {
sum += w;
}
for (auto const& [e, w, t] : ws) {
if (sum > w + w) return false;
sum -= w;
}
return true;
}
class maxlex : public maxsmt_solver_base {
struct cmp_soft {
bool operator()(soft const& s1, soft const& s2) const {
return s1.weight > s2.weight;
}
};
ast_manager& m;
maxsat_context& m_c;
bool update_assignment() {
model_ref mdl;
s().get_model(mdl);
if (mdl) {
m_model = mdl;
m_c.model_updated(mdl.get());
update_assignment(mdl);
}
return mdl.get() != nullptr;
}
void assert_value(soft& soft) {
switch (soft.value) {
case l_true:
s().assert_expr(soft.s);
break;
case l_false:
s().assert_expr(expr_ref(m.mk_not(soft.s), m));
break;
default:
break;
}
}
void update_assignment(model_ref & mdl) {
mdl->set_model_completion(true);
bool first_undef = true, second_undef = false;
for (auto & soft : m_soft) {
if (first_undef && soft.value != l_undef) {
continue;
}
else if (first_undef) {
SASSERT(soft.value == l_undef);
soft.set_value(l_true);
assert_value(soft);
first_undef = false;
}
else if (soft.value != l_false) {
lbool v = mdl->is_true(soft.s) ? l_true : l_undef;
if (v == l_undef) {
second_undef = true;
}
if (second_undef) {
soft.set_value(v);
}
else {
SASSERT(v == l_true);
soft.set_value(v);
assert_value(soft);
}
}
}
update_bounds();
}
void update_bounds() {
m_lower.reset();
m_upper.reset();
for (auto & soft : m_soft) {
switch (soft.value) {
case l_undef:
m_upper += soft.weight;
break;
case l_true:
break;
case l_false:
m_lower += soft.weight;
m_upper += soft.weight;
break;
}
}
trace_bounds("maxlex");
}
void init() {
for (auto & soft : m_soft) {
soft.set_value(l_undef);
}
model_ref mdl;
s().get_model(mdl);
if (mdl) {
TRACE(opt, tout << *mdl << "\n";);
for (auto & soft : m_soft) {
if (!mdl->is_true(soft.s)) {
update_bounds();
return;
}
soft.set_value(l_true);
assert_value(soft);
}
update_assignment();
}
}
//
// include soft constraints that are known to be assignable to true after failed literal.
//
lbool maxlexN() {
unsigned sz = m_soft.size();
for (unsigned i = 0; i < sz; ++i) {
auto& soft = m_soft[i];
if (soft.value != l_undef)
continue;
expr_ref_vector asms(m);
asms.push_back(soft.s);
lbool is_sat = s().check_sat(asms);
switch (is_sat) {
case l_true:
if (!update_assignment())
return l_undef;
SASSERT(soft.value == l_true || m.limit().is_canceled());
break;
case l_false:
soft.set_value(l_false);
assert_value(soft);
for (unsigned j = i + 1; j < sz; ++j) {
auto& soft2 = m_soft[j];
if (soft2.value != l_true) {
break;
}
assert_value(soft2);
}
update_bounds();
break;
case l_undef:
return l_undef;
}
}
return l_true;
}
public:
maxlex(maxsat_context& c, unsigned id, vector<soft>& s):
maxsmt_solver_base(c, s, id),
m(c.get_manager()),
m_c(c) {
// ensure that soft constraints are sorted with largest soft constraints first.
cmp_soft cmp;
std::sort(m_soft.begin(), m_soft.end(), cmp);
}
lbool operator()() override {
init();
return maxlexN();
}
void commit_assignment() override {
for (auto & soft : m_soft) {
if (soft.value == l_undef) {
return;
}
assert_value(soft);
}
}
};
maxsmt_solver_base* mk_maxlex(maxsat_context& c, unsigned id, vector<soft>& soft) {
return alloc(maxlex, c, id, soft);
}
}