CBMC
arrays.cpp
Go to the documentation of this file.
1 /*******************************************************************\
2 
3 Module:
4 
5 Author: Daniel Kroening, kroening@kroening.com
6 
7 \*******************************************************************/
8 
9 #include "arrays.h"
10 
11 #include <util/arith_tools.h>
12 #include <util/json.h>
13 #include <util/message.h>
14 #include <util/replace_expr.h>
15 #include <util/replace_symbol.h>
16 #include <util/std_expr.h>
17 
19 #include <solvers/prop/prop.h>
20 
21 #ifdef DEBUG
22 # include <util/format_expr.h>
23 
24 # include <iostream>
25 #endif
26 
27 #include <unordered_set>
28 
30  const namespacet &_ns,
31  propt &_prop,
32  message_handlert &_message_handler,
33  bool _get_array_constraints)
34  : equalityt(_prop, _message_handler),
35  ns(_ns),
36  log(_message_handler),
37  message_handler(_message_handler)
38 {
39  lazy_arrays = false; // will be set to true when --refine is used
40  incremental_cache = false; // for incremental solving
41  // get_array_constraints is true when --show-array-constraints is used
42  get_array_constraints = _get_array_constraints;
43 }
44 
46 {
47  // we are not allowed to put the index directly in the
48  // entry for the root of the equivalence class
49  // because this map is accessed during building the error trace
50  std::size_t number=arrays.number(index.array());
51  if(index_map[number].insert(index.index()).second)
52  update_indices.insert(number);
53 }
54 
56  const equal_exprt &equality)
57 {
58  const exprt &op0=equality.op0();
59  const exprt &op1=equality.op1();
60 
62  op0.type() == op1.type(),
63  "record_array_equality got equality without matching types",
64  irep_pretty_diagnosticst{equality});
65 
67  op0.type().id() == ID_array,
68  "record_array_equality parameter should be array-typed");
69 
70  array_equalities.push_back(array_equalityt());
71 
72  array_equalities.back().f1=op0;
73  array_equalities.back().f2=op1;
74  array_equalities.back().l=SUB::equality(op0, op1);
75 
76  arrays.make_union(op0, op1);
77  collect_arrays(op0);
78  collect_arrays(op1);
79 
80  return array_equalities.back().l;
81 }
82 
84 {
85  for(std::size_t i=0; i<arrays.size(); i++)
86  {
88  }
89 }
90 
92 {
93  if(expr.id()!=ID_index)
94  {
95  if(expr.id() == ID_array_comprehension)
97  to_array_comprehension_expr(expr).arg().get_identifier());
98 
99  for(const auto &op : expr.operands())
100  collect_indices(op);
101  }
102  else
103  {
104  const index_exprt &e = to_index_expr(expr);
105 
106  if(
107  e.index().id() == ID_symbol &&
109  to_symbol_expr(e.index()).get_identifier()) != 0)
110  {
111  return;
112  }
113 
114  collect_indices(e.index()); // necessary?
115 
116  const typet &array_op_type = e.array().type();
117 
118  if(array_op_type.id()==ID_array)
119  {
120  const array_typet &array_type=
121  to_array_type(array_op_type);
122 
123  if(is_unbounded_array(array_type))
124  {
126  }
127  }
128  }
129 }
130 
132 {
133  const array_typet &array_type = to_array_type(a.type());
134 
135  if(a.id()==ID_with)
136  {
137  const with_exprt &with_expr=to_with_expr(a);
138 
140  array_type == with_expr.old().type(),
141  "collect_arrays got 'with' without matching types",
143 
144  arrays.make_union(a, with_expr.old());
145  collect_arrays(with_expr.old());
146 
147  // make sure this shows as an application
148  for(std::size_t i = 1; i < with_expr.operands().size(); i += 2)
149  {
150  index_exprt index_expr(with_expr.old(), with_expr.operands()[i]);
151  record_array_index(index_expr);
152  }
153  }
154  else if(a.id()==ID_update)
155  {
156  const update_exprt &update_expr=to_update_expr(a);
157 
159  array_type == update_expr.old().type(),
160  "collect_arrays got 'update' without matching types",
162 
163  arrays.make_union(a, update_expr.old());
164  collect_arrays(update_expr.old());
165 
166 #if 0
167  // make sure this shows as an application
168  index_exprt index_expr(update_expr.old(), update_expr.index());
169  record_array_index(index_expr);
170 #endif
171  }
172  else if(a.id()==ID_if)
173  {
174  const if_exprt &if_expr=to_if_expr(a);
175 
177  array_type == if_expr.true_case().type(),
178  "collect_arrays got if without matching types",
180 
182  array_type == if_expr.false_case().type(),
183  "collect_arrays got if without matching types",
185 
186  arrays.make_union(a, if_expr.true_case());
187  arrays.make_union(a, if_expr.false_case());
188  collect_arrays(if_expr.true_case());
189  collect_arrays(if_expr.false_case());
190  }
191  else if(a.id()==ID_symbol)
192  {
193  }
194  else if(a.id()==ID_nondet_symbol)
195  {
196  }
197  else if(a.id()==ID_member)
198  {
199  const auto &struct_op = to_member_expr(a).struct_op();
200 
202  struct_op.id() == ID_symbol || struct_op.id() == ID_nondet_symbol,
203  "unexpected array expression: member with '" + struct_op.id_string() +
204  "'");
205  }
206  else if(a.is_constant() || a.id() == ID_array || a.id() == ID_string_constant)
207  {
208  }
209  else if(a.id()==ID_array_of)
210  {
211  }
212  else if(a.id()==ID_byte_update_little_endian ||
213  a.id()==ID_byte_update_big_endian)
214  {
216  false,
217  "byte_update should be removed before collect_arrays");
218  }
219  else if(a.id()==ID_typecast)
220  {
221  const auto &typecast_op = to_typecast_expr(a).op();
222 
223  // cast between array types?
225  typecast_op.type().id() == ID_array,
226  "unexpected array type cast from " + typecast_op.type().id_string());
227 
228  arrays.make_union(a, typecast_op);
229  collect_arrays(typecast_op);
230  }
231  else if(a.id()==ID_index)
232  {
233  // nested unbounded arrays
234  const auto &array_op = to_index_expr(a).array();
235  arrays.make_union(a, array_op);
236  collect_arrays(array_op);
237  }
238  else if(a.id() == ID_array_comprehension)
239  {
240  }
241  else if(auto let_expr = expr_try_dynamic_cast<let_exprt>(a))
242  {
243  arrays.make_union(a, let_expr->where());
244  collect_arrays(let_expr->where());
245  }
246  else
247  {
249  false,
250  "unexpected array expression (collect_arrays): '" + a.id_string() + "'");
251  }
252 }
253 
256 {
257  if(lazy_arrays && refine)
258  {
259  // lazily add the constraint
261  {
262  if(expr_map.find(lazy.lazy) == expr_map.end())
263  {
264  lazy_array_constraints.push_back(lazy);
265  expr_map[lazy.lazy] = true;
266  }
267  }
268  else
269  {
270  lazy_array_constraints.push_back(lazy);
271  }
272  }
273  else
274  {
275  // add the constraint eagerly
277  }
278 }
279 
281 {
282  collect_indices();
283  // at this point all indices should in the index set
284 
285  // reduce initial index map
286  update_index_map(true);
287 
288  // add constraints for if, with, array_of, lambda
289  std::set<std::size_t> roots_to_process, updated_roots;
290  for(std::size_t i=0; i<arrays.size(); i++)
291  roots_to_process.insert(arrays.find_number(i));
292 
293  while(!roots_to_process.empty())
294  {
295  for(std::size_t i = 0; i < arrays.size(); i++)
296  {
297  if(roots_to_process.count(arrays.find_number(i)) == 0)
298  continue;
299 
300  // take a copy as arrays may get modified by add_array_constraints
301  // in case of nested unbounded arrays
302  exprt a = arrays[i];
303 
305 
306  // we have to update before it gets used in the next add_* call
307  for(const std::size_t u : update_indices)
308  updated_roots.insert(arrays.find_number(u));
309  update_index_map(false);
310  }
311 
312  roots_to_process = std::move(updated_roots);
313  updated_roots.clear();
314  }
315 
316  // add constraints for equalities
317  for(const auto &equality : array_equalities)
318  {
321  equality);
322 
323  // update_index_map should not be necessary here
324  }
325 
326  // add the Ackermann constraints
328 }
329 
331 {
332  // this is quadratic!
333 
334 #ifdef DEBUG
335  std::cout << "arrays.size(): " << arrays.size() << '\n';
336 #endif
337 
338  // iterate over arrays
339  for(std::size_t i=0; i<arrays.size(); i++)
340  {
341  const index_sett &index_set=index_map[arrays.find_number(i)];
342 
343 #ifdef DEBUG
344  std::cout << "index_set.size(): " << index_set.size() << '\n';
345 #endif
346 
347  // iterate over indices, 2x!
348  for(index_sett::const_iterator
349  i1=index_set.begin();
350  i1!=index_set.end();
351  i1++)
352  for(index_sett::const_iterator
353  i2=i1;
354  i2!=index_set.end();
355  i2++)
356  if(i1!=i2)
357  {
358  if(i1->is_constant() && i2->is_constant())
359  continue;
360 
361  // index equality
362  const equal_exprt indices_equal(
363  *i1, typecast_exprt::conditional_cast(*i2, i1->type()));
364 
365  literalt indices_equal_lit=convert(indices_equal);
366 
367  if(indices_equal_lit!=const_literal(false))
368  {
369  const typet &subtype =
370  to_array_type(arrays[i].type()).element_type();
371  index_exprt index_expr1(arrays[i], *i1, subtype);
372 
373  index_exprt index_expr2=index_expr1;
374  index_expr2.index()=*i2;
375 
376  equal_exprt values_equal(index_expr1, index_expr2);
377 
378  // add constraint
380  implies_exprt(literal_exprt(indices_equal_lit), values_equal));
381  add_array_constraint(lazy, true); // added lazily
383 
384 #if 0 // old code for adding, not significantly faster
385  prop.lcnf(!indices_equal_lit, convert(values_equal));
386 #endif
387  }
388  }
389  }
390 }
391 
393 void arrayst::update_index_map(std::size_t i)
394 {
395  if(arrays.is_root_number(i))
396  return;
397 
398  std::size_t root_number=arrays.find_number(i);
399  INVARIANT(root_number!=i, "is_root_number incorrect?");
400 
401  index_sett &root_index_set=index_map[root_number];
402  index_sett &index_set=index_map[i];
403 
404  root_index_set.insert(index_set.begin(), index_set.end());
405 }
406 
407 void arrayst::update_index_map(bool update_all)
408 {
409  // iterate over non-roots
410  // possible reasons why update is needed:
411  // -- there are new equivalence classes in arrays
412  // -- there are new indices for arrays that are not the root
413  // of an equivalence class
414  // (and we cannot do that in record_array_index())
415  // -- equivalence classes have been merged
416  if(update_all)
417  {
418  for(std::size_t i=0; i<arrays.size(); i++)
419  update_index_map(i);
420  }
421  else
422  {
423  for(const auto &index : update_indices)
424  update_index_map(index);
425 
426  update_indices.clear();
427  }
428 
429 #ifdef DEBUG
430  // print index sets
431  for(const auto &index_entry : index_map)
432  for(const auto &index : index_entry.second)
433  std::cout << "Index set (" << index_entry.first << " = "
434  << arrays.find_number(index_entry.first) << " = "
435  << format(arrays[arrays.find_number(index_entry.first)])
436  << "): " << format(index) << '\n';
437  std::cout << "-----\n";
438 #endif
439 }
440 
442  const index_sett &index_set,
443  const array_equalityt &array_equality)
444 {
445  // add constraints x=y => x[i]=y[i]
446 
447  for(const auto &index : index_set)
448  {
449  const typet &element_type1 =
450  to_array_type(array_equality.f1.type()).element_type();
451  index_exprt index_expr1(array_equality.f1, index, element_type1);
452 
453  const typet &element_type2 =
454  to_array_type(array_equality.f2.type()).element_type();
455  index_exprt index_expr2(array_equality.f2, index, element_type2);
456 
458  index_expr1.type()==index_expr2.type(),
459  "array elements should all have same type");
460 
461  array_equalityt equal;
462  equal.f1 = index_expr1;
463  equal.f2 = index_expr2;
464  equal.l = array_equality.l;
465  equal_exprt equality_expr(index_expr1, index_expr2);
466 
467  // add constraint
468  // equality constraints are not added lazily
469  // convert must be done to guarantee correct update of the index_set
470  prop.lcnf(!array_equality.l, convert(equality_expr));
472  }
473 }
474 
476  const index_sett &index_set,
477  const exprt &expr)
478 {
479  if(expr.id()==ID_with)
480  return add_array_constraints_with(index_set, to_with_expr(expr));
481  else if(expr.id()==ID_update)
482  return add_array_constraints_update(index_set, to_update_expr(expr));
483  else if(expr.id()==ID_if)
484  return add_array_constraints_if(index_set, to_if_expr(expr));
485  else if(expr.id()==ID_array_of)
486  return add_array_constraints_array_of(index_set, to_array_of_expr(expr));
487  else if(expr.id() == ID_array)
488  return add_array_constraints_array_constant(index_set, to_array_expr(expr));
489  else if(expr.id() == ID_array_comprehension)
490  {
492  index_set, to_array_comprehension_expr(expr));
493  }
494  else if(
495  expr.id() == ID_symbol || expr.id() == ID_nondet_symbol ||
496  expr.is_constant() || expr.id() == "zero_string" ||
497  expr.id() == ID_string_constant)
498  {
499  }
500  else if(
501  expr.id() == ID_member &&
502  (to_member_expr(expr).struct_op().id() == ID_symbol ||
503  to_member_expr(expr).struct_op().id() == ID_nondet_symbol))
504  {
505  }
506  else if(expr.id()==ID_byte_update_little_endian ||
507  expr.id()==ID_byte_update_big_endian)
508  {
509  INVARIANT(false, "byte_update should be removed before arrayst");
510  }
511  else if(expr.id()==ID_typecast)
512  {
513  // we got a=(type[])b
514  const auto &expr_typecast_op = to_typecast_expr(expr).op();
515 
516  // add a[i]=b[i]
517  for(const auto &index : index_set)
518  {
519  const typet &element_type = to_array_type(expr.type()).element_type();
520  index_exprt index_expr1(expr, index, element_type);
521  index_exprt index_expr2(expr_typecast_op, index, element_type);
522 
524  index_expr1.type()==index_expr2.type(),
525  "array elements should all have same type");
526 
527  // add constraint
529  equal_exprt(index_expr1, index_expr2));
530  add_array_constraint(lazy, false); // added immediately
532  }
533  }
534  else if(expr.id()==ID_index)
535  {
536  }
537  else if(auto let_expr = expr_try_dynamic_cast<let_exprt>(expr))
538  {
539  // we got x=let(a=e, A)
540  // add x[i]=A[a/e][i]
541 
542  exprt where = let_expr->where();
543  replace_symbolt replace_symbol;
544  for(const auto &binding :
545  make_range(let_expr->variables()).zip(let_expr->values()))
546  {
547  replace_symbol.insert(binding.first, binding.second);
548  }
549  replace_symbol(where);
550 
551  for(const auto &index : index_set)
552  {
553  index_exprt index_expr{expr, index};
554  index_exprt where_indexed{where, index};
555 
556  // add constraint
558  lazy_typet::ARRAY_LET, equal_exprt{index_expr, where_indexed}};
559 
560  add_array_constraint(lazy, false); // added immediately
562  }
563  }
564  else
565  {
567  false,
568  "unexpected array expression (add_array_constraints): '" +
569  expr.id_string() + "'");
570  }
571 }
572 
574  const index_sett &index_set,
575  const with_exprt &expr)
576 {
577  // We got x=(y with [i:=v, j:=w, ...]).
578  // First add constraints x[i]=v, x[j]=w, ...
579  std::unordered_set<exprt, irep_hash> updated_indices;
580 
581  const exprt::operandst &operands = expr.operands();
582  for(std::size_t i = 1; i + 1 < operands.size(); i += 2)
583  {
584  const exprt &index = operands[i];
585  const exprt &value = operands[i + 1];
586 
587  index_exprt index_expr(
588  expr, index, to_array_type(expr.type()).element_type());
589 
591  index_expr.type() == value.type(),
592  "with-expression operand should match array element type",
594 
596  lazy_typet::ARRAY_WITH, equal_exprt(index_expr, value));
597  add_array_constraint(lazy, false); // added immediately
599 
600  updated_indices.insert(index);
601  }
602 
603  // For all other indices use the existing value, i.e., add constraints
604  // x[I]=y[I] for I!=i,j,...
605 
606  for(auto other_index : index_set)
607  {
608  if(updated_indices.find(other_index) == updated_indices.end())
609  {
610  // we first build the guard
611  exprt::operandst disjuncts;
612  disjuncts.reserve(updated_indices.size());
613  for(const auto &index : updated_indices)
614  {
615  disjuncts.push_back(equal_exprt{
616  index, typecast_exprt::conditional_cast(other_index, index.type())});
617  }
618 
619  literalt guard_lit = convert(disjunction(disjuncts));
620 
621  if(guard_lit!=const_literal(true))
622  {
623  const typet &element_type = to_array_type(expr.type()).element_type();
624  index_exprt index_expr1(expr, other_index, element_type);
625  index_exprt index_expr2(expr.old(), other_index, element_type);
626 
627  equal_exprt equality_expr(index_expr1, index_expr2);
628 
629  // add constraint
631  literal_exprt(guard_lit)));
632 
633  add_array_constraint(lazy, false); // added immediately
635 
636 #if 0 // old code for adding, not significantly faster
637  {
638  literalt equality_lit=convert(equality_expr);
639 
640  bvt bv;
641  bv.reserve(2);
642  bv.push_back(equality_lit);
643  bv.push_back(guard_lit);
644  prop.lcnf(bv);
645  }
646 #endif
647  }
648  }
649  }
650 }
651 
653  const index_sett &,
654  const update_exprt &)
655 {
656  // we got x=UPDATE(y, [i], v)
657  // add constaint x[i]=v
658 
659 #if 0
660  const exprt &index=expr.where();
661  const exprt &value=expr.new_value();
662 
663  {
664  index_exprt index_expr(expr, index, expr.type().subtype());
665 
667  index_expr.type()==value.type(),
668  "update operand should match array element type",
670 
671  set_to_true(equal_exprt(index_expr, value));
672  }
673 
674  // use other array index applications for "else" case
675  // add constraint x[I]=y[I] for I!=i
676 
677  for(auto other_index : index_set)
678  {
679  if(other_index!=index)
680  {
681  // we first build the guard
682 
683  other_index = typecast_exprt::conditional_cast(other_index, index.type());
684 
685  literalt guard_lit=convert(equal_exprt(index, other_index));
686 
687  if(guard_lit!=const_literal(true))
688  {
689  const typet &subtype=expr.type().subtype();
690  index_exprt index_expr1(expr, other_index, subtype);
691  index_exprt index_expr2(expr.op0(), other_index, subtype);
692 
693  equal_exprt equality_expr(index_expr1, index_expr2);
694 
695  literalt equality_lit=convert(equality_expr);
696 
697  // add constraint
698  bvt bv;
699  bv.reserve(2);
700  bv.push_back(equality_lit);
701  bv.push_back(guard_lit);
702  prop.lcnf(bv);
703  }
704  }
705  }
706 #endif
707 }
708 
710  const index_sett &index_set,
711  const array_of_exprt &expr)
712 {
713  // we got x=array_of[v]
714  // get other array index applications
715  // and add constraint x[i]=v
716 
717  for(const auto &index : index_set)
718  {
719  const typet &element_type = expr.type().element_type();
720  index_exprt index_expr(expr, index, element_type);
721 
723  index_expr.type() == expr.what().type(),
724  "array_of operand type should match array element type");
725 
726  // add constraint
728  lazy_typet::ARRAY_OF, equal_exprt(index_expr, expr.what()));
729  add_array_constraint(lazy, false); // added immediately
731  }
732 }
733 
735  const index_sett &index_set,
736  const array_exprt &expr)
737 {
738  // we got x = { v, ... } - add constraint x[i] = v
739  const exprt::operandst &operands = expr.operands();
740 
741  for(const auto &index : index_set)
742  {
743  const typet &element_type = expr.type().element_type();
744  const index_exprt index_expr{expr, index, element_type};
745 
746  if(index.is_constant())
747  {
748  // We have a constant index - just pick the element at that index from the
749  // array constant.
750 
751  const std::optional<std::size_t> i =
752  numeric_cast<std::size_t>(to_constant_expr(index));
753  // if the access is out of bounds, we leave it unconstrained
754  if(!i.has_value() || *i >= operands.size())
755  continue;
756 
757  const exprt v = operands[*i];
759  index_expr.type() == v.type(),
760  "array operand type should match array element type");
761 
762  // add constraint
764  equal_exprt{index_expr, v}};
765  add_array_constraint(lazy, false); // added immediately
767  }
768  else
769  {
770  // We have a non-constant index into an array constant. We need to build a
771  // case statement testing the index against all possible values. Whenever
772  // neighbouring array elements are the same, we can test the index against
773  // the range rather than individual elements. This should be particularly
774  // helpful when we have arrays of zeros, as is the case for initializers.
775 
776  std::vector<std::pair<std::size_t, std::size_t>> ranges;
777 
778  for(std::size_t i = 0; i < operands.size(); ++i)
779  {
780  if(ranges.empty() || operands[i] != operands[ranges.back().first])
781  ranges.emplace_back(i, i);
782  else
783  ranges.back().second = i;
784  }
785 
786  for(const auto &range : ranges)
787  {
788  exprt index_constraint;
789 
790  if(range.first == range.second)
791  {
792  index_constraint =
793  equal_exprt{index, from_integer(range.first, index.type())};
794  }
795  else
796  {
797  index_constraint = and_exprt{
799  from_integer(range.first, index.type()), ID_le, index},
801  index, ID_le, from_integer(range.second, index.type())}};
802  }
803 
806  implies_exprt{index_constraint,
807  equal_exprt{index_expr, operands[range.first]}}};
808  add_array_constraint(lazy, true); // added lazily
810  }
811  }
812  }
813 }
814 
816  const index_sett &index_set,
817  const array_comprehension_exprt &expr)
818 {
819  // we got x=lambda(i: e)
820  // get all other array index applications
821  // and add constraints x[j]=e[i/j]
822 
823  for(const auto &index : index_set)
824  {
825  index_exprt index_expr{expr, index};
826  exprt comprehension_body = expr.body();
827  replace_expr(expr.arg(), index, comprehension_body);
828 
829  // add constraint
832  equal_exprt(index_expr, comprehension_body));
833 
834  add_array_constraint(lazy, false); // added immediately
836  }
837 }
838 
840  const index_sett &index_set,
841  const if_exprt &expr)
842 {
843  // we got x=(c?a:b)
844  literalt cond_lit=convert(expr.cond());
845 
846  // get other array index applications
847  // and add c => x[i]=a[i]
848  // !c => x[i]=b[i]
849 
850  // first do true case
851 
852  for(const auto &index : index_set)
853  {
854  const typet &element_type = to_array_type(expr.type()).element_type();
855  index_exprt index_expr1(expr, index, element_type);
856  index_exprt index_expr2(expr.true_case(), index, element_type);
857 
858  // add implication
860  or_exprt(literal_exprt(!cond_lit),
861  equal_exprt(index_expr1, index_expr2)));
862  add_array_constraint(lazy, false); // added immediately
864 
865 #if 0 // old code for adding, not significantly faster
866  prop.lcnf(!cond_lit, convert(equal_exprt(index_expr1, index_expr2)));
867 #endif
868  }
869 
870  // now the false case
871  for(const auto &index : index_set)
872  {
873  const typet &element_type = to_array_type(expr.type()).element_type();
874  index_exprt index_expr1(expr, index, element_type);
875  index_exprt index_expr2(expr.false_case(), index, element_type);
876 
877  // add implication
880  or_exprt(literal_exprt(cond_lit),
881  equal_exprt(index_expr1, index_expr2)));
882  add_array_constraint(lazy, false); // added immediately
884 
885 #if 0 // old code for adding, not significantly faster
886  prop.lcnf(cond_lit, convert(equal_exprt(index_expr1, index_expr2)));
887 #endif
888  }
889 }
890 
892 {
893  switch(type)
894  {
896  return "arrayAckermann";
898  return "arrayWith";
900  return "arrayIf";
902  return "arrayOf";
904  return "arrayTypecast";
906  return "arrayConstant";
908  return "arrayComprehension";
910  return "arrayEquality";
912  return "arrayLet";
913  default:
914  UNREACHABLE;
915  }
916 }
917 
919 {
920  json_objectt json_result;
921  json_objectt &json_array_theory =
922  json_result["arrayConstraints"].make_object();
923 
924  size_t num_constraints = 0;
925 
926  array_constraint_countt::iterator it = array_constraint_count.begin();
927  while(it != array_constraint_count.end())
928  {
929  std::string contraint_type_string = enum_to_string(it->first);
930  json_array_theory[contraint_type_string] =
931  json_numbert(std::to_string(it->second));
932 
933  num_constraints += it->second;
934  it++;
935  }
936 
937  json_result["numOfConstraints"] =
938  json_numbert(std::to_string(num_constraints));
939  log.status() << ",\n" << json_result;
940 }
constant_exprt from_integer(const mp_integer &int_value, const typet &type)
Theory of Arrays with Extensionality.
Boolean AND.
Definition: std_expr.h:2120
Expression to define a mapping from an argument (index) to elements.
Definition: std_expr.h:3413
const exprt & body() const
Definition: std_expr.h:3451
const symbol_exprt & arg() const
Definition: std_expr.h:3437
Array constructor from list of elements.
Definition: std_expr.h:1616
const array_typet & type() const
Definition: std_expr.h:1623
Array constructor from single element.
Definition: std_expr.h:1553
exprt & what()
Definition: std_expr.h:1570
const array_typet & type() const
Definition: std_expr.h:1560
Arrays with given size.
Definition: std_types.h:807
const typet & element_type() const
The type of the elements of the array.
Definition: std_types.h:827
std::list< lazy_constraintt > lazy_array_constraints
Definition: arrays.h:115
std::unordered_set< irep_idt > array_comprehension_args
Definition: arrays.h:165
index_mapt index_map
Definition: arrays.h:85
void add_array_constraints_equality(const index_sett &index_set, const array_equalityt &array_equality)
Definition: arrays.cpp:441
std::set< std::size_t > update_indices
Definition: arrays.h:161
void add_array_constraints_array_of(const index_sett &index_set, const array_of_exprt &exprt)
Definition: arrays.cpp:709
void add_array_Ackermann_constraints()
Definition: arrays.cpp:330
bool lazy_arrays
Definition: arrays.h:112
void collect_indices()
Definition: arrays.cpp:83
void add_array_constraints_update(const index_sett &index_set, const update_exprt &expr)
Definition: arrays.cpp:652
void collect_arrays(const exprt &a)
Definition: arrays.cpp:131
union_find< exprt, irep_hash > arrays
Definition: arrays.h:78
literalt record_array_equality(const equal_exprt &expr)
Definition: arrays.cpp:55
void add_array_constraints_array_constant(const index_sett &index_set, const array_exprt &exprt)
Definition: arrays.cpp:734
arrayst(const namespacet &_ns, propt &_prop, message_handlert &message_handler, bool get_array_constraints=false)
Definition: arrays.cpp:29
constraint_typet
Definition: arrays.h:120
std::map< exprt, bool > expr_map
Definition: arrays.h:117
void add_array_constraints_if(const index_sett &index_set, const if_exprt &exprt)
Definition: arrays.cpp:839
std::string enum_to_string(constraint_typet)
Definition: arrays.cpp:891
bool get_array_constraints
Definition: arrays.h:114
void add_array_constraints()
Definition: arrays.cpp:280
void add_array_constraints_comprehension(const index_sett &index_set, const array_comprehension_exprt &expr)
Definition: arrays.cpp:815
virtual bool is_unbounded_array(const typet &type) const =0
void record_array_index(const index_exprt &expr)
Definition: arrays.cpp:45
array_equalitiest array_equalities
Definition: arrays.h:75
std::set< exprt > index_sett
Definition: arrays.h:81
void add_array_constraint(const lazy_constraintt &lazy, bool refine=true)
adds array constraints (refine=true...lazily for the refinement loop)
Definition: arrays.cpp:255
array_constraint_countt array_constraint_count
Definition: arrays.h:133
void add_array_constraints_with(const index_sett &index_set, const with_exprt &expr)
Definition: arrays.cpp:573
bool incremental_cache
Definition: arrays.h:113
void display_array_constraint_count()
Definition: arrays.cpp:918
void update_index_map(bool update_all)
Definition: arrays.cpp:407
messaget log
Definition: arrays.h:57
A base class for expressions that are predicates, i.e., Boolean-typed, and that take exactly two argu...
Definition: std_expr.h:731
void set_to_true(const exprt &)
For a Boolean expression expr, add the constraint 'expr'.
Equality.
Definition: std_expr.h:1361
virtual literalt equality(const exprt &e1, const exprt &e2)
Definition: equality.cpp:17
Base class for all expressions.
Definition: expr.h:56
std::vector< exprt > operandst
Definition: expr.h:58
typet & type()
Return the type of the expression.
Definition: expr.h:84
bool is_constant() const
Return whether the expression is a constant.
Definition: expr.h:212
operandst & operands()
Definition: expr.h:94
The trinary if-then-else operator.
Definition: std_expr.h:2370
exprt & true_case()
Definition: std_expr.h:2397
exprt & false_case()
Definition: std_expr.h:2407
exprt & cond()
Definition: std_expr.h:2387
Boolean implication.
Definition: std_expr.h:2183
Array index operator.
Definition: std_expr.h:1465
exprt & array()
Definition: std_expr.h:1495
exprt & index()
Definition: std_expr.h:1505
const std::string & id_string() const
Definition: irep.h:391
const irep_idt & id() const
Definition: irep.h:388
json_objectt & make_object()
Definition: json.h:436
const exprt & struct_op() const
Definition: std_expr.h:2882
mstreamt & status() const
Definition: message.h:406
A namespacet is essentially one or two symbol tables bound together, to allow for symbol lookups in t...
Definition: namespace.h:94
Boolean OR.
Definition: std_expr.h:2228
literalt convert(const exprt &expr) override
Convert a Boolean expression and return the corresponding literal.
TO_BE_DOCUMENTED.
Definition: prop.h:25
void l_set_to_true(literalt a)
Definition: prop.h:52
void lcnf(literalt l0, literalt l1)
Definition: prop.h:58
Replace a symbol expression by a given expression.
void insert(const class symbol_exprt &old_expr, const exprt &new_expr)
Sets old_expr to be replaced by new_expr if we don't already have a replacement; otherwise does nothi...
const irep_idt & get_identifier() const
Definition: std_expr.h:160
static exprt conditional_cast(const exprt &expr, const typet &type)
Definition: std_expr.h:2076
The type of an expression, extends irept.
Definition: type.h:29
const exprt & op() const
Definition: std_expr.h:391
size_type number(const T &a)
Definition: union_find.h:235
bool make_union(const T &a, const T &b)
Definition: union_find.h:155
size_t size() const
Definition: union_find.h:268
size_type find_number(const_iterator it) const
Definition: union_find.h:201
bool is_root_number(size_type a) const
Definition: union_find.h:216
Operator to update elements in structs and arrays.
Definition: std_expr.h:2655
exprt & old()
Definition: std_expr.h:2667
Operator to update elements in structs and arrays.
Definition: std_expr.h:2471
exprt & old()
Definition: std_expr.h:2481
static format_containert< T > format(const T &o)
Definition: format.h:37
auto lazy(funt fun) -> lazyt< decltype(fun())>
Delay the computation of fun to the next time the force method is called.
Definition: lazy.h:49
std::vector< literalt > bvt
Definition: literal.h:201
literalt const_literal(bool value)
Definition: literal.h:188
double log(double x)
Definition: math.c:2776
ranget< iteratort > make_range(iteratort begin, iteratort end)
Definition: range.h:522
bool replace_expr(const exprt &what, const exprt &by, exprt &dest)
#define UNREACHABLE
This should be used to mark dead code.
Definition: invariant.h:525
#define DATA_INVARIANT(CONDITION, REASON)
This condition should be used to document that assumptions that are made on goto_functions,...
Definition: invariant.h:534
#define DATA_INVARIANT_WITH_DIAGNOSTICS(CONDITION, REASON,...)
Definition: invariant.h:535
exprt disjunction(const exprt::operandst &op)
1) generates a disjunction for two or more operands 2) for one operand, returns the operand 3) return...
Definition: std_expr.cpp:71
API to expression classes.
const if_exprt & to_if_expr(const exprt &expr)
Cast an exprt to an if_exprt.
Definition: std_expr.h:2450
const update_exprt & to_update_expr(const exprt &expr)
Cast an exprt to an update_exprt.
Definition: std_expr.h:2738
const constant_exprt & to_constant_expr(const exprt &expr)
Cast an exprt to a constant_exprt.
Definition: std_expr.h:3045
const symbol_exprt & to_symbol_expr(const exprt &expr)
Cast an exprt to a symbol_exprt.
Definition: std_expr.h:272
const array_exprt & to_array_expr(const exprt &expr)
Cast an exprt to an array_exprt.
Definition: std_expr.h:1660
const array_comprehension_exprt & to_array_comprehension_expr(const exprt &expr)
Cast an exprt to a array_comprehension_exprt.
Definition: std_expr.h:3480
const typecast_exprt & to_typecast_expr(const exprt &expr)
Cast an exprt to a typecast_exprt.
Definition: std_expr.h:2102
const with_exprt & to_with_expr(const exprt &expr)
Cast an exprt to a with_exprt.
Definition: std_expr.h:2533
const array_of_exprt & to_array_of_expr(const exprt &expr)
Cast an exprt to an array_of_exprt.
Definition: std_expr.h:1598
const member_exprt & to_member_expr(const exprt &expr)
Cast an exprt to a member_exprt.
Definition: std_expr.h:2936
const index_exprt & to_index_expr(const exprt &expr)
Cast an exprt to an index_exprt.
Definition: std_expr.h:1533
const array_typet & to_array_type(const typet &type)
Cast a typet to an array_typet.
Definition: std_types.h:888
std::string to_string(const string_not_contains_constraintt &expr)
Used for debug printing.