@@ -21,10 +21,27 @@ Author: Alberto Griggio, alberto.griggio@gmail.com
2121#include < langapi/language_util.h>
2222#include < java_bytecode/java_types.h>
2323
24+ /* ******************************************************************\
25+
26+ Constructor: string_refinementt
27+
28+ Inputs: a namespace, a decision procedure, a bound on the number
29+ of refinements and a boolean flag `concretize_result`
30+
31+ Purpose: refinement_bound is a bound on the number of refinement allowed.
32+ if `concretize_result` is set to true, at the end of the decision
33+ procedure, the solver try to find a concrete value for each
34+ character
35+
36+ \*******************************************************************/
37+
2438string_refinementt::string_refinementt (
25- const namespacet &_ns, propt &_prop, unsigned refinement_bound):
39+ const namespacet &_ns,
40+ propt &_prop,
41+ unsigned refinement_bound):
2642 supert(_ns, _prop),
2743 use_counter_example(false ),
44+ do_concretizing(false ),
2845 initial_loop_bound(refinement_bound)
2946{ }
3047
@@ -194,7 +211,7 @@ exprt string_refinementt::substitute_function_applications(exprt expr)
194211 return expr;
195212}
196213
197- bool string_refinementt::is_char_array (const typet &type)
214+ bool string_refinementt::is_char_array (const typet &type) const
198215{
199216 if (type.id ()==ID_symbol)
200217 return is_char_array (ns.follow (type));
@@ -220,7 +237,12 @@ bool string_refinementt::add_axioms_for_string_assigns(const exprt &lhs,
220237 if (is_char_array (rhs.type ()))
221238 {
222239 set_char_array_equality (lhs, rhs);
223- add_symbol_to_symbol_map (lhs, rhs);
240+ if (rhs.id () != ID_nondet_symbol)
241+ add_symbol_to_symbol_map (lhs, rhs);
242+ else
243+ add_symbol_to_symbol_map (
244+ lhs, generator.fresh_symbol (" nondet_array" , lhs.type ()));
245+
224246 return false ;
225247 }
226248 if (refined_string_typet::is_refined_string_type (rhs.type ()))
@@ -235,6 +257,46 @@ bool string_refinementt::add_axioms_for_string_assigns(const exprt &lhs,
235257
236258/* ******************************************************************\
237259
260+ Function: string_refinementt::concretize_results
261+
262+ Purpose: For each string whose length has been solved, add constants
263+ to the index set to force the solver to pick concrete values
264+ for each character
265+
266+ \*******************************************************************/
267+
268+ void string_refinementt::concretize_results ()
269+ {
270+ for (const auto & it : symbol_resolve)
271+ {
272+ if (refined_string_typet::is_refined_string_type (it.second .type ()))
273+ {
274+ string_exprt str=to_string_expr (it.second );
275+ exprt length=current_model[str.length ()];
276+ mp_integer found_length;
277+ if (!to_integer (length, found_length))
278+ {
279+ assert (found_length.is_long () && found_length >= 0 );
280+ size_t concretize_limit=found_length.to_long ();
281+ concretize_limit=concretize_limit>MAX_CONCRETE_STRING_SIZE?
282+ MAX_CONCRETE_STRING_SIZE:concretize_limit;
283+ exprt content_expr=str.content ();
284+ replace_expr (current_model, content_expr);
285+ for (size_t i=0 ; i<concretize_limit; ++i)
286+ {
287+ auto i_expr=from_integer (i, str.length ().type ());
288+ debug () << " Concretizing " << from_expr (content_expr)
289+ << " / " << i << eom;
290+ current_index_set[str.content ()].insert (i_expr);
291+ }
292+ }
293+ }
294+ }
295+ add_instantiations ();
296+ }
297+
298+ /* ******************************************************************\
299+
238300Function: string_refinementt::set_to
239301
240302 Inputs: an expression and the value to set it to
@@ -397,7 +459,13 @@ decision_proceduret::resultt string_refinementt::dec_solve()
397459 if (current_index_set.empty ())
398460 {
399461 debug () << " current index set is empty" << eom;
400- return D_SATISFIABLE;
462+ if (do_concretizing)
463+ {
464+ concretize_results ();
465+ do_concretizing=false ;
466+ }
467+ else
468+ return D_SATISFIABLE;
401469 }
402470
403471 display_index_set ();
@@ -488,7 +556,7 @@ Function: string_refinementt::get_array
488556
489557exprt string_refinementt::get_array (const exprt &arr, const exprt &size)
490558{
491- exprt arr_val=get (arr);
559+ exprt arr_val=get_array (arr);
492560 exprt size_val=get (size);
493561 typet char_type=arr.type ().subtype ();
494562 typet index_type=size.type ();
@@ -566,6 +634,32 @@ exprt string_refinementt::get_array(const exprt &arr, const exprt &size)
566634 return ret;
567635}
568636
637+
638+ /* ******************************************************************\
639+
640+ Function: string_refinementt::get_array
641+
642+ Inputs: an expression representing an array
643+
644+ Outputs: an expression
645+
646+ Purpose: get a model of an array of unknown size and infer the size if
647+ possible
648+
649+ \*******************************************************************/
650+
651+ exprt string_refinementt::get_array (const exprt &arr)
652+ {
653+ exprt arr_model=supert::get (arr);
654+ if (arr_model.id ()==ID_array)
655+ {
656+ array_typet &arr_type=to_array_type (arr_model.type ());
657+ arr_type.size ()=from_integer (
658+ arr_model.operands ().size (), arr_type.size ().type ());
659+ }
660+ return arr_model;
661+ }
662+
569663/* ******************************************************************\
570664
571665Function: string_refinementt::string_of_array
@@ -616,56 +710,64 @@ std::string string_refinementt::string_of_array(const array_exprt &arr)
616710
617711Function: string_refinementt::fill_model
618712
619- Outputs: a replace map
620-
621- Purpose: maps the variable created by the solver to constant expressions
622- given by the current model
713+ Purpose: Fill in `current_model` by mapping the variables created by
714+ the solver to constant expressions given by the current model
623715
624716\*******************************************************************/
625717
626- replace_mapt string_refinementt::fill_model ()
718+ void string_refinementt::fill_model ()
627719{
628- replace_mapt fmodel;
629-
630720 for (auto it : symbol_resolve)
631721 {
632722 if (refined_string_typet::is_refined_string_type (it.second .type ()))
633723 {
634724 string_exprt refined=to_string_expr (it.second );
725+ // TODO: check whith this is necessary:
635726 replace_expr (symbol_resolve, refined);
636727 const exprt &econtent=refined.content ();
637728 const exprt &elength=refined.length ();
638729
639- exprt len=get (elength);
730+ exprt len=supert:: get (elength);
640731 exprt arr=get_array (econtent, len);
641732
642- fmodel[elength]=len;
643- fmodel[econtent]=arr;
644-
733+ current_model[elength]=len;
734+ current_model[econtent]=arr;
645735 debug () << from_expr (to_symbol_expr (it.first )) << " ="
646736 << from_expr (refined);
737+
647738 if (arr.id ()==ID_array)
648739 debug () << " = \" " << string_of_array (to_array_expr (arr))
649740 << " \" (size:" << from_expr (len) << " )" << eom;
650741 else
651742 debug () << " = " << from_expr (arr) << " " << eom;
652743 }
744+ else
745+ {
746+ assert (is_char_array (it.second .type ()));
747+ exprt arr=it.second ;
748+ replace_expr (symbol_resolve, arr);
749+ replace_expr (current_model, arr);
750+ exprt arr_model=get_array (arr);
751+ current_model[it.first ]=arr_model;
752+
753+ debug () << from_expr (to_symbol_expr (it.first )) << " ="
754+ << from_expr (arr) << " = " << from_expr (arr_model) << " " << eom;
755+ }
653756 }
654757
655758 for (auto it : generator.boolean_symbols )
656759 {
657760 debug () << " " << it.get_identifier () << " := "
658- << from_expr (get (it)) << eom;
659- fmodel [it]=get (it);
761+ << from_expr (supert:: get (it)) << eom;
762+ current_model [it]=supert:: get (it);
660763 }
661764
662765 for (auto it : generator.index_symbols )
663766 {
664- debug () << " " << it.get_identifier () << " := "
665- << from_expr (get (it)) << eom;
666- fmodel [it]=get (it);
767+ debug () << " " << it.get_identifier () << " := "
768+ << from_expr (supert:: get (it)) << eom;
769+ current_model [it]=supert:: get (it);
667770 }
668- return fmodel;
669771}
670772
671773/* ******************************************************************\
@@ -730,7 +832,7 @@ bool string_refinementt::check_axioms()
730832 << " ===========================================" << eom;
731833 debug () << " string_refinementt::check_axioms: build the"
732834 << " interpretation from the model of the prop_solver" << eom;
733- replace_mapt fmodel= fill_model ();
835+ fill_model ();
734836
735837 // Maps from indexes of violated universal axiom to a witness of violation
736838 std::map<size_t , exprt> violated;
@@ -746,10 +848,10 @@ bool string_refinementt::check_axioms()
746848 exprt prem=axiom.premise ();
747849 exprt body=axiom.body ();
748850
749- replace_expr (fmodel , bound_inf);
750- replace_expr (fmodel , bound_sup);
751- replace_expr (fmodel , prem);
752- replace_expr (fmodel , body);
851+ replace_expr (current_model , bound_inf);
852+ replace_expr (current_model , bound_sup);
853+ replace_expr (current_model , prem);
854+ replace_expr (current_model , body);
753855 string_constraintt axiom_in_model (
754856 univ_var, bound_inf, bound_sup, prem, body);
755857
@@ -1320,3 +1422,23 @@ void string_refinementt::instantiate_not_contains(
13201422 new_lemmas.push_back (witness_bounds);
13211423 }
13221424}
1425+
1426+ /* ******************************************************************\
1427+
1428+ Function: string_refinementt::get
1429+
1430+ Inputs: an expression
1431+
1432+ Outputs: an expression
1433+
1434+ Purpose: evaluation of the expression in the current model
1435+
1436+ \*******************************************************************/
1437+
1438+ exprt string_refinementt::get (const exprt &expr) const
1439+ {
1440+ exprt ecopy (expr);
1441+ replace_expr (symbol_resolve, ecopy);
1442+ replace_expr (current_model, ecopy);
1443+ return supert::get (ecopy);
1444+ }
0 commit comments