3
0
Fork 0
mirror of https://github.com/Z3Prover/z3 synced 2025-10-09 01:11:55 +00:00

move to structured types

Signed-off-by: Nikolaj Bjorner <nbjorner@microsoft.com>
This commit is contained in:
Nikolaj Bjorner 2025-09-05 11:31:40 -07:00
parent 975fd58e64
commit 2a272e1507

View file

@ -5,8 +5,7 @@
#include <cmath> #include <cmath>
#include <cassert> #include <cassert>
#include <iostream> #include <iostream>
#include <random>
using unsigned_vector = std::vector<unsigned>;
std::mutex cout_mutex; std::mutex cout_mutex;
// Initially there are no cubes. // Initially there are no cubes.
@ -20,7 +19,33 @@ std::mutex cout_mutex;
_out_ \ _out_ \
} }
inline std::ostream& operator<<(std::ostream& out, std::vector<int> const& v) { struct atom {
unsigned id = UINT_MAX;
atom() {}
atom(unsigned id) : id(id) {}
bool operator<(atom const& other) const { return id < other.id; }
bool operator==(atom const& other) const { return id == other.id; }
bool is_null() const { return id == UINT_MAX; }
};
struct literal {
atom a;
bool sign;
literal(atom a, bool s = false) : a(a), sign(s) {}
literal operator~() const { return literal(a, !sign); }
bool operator==(literal const& other) const { return a == other.a && sign == other.sign; }
};
inline std::ostream& operator<<(std::ostream& out, literal const& l) {
if (!l.sign)
out << "-";
out << l.a.id;
return out;
}
using literal_vector = std::vector<literal>;
inline std::ostream& operator<<(std::ostream& out, literal_vector const& v) {
out << "["; out << "[";
for (unsigned i = 0; i < v.size(); ++i) { for (unsigned i = 0; i < v.size(); ++i) {
if (i > 0) if (i > 0)
@ -37,42 +62,101 @@ enum status {
active active
}; };
struct node { struct node {
node* left = nullptr; node* left = nullptr;
node* right = nullptr; node* right = nullptr;
node* parent = nullptr; node* parent = nullptr;
unsigned atom = UINT_MAX; atom atom = UINT_MAX;
status status = status::open; status status = status::open;
node() {} node() {}
node(node* parent) : parent(parent) { node(node* parent) : parent(parent) {
} }
node(node* parent, int lit) : parent(parent) { node(node* parent, literal lit) : parent(parent) {
parent->atom = std::abs(lit); parent->atom = lit.a;
if (lit < 0) if (lit.sign)
parent->left = this; parent->left = this;
else else
parent->right = this; parent->right = this;
} }
std::vector<int> get_cube() { literal_vector get_cube() {
std::vector<int> path; literal_vector path;
auto t = this; auto t = this;
while (t->parent) { while (t->parent) {
int lit = t->parent->atom; literal lit = t->parent->atom;
if (t == t->parent->left) if (t == t->parent->left)
lit = -lit; lit = ~lit;
path.push_back(lit); path.push_back(lit);
t = t->parent; t = t->parent;
} }
std::reverse(path.begin(), path.end()); std::reverse(path.begin(), path.end());
return path; return path;
} }
void display(std::ostream& out, unsigned indent) const {
auto t = this;
for (unsigned i = 0; i < indent; ++i)
out << " ";
if (!t->atom.is_null())
out << t->atom;
else
out << "leaf";
out << (t->status == status::open ? " (o)" : t->status == status::closed ? " (c)" : " (a)");
out << "\n";
if (t->left)
t->left->display(out, indent + 2);
if (t->right)
t->right->display(out, indent + 2);
}
std::ostream& display(std::ostream& out) const {
display(out, 0);
return out;
}
node* get_open() {
if (!left && !right && status == status::open)
return this;
if (left) {
auto r = left->get_open();
if (r)
return r;
}
if (right) {
auto r = right->get_open();
if (r)
return r;
}
return nullptr;
}
node* get_active() {
if (status == status::active)
return this;
if (left) {
auto r = left->get_active();
if (r)
return r;
}
if (right) {
auto r = right->get_active();
if (r)
return r;
}
return nullptr;
}
}; };
class search_tree { class search_tree {
node* root; node* root;
void close_rec(node* t) { void close_rec(node* t) {
// if t->status == status::active, you can possibly pre-empt a worker.
t->status = status::closed; t->status = status::closed;
if (t->left) if (t->left)
close_rec(t->left); close_rec(t->left);
@ -80,81 +164,29 @@ class search_tree {
close_rec(t->right); close_rec(t->right);
} }
bool contains(std::vector<int> const& core, int lit) const { bool contains(literal_vector const& core, literal lit) const {
for (auto c : core) for (auto c : core)
if (lit == c) if (lit == c)
return true; return true;
return false; return false;
} }
void display_rec(std::ostream& out, node* t, unsigned indent) const {
for (unsigned i = 0; i < indent; ++i)
out << " ";
if (t->atom != UINT_MAX)
out << t->atom;
else
out << "leaf";
out << (t->status == status::open ? " (o)" : t->status == status::closed ? " (c)" : " (a)");
out << "\n";
if (t->left)
display_rec(out, t->left, indent + 2);
if (t->right)
display_rec(out, t->right, indent + 2);
}
node* get_open_rec(node* t) const {
if (!t->left && !t->right && t->status == status::open)
return t;
if (t->left) {
auto r = get_open_rec(t->left);
if (r)
return r;
}
if (t->right) {
auto r = get_open_rec(t->right);
if (r)
return r;
}
return nullptr;
}
node* get_active_rec(node* t) const {
if (t->status == status::active)
return t;
if (t->left) {
auto r = get_active_rec(t->left);
if (r)
return r;
}
if (t->right) {
auto r = get_active_rec(t->right);
if (r)
return r;
}
return nullptr;
}
public: public:
search_tree() { search_tree() {
root = new node; root = new node;
} }
node* add_path(std::vector<int> const& path) { node* add_path(literal_vector const& path) {
auto t = root; auto t = root;
unsigned i = 0; for (auto lit : path) {
while (i < path.size()) { atom atom = lit.a;
int lit = path[i]; if (t->atom.is_null()) {
unsigned atom = std::abs(lit);
bool sign = lit < 0;
if (t->atom == UINT_MAX) {
t->atom = atom; t->atom = atom;
t->status = status::open;
} }
assert(t->atom == atom); assert(t->atom == atom);
if (sign) { t->status = status::open;
if (lit.sign) {
if (!t->left) if (!t->left)
t = new node(t, lit); t = new node(t, lit);
else else
@ -166,18 +198,16 @@ public:
else else
t = t->right; t = t->right;
} }
i++;
} }
t->status = status::open;
return t; return t;
} }
node* get_open() const { node* get_open() const {
return get_open_rec(root); return root->get_open();
} }
node* get_active() const { node* get_active() const {
return get_active_rec(root); return root->get_active();
} }
bool is_closed() const { bool is_closed() const {
@ -185,30 +215,24 @@ public:
} }
// close a branch that contains a core // close a branch that contains a core
void close(std::vector<int> const& path, std::vector<int> const& core) { void close(literal_vector const& path, literal_vector const& core) {
unsigned num_hit = 0; unsigned num_hit = 0;
unsigned i = 0;
auto t = root; auto t = root;
while (num_hit < core.size()) { for (unsigned i = 0; num_hit < core.size(); ++i) {
assert(i < path.size());
LOG_OUT(std::cout << "close " << path << " " << core << " at " << i << " " << t->atom << "\n";); LOG_OUT(std::cout << "close " << path << " " << core << " at " << i << " " << t->atom << "\n";);
int lit = path[i]; literal lit = path[i];
unsigned atom = std::abs(lit); atom atom = lit.a;
bool sign = lit < 0;
auto next_t = sign ? t->left : t->right;
if (!next_t)
break;
assert(t->atom == atom); assert(t->atom == atom);
t = next_t; t = lit.sign ? t->left : t->right;
if (contains(core, lit)) if (contains(core, lit))
num_hit++; num_hit++;
++i;
} }
close_rec(t); close_rec(t);
} }
std::ostream& display(std::ostream& out) const { std::ostream& display(std::ostream& out) const {
display_rec(out, root, 0); return root->display(out);
return out;
} }
}; };
@ -224,24 +248,24 @@ public:
cube_manager(unsigned num_workers) : num_workers(num_workers) {} cube_manager(unsigned num_workers) : num_workers(num_workers) {}
~cube_manager() {} ~cube_manager() {}
void add_atom(int atom) { void add_atom(atom atom) {
std::lock_guard<std::mutex> lock(mutex); std::lock_guard<std::mutex> lock(mutex);
if (!at_start) if (!at_start)
return; return;
LOG_OUT(std::cout << "adding atom " << atom << "\n";); LOG_OUT(std::cout << "adding atom " << atom << "\n";);
at_start = false; at_start = false;
tree.add_path({atom}); tree.add_path({ literal(atom) });
tree.add_path({ -atom }); tree.add_path({ ~literal(atom) });
LOG_OUT(tree.display(std::cout);); LOG_OUT(tree.display(std::cout););
cv.notify_all(); cv.notify_all();
} }
void add_cube(std::vector<int>& cube, int atom) { void add_cube(literal_vector& cube, literal lit) {
std::lock_guard<std::mutex> lock(mutex); std::lock_guard<std::mutex> lock(mutex);
std::vector<int> cube1(cube); literal_vector cube1(cube);
cube1.push_back(atom); cube1.push_back(lit);
tree.add_path(cube1); tree.add_path(cube1);
cube.push_back(-atom); cube.push_back(~lit);
auto t = tree.add_path(cube); auto t = tree.add_path(cube);
t->status = status::active; t->status = status::active;
at_start = false; at_start = false;
@ -249,7 +273,7 @@ public:
LOG_OUT(std::cout << "adding cube " << cube1 << " and " << cube << "\n";); LOG_OUT(std::cout << "adding cube " << cube1 << " and " << cube << "\n";);
} }
bool get_cube(std::vector<int>& cube) { bool get_cube(literal_vector& cube) {
std::unique_lock<std::mutex> lock(mutex); std::unique_lock<std::mutex> lock(mutex);
if (at_start) { if (at_start) {
cube.clear(); cube.clear();
@ -273,7 +297,7 @@ public:
return true; return true;
} }
void close(std::vector<int> const& path, std::vector<int> const& core) { void close(literal_vector const& path, literal_vector const& core) {
std::lock_guard<std::mutex> lock(mutex); std::lock_guard<std::mutex> lock(mutex);
tree.close(path, core); tree.close(path, core);
LOG_OUT(std::cout << "closing "; tree.display(std::cout);); LOG_OUT(std::cout << "closing "; tree.display(std::cout););
@ -286,12 +310,11 @@ public:
}; };
struct random_gen { struct random_gen {
unsigned idx = 0; unsigned idx = std::rand();
random_gen(unsigned seed) : idx(seed) {} random_gen(unsigned seed) : idx(seed) {}
unsigned operator()(unsigned k) { unsigned operator()(unsigned k) {
idx += (idx + 1) * (idx << 3 + 2); return std::rand() % k;
return idx % k;
} }
}; };
@ -300,10 +323,10 @@ class worker {
cube_manager& cm; cube_manager& cm;
random_gen m_rand; random_gen m_rand;
bool solve_cube(const std::vector<int>& cube) { bool solve_cube(const literal_vector& cube) {
// dummy implementation // dummy implementation
LOG_OUT(std::cout << id << " solving " << cube << "\n";); LOG_OUT(std::cout << id << " solving " << cube << "\n";);
std::this_thread::sleep_for(std::chrono::milliseconds(100 + m_rand(1000))); std::this_thread::sleep_for(std::chrono::milliseconds(50 + m_rand(100)));
// the deeper the cube, the more likely we are to succeed. // the deeper the cube, the more likely we are to succeed.
// 1 - (9/10)^(|cube|) success probability // 1 - (9/10)^(|cube|) success probability
if (cube.empty()) if (cube.empty())
@ -319,29 +342,32 @@ public:
worker(unsigned id, cube_manager& cm) : id(id), cm(cm), m_rand(id) {} worker(unsigned id, cube_manager& cm) : id(id), cm(cm), m_rand(id) {}
~worker() {} ~worker() {}
void run() { void run() {
std::vector<int> cube; literal_vector cube;
while (cm.get_cube(cube)) { while (cm.get_cube(cube)) {
while (true) { while (true) {
if (solve_cube(cube)) { if (solve_cube(cube)) {
std::vector<int> core; literal_vector core;
for (auto l : cube) for (auto l : cube)
if (m_rand(2) == 0) if (m_rand(2) == 0)
core.push_back(l); core.push_back(l);
cm.close(cube, core); cm.close(cube, core);
break; break;
} }
int atom = 1 + cube.size() + 1000 * id; atom atom = 1 + cube.size() + 1000 * id;
if (cube.empty()) { if (cube.empty()) {
cm.add_atom(atom); cm.add_atom(atom);
break; break;
} }
literal lit(atom);
if (m_rand(2) == 0) if (m_rand(2) == 0)
atom = -atom; lit = ~lit;
cm.add_cube(cube, atom);
} cm.add_cube(cube, lit);
LOG_OUT(std::cout << id << " getting new cube\n";); LOG_OUT(std::cout << id << " getting new cube\n";);
} }
} }
}
}; };
@ -371,7 +397,7 @@ public:
}; };
int main() { int main() {
parallel_cuber sp(3); parallel_cuber sp(8);
sp.start(); sp.start();
return 0; return 0;
} }