Skip to content

Commit 80c553d

Browse files
missing file
Signed-off-by: Nikolaj Bjorner <[email protected]>
1 parent 77fed8b commit 80c553d

File tree

1 file changed

+146
-0
lines changed

1 file changed

+146
-0
lines changed

src/ast/simplifiers/randomizer.h

Lines changed: 146 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,146 @@
1+
2+
/*++
3+
Copyright (c) 2025 Microsoft Corporation
4+
5+
Module Name:
6+
7+
randomizer.h
8+
9+
Abstract:
10+
11+
Simplifier that randomizes formulas by renaming uninterpreted functions and permuting arguments of associative and commutative functions.
12+
13+
Author:
14+
15+
Nikolaj Bjorner nbjorner 20-05-2025
16+
17+
--*/
18+
19+
#pragma once
20+
21+
#include "ast/ast.h"
22+
#include "ast/ast_pp.h"
23+
#include "ast/simplifiers/dependent_expr_state.h"
24+
#include "util/obj_hashtable.h"
25+
#include <algorithm>
26+
27+
class randomizer_simplifier : public dependent_expr_simplifier {
28+
ast_manager& m;
29+
obj_map<func_decl, func_decl*> m_rename;
30+
ast_ref_vector m_ast_trail;
31+
expr_ref_vector m_new_exprs;
32+
ptr_vector<expr> m_todo, m_args;
33+
random_gen m_rand;
34+
35+
func_decl* get_random_func_decl(func_decl* f) {
36+
func_decl* r = nullptr;
37+
if (m_rename.find(f, r))
38+
return r;
39+
// Create a new random name
40+
std::string rand_name = f->get_name().str() + "_rand_" + std::to_string(m_rand());
41+
symbol new_sym(rand_name.c_str());
42+
r = m.mk_func_decl(new_sym, f->get_arity(), f->get_domain(), f->get_range());
43+
m_rename.insert(f, r);
44+
m_ast_trail.push_back(r);
45+
m_ast_trail.push_back(f);
46+
47+
m_trail.push(insert_obj_map(m_rename, f));
48+
m_trail.push(push_back_vector(m_ast_trail));
49+
m_trail.push(push_back_vector(m_ast_trail));
50+
51+
52+
m_args.reset();
53+
for (unsigned i = 0; i < f->get_arity(); ++i)
54+
m_args.push_back(m.mk_var(i, f->get_domain(i)));
55+
m_fmls.model_trail().hide(r);
56+
m_fmls.model_trail().push(f, m.mk_app(r, m_args), nullptr, {});
57+
return r;
58+
}
59+
60+
void push_new_expr(expr* e, expr* new_e) {
61+
m_new_exprs.setx(e->get_id(), new_e);
62+
m_ast_trail.push_back(e);
63+
m_trail.push(push_back_vector(m_ast_trail));
64+
m_trail.push(set_vector_idx_trail(m_new_exprs, e->get_id()));
65+
m_todo.pop_back();
66+
}
67+
68+
expr* get_new_expr(expr* e) {
69+
return m_new_exprs.get(e->get_id(), nullptr);
70+
}
71+
72+
void randomize(expr* e) {
73+
m_todo.push_back(e);
74+
while (!m_todo.empty()) {
75+
e = m_todo.back();
76+
if (get_new_expr(e))
77+
m_todo.pop_back();
78+
else if (is_app(e)) {
79+
auto f = to_app(e)->get_decl();
80+
// If uninterpreted function, rename
81+
if (is_uninterp(f))
82+
f = get_random_func_decl(f);
83+
m_args.reset();
84+
auto arity = to_app(e)->get_num_args();
85+
for (expr* arg : *to_app(e)) {
86+
expr* new_arg = get_new_expr(arg);
87+
if (new_arg)
88+
m_args.push_back(new_arg);
89+
else
90+
m_todo.push_back(arg);
91+
}
92+
if (m_args.size() < arity)
93+
continue;
94+
if (f->is_associative() && f->is_commutative() && arity > 1)
95+
shuffle(m_args.size(), m_args.data(), m_rand);
96+
expr_ref new_e(m.mk_app(f, m_args.size(), m_args.data()), m);
97+
push_new_expr(e, new_e);
98+
}
99+
else if (is_quantifier(e)) {
100+
quantifier* q = to_quantifier(e);
101+
expr* body = q->get_expr();
102+
expr* new_body = get_new_expr(body);
103+
if (new_body) {
104+
expr_ref new_e(m.update_quantifier(q, new_body), m);
105+
push_new_expr(e, new_e);
106+
}
107+
else
108+
m_todo.push_back(body);
109+
}
110+
else
111+
push_new_expr(e, e);
112+
}
113+
}
114+
115+
public:
116+
randomizer_simplifier(ast_manager& m, params_ref const & p, dependent_expr_state& fmls)
117+
: dependent_expr_simplifier(m, fmls), m(m), m_ast_trail(m), m_new_exprs(m) {
118+
// set m_rand reading from parameter?
119+
}
120+
121+
char const* name() const override { return "randomizer"; }
122+
123+
void reduce() override {
124+
for (unsigned idx : indices()) {
125+
auto d = m_fmls[idx];
126+
randomize(d.fml());
127+
m_fmls.update(idx, dependent_expr(m, get_new_expr(d.fml()), d.pr(), d.dep()));
128+
}
129+
unsigned num_fmls = qtail() - qhead();
130+
for (unsigned i = qhead(); i < qtail(); ++i) {
131+
unsigned j = qhead() + m_rand(num_fmls);
132+
if (i == j)
133+
continue;
134+
auto d1 = m_fmls[i];
135+
auto d2 = m_fmls[j];
136+
m_fmls.update(i, d2);
137+
m_fmls.update(j, d1);
138+
}
139+
}
140+
141+
bool supports_proofs() const override { return false; }
142+
};
143+
144+
/*
145+
ADD_SIMPLIFIER("randomizer", "shuffle assertions and rename uninterpreted functions.", "alloc(randomizer_simplifier, m, p, s)")
146+
*/

0 commit comments

Comments
 (0)