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