3
0
Fork 0
mirror of https://github.com/Z3Prover/z3 synced 2025-08-31 23:34:55 +00:00

Parallel solving (#7758)

* very basic setup

* ensure solve_eqs is fully disabled when smt.solve_eqs=false, #7743

Signed-off-by: Nikolaj Bjorner <nbjorner@microsoft.com>

* respect smt configuration parameter in elim_unconstrained simplifier

Signed-off-by: Nikolaj Bjorner <nbjorner@microsoft.com>

* indentation

* add bash files for test runs

* add option to selectively disable variable solving for only ground expressions

Signed-off-by: Nikolaj Bjorner <nbjorner@microsoft.com>

* remove verbose output

Signed-off-by: Nikolaj Bjorner <nbjorner@microsoft.com>

* fix #7745

axioms for len(substr(...)) escaped due to nested rewriting

* ensure atomic constraints are processed by arithmetic solver

* #7739 optimization

add simplification rule for at(x, offset) = ""

Introducing j just postpones some rewrites that prevent useful simplifications. Z3 already uses common sub-expressions.
The example highlights some opportunities for simplification, noteworthy at(..) = "".
The example is solved in both versions after adding this simplification.

* fix unsound len(substr) axiom

Signed-off-by: Nikolaj Bjorner <nbjorner@microsoft.com>

* FreshConst is_sort (#7748)

* #7750

add pre-processing simplification

* Add parameter validation for selected API functions

* updates to ac-plugin

fix incrementality bugs by allowing destructive updates during saturation at the cost of redoing saturation after a pop.

* enable passive, add check for bloom up-to-date

* add top-k fixed-sized min-heap priority queue for top scoring literals

* set up worker thread batch manager for multithreaded batch cubes paradigm, need to debug as I am getting segfault still

* fix bug in parallel solving batch setup

* fix bug

* allow for internalize implies

* disable pre-processing during cubing

* debugging

* remove default constructor

* remove a bunch of string copies

* Update euf_ac_plugin.cpp

include reduction rules in forward simplification

* Update euf_completion.cpp

try out restricting scope of equalities added by instantation

* Update smt_parallel.cpp

Drop non-relevant units from shared structures.

* process cubes as lists of individual lits

* merge

* Add support for Algebraic Datatypes in JavaScript/TypeScript bindings (#7734)

* Initial plan

* Add datatype type definitions to types.ts (work in progress)

Co-authored-by: NikolajBjorner <3085284+NikolajBjorner@users.noreply.github.com>

* Complete datatype type definitions with working TypeScript compilation

Co-authored-by: NikolajBjorner <3085284+NikolajBjorner@users.noreply.github.com>

* Implement core datatype functionality with TypeScript compilation success

Co-authored-by: NikolajBjorner <3085284+NikolajBjorner@users.noreply.github.com>

* Complete datatype implementation with full Context integration and tests

Co-authored-by: NikolajBjorner <3085284+NikolajBjorner@users.noreply.github.com>

---------

Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
Co-authored-by: NikolajBjorner <3085284+NikolajBjorner@users.noreply.github.com>

* chipping away at the new code structure

---------

Signed-off-by: Nikolaj Bjorner <nbjorner@microsoft.com>
Co-authored-by: Nikolaj Bjorner <nbjorner@microsoft.com>
Co-authored-by: humnrdble <83878671+humnrdble@users.noreply.github.com>
Co-authored-by: Nuno Lopes <nuno.lopes@tecnico.ulisboa.pt>
Co-authored-by: Copilot <198982749+Copilot@users.noreply.github.com>
Co-authored-by: NikolajBjorner <3085284+NikolajBjorner@users.noreply.github.com>
This commit is contained in:
Ilana Shapiro 2025-08-05 09:06:36 -07:00 committed by GitHub
parent 0ac6abf3a8
commit aa5d833b38
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
11 changed files with 552 additions and 469 deletions

View file

@ -278,17 +278,9 @@ namespace euf {
if (!m_shared.empty())
out << "shared monomials:\n";
for (auto const& s : m_shared) {
out << g.bpp(s.n) << ": " << s.m << " r: " << g.bpp(s.n->get_root()) << "\n";
out << g.bpp(s.n) << " r " << g.bpp(s.n->get_root()) << " - " << s.m << ": " << m_pp_ll(*this, monomial(s.m)) << "\n";
}
#if 0
i = 0;
for (auto m : m_monomials) {
out << i << ": ";
display_monomial_ll(out, m);
out << "\n";
++i;
}
#endif
for (auto n : m_nodes) {
if (!n)
continue;
@ -361,19 +353,16 @@ namespace euf {
if (!orient_equation(eq))
return false;
#if 1
if (is_reducing(eq))
is_active = true;
#else
is_active = true; // set to active by default
#endif
if (!is_active) {
m_passive.push_back(eq);
return true;
}
eq.status = eq_status::is_to_simplify_eq;
m_active.push_back(eq);
auto& ml = monomial(eq.l);
auto& mr = monomial(eq.r);
@ -621,9 +610,9 @@ namespace euf {
// simplify eq using processed
TRACE(plugin,
for (auto other_eq : forward_iterator(eq_id))
tout << "forward iterator " << eq_id << " vs " << other_eq << " " << is_processed(other_eq) << "\n");
tout << "forward iterator " << eq_pp_ll(*this, m_active[eq_id]) << " vs " << eq_pp_ll(*this, m_active[other_eq]) << "\n");
for (auto other_eq : forward_iterator(eq_id))
if (is_processed(other_eq) && forward_simplify(eq_id, other_eq))
if ((is_processed(other_eq) || is_reducing(other_eq)) && forward_simplify(eq_id, other_eq))
goto loop_start;
auto& eq = m_active[eq_id];
@ -914,6 +903,8 @@ namespace euf {
set_status(dst_eq, eq_status::is_dead_eq);
return true;
}
SASSERT(!are_equal(m_active[src_eq], m_active[dst_eq]));
if (!is_equation_oriented(src))
return false;
// check that src.l is a subset of dst.r
@ -1088,23 +1079,18 @@ namespace euf {
// rewrite monomial to normal form.
bool ac_plugin::reduce(ptr_vector<node>& m, justification& j) {
bool change = false;
unsigned sz = m.size();
do {
init_loop:
if (m.size() == 1)
return change;
bloom b;
init_ref_counts(m, m_m_counts);
for (auto n : m) {
if (n->is_zero) {
m[0] = n;
m.shrink(1);
change = true;
break;
}
for (auto eq : n->eqs) {
continue;
if (!is_reducing(eq)) // also can use processed?
continue;
auto& src = m_active[eq];
if (!is_equation_oriented(src))
@ -1116,17 +1102,16 @@ namespace euf {
TRACE(plugin, display_equation_ll(tout << "reduce ", src) << "\n");
SASSERT(is_correct_ref_count(monomial(src.l), m_eq_counts));
//display_equation_ll(std::cout << "reduce ", src) << ": ";
//display_monomial_ll(std::cout, m);
for (auto n : m)
for (auto s : n->shared)
m_shared_todo.insert(s);
rewrite1(m_eq_counts, monomial(src.r), m_m_counts, m);
//display_monomial_ll(std::cout << " -> ", m) << "\n";
j = join(j, eq);
change = true;
goto init_loop;
}
}
} while (false);
VERIFY(sz >= m.size());
return change;
}
@ -1287,6 +1272,8 @@ namespace euf {
continue;
}
change = true;
for (auto s : n->shared)
m_shared_todo.insert(s);
if (r.size() == 0)
// if r is empty, we can remove n from l
continue;
@ -1407,9 +1394,11 @@ namespace euf {
TRACE(plugin_verbose, tout << "num shared todo " << m_shared_todo.size() << "\n");
if (m_shared_todo.empty())
return;
while (!m_shared_todo.empty()) {
auto idx = *m_shared_todo.begin();
m_shared_todo.remove(idx);
m_shared_todo.remove(idx);
TRACE(plugin, tout << "index " << idx << " shared size " << m_shared.size() << "\n");
if (idx < m_shared.size())
simplify_shared(idx, m_shared[idx]);
}
@ -1431,7 +1420,7 @@ namespace euf {
auto old_m = s.m;
auto old_n = monomial(old_m).m_src;
ptr_vector<node> m1(monomial(old_m).m_nodes);
TRACE(plugin_verbose, tout << "simplify shared: " << g.bpp(old_n) << ": " << m_pp_ll(*this, monomial(old_m)) << "\n");
TRACE(plugin, tout << "simplify shared: " << g.bpp(old_n) << ": " << m_pp_ll(*this, monomial(old_m)) << "\n");
if (!reduce(m1, j))
return;

View file

@ -268,7 +268,6 @@ namespace euf {
expr_ref r(f, m);
m_rewriter(r);
f = r.get();
// verbose_stream() << r << "\n";
auto cons = m.mk_app(symbol("consequence"), 1, &f, m.mk_bool_sort());
m_fmls.add(dependent_expr(m, cons, nullptr, nullptr));
}
@ -317,35 +316,43 @@ namespace euf {
expr_ref y1(y, m);
m_rewriter(x1);
m_rewriter(y1);
add_quantifiers(x1);
add_quantifiers(y1);
enode* a = mk_enode(x1);
enode* b = mk_enode(y1);
if (a->get_root() == b->get_root())
return;
m_egraph.merge(a, b, to_ptr(push_pr_dep(pr, d)));
m_egraph.propagate();
return;
TRACE(euf, tout << "merge and propagate\n");
add_children(a);
add_children(b);
m_egraph.merge(a, b, to_ptr(push_pr_dep(pr, d)));
m_egraph.propagate();
m_should_propagate = true;
#if 0
auto a1 = mk_enode(x);
if (a1->get_root() != a->get_root()) {
auto b1 = mk_enode(y);
if (a->get_root() != a1->get_root()) {
add_children(a1);;
m_egraph.merge(a, a1, nullptr);
m_egraph.propagate();
add_children(a1);
}
auto b1 = mk_enode(y);
if (b1->get_root() != b->get_root()) {
TRACE(euf, tout << "merge and propagate\n");
m_egraph.merge(b, b1, nullptr);
m_egraph.propagate();
add_children(b1);
}
m_should_propagate = true;
if (m_side_condition_solver)
if (b->get_root() != b1->get_root()) {
add_children(b1);
m_egraph.merge(b, b1, nullptr);
m_egraph.propagate();
}
#endif
if (m_side_condition_solver && a->get_root() != b->get_root())
m_side_condition_solver->add_constraint(f, pr, d);
IF_VERBOSE(1, verbose_stream() << "eq: " << mk_pp(x1, m) << " == " << mk_pp(y1, m) << "\n");
IF_VERBOSE(1, verbose_stream() << "eq: " << a->get_root_id() << " " << b->get_root_id() << " "
<< x1 << " == " << y1 << "\n");
}
else if (m.is_not(f, f)) {
enode* n = mk_enode(f);
@ -689,7 +696,7 @@ namespace euf {
b = new (mem) binding(q, pat, max_generation, min_top, max_top);
b->init(b);
for (unsigned i = 0; i < n; ++i)
b->m_nodes[i] = _binding[i];
b->m_nodes[i] = _binding[i]->get_root();
m_bindings.insert(b);
get_trail().push(insert_map<bindings, binding*>(m_bindings, b));
@ -748,12 +755,13 @@ namespace euf {
void completion::apply_binding(binding& b, quantifier* q, expr_ref_vector const& s) {
var_subst subst(m);
expr_ref r = subst(q->get_expr(), s);
expr_ref r = subst(q->get_expr(), s);
scoped_generation sg(*this, b.m_max_top_generation + 1);
auto [pr, d] = get_dependency(q);
if (pr)
pr = m.mk_quant_inst(m.mk_or(m.mk_not(q), r), s.size(), s.data());
m_consequences.push_back(r);
TRACE(euf_completion, tout << "new instantiation: " << r << " q: " << mk_pp(q, m) << "\n");
add_constraint(r, pr, d);
propagate_rules();
m_egraph.propagate();
@ -1022,7 +1030,7 @@ namespace euf {
}
enode* n = m_egraph.find(f);
if (!n) n = mk_enode(f);
enode* r = n->get_root();
d = m.mk_join(d, explain_eq(n, r));
d = m.mk_join(d, m_deps.get(r->get_id(), nullptr));