1 /*++
2 Copyright (c) 2006 Microsoft Corporation
3 
4 Module Name:
5 
6     array_decl_plugin.cpp
7 
8 Abstract:
9 
10     <abstract>
11 
12 Author:
13 
14     Leonardo de Moura (leonardo) 2008-01-09
15 
16 Revision History:
17 
18 --*/
19 #include<sstream>
20 #include "ast/array_decl_plugin.h"
21 #include "util/warning.h"
22 #include "ast/ast_pp.h"
23 #include "ast/ast_ll_pp.h"
24 #include "ast/arith_decl_plugin.h"
25 
array_decl_plugin()26 array_decl_plugin::array_decl_plugin():
27     m_store_sym("store"),
28     m_select_sym("select"),
29     m_const_sym("const"),
30     m_default_sym("default"),
31     m_map_sym("map"),
32     m_set_union_sym("union"),
33     m_set_intersect_sym("intersection"),
34     m_set_difference_sym("setminus"),
35     m_set_complement_sym("complement"),
36     m_set_subset_sym("subset"),
37     m_array_ext_sym("array-ext"),
38     m_as_array_sym("as-array"),
39     m_set_has_size_sym("set-has-size"),
40     m_set_card_sym("card") {
41 }
42 
43 #define ARRAY_SORT_STR "Array"
44 
mk_sort(decl_kind k,unsigned num_parameters,parameter const * parameters)45 sort * array_decl_plugin::mk_sort(decl_kind k, unsigned num_parameters, parameter const * parameters) {
46 
47     if (k == _SET_SORT) {
48         if (num_parameters != 1) {
49             m_manager->raise_exception("invalid array sort definition, invalid number of parameters");
50             return nullptr;
51         }
52         parameter params[2] = { parameters[0], parameter(m_manager->mk_bool_sort()) };
53         return mk_sort(ARRAY_SORT, 2, params);
54     }
55     SASSERT(k == ARRAY_SORT);
56     if (num_parameters < 2) {
57         m_manager->raise_exception("invalid array sort definition, invalid number of parameters");
58         return nullptr;
59     }
60 
61     for (unsigned i = 0; i < num_parameters; i++) {
62         if (!parameters[i].is_ast() || !is_sort(parameters[i].get_ast())) {
63             m_manager->raise_exception("invalid array sort definition, parameter is not a sort");
64             return nullptr;
65         }
66     }
67     sort * range = to_sort(parameters[num_parameters - 1].get_ast());
68     TRACE("array_decl_plugin_bug", tout << mk_pp(range, *m_manager) << "\n";);
69     if (!range->is_infinite() && !range->is_very_big() && (1 == range->get_num_elements().size())) {
70         return m_manager->mk_sort(symbol(ARRAY_SORT_STR), sort_info(m_family_id, ARRAY_SORT, 1,
71                                                              num_parameters, parameters));
72     }
73     bool is_infinite = false;
74     bool is_very_big = false;
75     for (unsigned i = 0; i < num_parameters; i++) {
76         sort * s = to_sort(parameters[i].get_ast());
77         if (s->is_infinite()) {
78             is_infinite = true;
79         }
80         if (s->is_very_big()) {
81             is_very_big = true;
82         }
83     }
84     if (is_infinite) {
85         return m_manager->mk_sort(symbol(ARRAY_SORT_STR), sort_info(m_family_id, ARRAY_SORT, num_parameters, parameters));
86     }
87     else if (is_very_big) {
88         return m_manager->mk_sort(symbol(ARRAY_SORT_STR), sort_info(m_family_id, ARRAY_SORT, sort_size::mk_very_big(),
89                                                              num_parameters, parameters));
90     }
91     else {
92         rational domain_sz(1);
93         rational num_elements;
94         for (unsigned i = 0; i < num_parameters - 1; i++) {
95             domain_sz *= rational(to_sort(parameters[i].get_ast())->get_num_elements().size(),rational::ui64());
96         }
97         if (domain_sz <= rational(128)) {
98             num_elements = rational(range->get_num_elements().size(),rational::ui64());
99             num_elements = power(num_elements, static_cast<int>(domain_sz.get_int64()));
100         }
101 
102         if (domain_sz > rational(128) || !num_elements.is_uint64()) {
103             // too many elements...
104             return m_manager->mk_sort(symbol(ARRAY_SORT_STR),
105                                       sort_info(m_family_id,
106                                                 ARRAY_SORT,
107                                                 sort_size::mk_very_big(),
108                                                 num_parameters,
109                                                 parameters));
110         }
111         else {
112             return m_manager->mk_sort(symbol(ARRAY_SORT_STR), sort_info(m_family_id, ARRAY_SORT, num_elements.get_uint64(),
113                                                                  num_parameters, parameters));
114         }
115     }
116 }
117 
is_array_sort(sort * s) const118 bool array_decl_plugin::is_array_sort(sort* s) const {
119     return m_family_id == s->get_family_id() && s->get_decl_kind() == ARRAY_SORT;
120 }
121 
122 
mk_const(sort * s,unsigned arity,sort * const * domain)123 func_decl * array_decl_plugin::mk_const(sort * s, unsigned arity, sort * const * domain) {
124     if (arity != 1) {
125         m_manager->raise_exception("invalid const array definition, invalid domain size");
126         return nullptr;
127     }
128     if (!is_array_sort(s)) {
129         m_manager->raise_exception("invalid const array definition, parameter is not an array sort");
130         return nullptr;
131     }
132     if (get_array_range(s) != domain[0]) {
133         m_manager->raise_exception("invalid const array definition, sort mismatch between array range and argument");
134         return nullptr;
135     }
136     parameter param(s);
137     func_decl_info info(m_family_id, OP_CONST_ARRAY, 1, &param);
138     info.m_private_parameters = true;
139     return m_manager->mk_func_decl(m_const_sym, arity, domain, s, info);
140 }
141 
mk_map(func_decl * f,unsigned arity,sort * const * domain)142 func_decl * array_decl_plugin::mk_map(func_decl* f, unsigned arity, sort* const* domain) {
143     if (arity != f->get_arity()) {
144         std::ostringstream buffer;
145         buffer << "map expects to take as many arguments as the function being mapped, "
146                << "it was given " << arity << " but expects " << f->get_arity();
147         m_manager->raise_exception(buffer.str());
148         return nullptr;
149     }
150     if (arity == 0) {
151         m_manager->raise_exception("don't use map on constants");
152         return nullptr;
153     }
154     //
155     // check that each domain[i] is an array sort
156     // with the same domains and same ranges.
157     // and that the ranges coincide with the domain of f.
158     //
159     unsigned dom_arity = get_array_arity(domain[0]);
160     for (unsigned i = 0; i < arity; ++i) {
161         if (!is_array_sort(domain[i])) {
162             std::ostringstream buffer;
163             buffer << "map expects an array sort as argument at position " << i;
164             m_manager->raise_exception(buffer.str());
165             return nullptr;
166         }
167         if (get_array_arity(domain[i]) != dom_arity) {
168             std::ostringstream buffer;
169             buffer << "map expects all arguments to have the same array domain,  "
170                    << "this is not the case for argument " << i;
171             m_manager->raise_exception(buffer.str());
172             return nullptr;
173         }
174         for (unsigned j = 0; j < dom_arity; ++j) {
175             if (get_array_domain(domain[i],j) != get_array_domain(domain[0],j)) {
176                 std::ostringstream buffer;
177                 buffer << "map expects all arguments to have the same array domain, "
178                        << "this is not the case for argument " << i;
179                 m_manager->raise_exception(buffer.str());
180                 return nullptr;
181             }
182         }
183         if (get_array_range(domain[i]) != f->get_domain(i)) {
184             std::ostringstream buffer;
185             buffer << "map expects the argument at position " << i
186                    << " to have the array range the same as the function";
187             m_manager->raise_exception(buffer.str());
188             return nullptr;
189         }
190     }
191     vector<parameter> parameters;
192     for (unsigned i = 0; i < dom_arity; ++i) {
193         parameters.push_back(domain[0]->get_parameter(i));
194     }
195     parameters.push_back(parameter(f->get_range()));
196     sort* range = mk_sort(ARRAY_SORT, parameters.size(), parameters.data());
197     parameter param(f);
198     func_decl_info info(m_family_id, OP_ARRAY_MAP, 1, &param);
199     //
200     // left_associative, right_associative, commutative are inherited.
201     // m_injective is inherited, since:
202     // forall x . g(f(x)) = x implies forall X .  map(g)(map(f)(X)) = X
203     // since map(g)(map(f)(X))[i] = g(f(X[i])) = X[i]
204     //
205 
206     info.set_right_associative(f->is_right_associative());
207     info.set_left_associative(f->is_left_associative());
208     info.set_commutative(f->is_commutative());
209     info.set_injective(f->is_injective());
210     return m_manager->mk_func_decl(m_map_sym, arity, domain, range, info);
211 }
212 
213 
mk_default(unsigned domain_size,sort * const * domain)214 func_decl * array_decl_plugin::mk_default(unsigned domain_size, sort * const * domain) {
215     if (domain_size != 1) {
216         m_manager->raise_exception("invalid default array definition, invalid domain size");
217         return nullptr;
218     }
219     // check that domain[0] is an array sort.
220     unsigned num_parameters = domain[0]->get_num_parameters();
221 
222     if (num_parameters <= 1) {
223         m_manager->raise_exception("parameter mismatch. There should be more than one parameter to defaults");
224         return nullptr;
225     }
226     parameter param(domain[0]->get_parameter(num_parameters-1));
227     if (!param.is_ast() || !is_sort(param.get_ast())) {
228         m_manager->raise_exception("last parameter should be a sort");
229         return nullptr;
230     }
231     sort * s = to_sort(param.get_ast());
232 
233     return m_manager->mk_func_decl(m_default_sym, domain_size, domain, s,
234                                    func_decl_info(m_family_id, OP_ARRAY_DEFAULT));
235 }
236 
237 
mk_select(unsigned arity,sort * const * domain)238 func_decl* array_decl_plugin::mk_select(unsigned arity, sort * const * domain) {
239     if (arity <= 1) {
240         m_manager->raise_exception("select takes at least two arguments");
241         return nullptr;
242     }
243     sort * s = domain[0];
244     unsigned num_parameters = s->get_num_parameters();
245     parameter const* parameters = s->get_parameters();
246 
247     if (num_parameters != arity) {
248         std::stringstream strm;
249         strm << "select requires " << num_parameters << " arguments, but was provided with " << arity << " arguments";
250         m_manager->raise_exception(strm.str());
251         return nullptr;
252     }
253     ptr_buffer<sort> new_domain; // we need this because of coercions.
254     new_domain.push_back(s);
255     for (unsigned i = 0; i + 1 < num_parameters; ++i) {
256         if (!parameters[i].is_ast() ||
257             !is_sort(parameters[i].get_ast()) ||
258             !m_manager->compatible_sorts(domain[i+1], to_sort(parameters[i].get_ast()))) {
259             std::stringstream strm;
260             strm << "domain sort " << sort_ref(domain[i+1], *m_manager) << " and parameter ";
261             strm << parameter_pp(parameters[i], *m_manager) << " do not match";
262             m_manager->raise_exception(strm.str());
263             return nullptr;
264         }
265         new_domain.push_back(to_sort(parameters[i].get_ast()));
266     }
267     SASSERT(new_domain.size() == arity);
268     return m_manager->mk_func_decl(m_select_sym, arity, new_domain.data(), get_array_range(domain[0]),
269                                    func_decl_info(m_family_id, OP_SELECT));
270 }
271 
mk_store(unsigned arity,sort * const * domain)272 func_decl * array_decl_plugin::mk_store(unsigned arity, sort * const * domain) {
273     if (arity < 3) {
274         m_manager->raise_exception("store takes at least 3 arguments");
275         return nullptr;
276     }
277     sort * s = domain[0];
278     unsigned num_parameters = s->get_num_parameters();
279     parameter const * parameters = s->get_parameters();
280     if (!is_array_sort(s)) {
281         m_manager->raise_exception("store expects the first argument sort to be an array");
282         UNREACHABLE();
283         return nullptr;
284     }
285     if (arity != num_parameters+1) {
286         std::ostringstream buffer;
287         buffer << "store expects the first argument to be an array taking " << num_parameters+1
288                << ", instead it was passed " << (arity - 1) << "arguments";
289         m_manager->raise_exception(buffer.str());
290         UNREACHABLE();
291         return nullptr;
292     }
293     ptr_buffer<sort> new_domain; // we need this because of coercions.
294     new_domain.push_back(s);
295     for (unsigned i = 0; i < num_parameters; ++i) {
296         if (!parameters[i].is_ast() || !is_sort(parameters[i].get_ast())) {
297             m_manager->raise_exception("expecting sort parameter");
298             return nullptr;
299         }
300         sort* srt1 = to_sort(parameters[i].get_ast());
301         sort* srt2 = domain[i+1];
302         if (!m_manager->compatible_sorts(srt1, srt2)) {
303             std::stringstream strm;
304             strm << "domain sort " << sort_ref(srt2, *m_manager) << " and parameter sort " << sort_ref(srt1, *m_manager) << " do not match";
305             m_manager->raise_exception(strm.str());
306             UNREACHABLE();
307             return nullptr;
308         }
309         new_domain.push_back(to_sort(parameters[i].get_ast()));
310     }
311     SASSERT(new_domain.size() == arity);
312     return m_manager->mk_func_decl(m_store_sym, arity, new_domain.data(), domain[0],
313                                    func_decl_info(m_family_id, OP_STORE));
314 }
315 
mk_array_ext(unsigned arity,sort * const * domain,unsigned i)316 func_decl * array_decl_plugin::mk_array_ext(unsigned arity, sort * const * domain, unsigned i) {
317     if (arity != 2 || domain[0] != domain[1]) {
318         UNREACHABLE();
319         return nullptr;
320     }
321     sort * s = domain[0];
322     unsigned num_parameters = s->get_num_parameters();
323     if (num_parameters == 0 || i >= num_parameters - 1) {
324         UNREACHABLE();
325         return nullptr;
326     }
327     sort * r = to_sort(s->get_parameter(i).get_ast());
328     parameter param(i);
329     return m_manager->mk_func_decl(m_array_ext_sym, arity, domain, r, func_decl_info(m_family_id, OP_ARRAY_EXT, 1, &param));
330 }
331 
332 
check_set_arguments(unsigned arity,sort * const * domain)333 bool array_decl_plugin::check_set_arguments(unsigned arity, sort * const * domain) {
334     for (unsigned i = 0; i < arity; ++i) {
335         if (domain[i] != domain[0]) {
336             std::ostringstream buffer;
337             buffer << "arguments " << 1 << " and " << (i+1) << " have different sorts";
338             m_manager->raise_exception(buffer.str());
339             return false;
340         }
341         if (domain[i]->get_family_id() != m_family_id) {
342             std::ostringstream buffer;
343             buffer << "argument " << (i+1) << " is not of array sort";
344             m_manager->raise_exception(buffer.str());
345             return false;
346         }
347     }
348     if (arity > 0) {
349         unsigned num_params = domain[0]->get_num_parameters();
350         parameter const* params = domain[0]->get_parameters();
351         if (1 >= num_params) {
352             m_manager->raise_exception("expecting 2 or more parameters");
353             UNREACHABLE();
354             return false;
355         }
356         if (!params[num_params-1].is_ast()) {
357             m_manager->raise_exception("expecting term parameters");
358             UNREACHABLE();
359             return false;
360         }
361         if (!is_sort(params[num_params-1].get_ast()) || !m_manager->is_bool(to_sort(params[num_params-1].get_ast()))) {
362             m_manager->raise_exception("expecting boolean range");
363             UNREACHABLE();
364             return false;
365         }
366     }
367     return true;
368 }
369 
mk_set_union(unsigned arity,sort * const * domain)370 func_decl * array_decl_plugin::mk_set_union(unsigned arity, sort * const * domain) {
371 
372     if (arity == 0) {
373         m_manager->raise_exception("union takes at least one argument");
374         return nullptr;
375     }
376     sort * s = domain[0];
377     if (!check_set_arguments(arity, domain)) {
378         return nullptr;
379     }
380     parameter param(s);
381     func_decl_info info(m_family_id, OP_SET_UNION, 1, &param);
382     info.set_associative();
383     info.set_commutative();
384     info.set_idempotent();
385     sort* domain2[2] = { domain[0], domain[0] };
386     return m_manager->mk_func_decl(m_set_union_sym, 2, domain2, domain[0], info);
387 }
388 
mk_set_intersect(unsigned arity,sort * const * domain)389 func_decl * array_decl_plugin::mk_set_intersect(unsigned arity, sort * const * domain) {
390 
391     if (arity == 0) {
392         m_manager->raise_exception("intersection takes at least one argument");
393         return nullptr;
394     }
395     if (!check_set_arguments(arity, domain)) {
396         return nullptr;
397     }
398     func_decl_info info(m_family_id, OP_SET_INTERSECT);
399     info.set_associative();
400     info.set_commutative();
401     info.set_idempotent();
402     sort* domain2[2] = { domain[0], domain[0] };
403     return m_manager->mk_func_decl(m_set_intersect_sym, 2, domain2, domain[0], info);
404 }
405 
mk_set_difference(unsigned arity,sort * const * domain)406 func_decl * array_decl_plugin::mk_set_difference(unsigned arity, sort * const * domain) {
407     if (arity != 2) {
408         m_manager->raise_exception("set difference takes precisely two arguments");
409         return nullptr;
410     }
411     if (!check_set_arguments(arity, domain)) {
412         return nullptr;
413     }
414     return m_manager->mk_func_decl(m_set_difference_sym, arity, domain, domain[0],
415                                    func_decl_info(m_family_id, OP_SET_DIFFERENCE));
416 }
417 
mk_set_complement(unsigned arity,sort * const * domain)418 func_decl * array_decl_plugin::mk_set_complement(unsigned arity, sort * const * domain) {
419     if (arity != 1) {
420         m_manager->raise_exception("set complement takes one argument");
421         return nullptr;
422     }
423     if (!check_set_arguments(arity, domain)) {
424         return nullptr;
425     }
426     return m_manager->mk_func_decl(m_set_complement_sym, arity, domain, domain[0],
427                                    func_decl_info(m_family_id, OP_SET_COMPLEMENT));
428 }
429 
mk_set_subset(unsigned arity,sort * const * domain)430 func_decl * array_decl_plugin::mk_set_subset(unsigned arity, sort * const * domain) {
431     if (arity != 2) {
432         m_manager->raise_exception("subset takes two arguments");
433         return nullptr;
434     }
435     if (!check_set_arguments(arity, domain)) {
436         return nullptr;
437     }
438     sort * bool_sort = m_manager->mk_bool_sort();
439     return m_manager->mk_func_decl(m_set_subset_sym, arity, domain, bool_sort,
440                                    func_decl_info(m_family_id, OP_SET_SUBSET));
441 }
442 
mk_set_card(unsigned arity,sort * const * domain)443 func_decl * array_decl_plugin::mk_set_card(unsigned arity, sort * const* domain) {
444     if (arity != 1) {
445         m_manager->raise_exception("card takes only one argument");
446         return nullptr;
447     }
448 
449     arith_util arith(*m_manager);
450     if (!is_array_sort(domain[0]) || !m_manager->is_bool(get_array_range(domain[0]))) {
451         m_manager->raise_exception("card expects an array of Booleans");
452     }
453     sort * int_sort = arith.mk_int();
454     return m_manager->mk_func_decl(m_set_card_sym, arity, domain, int_sort,
455                                    func_decl_info(m_family_id, OP_SET_CARD));
456 }
457 
mk_set_has_size(unsigned arity,sort * const * domain)458 func_decl * array_decl_plugin::mk_set_has_size(unsigned arity, sort * const* domain) {
459     if (arity != 2) {
460         m_manager->raise_exception("set-has-size takes two arguments");
461         return nullptr;
462     }
463     m_manager->raise_exception("set-has-size is not supported");
464     // domain[0] is a Boolean array,
465     // domain[1] is Int
466     arith_util arith(*m_manager);
467     if (!arith.is_int(domain[1])) {
468         m_manager->raise_exception("set-has-size expects second argument to be an integer");
469     }
470     if (!is_array_sort(domain[0]) || !m_manager->is_bool(get_array_range(domain[0]))) {
471         m_manager->raise_exception("set-has-size expects first argument to be an array of Booleans");
472     }
473     sort * bool_sort = m_manager->mk_bool_sort();
474     return m_manager->mk_func_decl(m_set_has_size_sym, arity, domain, bool_sort,
475                                    func_decl_info(m_family_id, OP_SET_HAS_SIZE));
476 }
477 
mk_as_array(func_decl * f)478 func_decl * array_decl_plugin::mk_as_array(func_decl * f) {
479     vector<parameter> parameters;
480     for (unsigned i = 0; i < f->get_arity(); i++) {
481         parameters.push_back(parameter(f->get_domain(i)));
482     }
483     parameters.push_back(parameter(f->get_range()));
484     sort * s = mk_sort(ARRAY_SORT, parameters.size(), parameters.data());
485     parameter param(f);
486     func_decl_info info(m_family_id, OP_AS_ARRAY, 1, &param);
487     return m_manager->mk_const_decl(m_as_array_sym, s, info);
488 }
489 
490 
mk_func_decl(decl_kind k,unsigned num_parameters,parameter const * parameters,unsigned arity,sort * const * domain,sort * range)491 func_decl * array_decl_plugin::mk_func_decl(decl_kind k, unsigned num_parameters, parameter const * parameters,
492                                             unsigned arity, sort * const * domain, sort * range) {
493     switch (k) {
494     case OP_SELECT:
495         return mk_select(arity, domain);
496     case OP_STORE:
497         return mk_store(arity, domain);
498     case OP_CONST_ARRAY: {
499         if (num_parameters == 1 && parameters[0].is_ast() && is_sort(parameters[0].get_ast())) {
500             sort * s = to_sort(parameters[0].get_ast());
501             return mk_const(s, arity, domain);
502         }
503         else if (range != nullptr) {
504             return mk_const(range, arity, domain);
505         }
506         else {
507             m_manager->raise_exception("array operation requires one sort parameter (the array sort)");
508             UNREACHABLE();
509             return nullptr;
510         }
511     }
512     case OP_ARRAY_MAP: {
513         if (num_parameters != 1 || !parameters[0].is_ast() || !is_func_decl(parameters[0].get_ast())) {
514             m_manager->raise_exception("array operation requires one function declaration parameter (the function to be mapped)");
515             UNREACHABLE();
516             return nullptr;
517         }
518         func_decl * f = to_func_decl(parameters[0].get_ast());
519         return mk_map(f, arity, domain);
520     }
521     case OP_ARRAY_EXT:
522         if (num_parameters == 0) {
523             return mk_array_ext(arity, domain, 0);
524         }
525         if (num_parameters != 1 || !parameters[0].is_int()) {
526             UNREACHABLE();
527             return nullptr;
528         }
529         return mk_array_ext(arity, domain, parameters[0].get_int());
530     case OP_ARRAY_DEFAULT:
531         return mk_default(arity, domain);
532     case OP_SET_UNION:
533         return mk_set_union(arity, domain);
534     case OP_SET_INTERSECT:
535         return mk_set_intersect(arity, domain);
536     case OP_SET_DIFFERENCE:
537         return mk_set_difference(arity, domain);
538     case OP_SET_COMPLEMENT:
539         return mk_set_complement(arity, domain);
540     case OP_SET_SUBSET:
541         return mk_set_subset(arity, domain);
542     case OP_SET_HAS_SIZE:
543         return mk_set_has_size(arity, domain);
544     case OP_SET_CARD:
545         return mk_set_card(arity, domain);
546     case OP_AS_ARRAY: {
547         if (num_parameters != 1 ||
548             !parameters[0].is_ast() ||
549             !is_func_decl(parameters[0].get_ast()) ||
550             to_func_decl(parameters[0].get_ast())->get_arity() == 0) {
551             TRACE("array_bug",
552                   tout << "num_parameters: " << num_parameters << std::endl;
553                   tout << "parameter.kind: " << parameters[0].is_int() << " " << parameters[0].is_ast() << " " << parameters[0].is_symbol() << "\n";
554                   tout << "as-array-bug: " << to_func_decl(parameters[0].get_ast())->get_name() << " " << to_func_decl(parameters[0].get_ast())->get_arity() << std::endl;);
555             m_manager->raise_exception("as-array takes one parameter, a function declaration with arity greater than zero");
556             UNREACHABLE();
557             return nullptr;
558         }
559         func_decl * f = to_func_decl(parameters[0].get_ast());
560         return mk_as_array(f);
561     }
562     default: return nullptr;
563     }
564 }
565 
get_sort_names(svector<builtin_name> & sort_names,symbol const & logic)566 void array_decl_plugin::get_sort_names(svector<builtin_name>& sort_names, symbol const & logic) {
567     sort_names.push_back(builtin_name(ARRAY_SORT_STR, ARRAY_SORT));
568     sort_names.push_back(builtin_name("=>", ARRAY_SORT));
569     if (logic == symbol::null || logic == symbol("HORN") || logic == symbol("ALL")) {
570         // this could easily break users even though it is already used in CVC4:
571         sort_names.push_back(builtin_name("Set", _SET_SORT));
572     }
573 }
574 
get_op_names(svector<builtin_name> & op_names,symbol const & logic)575 void array_decl_plugin::get_op_names(svector<builtin_name>& op_names, symbol const & logic) {
576     op_names.push_back(builtin_name("store",OP_STORE));
577     op_names.push_back(builtin_name("select",OP_SELECT));
578     if (logic == symbol::null || logic == symbol("HORN") || logic == symbol("ALL")) {
579         // none of the SMT2 logics support these extensions
580         op_names.push_back(builtin_name("const",OP_CONST_ARRAY));
581         op_names.push_back(builtin_name("map",OP_ARRAY_MAP));
582         op_names.push_back(builtin_name("default",OP_ARRAY_DEFAULT));
583         op_names.push_back(builtin_name("union",OP_SET_UNION));
584         op_names.push_back(builtin_name("intersection",OP_SET_INTERSECT));
585         op_names.push_back(builtin_name("setminus",OP_SET_DIFFERENCE));
586         op_names.push_back(builtin_name("complement",OP_SET_COMPLEMENT));
587         op_names.push_back(builtin_name("subset",OP_SET_SUBSET));
588         op_names.push_back(builtin_name("as-array", OP_AS_ARRAY));
589         op_names.push_back(builtin_name("array-ext", OP_ARRAY_EXT));
590 #if 0
591         op_names.push_back(builtin_name("set-has-size", OP_SET_HAS_SIZE));
592         op_names.push_back(builtin_name("card", OP_SET_CARD));
593 #endif
594     }
595 }
596 
597 
get_some_value(sort * s)598 expr * array_decl_plugin::get_some_value(sort * s) {
599     SASSERT(s->is_sort_of(m_family_id, ARRAY_SORT));
600     sort * r = to_sort(s->get_parameter(s->get_num_parameters() - 1).get_ast());
601     expr * v = m_manager->get_some_value(r);
602     parameter p(s);
603     return m_manager->mk_app(m_family_id, OP_CONST_ARRAY, 1, &p, 1, &v);
604 }
605 
is_fully_interp(sort * s) const606 bool array_decl_plugin::is_fully_interp(sort * s) const {
607     SASSERT(s->is_sort_of(m_family_id, ARRAY_SORT));
608     unsigned sz = get_array_arity(s);
609     for (unsigned i = 0; i < sz; i++) {
610         if (!m_manager->is_fully_interp(get_array_domain(s, i)))
611             return false;
612     }
613     return m_manager->is_fully_interp(get_array_range(s));
614 }
615 
get_as_array_func_decl(expr * n) const616 func_decl * array_recognizers::get_as_array_func_decl(expr * n) const {
617     SASSERT(is_as_array(n));
618     return to_func_decl(to_app(n)->get_decl()->get_parameter(0).get_ast());
619 }
620 
get_map_func_decl(func_decl * f) const621 func_decl * array_recognizers::get_map_func_decl(func_decl* f) const {
622     SASSERT(f->get_num_parameters() == 1);
623     SASSERT(f->get_parameter(0).is_ast());
624     SASSERT(is_func_decl(f->get_parameter(0).get_ast()));
625     return to_func_decl(f->get_parameter(0).get_ast());
626 }
627 
get_as_array_func_decl(func_decl * f) const628 func_decl * array_recognizers::get_as_array_func_decl(func_decl * f) const {
629     SASSERT(is_as_array(f));
630     return to_func_decl(f->get_parameter(0).get_ast());
631 }
632 
is_const(expr * e,expr * & v) const633 bool array_recognizers::is_const(expr* e, expr*& v) const {
634     return is_const(e) && (v = to_app(e)->get_arg(0), true);
635 }
636 
is_store_ext(expr * _e,expr_ref & a,expr_ref_vector & args,expr_ref & value)637 bool array_recognizers::is_store_ext(expr* _e, expr_ref& a, expr_ref_vector& args, expr_ref& value) {
638     if (is_store(_e)) {
639         app* e = to_app(_e);
640         a = e->get_arg(0);
641         unsigned sz = e->get_num_args();
642         args.reset();
643         for (unsigned i = 1; i < sz-1; ++i) {
644             args.push_back(e->get_arg(i));
645         }
646         value = e->get_arg(sz-1);
647         return true;
648     }
649     return false;
650 }
651 
652 
array_util(ast_manager & m)653 array_util::array_util(ast_manager& m):
654     array_recognizers(m.mk_family_id("array")),
655     m_manager(m) {
656 }
657 
is_as_array_tree(expr * n)658 bool array_util::is_as_array_tree(expr * n) {
659     ptr_buffer<expr, 32> todo;
660     todo.push_back(n);
661     while (!todo.empty()) {
662         expr * curr = todo.back();
663         todo.pop_back();
664         if (is_as_array(curr))
665             continue;
666         if (m_manager.is_ite(curr)) {
667             todo.push_back(to_app(curr)->get_arg(1));
668             todo.push_back(to_app(curr)->get_arg(2));
669             continue;
670         }
671         return false;
672     }
673     return true;
674 }
675 
mk_array_sort(unsigned arity,sort * const * domain,sort * range)676 sort * array_util::mk_array_sort(unsigned arity, sort* const* domain, sort* range) {
677     vector<parameter> params;
678     for (unsigned i = 0; i < arity; ++i) {
679         params.push_back(parameter(domain[i]));
680     }
681     params.push_back(parameter(range));
682     return m_manager.mk_sort(m_fid, ARRAY_SORT, params.size(), params.data());
683 }
684 
mk_array_ext(sort * domain,unsigned i)685 func_decl* array_util::mk_array_ext(sort *domain, unsigned i) {
686     sort * domains[2] = { domain, domain };
687     parameter p(i);
688     return m_manager.mk_func_decl(m_fid, OP_ARRAY_EXT, 1, &p, 2, domains);
689 }
690