@@ -923,6 +923,70 @@ void string_refinementt::substitute_array_access(exprt &expr) const
923
923
}
924
924
}
925
925
926
+ // / negates the constraint and add it to the solver. the intended usage is to
927
+ // / find an assignement of the universal variable that would violate the axiom,
928
+ // / to avoid false positives the symbols other than the universal variable
929
+ // / should have been replaced by there valuation in the current model
930
+ // / \par parameters: a string constraint and a solver for non string expressions
931
+ void string_refinementt::add_negation_of_not_contains_constraint_to_solver (
932
+ const string_not_contains_constraintt &axiom, symbol_exprt &univ_var,
933
+ exprt val, supert &solver)
934
+ {
935
+ exprt lbu=axiom.univ_lower_bound ();
936
+ exprt ubu=axiom.univ_upper_bound ();
937
+ if (lbu.id ()==ID_constant && ubu.id ()==ID_constant)
938
+ {
939
+ mp_integer lb_int, ub_int;
940
+ to_integer (to_constant_expr (lbu), lb_int);
941
+ to_integer (to_constant_expr (ubu), ub_int);
942
+ if (ub_int<=lb_int)
943
+ {
944
+ debug () << " empty constraint with current model" << eom;
945
+ solver << false_exprt ();
946
+ return ;
947
+ }
948
+ }
949
+
950
+ exprt lbe=axiom.exists_lower_bound ();
951
+ exprt ube=axiom.exists_upper_bound ();
952
+ if (lbe.id ()==ID_constant && ube.id ()==ID_constant)
953
+ {
954
+ mp_integer lb_int, ub_int;
955
+ to_integer (to_constant_expr (lbe), lb_int);
956
+ to_integer (to_constant_expr (ube), ub_int);
957
+ if (ub_int<=lb_int)
958
+ {
959
+ debug () << " empty constraint with current model" << eom;
960
+ solver << false_exprt ();
961
+ return ;
962
+ }
963
+ }
964
+
965
+ if (axiom.premise ()==false_exprt ())
966
+ {
967
+ debug () << " (string_refinement::check_axioms) adding false" << eom;
968
+ solver << false_exprt ();
969
+ return ;
970
+ }
971
+
972
+ // Witness is the Skolem function for the existential, which we evaluate at
973
+ // univ_var.
974
+ and_exprt univ_bounds (
975
+ binary_relation_exprt (lbu, ID_le, univ_var),
976
+ binary_relation_exprt (ubu, ID_gt, univ_var));
977
+ and_exprt exists_bounds (
978
+ binary_relation_exprt (lbu, ID_le, val),
979
+ binary_relation_exprt (ubu, ID_gt, val));
980
+ equal_exprt equal_chars (
981
+ axiom.s0 ()[plus_exprt (univ_var, val)],
982
+ axiom.s1 ()[val]);
983
+ and_exprt negaxiom (univ_bounds, axiom.premise (), exists_bounds, equal_chars);
984
+
985
+ debug () << " (sr::check_axioms) negated axiom: " << from_expr (ns, " " , negaxiom) << eom;
986
+ substitute_array_access (negaxiom);
987
+ solver << negaxiom;
988
+ }
989
+
926
990
// / negates the constraint and add it to the solver. the intended usage is to
927
991
// / find an assignement of the universal variable that would violate the axiom,
928
992
// / to avoid false positives the symbols other than the universal variable
@@ -1011,31 +1075,71 @@ bool string_refinementt::check_axioms()
1011
1075
}
1012
1076
}
1013
1077
1014
- // tells whether one of the not_contains constraint can be violated
1015
- bool violated_not_contains=false ;
1078
+ // Maps from indexes of violated not_contains axiom to a witness of violation
1079
+ std::map<size_t , exprt> violated_not;
1080
+
1016
1081
debug () << " there are " << not_contains_axioms.size ()
1017
1082
<< " not_contains axioms" << eom;
1018
-
1019
- for (auto nc_axiom : not_contains_axioms)
1083
+ for (size_t i=0 ; i<not_contains_axioms.size (); i++)
1020
1084
{
1021
- typet index_type=nc_axiom.s0 ().length ().type ();
1022
- exprt zero=from_integer (0 , index_type);
1023
- exprt witness=generator.get_witness_of (nc_axiom, zero);
1085
+ const string_not_contains_constraintt &nc_axiom=not_contains_axioms[i];
1086
+ exprt univ_bound_inf=nc_axiom.univ_lower_bound ();
1087
+ exprt univ_bound_sup=nc_axiom.univ_upper_bound ();
1088
+ exprt prem=nc_axiom.premise ();
1089
+ exprt exists_bound_inf=nc_axiom.exists_lower_bound ();
1090
+ exprt exists_bound_sup=nc_axiom.exists_upper_bound ();
1091
+ const string_exprt s0=nc_axiom.s0 ();
1092
+ const string_exprt s1=nc_axiom.s1 ();
1093
+
1094
+ symbol_exprt univ_var=generator.fresh_symbol (
1095
+ " not_contains_univ_var" , nc_axiom.s0 ().length ().type ());
1096
+ exprt witness=generator.get_witness_of (nc_axiom, univ_var);
1024
1097
exprt val=get (witness);
1025
- violated_not_contains=true ;
1098
+ string_not_contains_constraintt nc_axiom_in_model (
1099
+ get (univ_bound_inf), get (univ_bound_sup), get (prem),
1100
+ get (exists_bound_inf), get (exists_bound_sup),
1101
+ to_string_expr (get (s0)), to_string_expr (get (s1)));
1102
+
1103
+ satcheck_no_simplifiert sat_check;
1104
+ supert solver (ns, sat_check);
1105
+ solver.set_ui (ui);
1106
+ add_negation_of_not_contains_constraint_to_solver (
1107
+ nc_axiom_in_model, univ_var, val, solver);
1108
+
1109
+ switch (solver ())
1110
+ {
1111
+ case decision_proceduret::resultt::D_SATISFIABLE:
1112
+ {
1113
+ exprt val=solver.get (univ_var);
1114
+ debug () << " string constraint can be violated for "
1115
+ << univ_var.get_identifier ()
1116
+ << " = " << from_expr (ns, " " , val) << eom;
1117
+ violated_not[i]=val;
1118
+ }
1119
+ break ;
1120
+ case decision_proceduret::resultt::D_UNSATISFIABLE:
1121
+ break ;
1122
+ default :
1123
+ throw " failure in checking axiom" ;
1124
+ }
1026
1125
}
1027
1126
1028
- if (violated.empty () && !violated_not_contains )
1127
+ if (violated.empty () && violated_not. empty () )
1029
1128
{
1030
1129
debug () << " no violated property" << eom;
1031
1130
return true ;
1032
1131
}
1033
1132
else
1034
1133
{
1035
- debug () << violated.size () << " string axioms can be violated" << eom;
1134
+ debug () << violated.size ()
1135
+ << " universal string axioms can be violated" << eom;
1136
+ debug () << violated_not.size ()
1137
+ << " not_contains string axioms can be violated" << eom;
1036
1138
1037
1139
if (use_counter_example)
1038
1140
{
1141
+ // TODO: add counter examples for not_contains?
1142
+
1039
1143
// Checking if the current solution satisfies the constraints
1040
1144
for (const auto &v : violated)
1041
1145
{
0 commit comments