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, ¶m);
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, ¶m);
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, ¶m));
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, ¶m);
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, ¶m);
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