1515#include < util/deprecate.h>
1616
1717// / Add axioms stating that the returned expression is true exactly when the
18- // / first string is a prefix of the second one, starting at position offset.
18+ // / offset is greater or equal to 0 and the first string is a prefix of the
19+ // / second one, starting at position offset.
1920// /
2021// / These axioms are:
21- // / 1. \f$ {\tt isprefix} \Rightarrow |str| \ge | {\tt prefix}|+offset \f$
22+ // / 1. \f$ {\tt isprefix} \Rightarrow {\tt offset_within_bounds} \f$
2223// / 2. \f$ \forall 0 \le qvar<|{\tt prefix}|.\ {\tt isprefix}
2324// / \Rightarrow s0[witness+{\tt offset}]=s2[witness] \f$
24- // / 3. \f$ !{\tt isprefix} \Rightarrow |{\tt str}|<|{\tt prefix}|+{\tt offset}
25+ // / 3. \f$ (\lnot {\tt isprefix} \Rightarrow
26+ // / \lnot {\tt offset_within_bounds}
2527// / \lor (0 \le witness<|{\tt prefix}|
26- // / \land {\tt str}[witness+{\tt offset}] \ne {\tt prefix}[witness])\f$
27- // /
28+ // / \land {\tt str}[witness+{\tt offset}] \ne {\tt prefix}[witness])\f$
29+ // / where \f$ {\tt offset_within_bounds} \f$ is
30+ // / \f$ offset \ge 0 \land offset < |str| \land
31+ // / |str| - |{\tt prefix}| \ge offset \f$
2832// / \param prefix: an array of characters
2933// / \param str: an array of characters
3034// / \param offset: an integer
@@ -34,34 +38,39 @@ exprt string_constraint_generatort::add_axioms_for_is_prefix(
3438 const array_string_exprt &str,
3539 const exprt &offset)
3640{
37- symbol_exprt isprefix=fresh_boolean (" isprefix" );
38- const typet &index_type=str.length ().type ();
41+ const symbol_exprt isprefix = fresh_boolean (" isprefix" );
42+ const typet &index_type = str.length ().type ();
43+ const exprt offset_within_bounds = and_exprt (
44+ binary_relation_exprt (offset, ID_ge, from_integer (0 , offset.type ())),
45+ binary_relation_exprt (offset, ID_le, str.length ()),
46+ binary_relation_exprt (
47+ minus_exprt (str.length (), offset), ID_ge, prefix.length ()));
3948
4049 // Axiom 1.
41- lemmas.push_back (
42- implies_exprt (
43- isprefix, str.axiom_for_length_ge (plus_exprt (prefix.length (), offset))));
44-
45- symbol_exprt qvar=fresh_univ_index (" QA_isprefix" , index_type);
46- string_constraintt a2 (
47- qvar,
48- prefix.length (),
49- implies_exprt (
50- isprefix, equal_exprt (str[plus_exprt (qvar, offset)], prefix[qvar])));
51- constraints.push_back (a2);
52-
53- symbol_exprt witness=fresh_exist_index (" witness_not_isprefix" , index_type);
54- and_exprt witness_diff (
55- axiom_for_is_positive_index (witness),
56- and_exprt (
50+ lemmas.push_back (implies_exprt (isprefix, offset_within_bounds));
51+
52+ // Axiom 2.
53+ constraints.push_back ([&] {
54+ const symbol_exprt qvar = fresh_univ_index (" QA_isprefix" , index_type);
55+ const exprt body = implies_exprt (
56+ isprefix, equal_exprt (str[plus_exprt (qvar, offset)], prefix[qvar]));
57+ return string_constraintt (qvar, prefix.length (), body);
58+ }());
59+
60+ // Axiom 3.
61+ lemmas.push_back ([&] {
62+ const exprt witness = fresh_exist_index (" witness_not_isprefix" , index_type);
63+ const exprt strings_differ_at_witness = and_exprt (
64+ axiom_for_is_positive_index (witness),
5765 prefix.axiom_for_length_gt (witness),
58- notequal_exprt (str[plus_exprt (witness, offset)], prefix[witness])));
59- or_exprt s0_notpref_s1 (
60- not_exprt (str.axiom_for_length_ge (plus_exprt (prefix.length (), offset))),
61- witness_diff);
66+ notequal_exprt (str[plus_exprt (witness, offset)], prefix[witness]));
67+ const exprt s1_does_not_start_with_s0 = or_exprt (
68+ not_exprt (offset_within_bounds),
69+ not_exprt (str.axiom_for_length_ge (plus_exprt (prefix.length (), offset))),
70+ strings_differ_at_witness);
71+ return implies_exprt (not_exprt (isprefix), s1_does_not_start_with_s0);
72+ }());
6273
63- implies_exprt a3 (not_exprt (isprefix), s0_notpref_s1);
64- lemmas.push_back (a3);
6574 return isprefix;
6675}
6776
0 commit comments