Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
201 commits
Select commit Hold shift + click to select a range
41b5c64
very basic setup
ilanashapiro Jul 23, 2025
563906d
Merge branch 'Z3Prover:master' into parallel-solving
ilanashapiro Jul 24, 2025
4b87458
Merge remote-tracking branch 'upstream/ilana' into parallel-solving
ilanashapiro Jul 24, 2025
a6c51df
ensure solve_eqs is fully disabled when smt.solve_eqs=false, #7743
NikolajBjorner Jul 24, 2025
01633f7
respect smt configuration parameter in elim_unconstrained simplifier
NikolajBjorner Jul 24, 2025
1a488bb
indentation
NikolajBjorner Jul 25, 2025
6550495
add bash files for test runs
ilanashapiro Jul 25, 2025
e549286
add option to selectively disable variable solving for only ground ex…
NikolajBjorner Jul 26, 2025
95be0cf
remove verbose output
NikolajBjorner Jul 26, 2025
0528c86
fix #7745
NikolajBjorner Jul 26, 2025
8e1a528
ensure atomic constraints are processed by arithmetic solver
NikolajBjorner Jul 26, 2025
1f8b081
#7739 optimization
NikolajBjorner Jul 26, 2025
ad2934f
fix unsound len(substr) axiom
NikolajBjorner Jul 26, 2025
eb24488
FreshConst is_sort (#7748)
humnrdble Jul 27, 2025
e3139d4
#7750
NikolajBjorner Jul 27, 2025
0761394
Add parameter validation for selected API functions
NikolajBjorner Jul 27, 2025
67695b4
updates to ac-plugin
NikolajBjorner Jul 27, 2025
f77123c
enable passive, add check for bloom up-to-date
NikolajBjorner Jul 28, 2025
36fbee3
add top-k fixed-sized min-heap priority queue for top scoring literals
ilanashapiro Jul 28, 2025
f607a70
Merge branch 'Z3Prover:master' into parallel-solving
ilanashapiro Jul 28, 2025
4eeb98d
Merge branch 'ilana' into parallel-solving
NikolajBjorner Jul 29, 2025
2c188a5
set up worker thread batch manager for multithreaded batch cubes para…
ilanashapiro Jul 29, 2025
375d537
Merge branch 'parallel-solving' of github.com:ilanashapiro/z3 into pa…
ilanashapiro Jul 29, 2025
8a6cbec
fix bug in parallel solving batch setup
ilanashapiro Jul 30, 2025
e6213f8
fix bug
ilanashapiro Jul 31, 2025
2d876d5
allow for internalize implies
NikolajBjorner Aug 1, 2025
89cc9bd
disable pre-processing during cubing
NikolajBjorner Aug 1, 2025
12df9f8
Merge branch 'Z3Prover:master' into parallel-solving
ilanashapiro Aug 1, 2025
2a26776
debugging
ilanashapiro Aug 1, 2025
33c184f
Merge branch 'parallel-solving' of github.com:ilanashapiro/z3 into pa…
ilanashapiro Aug 1, 2025
97aa46a
remove default constructor
nunoplopes Aug 3, 2025
f23b053
remove a bunch of string copies
nunoplopes Aug 3, 2025
d8fafd8
Update euf_ac_plugin.cpp
NikolajBjorner Aug 3, 2025
b9b3e0d
Update euf_completion.cpp
NikolajBjorner Aug 3, 2025
d66fabe
Update smt_parallel.cpp
NikolajBjorner Aug 3, 2025
aac8787
process cubes as lists of individual lits
ilanashapiro Aug 4, 2025
a0a0670
Merge branch 'ilana' into parallel-solving
NikolajBjorner Aug 4, 2025
c9c3548
Merge branch 'Z3Prover:master' into parallel-solving
ilanashapiro Aug 4, 2025
7df95c0
merge
ilanashapiro Aug 4, 2025
cc8bc84
Merge branch 'parallel-solving' of github.com:ilanashapiro/z3 into pa…
ilanashapiro Aug 4, 2025
e520a42
merge
ilanashapiro Aug 4, 2025
7a8ba4b
Add support for Algebraic Datatypes in JavaScript/TypeScript bindings…
Copilot Aug 5, 2025
3982b29
chipping away at the new code structure
ilanashapiro Aug 5, 2025
0b21376
Merge branch 'Z3Prover:master' into parallel-solving
ilanashapiro Aug 5, 2025
2fce048
comments
ilanashapiro Aug 5, 2025
cdcc89a
merge
ilanashapiro Aug 5, 2025
d0bf711
Merge branch 'parallel-solving' of github.com:ilanashapiro/z3 into pa…
ilanashapiro Aug 5, 2025
723de8d
debug infinite recursion and split cubes on existing split atoms that…
ilanashapiro Aug 6, 2025
58e3121
share lemmas, learn from unsat core, try to debug a couple of things,…
ilanashapiro Aug 6, 2025
445339d
merge
ilanashapiro Aug 6, 2025
870729b
merge
ilanashapiro Aug 6, 2025
b1ab695
fix #7603: race condition in Ctrl-C handling (#7755)
nunoplopes Aug 6, 2025
d4a4dd6
add arithemtic saturation
NikolajBjorner Aug 6, 2025
b33f444
add an option to register callback on quantifier instantiation
NikolajBjorner Aug 7, 2025
aad511d
missing new closure
NikolajBjorner Aug 7, 2025
31a3037
add Z3_solver_propagate_on_binding to ml callback declarations
NikolajBjorner Aug 7, 2025
d218e87
add python file
levnach Aug 6, 2025
efa63db
debug under defined calls
levnach Aug 7, 2025
eeb1c18
more untangle params
levnach Aug 7, 2025
3eda386
precalc parameters to define the eval order
levnach Aug 7, 2025
f5016b4
remove a printout
levnach Aug 7, 2025
30830aa
rename a Python file
levnach Aug 7, 2025
fa3d341
add on_binding callbacks across APIs
NikolajBjorner Aug 7, 2025
d57dd6e
use jboolean in Native interface
NikolajBjorner Aug 7, 2025
0cefc92
register on_binding attribute
NikolajBjorner Aug 7, 2025
7ba967e
fix java build for java bindings
NikolajBjorner Aug 7, 2025
2ac1b24
avoid interferring side-effects in function calls
NikolajBjorner Aug 7, 2025
fcd3a70
remove theory_str and classes that are only used by it
NikolajBjorner Aug 8, 2025
baa0588
remove automata from python build
NikolajBjorner Aug 8, 2025
efb0bda
remove ref to theory_str
NikolajBjorner Aug 8, 2025
88293bf
get the finest factorizations before project
levnach Aug 7, 2025
8598a74
rename add_lcs to add_lc
levnach Aug 8, 2025
72757c4
resolve bad bug about l2g and g2l translators using wrong global cont…
ilanashapiro Aug 8, 2025
a9228f4
initial attempt at dynamically switching from greedy to frugal splitt…
ilanashapiro Aug 9, 2025
b7d5add
Update RELEASE_NOTES.md
NikolajBjorner Aug 10, 2025
8493c30
resolve bug about not translating managers correctly for the second p…
ilanashapiro Aug 11, 2025
2e6d95d
Merge branch 'Z3Prover:master' into parallel-solving
ilanashapiro Aug 11, 2025
e33dc47
remove unused square-free check
levnach Aug 11, 2025
7d57e6f
Merge branch 'ilana' into parallel-solving
NikolajBjorner Aug 11, 2025
6b3b8ac
add some debug prints and impelement internal polynomial fix
ilanashapiro Aug 11, 2025
ffb4bf1
merge
ilanashapiro Aug 11, 2025
de64a53
Merge branch 'parallel-solving' of github.com:ilanashapiro/z3 into pa…
ilanashapiro Aug 11, 2025
53eb2ca
Merge branch 'Z3Prover:master' into parallel-solving
ilanashapiro Aug 11, 2025
9373fec
Merge branch 'parallel-solving' of github.com:ilanashapiro/z3 into pa…
ilanashapiro Aug 11, 2025
cf8a17a
restore the square-free check
levnach Aug 11, 2025
ef61315
add some comments and debug m_assumptions_used
ilanashapiro Aug 11, 2025
a32b7ba
redo greedy->frugal strategy so we don't split on existing cubes in f…
ilanashapiro Aug 12, 2025
d864226
set up initial scaffolding for sharing clauses between threads and ba…
ilanashapiro Aug 12, 2025
f895dbc
merge
ilanashapiro Aug 12, 2025
efa5219
Merge remote-tracking branch 'upstream/ilana' into parallel-solving
ilanashapiro Aug 12, 2025
6486d92
Add .github/copilot-instructions.md with comprehensive Z3 development…
Copilot Aug 12, 2025
d375d97
Bump actions/checkout from 4 to 5 (#7773)
dependabot[bot] Aug 12, 2025
4bd40e9
turn off logging at level 0 for testing
ilanashapiro Aug 12, 2025
bdd0122
Merge remote-tracking branch 'upstream/ilana' into parallel-solving
ilanashapiro Aug 13, 2025
ae64207
add max thread conflicts backoff
ilanashapiro Aug 13, 2025
c8e866f
Parallel solving (#7775)
ilanashapiro Aug 13, 2025
3abb091
fix #7776
NikolajBjorner Aug 13, 2025
57a60c8
add > operator as shorthand for Array
NikolajBjorner Aug 13, 2025
237891c
updates to euf completion
NikolajBjorner Aug 13, 2025
bba1111
resolve bug about not popping local ctx to base level before collecti…
ilanashapiro Aug 13, 2025
eb7fd9e
Add virtual translate method to solver_factory class (#7780)
Copilot Aug 14, 2025
7f25a0d
put return_cubes under lock
ilanashapiro Aug 14, 2025
3ba08bd
Revert "resolve bug about not popping local ctx to base level before …
ilanashapiro Aug 14, 2025
6df8b39
Update seq_rewriter.cpp
NikolajBjorner Aug 14, 2025
174d64c
fix releaseNotesSource to inline
NikolajBjorner Aug 14, 2025
4362f2d
merge
ilanashapiro Aug 15, 2025
1e7832a
Use solver factory translate method in Z3_solver_translate (#7782)
Copilot Aug 15, 2025
e24a5b6
Revert "Parallel solving (#7775)" (#7777)
NikolajBjorner Aug 15, 2025
7422d81
remove upload artifact for azure-pipeline
NikolajBjorner Aug 15, 2025
a467d8c
Fix compilation warning: add missing is_passive_eq case to switch sta…
Copilot Aug 15, 2025
7b8482a
Remove NugetPublishNightly stage from nightly.yaml (#7787)
Copilot Aug 15, 2025
7250146
add more params
ilanashapiro Aug 15, 2025
063c09b
merge, and remove misleading defaults
ilanashapiro Aug 15, 2025
9b8dc4a
Merge remote-tracking branch 'upstream/ilana' into parallel-solving
ilanashapiro Aug 15, 2025
a121e6c
enable pypi public
NikolajBjorner Aug 15, 2025
d8bf0e0
Fix nullptr dereference in pp_symbol when handling null symbol names …
Copilot Aug 17, 2025
c75b8ec
add option to control epsilon #7791
NikolajBjorner Aug 17, 2025
4082e4e
update on euf
NikolajBjorner Aug 17, 2025
ff74af7
check for internalized in solve_for
NikolajBjorner Aug 17, 2025
5ad5899
merge
ilanashapiro Aug 17, 2025
7ff0b24
fix #7792
NikolajBjorner Aug 18, 2025
4542fc0
update version number to 4.15.4
NikolajBjorner Aug 18, 2025
21e3168
fix #7753
NikolajBjorner Aug 18, 2025
debe043
fix #7796
NikolajBjorner Aug 18, 2025
b1eb5b5
Merge remote-tracking branch 'upstream/ilana' into parallel-solving
ilanashapiro Aug 19, 2025
265265a
Create centralized version management with VERSION.txt (#7802)
Copilot Aug 20, 2025
7265563
read version from VERSION.txt
NikolajBjorner Aug 20, 2025
02f195a
fix version parse
NikolajBjorner Aug 20, 2025
fa0f9c9
fix parsing of version
NikolajBjorner Aug 20, 2025
48c8da4
add param tuning experiment in python
ilanashapiro Aug 21, 2025
47ce383
Merge branch 'Z3Prover:master' into parallel-solving
ilanashapiro Aug 21, 2025
4e3734d
Merge remote-tracking branch 'upstream/ilana' into parallel-solving
ilanashapiro Aug 22, 2025
d5764a1
Merge branch 'parallel-solving' of github.com:ilanashapiro/z3 into pa…
ilanashapiro Aug 22, 2025
05e8c2e
Merge remote-tracking branch 'upstream/ilana' into parallel-solving
ilanashapiro Aug 22, 2025
5d29eb1
Fix Azure Pipeline PyPI package builds by including VERSION.txt in so…
Copilot Aug 23, 2025
64419ad
Update nightly.yaml to match release.yml NuGet tool installer changes…
Copilot Aug 23, 2025
4792068
Attempt at adding the README to the NuGet package (#7807)
SolalPirelli Aug 23, 2025
12e7478
add resources
NikolajBjorner Aug 23, 2025
7e6e96f
remove resources directive again
NikolajBjorner Aug 23, 2025
ba068d7
Document how to use system-installed Z3 with CMake projects (#7809)
Copilot Aug 23, 2025
8d395d6
Fix Julia bindings linker errors on Windows MSVC (#7794)
Copilot Aug 23, 2025
21e63db
add print for version file
NikolajBjorner Aug 23, 2025
3b03636
add more logging to setup.py
NikolajBjorner Aug 23, 2025
778b9a5
try diferennt dirs
NikolajBjorner Aug 24, 2025
1987b3d
try src_dir_repo
NikolajBjorner Aug 24, 2025
438b41a
try other dir
NikolajBjorner Aug 24, 2025
867bc6a
remove extra characters
NikolajBjorner Aug 24, 2025
be22111
more output
NikolajBjorner Aug 24, 2025
116e1ec
print dirs
NikolajBjorner Aug 24, 2025
2874645
copy VERSION from SRC_DIR
NikolajBjorner Aug 24, 2025
300e0ae
Move VERSION.txt to scripts directory and update all references (#7811)
Copilot Aug 24, 2025
12563c6
clean up a little of the handling of VERSION.txt
NikolajBjorner Aug 24, 2025
9bf74b5
add implementation and toggleable param for splitting frugal + choosi…
ilanashapiro Aug 25, 2025
8866cf5
Merge branch 'Z3Prover:master' into parallel-solving
ilanashapiro Aug 25, 2025
58dc54e
remove priority queue for top-k lits and replace with simple linear s…
ilanashapiro Aug 25, 2025
0901711
Merge branch 'parallel-solving' of github.com:ilanashapiro/z3 into pa…
ilanashapiro Aug 25, 2025
b9256ba
Add new configurations for SMT parallel settings
ilanashapiro Aug 25, 2025
894c0e9
Bugfix: post-build sanity check when an old version of ocaml-z3 is in…
arbipher Aug 25, 2025
12dd705
Rename configuration from 'shareconflicts' to 'depthsplitting'
ilanashapiro Aug 25, 2025
0fdf5bc
Fix configuration for depth splitting in notes
ilanashapiro Aug 25, 2025
43d2a1f
rename variables
ilanashapiro Aug 25, 2025
307a8c5
merge
ilanashapiro Aug 25, 2025
1bed5a4
remove double tweak versioning
NikolajBjorner Aug 26, 2025
c010a38
attempting to add backbone code, it does not work. still debugging th…
ilanashapiro Aug 27, 2025
5c2f244
depth splitting now applies to greedy+frugal unless specified otherwise
ilanashapiro Aug 27, 2025
7a1c5e3
Merge branch 'Z3Prover:master' into parallel-solving
ilanashapiro Aug 27, 2025
04ef9dc
Merge remote-tracking branch 'upstream/ilana' into parallel-solving
ilanashapiro Aug 27, 2025
44e3f22
debug the backbone crash (it was references not being counted)
ilanashapiro Aug 27, 2025
e6afc50
Merge branch 'parallel-solving' of github.com:ilanashapiro/z3 into pa…
ilanashapiro Aug 27, 2025
9ea6f2e
merge
ilanashapiro Aug 27, 2025
1fae0de
iterative deepening experiment (no PQ yet). the hardness heuristic is…
ilanashapiro Aug 29, 2025
a42d21f
fix iterative deepening bug: unsolved cube needs to get re-enqueued e…
ilanashapiro Aug 29, 2025
651b860
debug iterative deepening some more and add first attempt at PQ (unte…
ilanashapiro Aug 29, 2025
67f5962
merge
ilanashapiro Aug 29, 2025
c2c0194
Merge remote-tracking branch 'upstream/ilana' into parallel-solving
ilanashapiro Aug 31, 2025
7af7ba6
fix some bugs and the PQ approach is working for now. the depth sets …
ilanashapiro Sep 1, 2025
a3024b7
add new attempt at hardness function
ilanashapiro Sep 1, 2025
042ebf5
attempt to add different hardness functions including heule schur and…
ilanashapiro Sep 1, 2025
ded70a7
implement march and heule schur hardness functions based on sat_looka…
ilanashapiro Sep 2, 2025
de99704
merge
ilanashapiro Sep 2, 2025
f243963
add a lot of debug prints that need to be removed. some bugs are reso…
ilanashapiro Sep 2, 2025
a7c9480
debug in progress
ilanashapiro Sep 3, 2025
254416c
merge
ilanashapiro Sep 3, 2025
228bc1b
remove the incorrect preselection functions for march and heule-schur…
ilanashapiro Sep 3, 2025
2e0d5c4
debug a couple of things and change the hardness function
ilanashapiro Sep 4, 2025
5a97b28
tree version in progress
ilanashapiro Sep 5, 2025
94f7f84
merge
ilanashapiro Sep 5, 2025
77e2925
cube tree data structure version for sharing maximal solver context. …
ilanashapiro Sep 5, 2025
ff88bf1
slowly debugging (committing for saving progress)
ilanashapiro Sep 6, 2025
d80f6bf
debugged get_next_cube to align with how we're storing the prev_cube …
ilanashapiro Sep 6, 2025
470c298
debug manager translation problem
ilanashapiro Sep 6, 2025
98896d7
don't actually prune tree for UNSAT, too risky with multithreads. ins…
ilanashapiro Sep 6, 2025
cf9623f
it runs! but then crashes after a while
ilanashapiro Sep 6, 2025
26ad2da
Merge branch 'ilana' into parallel-solving
NikolajBjorner Sep 6, 2025
4ccff79
add optimization (or what is hopefully an optimization) about threads…
ilanashapiro Sep 7, 2025
aaf6849
merge
ilanashapiro Sep 7, 2025
38a7819
debug some things. exhausting the cube tree should return unsat now, …
ilanashapiro Sep 7, 2025
6fcf045
merge
ilanashapiro Sep 7, 2025
d24389a
fix small bug about making sure we're searching in the thread's front…
ilanashapiro Sep 7, 2025
95b5eb9
debug big problem about incorrectly deepcopying children when assinin…
ilanashapiro Sep 7, 2025
163b086
Merge branch 'ilana' into parallel-solving
NikolajBjorner Sep 7, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
95 changes: 89 additions & 6 deletions src/smt/CubeTree.h
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
#include "ast/ast_translation.h"
#include "ast/ast_ll_pp.h"

#include <vector>
#include <cstdlib> // rand()
Expand Down Expand Up @@ -44,14 +45,16 @@ class CubeTree {

CubeNode* get_root() { return root; } // if root is nullptr, tree is empty

void add_children(CubeNode* parent,
std::pair<CubeNode*, CubeNode*> add_children(CubeNode* parent,
const Cube& left_cube,
const Cube& right_cube) {
IF_VERBOSE(1, verbose_stream() << "CubeTree: adding children of sizes " << left_cube.size() << " and " << right_cube.size() << " under parent of size " << (parent ? parent->cube.size() : 0) << "\n");
CubeNode* left = new CubeNode(left_cube, parent);
CubeNode* right = new CubeNode(right_cube, parent);
parent->children.push_back(left);
parent->children.push_back(right);

return {left, right}; // return the newly created children
}

// Add a new node under an existing parent
Expand Down Expand Up @@ -106,7 +109,10 @@ class CubeTree {
// get closest cube to current by getting a random sibling of current (if current was UNSAT and we removed it from the tree)
// or by descending randomly to a leaf (if we split the current node) to get the newest cube split fromthe current
// we descend randomly to a leaf instead of just taking a random child because it's possible another thread made more descendants
CubeNode* get_next_cube(CubeNode* current, std::vector<CubeNode*>& frontier_roots) {

CubeNode* get_next_cube(CubeNode* current, std::vector<CubeNode*>& frontier_roots, ast_manager& m, unsigned worker_id) {
print_tree(m);

IF_VERBOSE(1, verbose_stream() << "CubeTree: current cube is null: " << (current == nullptr) << "\n");
if (!current) return nullptr;

Expand All @@ -126,19 +132,68 @@ class CubeTree {
CubeNode* node = current;
std::vector<CubeNode*> remaining_frontier_roots = frontier_roots;
bool is_unexplored_frontier = frontier_roots.size() > 0 && current->cube.size() < frontier_roots[0]->cube.size(); // i.e. current is above the frontier (which always happens when we start with the empty cube!!)
IF_VERBOSE(1, verbose_stream() << "CubeTree: current cube is " << (is_unexplored_frontier ? "above" : "within") << " the frontier\n");

IF_VERBOSE(1, verbose_stream() << "CubeTree: current cube is " << (is_unexplored_frontier ? "above" : "within") << " the frontier. Current cube has the following children: \n");
for (auto* child : current->children) {
IF_VERBOSE(1, verbose_stream() << " Child cube size: " << child->cube.size() << " Active: " << child->active << " Cube: ");
for (auto* e : child->cube) {
IF_VERBOSE(1, verbose_stream() << mk_bounded_pp(e, m, 3) << " ");
}
IF_VERBOSE(1, verbose_stream() << "\n");
}

// if current is above the frontier, start searching from the first frontier root
if (is_unexplored_frontier && !frontier_roots.empty()) {
IF_VERBOSE(1, verbose_stream() << "CubeTree: starting search from first frontier root\n");
IF_VERBOSE(1, verbose_stream() << "CubeTree: Worker " << worker_id << " starting search from first frontier root. Frontier roots are:\n");
for (auto* x : frontier_roots) {
IF_VERBOSE(1, verbose_stream() << " Cube size: " << x->cube.size() << " Active: " << x->active << " Cube: ");
for (auto* e : x->cube) {
IF_VERBOSE(1, verbose_stream() << mk_bounded_pp(e, m, 3) << " ");
}
IF_VERBOSE(1, verbose_stream() << "\n");
}
node = frontier_roots[0];
IF_VERBOSE(1, verbose_stream() << "CubeTree: Worker " << worker_id << " selected frontier root: ");
for (auto* e : node->cube) {
IF_VERBOSE(1, verbose_stream() << mk_bounded_pp(e, m, 3) << " ");
}
IF_VERBOSE(1, verbose_stream() << "\n");
IF_VERBOSE(1, verbose_stream() << "This frontier root has children:\n");
for (auto* child : node->children) {
IF_VERBOSE(1, verbose_stream() << " Child cube size: " << child->cube.size() << " Active: " << child->active << " Cube: ");
for (auto* e : child->cube) {
IF_VERBOSE(1, verbose_stream() << mk_bounded_pp(e, m, 3) << " ");
}
IF_VERBOSE(1, verbose_stream() << "\n");
}
}


while (node) {
// check active leaf descendants
CubeNode* leaf_descendant = nullptr;
leaf_descendant = find_active_leaf(node);
if (leaf_descendant) return leaf_descendant;

if (leaf_descendant) {
IF_VERBOSE(1, {verbose_stream() << "CubeTree: Worker " << worker_id << " found active leaf descendant under node (which could be the node itself): ";
for (auto* e : node->cube) {
verbose_stream() << mk_bounded_pp(e, m, 3) << " ";
}
verbose_stream() << "\n Active leaf descendant is: ";
for (auto* e : leaf_descendant->cube) {
verbose_stream() << mk_bounded_pp(e, m, 3) << " ";
}
verbose_stream() << "\n";
});
return leaf_descendant;
}

IF_VERBOSE(1, {verbose_stream() << "CubeTree: Worker " << worker_id << " found no active leaf descendants found under node: ";
for (auto* e : node->cube) {
verbose_stream() << mk_bounded_pp(e, m, 3) << " ";
}
verbose_stream() << "\n";
});


// DO NOT NEED to check siblings and their active leaf descendants
// since this is handled by the recusion up the tree!!
Expand Down Expand Up @@ -181,6 +236,13 @@ class CubeTree {
return nullptr;
}

// Pretty-print the entire cube tree
void print_tree(ast_manager& m) const {
IF_VERBOSE(1, verbose_stream() << "=== CubeTree Dump ===\n");
print_subtree(m, root, 0);
IF_VERBOSE(1, verbose_stream() << "=== End Dump ===\n");
}

private:
CubeNode* root;

Expand All @@ -202,4 +264,25 @@ class CubeTree {
}
delete node;
}

void print_subtree(ast_manager& m, CubeNode* node, int indent) const {
if (!node) return;

// indent according to depth
for (int i = 0; i < indent; i++) IF_VERBOSE(1, verbose_stream() << " ");

IF_VERBOSE(1, verbose_stream() << "Node@" << node
<< " size=" << node->cube.size()
<< " active=" << node->active
<< " cube={ ");

for (expr* e : node->cube) {
IF_VERBOSE(1, verbose_stream() << mk_bounded_pp(e, m, 3) << " ");
}
IF_VERBOSE(1, verbose_stream() << "}\n");

for (CubeNode* child : node->children) {
print_subtree(m, child, indent + 1);
}
}
};
91 changes: 67 additions & 24 deletions src/smt/smt_parallel.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -104,14 +104,22 @@ namespace smt {
LOG_WORKER(1, " Curr cube node is null: " << (m_curr_cube_node == nullptr) << "\n");
if (m_config.m_cubetree) {
// use std::tie so we don't overshadow cube_node!!!
std::tie(cube_node, cube) = b.get_cube_from_tree(m_g2l, frontier_roots, m_curr_cube_node); // cube node is the reference to the node in the tree, tells us how to get the next cube. "cube" is the translated cube we need for the solver

std::tie(cube_node, cube) = b.get_cube_from_tree(m_g2l, frontier_roots, id, m_curr_cube_node); // cube node is the reference to the node in the tree, tells us how to get the next cube. "cube" is the translated cube we need for the solver

LOG_WORKER(1, " Got cube node from CubeTree. Is null: " << (cube_node == nullptr) << "\n");
if (!cube_node) { // i.e. no more cubes
LOG_WORKER(1, " No more cubes from CubeTree, exiting\n");
return;
}
m_curr_cube_node = cube_node; // store the current cube so we know how to get the next closest cube from the tree
IF_VERBOSE(1, verbose_stream() << " Worker " << id << " got cube of size " << cube.size() << " from CubeTree\n");
IF_VERBOSE(1, {
verbose_stream() << " Worker " << id << " got cube of size " << cube.size() << " from CubeTree. Cube contents: ";
for (auto& e : cube) {
verbose_stream() << mk_bounded_pp(e, m, 3) << " ";
}
verbose_stream() << "\n";
});
} else {
cube = b.get_cube(m_g2l);
}
Expand Down Expand Up @@ -163,7 +171,30 @@ namespace smt {
b.return_cubes(m_l2g, cube, split_atoms, should_split, cube_hardness);
} else if (m_config.m_cubetree) {
IF_VERBOSE(1, verbose_stream() << " returning undef cube to CubeTree. Cube node is null: " << (cube_node == nullptr) << "\n");
b.return_cubes_tree(m_l2g, cube_node, split_atoms, frontier_roots);

bool is_new_frontier = frontier_roots.empty();
b.return_cubes_tree(m_l2g, cube_node, cube, split_atoms, frontier_roots);

if (is_new_frontier) {
IF_VERBOSE(1, {
verbose_stream() << " Worker " << id << " has new frontier roots, with the following children: \n";
for (auto* node : frontier_roots) {
verbose_stream() << " Cube size: " << node->cube.size() << " Active: " << node->active << " Cube: ";
for (auto* e : node->cube) {
verbose_stream() << mk_bounded_pp(e, m, 3) << " ";
}
verbose_stream() << " Children: ";
for (auto* child : node->children) {
verbose_stream() << "[";
for (auto* e : child->cube) {
verbose_stream() << mk_bounded_pp(e, m, 3) << " ";
}
verbose_stream() << "] ";
}
verbose_stream() << "\n";
}
});
}
} else {
b.return_cubes(m_l2g, cube, split_atoms);
}
Expand Down Expand Up @@ -385,7 +416,8 @@ namespace smt {
return r;
}

std::pair<CubeNode*, expr_ref_vector> parallel::batch_manager::get_cube_from_tree(ast_translation& g2l, std::vector<CubeNode*>& frontier_roots, CubeNode* prev_cube) {

std::pair<CubeNode*, expr_ref_vector> parallel::batch_manager::get_cube_from_tree(ast_translation& g2l, std::vector<CubeNode*>& frontier_roots, unsigned worker_id, CubeNode* prev_cube) {
std::scoped_lock lock(mux);
expr_ref_vector l_cube(g2l.to());
SASSERT(m_config.m_cubetree);
Expand All @@ -399,13 +431,13 @@ namespace smt {
m_cubes_tree.add_node(new_cube_node, nullptr);
return {new_cube_node, l_cube}; // return empty cube
} else if (!prev_cube) {
prev_cube = m_cubes_tree.get_root(); // if prev_cube is null, it means that another thread started the tree first. so we also start from the root (i.e. the empty cube)
return {prev_cube, l_cube};
return {m_cubes_tree.get_root(), l_cube}; // if prev_cube is null, it means that another thread started the tree first. so we also start from the root (i.e. the empty cube)
}

// get a cube from the CubeTree
SASSERT(!m_cubes_tree.empty());
CubeNode* next_cube_node = m_cubes_tree.get_next_cube(prev_cube, frontier_roots); // get the next cube in the tree closest to the prev cube (i.e. longest common prefix)

CubeNode* next_cube_node = m_cubes_tree.get_next_cube(prev_cube, frontier_roots, g2l.to(), worker_id); // get the next cube in the tree closest to the prev cube (i.e. longest common prefix)

IF_VERBOSE(1, verbose_stream() << "Batch manager giving out cube from CubeTree. Is null: " << (next_cube_node==nullptr) << "\n");

Expand All @@ -418,7 +450,6 @@ namespace smt {
l_cube.push_back(g2l(e));
}

IF_VERBOSE(1, verbose_stream() << " Cube size: " << l_cube.size() << "\n");
next_cube_node->active = false; // mark the cube as inactive (i.e. being processed by a worker)

return {next_cube_node, l_cube};
Expand Down Expand Up @@ -789,11 +820,9 @@ namespace smt {
}
}

void parallel::batch_manager::return_cubes_tree(ast_translation& l2g, CubeNode* cube_node, expr_ref_vector const& A_worker, std::vector<CubeNode*>& frontier_roots) {
IF_VERBOSE(1, verbose_stream() << " Returning cube to batch manager's cube tree.\n");
expr_ref_vector const& l_cube = cube_node->cube;
IF_VERBOSE(1, verbose_stream() << " Cube node null: " << (cube_node == nullptr) << "\n");
IF_VERBOSE(1, verbose_stream() << " PROCESSING CUBE of size: " << l_cube.size() << "\n");
void parallel::batch_manager::return_cubes_tree(ast_translation& l2g, CubeNode* cube_node, expr_ref_vector const& l_cube, expr_ref_vector const& A_worker, std::vector<CubeNode*>& frontier_roots) {
IF_VERBOSE(1, verbose_stream() << " Returning cube to batch manager's cube tree. Cube node null: " << (cube_node == nullptr) << " PROCESSING CUBE of size: " << l_cube.size() << "\n");


bool is_new_frontier = frontier_roots.empty(); // need to save this as a bool here, bc otherwise the frontier stops being populated after a single split atom
IF_VERBOSE(1, verbose_stream() << " Is new frontier: " << is_new_frontier << "\n");
Expand All @@ -818,17 +847,21 @@ namespace smt {
expr_ref_vector g_cube_neg = g_cube;
g_cube_neg.push_back(m.mk_not(atom));

m_cubes_tree.add_children(cube_node, g_cube_pos, g_cube_neg); // default is active
if (is_new_frontier) { // note: calling frontier_roots.empty() here would always return false after adding the first split atom
// add cube_pos and cube_neg to frontier roots
CubeNode* cube_node_pos = new CubeNode(*cube_node); // deep copy of the node
CubeNode* cube_node_neg = new CubeNode(*cube_node); // deep copy of the node
cube_node_pos->cube.push_back(atom); // modify cube
cube_node_neg->cube.push_back(m.mk_not(atom)); // modify cube

frontier_roots.push_back(cube_node_pos);
frontier_roots.push_back(cube_node_neg);
IF_VERBOSE(1, verbose_stream() << " Added split to frontier roots. Size now: " << frontier_roots.size() << "\n");

IF_VERBOSE(1, verbose_stream() << " Splitting positive and negative atoms: " << mk_pp(atom, m) << "," << mk_pp(m.mk_not(atom), m) << " from root: ");
//print the cube
for (auto& e : cube_node->cube)
IF_VERBOSE(1, verbose_stream() << mk_bounded_pp(e, m, 3) << " ");
IF_VERBOSE(1, verbose_stream() << "\n");

auto [left_child, right_child] = m_cubes_tree.add_children(cube_node, g_cube_pos, g_cube_neg); // note: default is active

if (is_new_frontier) {
frontier_roots.push_back(left_child);
frontier_roots.push_back(right_child);
IF_VERBOSE(1, verbose_stream() << " Added split to frontier roots. Size now: "
<< frontier_roots.size() << "\n");

}

m_stats.m_num_cubes += 2;
Expand All @@ -854,6 +887,16 @@ namespace smt {
IF_VERBOSE(1, verbose_stream() << " splitting worker cube on new atom " << mk_bounded_pp(g_atom, m, 3) << "\n");
add_split_atom_tree(g_atom);
}

IF_VERBOSE(1, verbose_stream() << " The returned cube:");
for (auto& e : l_cube)
IF_VERBOSE(1, verbose_stream() << mk_bounded_pp(e, m, 3) << " ");
IF_VERBOSE(1, verbose_stream() << " now has the following children:\n");
for (auto child : cube_node->children) {
for (auto& e : child->cube)
IF_VERBOSE(1, verbose_stream() << mk_bounded_pp(e, m, 3) << " ");
}
IF_VERBOSE(1, verbose_stream() << "\n");
}

expr_ref_vector parallel::worker::find_backbone_candidates() {
Expand Down
8 changes: 6 additions & 2 deletions src/smt/smt_parallel.h
Original file line number Diff line number Diff line change
Expand Up @@ -132,13 +132,17 @@ namespace smt {
// The batch manager returns the next cube to
//
expr_ref_vector get_cube(ast_translation& g2l); // FOR ALL NON-TREE VERSIONS
std::pair<CubeNode*, expr_ref_vector> get_cube_from_tree(ast_translation& g2l, std::vector<CubeNode*>& frontier_roots, CubeNode* prev_cube = nullptr);

std::pair<CubeNode*, expr_ref_vector> get_cube_from_tree(ast_translation& g2l, std::vector<CubeNode*>& frontier_roots, unsigned worker_id, CubeNode* prev_cube = nullptr);


//
// worker threads return unprocessed cubes to the batch manager together with split literal candidates.
// the batch manager re-enqueues unprocessed cubes and optionally splits them using the split_atoms returned by this and workers.
//
void return_cubes_tree(ast_translation& l2g, CubeNode* cube, expr_ref_vector const& split_atoms, std::vector<CubeNode*>& frontier_roots);

void return_cubes_tree(ast_translation& l2g, CubeNode* cube_node, expr_ref_vector const& cube, expr_ref_vector const& split_atoms, std::vector<CubeNode*>& frontier_roots);

// FOR ALL NON-TREE VERSIONS
void return_cubes(ast_translation& l2g, expr_ref_vector const& cube, expr_ref_vector const& split_atoms, const bool should_split=true, const double hardness=1.0);
void report_assumption_used(ast_translation& l2g, expr* assumption);
Expand Down