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