1 /*++
2 Copyright (c) 2011 Microsoft Corporation
3 
4 Module Name:
5 
6     model_smt2_pp.cpp
7 
8 Abstract:
9 
10     Pretty printer for models using SMT2 format.
11 
12 Author:
13 
14     Leonardo de Moura (leonardo)
15 
16 Revision History:
17 
18 
19 --*/
20 #include<sstream>
21 #include "model/model_smt2_pp.h"
22 #include "ast/ast_smt2_pp.h"
23 #include "ast/func_decl_dependencies.h"
24 #include "ast/recfun_decl_plugin.h"
25 #include "ast/pp.h"
26 using namespace format_ns;
27 
pp_indent(std::ostream & out,unsigned indent)28 static void pp_indent(std::ostream & out, unsigned indent) {
29     for (unsigned i = 0; i < indent; i++)
30         out << " ";
31 }
32 
pp_symbol(std::ostream & out,symbol const & s)33 static unsigned pp_symbol(std::ostream & out, symbol const & s) {
34     if (is_smt2_quoted_symbol(s)) {
35         std::string str = mk_smt2_quoted_symbol(s);
36         out << str;
37         return static_cast<unsigned>(str.length());
38     }
39     else if (s.is_numerical()) {
40         std::string str = s.str();
41         out << str;
42         return static_cast<unsigned>(str.length());
43     }
44     else {
45         out << s.bare_str();
46         return static_cast<unsigned>(strlen(s.bare_str()));
47     }
48 }
49 
50 #define TAB_SZ 2
51 
pp_uninterp_sorts(std::ostream & out,ast_printer_context & ctx,model_core const & md,unsigned indent)52 static void pp_uninterp_sorts(std::ostream & out, ast_printer_context & ctx, model_core const & md, unsigned indent) {
53     ast_manager & m = ctx.get_ast_manager();
54     ptr_buffer<format> f_conds;
55     unsigned num = md.get_num_uninterpreted_sorts();
56     for (unsigned i = 0; i < num; i++) {
57         sort * s = md.get_uninterpreted_sort(i);
58         ptr_vector<expr> const & u = md.get_universe(s);
59         std::ostringstream buffer;
60         buffer << "universe for ";
61         ctx.display(buffer, s, 13);
62         buffer << ":\n";
63         pp_indent(buffer, TAB_SZ);
64         for (expr* e : u) {
65             SASSERT(is_app(e));
66             app * c = to_app(e);
67             pp_symbol(buffer, c->get_decl()->get_name());
68             buffer << " ";
69         }
70         buffer << "\n-----------";
71         std::string buffer_str = buffer.str();
72         unsigned len = static_cast<unsigned>(buffer_str.length());
73         pp_indent(out, indent);
74         out << ";; ";
75         for (unsigned i = 0; i < len; i++) {
76             char c = buffer_str[i];
77             if (c == '\n') {
78                 out << "\n";
79                 pp_indent(out, indent);
80                 out << ";; ";
81             }
82             else {
83                 out << c;
84             }
85         }
86         out << "\n";
87         pp_indent(out, indent);
88         out << ";; definitions for universe elements:\n";
89         for (expr * e : u) {
90             app * c = to_app(e);
91             pp_indent(out, indent);
92             out << "(declare-fun ";
93             unsigned len  = pp_symbol(out, c->get_decl()->get_name());
94             out << " () ";
95             ctx.display(out, c->get_decl()->get_range(), indent + len + 16);
96             out << ")\n";
97         }
98         pp_indent(out, indent);
99         out << ";; cardinality constraint:\n";
100         f_conds.reset();
101         format * var = mk_string(m, "x");
102         for (expr* e : u) {
103             app * c = to_app(e);
104             symbol csym = c->get_decl()->get_name();
105             std::string cname;
106             if (is_smt2_quoted_symbol(csym))
107                 cname = mk_smt2_quoted_symbol(csym);
108             else
109                 cname = csym.str();
110             format * c_args[2] = { var, mk_string(m, cname) };
111             f_conds.push_back(mk_seq1<format**, f2f>(m, c_args, c_args+2, f2f(), "="));
112         }
113         SASSERT(!f_conds.empty());
114         format * f_cond;
115         if (f_conds.size() > 1)
116             f_cond = mk_seq1(m, f_conds.begin(), f_conds.end(), f2f(), "or");
117         else
118             f_cond = f_conds[0];
119         format_ref f_s(fm(m));
120         ctx.pp(s, f_s);
121         format * f_args[2] = { mk_compose(m,
122                                           mk_string(m, "((x "),
123                                           mk_indent(m, 4, mk_compose(m, f_s.get(), mk_string(m, "))")))),
124                                f_cond };
125         format_ref f_card(fm(m));
126         f_card = mk_indent(m, indent, mk_seq1<format**, f2f>(m, f_args, f_args+2, f2f(), "forall"));
127         pp_indent(out, indent);
128         pp(out, f_card, m);
129         out << "\n";
130         pp_indent(out, indent);
131         out << ";; -----------\n";
132     }
133 }
134 
pp_consts(std::ostream & out,ast_printer_context & ctx,model_core const & md,unsigned indent)135 static void pp_consts(std::ostream & out, ast_printer_context & ctx, model_core const & md, unsigned indent) {
136     unsigned num = md.get_num_constants();
137     for (unsigned i = 0; i < num; i++) {
138         func_decl * c = md.get_constant(i);
139         expr * c_i    = md.get_const_interp(c);
140         pp_indent(out, indent);
141         out << "(define-fun ";
142         unsigned len  = pp_symbol(out, c->get_name());
143         out << " () ";
144         ctx.display(out, c->get_range(), indent + len + 16);
145         out << "\n";
146         pp_indent(out, indent + TAB_SZ);
147         ctx.display(out, c_i);
148         out << ")\n";
149     }
150 }
151 
sort_fun_decls(ast_manager & m,model_core const & md,ptr_buffer<func_decl> & result)152 void sort_fun_decls(ast_manager & m, model_core const & md, ptr_buffer<func_decl> & result) {
153     func_decl_set         visited;
154     ptr_vector<func_decl> todo;
155     unsigned sz = md.get_num_functions();
156     for (unsigned i = 0; i < sz; i++) {
157         func_decl * f = md.get_function(i);
158         if (visited.contains(f))
159             continue;
160         visited.insert(f);
161         todo.push_back(f);
162         while (!todo.empty()) {
163             func_decl * curr = todo.back();
164             func_interp * curr_i = md.get_func_interp(curr);
165             SASSERT(curr_i != 0);
166             if (!curr_i->is_partial()) {
167                 func_decl_set deps;
168                 bool all_visited = true;
169                 collect_func_decls(m, curr_i->get_else(), deps);
170                 for (func_decl * d : deps) {
171                     if (d->get_arity() > 0 && md.has_interpretation(d) && !visited.contains(d)) {
172                         todo.push_back(d);
173                         visited.insert(d);
174                         all_visited = false;
175                     }
176                 }
177                 if (!all_visited)
178                     continue;
179             }
180             todo.pop_back();
181             result.push_back(curr);
182         }
183     }
184 }
185 
186 
pp_funs(std::ostream & out,ast_printer_context & ctx,model_core const & md,unsigned indent)187 static void pp_funs(std::ostream & out, ast_printer_context & ctx, model_core const & md, unsigned indent) {
188     ast_manager & m = ctx.get_ast_manager();
189     recfun::util recfun_util(m);
190     sbuffer<symbol>    var_names;
191     ptr_buffer<format> f_var_names;
192     ptr_buffer<format> f_arg_decls;
193     ptr_buffer<format> f_entries;
194     ptr_buffer<format> f_entry_conds;
195     ptr_buffer<func_decl> func_decls;
196     sort_fun_decls(m, md, func_decls);
197     for (func_decl * f : func_decls) {
198         if (recfun_util.is_defined(f) && !recfun_util.is_generated(f)) {
199             continue;
200         }
201         if (!m.is_considered_uninterpreted(f)) {
202             continue;
203         }
204         func_interp * f_i = md.get_func_interp(f);
205         SASSERT(f->get_arity() == f_i->get_arity());
206         format_ref body(fm(m));
207         var_names.reset();
208         if (f_i->is_partial()) {
209             body = mk_string(m, "#unspecified");
210             for (unsigned j = 0; j < f->get_arity(); j++) {
211                 std::stringstream strm;
212                 strm << "x!" << (j+1);
213                 var_names.push_back(symbol(strm.str()));
214             }
215         }
216         else {
217             ctx.pp(f_i->get_else(), f->get_arity(), "x", body, var_names);
218         }
219         TRACE("model_smt2_pp", for (unsigned i = 0; i < var_names.size(); i++) tout << var_names[i] << "\n";);
220         f_var_names.reset();
221         for (auto const& vn : var_names)
222             f_var_names.push_back(mk_string(m, vn.bare_str()));
223         f_arg_decls.reset();
224         for (unsigned i = 0; i < f->get_arity(); i++) {
225             format_ref f_domain(fm(m));
226             ctx.pp(f->get_domain(i), f_domain);
227             format * args[2] = { f_var_names[i], f_domain.get() };
228             f_arg_decls.push_back(mk_seq5<format**, f2f>(m, args, args+2, f2f()));
229         }
230         format * f_domain = mk_seq5(m, f_arg_decls.begin(), f_arg_decls.end(), f2f());
231         format_ref f_range(fm(m));
232         ctx.pp(f->get_range(), f_range);
233         if (f_i->num_entries() > 0) {
234             f_entries.reset();
235             for (unsigned i = 0; i < f_i->num_entries(); i++) {
236                 func_entry const * e = f_i->get_entry(i);
237                 f_entry_conds.reset();
238                 for (unsigned j = 0; j < f->get_arity(); j++) {
239                     format_ref f_arg(fm(m));
240                     ctx.pp(e->get_arg(j), f_arg);
241                     format * eq_args[2] = { f_var_names[j], f_arg.get() };
242                     f_entry_conds.push_back(mk_seq1<format**, f2f>(m, eq_args, eq_args+2, f2f(), "="));
243                 }
244                 format * f_entry_cond;
245                 SASSERT(!f_entry_conds.empty());
246                 if (f_entry_conds.size() > 1)
247                     f_entry_cond = mk_seq1(m, f_entry_conds.begin(), f_entry_conds.end(), f2f(), "and");
248                 else
249                     f_entry_cond = f_entry_conds[0];
250                 format_ref f_result(fm(m));
251                 ctx.pp(e->get_result(), f_result);
252                 if (i > 0)
253                     f_entries.push_back(mk_line_break(m));
254                 f_entries.push_back(mk_group(m, mk_compose(m,
255                                                            mk_string(m, "(ite "),
256                                                            mk_indent(m, 5, f_entry_cond),
257                                                            mk_indent(m, TAB_SZ, mk_compose(m,
258                                                                                            mk_line_break(m),
259                                                                                            f_result.get())))));
260             }
261             f_entries.push_back(mk_indent(m, TAB_SZ, mk_compose(m,
262                                                                 mk_line_break(m),
263                                                                 body.get())));
264             for (unsigned i = 0; i < f_i->num_entries(); i++)
265                 f_entries.push_back(mk_string(m, ")"));
266             body = mk_compose(m, f_entries.size(), f_entries.c_ptr());
267         }
268         format_ref def(fm(m));
269         std::string fname;
270         if (is_smt2_quoted_symbol(f->get_name()))
271             fname = mk_smt2_quoted_symbol(f->get_name());
272         else
273             fname = f->get_name().str();
274         def = mk_indent(m, indent, mk_compose(m,
275                                               mk_compose(m,
276                                                          mk_string(m, "(define-fun "),
277                                                          mk_string(m, fname),
278                                                          mk_string(m, " "),
279                                                          mk_compose(m,
280                                                                     f_domain,
281                                                                     mk_string(m, " "),
282                                                                     f_range)),
283                                               mk_indent(m, TAB_SZ, mk_compose(m,
284                                                                               mk_line_break(m),
285                                                                               body.get(),
286                                                                               mk_string(m, ")")))));
287         pp_indent(out, indent);
288         pp(out, def.get(), m);
289         out << "\n";
290     }
291 }
292 
model_smt2_pp(std::ostream & out,ast_printer_context & ctx,model_core const & m,unsigned indent)293 void model_smt2_pp(std::ostream & out, ast_printer_context & ctx, model_core const & m, unsigned indent) {
294     pp_uninterp_sorts(out, ctx, m, indent);
295     pp_consts(out, ctx, m, indent);
296     pp_funs(out, ctx, m, indent);
297 }
298 
model_smt2_pp(std::ostream & out,ast_manager & m,model_core const & md,unsigned indent)299 void model_smt2_pp(std::ostream & out, ast_manager & m, model_core const & md, unsigned indent) {
300     scoped_ptr<ast_printer_context> ctx;
301     ctx = mk_simple_ast_printer_context(m);
302     pp_uninterp_sorts(out, *(ctx.get()), md, indent);
303     pp_consts(out, *(ctx.get()), md, indent);
304     pp_funs(out, *(ctx.get()), md, indent);
305 }
306 
operator <<(std::ostream & out,model_core const & m)307 std::ostream& operator<<(std::ostream& out, model_core const& m) {
308     model_smt2_pp(out, m.get_manager(), m, 0);
309     return out;
310 }
311