3
0
Fork 0
mirror of https://github.com/Z3Prover/z3 synced 2025-04-09 19:01:50 +00:00
z3/test/symmetry.cpp
Leonardo de Moura 68269c43a6 other components
Signed-off-by: Leonardo de Moura <leonardo@microsoft.com>
2012-10-02 11:48:48 -07:00

1105 lines
32 KiB
C++

#ifdef _WINDOWS
#include "vector.h"
#include "region.h"
#include "trail.h"
#include "nat_set.h"
#include "stream_buffer.h"
#include "obj_hashtable.h"
class partition {
public:
class id {
friend class partition;
unsigned m_id;
id(unsigned idx): m_id(idx) {}
unsigned get_id() const { return m_id; }
public:
id() : m_id(0) {}
bool operator==(id const& other) const { return m_id == other.m_id; }
bool operator!=(id const& other) const { return m_id != other.m_id; }
std::ostream& display(std::ostream& out) const {
return out << "p" << m_id;
}
};
private:
static const unsigned invalid_length = 0xFFFFFFFF;
unsigned_vector m_vertices; // permutation of vertices
svector<id> m_roots; // pointers to class roots, the position in m_vertices that contains the root.
unsigned_vector m_lengths; // length of equivalence class, valid at root position.
unsigned_vector m_length_trail;
unsigned_vector m_offset_trail;
unsigned_vector m_length_lim;
bool invariant() const {
if (m_roots.size() != m_vertices.size()) {
return false;
}
if (m_roots.size() != m_lengths.size()) {
return false;
}
for (unsigned i = 0; i < m_roots.size(); ++i) {
if (!is_root(m_vertices[m_roots[m_vertices[i]].get_id()])) {
return false;
}
}
return true;
}
bool is_root(id class_id) const {
return
class_id.m_id < m_vertices.size() &&
m_roots[m_vertices[class_id.m_id]] == class_id;
}
public:
class mark {
partition& m_partition;
nat_set m_mark;
public:
mark(partition& p): m_partition(p) {
m_mark.assure_domain(p.m_roots.size());
}
void reset() {
m_mark.reset();
}
bool test_and_set(id class_id0) {
if (m_mark.contains(class_id0.m_id)) {
return false;
}
m_mark.insert(class_id0.m_id);
return true;
}
};
partition(unsigned size) {
for (unsigned i = 0; i < size; ++i) {
m_vertices.push_back(i);
m_roots.push_back(id(0));
m_lengths.push_back(invalid_length);
}
m_lengths[0] = size;
}
void push_scope() {
SASSERT(invariant());
m_length_lim.push_back(m_length_trail.size());
}
void pop_scope(unsigned num_scopes) {
if (num_scopes == 0) {
return;
}
unsigned lvl = m_length_lim.size();
SASSERT(num_scopes <= lvl);
unsigned new_lvl = lvl - num_scopes;
unsigned old_size = m_length_lim[new_lvl];
//
// NB. backtracking could be expensive in the case where
// we partition the same class multiple times during
// one level. Alternative is to maintain level indication
// together with length to avoid pushing redundant length
// constraints on the stack.
//
for (unsigned i = m_length_trail.size(); i > old_size; ) {
--i;
unsigned offset = m_offset_trail[i];
unsigned length = m_length_trail[i];
id class_id(offset);
if (length != invalid_length) {
for (unsigned j = 0; j < length; ++j) {
m_roots[m_vertices[offset + j]] = class_id;
}
}
m_lengths[offset] = length;
}
m_length_trail.shrink(old_size);
m_offset_trail.shrink(old_size);
m_length_lim.shrink(new_lvl);
SASSERT(invariant());
}
unsigned get_size(id class_id) const {
SASSERT(is_root(class_id));
return m_lengths[class_id.m_id];
}
unsigned * get_elems(id class_id) {
SASSERT(is_root(class_id));
return m_vertices.begin() + class_id.m_id;
}
unsigned const * get_elems(id class_id) const {
return m_vertices.begin() + class_id.m_id;
}
void mk_partition(unsigned length, unsigned const* vertices) {
SASSERT(m_vertices.begin() <= vertices);
SASSERT(vertices < m_vertices.begin() + m_vertices.size());
unsigned offset = static_cast<unsigned>(vertices - m_vertices.begin());
m_length_trail.push_back(m_lengths[offset]);
m_offset_trail.push_back(offset);
m_lengths[offset] = length;
id class_id(offset);
for (unsigned i = 0; i < length; ++i) {
m_roots[vertices[i]] = class_id;
}
}
id operator[](unsigned v) const {
return m_roots[v];
}
void display(std::ostream& out) {
for (unsigned i = 0; i < m_vertices.size(); ++i) {
out << m_vertices[i] << " |-> " << m_roots[m_vertices[i]].m_id << "\n";
}
}
void copy_vertices(unsigned_vector& vertices) {
vertices = m_vertices;
}
void split(id id, unsigned v, unsigned pos) {
// split class id into two parts.
// put var v at position pos in a singleton class.
//
// TBD: can swap into last place to save updates to ids.
// TBD: nothing ensures vertices are invariant under backtracking.
// TBD: the new partitions should be added to m_todo in
// the refiner.
//
unsigned offset = id.get_id();
if (pos > offset) {
unsigned length = m_lengths[offset];
std::swap(m_vertices.begin()[pos],m_vertices.begin()[offset]);
SASSERT(length > 1);
mk_partition(1, m_vertices.begin()+offset);
mk_partition(length-1,m_vertices.begin()+offset+1);
}
}
bool next_split(id& class_id) {
//
// TBD: find first non-singleton partition that is not already
// split on.
//
return false;
}
};
class graph {
// vertex adjacency graph:
vector<vector<unsigned,false> > m_in;
vector<vector<unsigned,false> > m_out;
unsigned m_max_degree;
public:
graph() : m_max_degree(0) {}
void add_vertex(unsigned v) {
if (get_num_vertices() <= v) {
m_out.resize(v+1,vector<unsigned,false>());
m_in.resize(v+1,vector<unsigned,false>());
}
SASSERT(get_num_vertices() == m_in.size());
SASSERT(get_num_vertices() == m_out.size());
SASSERT(v < get_num_vertices());
}
void add_edge(unsigned src, unsigned dst) {
SASSERT(src < get_num_vertices());
SASSERT(dst < get_num_vertices());
m_out[src].push_back(dst);
m_in[dst].push_back(src);
if (m_out[src].size() > m_max_degree) {
m_max_degree = m_out[src].size();
}
}
unsigned get_num_in(unsigned dst) const {
return m_in[dst].size();
}
unsigned get_src(unsigned dst, unsigned idx) const {
return m_in[dst][idx];
}
unsigned get_dst(unsigned src, unsigned idx) const {
return m_out[src][idx];
}
unsigned get_num_out(unsigned src) const {
return m_out[src].size();
}
unsigned get_num_vertices() const {
return m_in.size();
}
unsigned get_max_degree() const {
return m_max_degree;
}
};
class partition_refiner {
partition& m_partition;
graph& m_graph;
partition::mark m_mark;
//
// Temporary variables.
//
svector<partition::id> m_todo;
svector<partition::id> m_inverse;
//
// For bucketizing bisimilar nodes.
//
vector<unsigned,false> m_non_empty_buckets;
vector<unsigned_vector> m_buckets;
public:
partition_refiner(partition& p, graph& g): m_partition(p), m_graph(g), m_mark(p) {
m_buckets.resize(m_graph.get_max_degree()+1);
}
void add_refine_class(partition::id id) {
m_todo.push_back(id);
}
//
//
// compute equivalence classes for vertices
// based on partition refinement.
//
// m_todo contains node classes to partition refine.
//
void partition_refinement() {
for (unsigned i = 0; i < m_todo.size(); ++i) {
partition_refinement(m_todo[i]);
}
m_todo.reset();
}
private:
//
// refine classes with vertices entering id_dst
// TBD: if we already refined id_dst, then avoid redundant re-refining?
//
void partition_refinement(partition::id id_dst) {
m_mark.reset();
unsigned class_sz = m_partition.get_size(id_dst);
unsigned const* elems = m_partition.get_elems(id_dst);
for (unsigned j = 0; j < class_sz; ++j) {
unsigned dst = elems[j];
unsigned in_degree = m_graph.get_num_in(dst);
for (unsigned k = 0; k < in_degree; ++k) {
unsigned src = m_graph.get_src(dst,k);
partition::id id_src = m_partition[src];
if (m_mark.test_and_set(id_src)) {
partition_refinement(id_src, id_dst);
}
}
}
}
//
// refined partition algorithm based on
// counting number of edges to id_dst.
//
void partition_refinement(partition::id id_src, partition::id id_dst) {
unsigned src_sz = m_partition.get_size(id_src);
unsigned* src_elems = m_partition.get_elems(id_src);
//
// First pass: count number of connections to id_dst.
// Move vertices with 0 count into prefix.
// Count max-count
//
unsigned max_count = 0;
unsigned num_max_count = 0;
unsigned num_zeros = 0;
for (unsigned j = 0; j < src_sz; ++j) {
unsigned src = src_elems[j];
unsigned count = 0;
unsigned out_degree = m_graph.get_num_out(src);
for (unsigned k = 0; k < out_degree; ++k) {
unsigned dst = m_graph.get_dst(src,k);
if (m_partition[dst] == id_src) {
++count;
}
}
if (count > max_count) {
max_count = count;
num_max_count = 1;
}
else if (count == max_count) {
++num_max_count;
}
if (count == 0) {
SASSERT(num_zeros <= j);
if (num_zeros < j) {
std::swap(src_elems[j],src_elems[num_zeros]);
}
++num_zeros;
}
else {
m_buckets[count].push_back(src);
if (m_buckets[count].size() == 1) {
m_non_empty_buckets.push_back(count);
}
}
}
//
// All vertices have the same degree.
//
if (num_max_count == src_sz) {
reset_buckets();
return;
}
//
// at least two vertices have different counts
// reaching id_src.
//
//
// Second pass: refine [src_elems+num_zeros..src_elems+src_size-1] based on count-sort.
//
SASSERT(m_non_empty_buckets.size() >= 1);
unsigned largest_bucket_pos = 0;
unsigned largest_bucket_sz = num_zeros;
unsigned pos = num_zeros;
if (num_zeros > 0) {
m_partition.mk_partition(num_zeros, src_elems);
}
for (unsigned i = 0; i < m_non_empty_buckets.size(); ++i) {
unsigned bucket_id = m_non_empty_buckets[i];
unsigned_vector const& bucket = m_buckets[bucket_id];
unsigned bucket_sz = bucket.size();
SASSERT(bucket_sz > 0);
for (unsigned j = 0; j < bucket_sz; ++j) {
src_elems[pos+j] = bucket[j];
}
if (largest_bucket_sz < bucket_sz) {
largest_bucket_sz = bucket_sz;
largest_bucket_pos = pos;
}
m_partition.mk_partition(bucket_sz, src_elems+pos);
pos += bucket_sz;
}
//
// Insert all partitions except for largest_bucket_pos.
//
pos = 0;
if (num_zeros > 0 && largest_bucket_pos != 0) {
m_todo.push_back(m_partition[src_elems[0]]);
}
pos += num_zeros;
for (unsigned i = 0; i < m_non_empty_buckets.size(); ++i) {
unsigned sz = m_buckets[m_non_empty_buckets[i]].size();
if (pos != largest_bucket_pos) {
m_todo.push_back(m_partition[src_elems[pos]]);
}
pos += sz;
}
// reset buckets that were used.
reset_buckets();
}
void reset_buckets() {
for (unsigned i = 0; i < m_non_empty_buckets.size(); ++i) {
m_buckets[m_non_empty_buckets[i]].reset();
}
m_non_empty_buckets.reset();
}
};
class automorphism_search {
struct stats {
unsigned m_nodes;
unsigned m_max_level;
stats() : m_nodes(0), m_max_level(0) {}
};
bool m_first;
unsigned_vector m_first_permutation;
partition_refiner m_refiner;
stats m_stats;
partition& m_partition;
graph& m_graph;
unsigned_vector m_num_elems;
ptr_vector<unsigned> m_elems;
public:
automorphism_search(partition& p, graph& g):
m_first(true),
m_refiner(p,g),
m_partition(p),
m_graph(g)
{}
void search_main() {
search();
}
private:
bool propagate(partition::id& id) {
m_refiner.partition_refinement();
if (m_partition.next_split(id)) {
return true;
}
if (m_first) {
m_first = false;
m_partition.copy_vertices(m_first_permutation);
pop_scope(1);
}
else {
// not the first node.
// process this.
// TBD
}
return false;
}
//
// enumerate elements from partition id:
//
void search() {
partition::id id;
unsigned num_elems;
unsigned * elems;
while (true) {
if (propagate(id)) {
push_scope();
num_elems = m_partition.get_size(id);
elems = m_partition.get_elems(id);
SASSERT(num_elems > 0);
m_num_elems.push_back(num_elems);
m_elems.push_back(elems);
}
else if (get_level() == 0) {
return;
}
else {
num_elems = m_num_elems.back();
elems = m_elems.back();
}
// TBD orbits.
if (num_elems == 0) {
pop_scope(1);
}
else {
m_partition.split(id, elems[0], 0); // TBD
--m_num_elems.back();
++m_elems.back();
}
}
}
// TBD:
void push_scope() {}
void pop_scope(unsigned num_scopes) {}
unsigned get_level() { return 0; }
};
void tst_symmetry0() {
graph g;
partition p(6);
for (unsigned i = 0; i < 6; ++i) {
g.add_vertex(i);
}
for (unsigned i = 0; i < 3; ++i) {
g.add_edge(i,i+3);
}
g.add_edge(0,1);
g.add_edge(1,2);
g.add_edge(2,0);
partition_refiner r(p,g);
r.add_refine_class(p[0]);
r.partition_refinement();
p.display(std::cout);
}
#include "ast.h"
#include "smtparser.h"
#include "array_decl_plugin.h"
#include "bv_decl_plugin.h"
#include "arith_decl_plugin.h"
#include "ast_pp.h"
#include "basic_simplifier_plugin.h"
#include "front_end_params.h"
#include "smt_context.h"
class expr_symmetry_graph {
template<class T>
class labeling : public obj_map<T const, unsigned> {
unsigned m_count;
u_map<T*> m_inverse;
public:
labeling() : m_count(0) {}
unsigned get_count() const { return m_count; }
unsigned get_label(T* e) {
unsigned lbl = 0;
if (!find(e, lbl)) {
insert(e, ++m_count);
lbl = m_count;
m_inverse.insert(lbl, e);
}
return lbl;
}
unsigned get_existing_label(T* e) {
unsigned lbl = 0;
if (!find(e, lbl)) {
UNREACHABLE();
}
return lbl;
}
T* get_inverse(unsigned n) {
T* a = 0;
if (!m_inverse.find(n, a)) {
return 0;
}
return a;
}
};
ast_manager m_mgr;
labeling<expr> m_node_id;
expr_ref_vector m_formulas;
expr_ref_vector m_symmetry_breakers;
expr_ref_vector m_aux_preds;
typedef obj_map<func_decl const, unsigned> func_decl_map;
bool is_labeled_function(func_decl* d) {
if (d->is_commutative() || d->get_arity() <= 1) {
return false;
}
if (m_mgr.is_distinct(d)) {
return false;
}
return true;
}
// TBD: we are not really interested in symmetries on unit literals.
void print_graph(std::ostream& out, unsigned num_exprs, expr *const* exprs) {
ptr_vector<expr> todo;
ast_mark mark;
unsigned num_vertices = 0, num_edges = 0;
unsigned num_arity_colors = 0;
labeling<ast> node_color;
func_decl_map arity_color_map;
todo.append(num_exprs, exprs);
while (!todo.empty()) {
expr* e = todo.back();
todo.pop_back();
if (m_node_id.contains(e)) {
continue;
}
m_node_id.get_label(e);
++num_vertices;
if (is_app(e)) {
app* a = to_app(e);
func_decl* d = a->get_decl();
node_color.get_label(d);
unsigned arity = a->get_num_args();
todo.append(arity, a->get_args());
if (!is_labeled_function(d)) {
num_edges += arity;
}
else {
num_edges += 2*arity;
if (!arity_color_map.contains(d)) {
arity_color_map.insert(d,num_arity_colors);
num_arity_colors += arity;
}
}
}
}
num_vertices = m_node_id.get_count() + num_arity_colors;
out << "p edge " << num_vertices << " " << num_edges << "\n";
// print graph
// print nodes used for arities:
func_decl_map::iterator it = arity_color_map.begin();
func_decl_map::iterator end = arity_color_map.end();
for (; it != end; ++it) {
func_decl const* d = (*it).m_key;
unsigned offset = (*it).m_value;
for (unsigned i = 0; i < d->get_arity(); ++i) {
out << "n " << offset + m_node_id.get_count() + i << " " << i + 1 << "\n";
}
}
todo.append(num_exprs, exprs);
while (!todo.empty()) {
expr* e = todo.back();
todo.pop_back();
if (mark.is_marked(e)) {
continue;
}
mark.mark(e,true);
unsigned id = m_node_id.get_existing_label(e);
if (is_app(e)) {
app* a = to_app(e);
func_decl* d = a->get_decl();
unsigned arity = a->get_num_args();
unsigned offset;
todo.append(arity, a->get_args());
out << "c " << d->get_name() << "\n";
if(m_mgr.is_value(a) || arity > 0) {
out << "n " << id << " " << node_color.get_label(d) << "\n";
}
else {
out << "n " << id << " 0\n";
}
if (is_labeled_function(d) && !arity_color_map.find(d,offset)) {
UNREACHABLE();
}
for (unsigned i = 0; i < arity; ++i) {
unsigned id2 = m_node_id.get_existing_label(a->get_arg(i));
if (!is_labeled_function(d)) {
out << "e " << id << " " << id2 << "\n";
}
else {
unsigned color = offset + m_node_id.get_count() + i;
out << "e " << id << " " << color << "\n";
out << "e " << color << " " << id2 << "\n";
}
}
}
}
}
public:
expr_symmetry_graph() :
m_formulas(m_mgr),
m_symmetry_breakers(m_mgr),
m_aux_preds(m_mgr) {
}
void parse_file(char const* file_path, char const* file_tmp) {
smtlib::parser* parser = smtlib::parser::create(m_mgr);
m_mgr.register_decl_plugins();
parser->initialize_smtlib();
if (!parser->parse_file(file_path)) {
std::cout << "Could not parse file : " << file_path << std::endl;
dealloc(parser);
return;
}
smtlib::benchmark* b = parser->get_benchmark();
smtlib::theory::expr_iterator it = b->begin_formulas();
smtlib::theory::expr_iterator end = b->end_formulas();
for (; it != end; ++it) {
m_formulas.push_back(*it);
}
it = b->begin_axioms();
end = b->end_axioms();
for (; it != end; ++it) {
m_formulas.push_back(*it);
}
std::ofstream out(file_tmp);
if (out.bad() || out.fail()) {
std::cerr << "Error: failed to open file \"" << file_tmp << "\" for writing.\n";
exit(ERR_OPEN_FILE);
}
print_graph(out, m_formulas.size(), m_formulas.c_ptr());
out.close();
dealloc(parser);
}
private:
static void skip_blank(stream_buffer& inp) {
while (*inp == ' ' || *inp == '\t' || *inp == '\r') {
++inp;
}
}
static bool read_line(stream_buffer& inp) {
while (*inp != EOF && *inp != '\n') {
++inp;
}
if (*inp == EOF) {
return false;
}
++inp;
return true;
}
enum token_type {
t_undef,
t_eof,
t_alpha,
t_digit,
t_special
};
static token_type get_token_type(int c) {
if ('0' <= c && c <= '9') {
return t_digit;
}
if ('a' <= c && c <= 'z') {
return t_alpha;
}
if ('A' <= c && c <= 'Z') {
return t_alpha;
}
return t_special;
}
static bool read_token(stream_buffer& in, std::string& token, token_type& ty1) {
skip_blank(in);
ty1 = t_undef;
if (*in == EOF) {
ty1 = t_eof;
return false;
}
token.clear();
while (*in != '\n' &&
*in != ' ' &&
*in != '\r' &&
*in != '\t' &&
*in != EOF) {
token_type ty2 = get_token_type(*in);
if (ty1 == t_undef) {
ty1 = ty2;
token.push_back(*in);
++in;
}
else if (ty2 != t_special && ty1 == ty2) {
token.push_back(*in);
++in;
}
else {
break;
}
}
return true;
}
static bool read_token(stream_buffer& in, char const* token) {
token_type ty;
std::string s;
return
read_token(in, s, ty) &&
0 == strcmp(s.c_str(), token);
}
static bool read_unsigned(char const* token, unsigned& u) {
u = 0;
while (*token) {
if ('0' <= *token && *token <= '9') {
u = 10*u + (*token - '0');
++token;
}
else {
return false;
}
}
return true;
}
static bool read_unsigned(stream_buffer& in, unsigned& u) {
std::string token;
token_type ty = t_undef;
if (!(read_token(in, token, ty) && ty == t_digit)) {
return false;
}
return read_unsigned(token.c_str(), u);
}
void print_cycle(unsigned_vector const& permutation) {
for (unsigned i = 0; i < permutation.size(); ++i) {
ast* a = m_node_id.get_inverse(permutation[i]);
if (a) {
std::cout << mk_pp(a, m_mgr) << " ";
}
}
std::cout << "\n";
}
void mk_symmetry_breaker(vector<unsigned_vector> const& permutation) {
expr_ref p(m_mgr);
p = m_mgr.mk_true();
expr_ref_vector preds(m_mgr);
basic_simplifier_plugin util(m_mgr);
for (unsigned i = 0; i < permutation.size(); ++i) {
unsigned_vector const& cycle = permutation[i];
if (cycle.size() <= 1) {
continue;
}
unsigned n = cycle[0];
expr* first = m_node_id.get_inverse(n);
if (!first) {
continue;
}
if (m_mgr.is_or(first) || m_mgr.is_not(first) || m_mgr.is_implies(first) || m_mgr.is_and(first)) {
continue;
}
if (!m_mgr.is_bool(first)) {
continue;
}
// cycle has at least 2 elements, all elements are predicates
// that are not Boolean connectives.
for (unsigned j = 0; j + 1 < cycle.size(); ++j) {
expr_ref q(m_mgr), a(m_mgr), b(m_mgr), ab(m_mgr), ba(m_mgr), e(m_mgr), abq(m_mgr);
if (j + 2 < cycle.size() || i + 1 < permutation.size()) {
q = m_mgr.mk_fresh_const("p",m_mgr.mk_bool_sort());
m_aux_preds.push_back(q.get());
}
else {
q = m_mgr.mk_true();
}
a = m_node_id.get_inverse(cycle[j]);
b = m_node_id.get_inverse(cycle[j+1]);
util.mk_implies(a,b,ab);
util.mk_implies(b,a,ba);
util.mk_and(ab, q, abq);
util.mk_implies(p,abq,e);
m_symmetry_breakers.push_back(e.get());
util.mk_and(ba.get(),q.get(),p);
}
}
}
bool read_cycle(stream_buffer& in, vector<unsigned_vector>& permutation) {
unsigned_vector cycle;
unsigned n;
token_type ty;
std::string token;
if (!(read_token(in, token, ty) && ty == t_special && strcmp(token.c_str(),"(") == 0)) {
std::cout << "read (\n";
return false;
}
if (!read_unsigned(in, n)) {
std::cout << "read unsigned\n";
return false;
}
cycle.push_back(n);
while (true) {
if (!read_token(in, token, ty)) {
std::cout << "read next token\n";
return false;
}
if (0 == strcmp(token.c_str(),")")) {
break;
}
if (0 != strcmp(token.c_str(),",")) {
std::cout << "read ,\n";
return false;
}
if (!read_token(in, token, ty)) {
std::cout << "read next token\n";
return false;
}
if (!read_unsigned(token.c_str(), n)) {
std::cout << "read number\n";
return false;
}
cycle.push_back(n);
}
// print_cycle(cycle);
permutation.push_back(cycle);
return true;
}
bool read_permutation(stream_buffer& in) {
vector<unsigned_vector> permutation;
while (*in != '\n') {
if (!read_cycle(in, permutation)) {
return false;
}
}
++in;
mk_symmetry_breaker(permutation);
return true;
}
public:
void parse_generators(char const* symmetry_file) {
std::fstream in(symmetry_file);
if (in.bad() || in.fail()) {
std::cerr << "Error: failed to open file \"" << symmetry_file << "\" for reading.\n";
exit(ERR_OPEN_FILE);
}
{
stream_buffer in_buf(in);
while (true) {
if (!read_token(in_buf, "Generator")) {
if (read_line(in_buf)) {
continue;
}
break;
}
if (!read_token(in_buf, ":")) {
break;
}
if (!read_permutation(in_buf)) {
std::cout << "Could not read generator\n";
char buffer[2] = { *in_buf, 0 };
std::cout << buffer << "\n";
break;
}
std::cout << "Read generator\n";
// convert back to symmetry breaking.
}
}
in.close();
}
public:
static void run_bliss(char const* file_in, char const* file_out) {
char const* bliss_exe = "C:\\users\\nbjorner\\Documents\\Downloads\\bliss-0.50\\bliss-0.50\\bliss.exe";
char buffer[4024];
#if _WINDOWS
sprintf_s(buffer, ARRAYSIZE(buffer), "%s -directed %s > %s", bliss_exe, file_in, file_out);
#else
sprintf(buffer, "%s -directed %s > %s", bliss_exe, file_in, file_out);
#endif
system(buffer);
}
void print_symmetry_breakers(const char* out_file) {
std::ofstream out(out_file);
if (out.bad() || out.fail()) {
std::cerr << "Error: failed to open file \"" << out_file << "\" for writing.\n";
exit(ERR_OPEN_FILE);
}
out << ":extrapreds (";
for (unsigned i = 0; i < m_aux_preds.size(); ++i) {
out << "(" << mk_pp(m_aux_preds[i].get(), m_mgr) << ") ";
}
out << ")\n";
for (unsigned i = 0; i < m_symmetry_breakers.size(); ++i) {
out << ":assumption " << mk_pp(m_symmetry_breakers[i].get(), m_mgr) << "\n";
}
out.close();
}
void prove_with_symmetry_breakers() {
front_end_params params;
smt::context ctx(m_mgr, params);
for (unsigned i = 0; i < m_formulas.size(); ++i) {
ctx.assert_expr(m_formulas[i].get());
}
for (unsigned i = 0; i < m_symmetry_breakers.size(); ++i) {
ctx.assert_expr(m_symmetry_breakers[i].get());
}
lbool result = ctx.setup_and_check();
std::cout << result << "\n";
ctx.display_statistics(std::cout);
}
};
void tst_symmetry_parse(char** argv, int argc, int& i) {
if (i+2 < argc) {
char const* file_in = argv[i+1];
char const* file_tmp1 = "C:\\tmp\\bliss_in.txt";
char const* file_tmp2 = "C:\\tmp\\bliss_out.txt";
char const* file_out = argv[i+2];
expr_symmetry_graph graph;
graph.parse_file(file_in, file_tmp1);
graph.run_bliss(file_tmp1, file_tmp2);
graph.parse_generators(file_tmp2);
graph.print_symmetry_breakers(file_out);
i += 2;
}
else {
std::cout << "usage <file_in>.smt <bliss_graph(out)> <bliss_result(out)> <file_out>.smt \n";
}
}
void tst_symmetry_prove(char** argv, int argc, int& i) {
if (i+1 < argc) {
char const* file_in = argv[i+1];
char const* file_tmp1 = "C:\\tmp\\bliss_in.txt";
char const* file_tmp2 = "C:\\tmp\\bliss_out.txt";
expr_symmetry_graph graph;
graph.parse_file(file_in, file_tmp1);
graph.run_bliss(file_tmp1, file_tmp2);
graph.parse_generators(file_tmp2);
graph.prove_with_symmetry_breakers();
i += 1;
}
else {
std::cout << "usage <file_in>.smt\n";
}
}
void tst_symmetry() {
char const* arg = "C:\\tvm\\src\\benchmarks\\zap\\smt-lib\\QF_IDL\\queens_bench\\toroidal_bench\\toroidal_queen2-1.smt";
expr_symmetry_graph graph;
graph.parse_file(arg, 0);
}
#else
void tst_symmetry_parse(char** argv, int argc, int& i) {
}
void tst_symmetry_prove(char** argv, int argc, int& i) {
}
void tst_symmetry() {
}
#endif