@@ -1833,18 +1833,17 @@ static void update_index_set(
18331833 }
18341834}
18351835
1836- // / Finds an index on `str` used in `expr` that contains `qvar`, for instance
1837- // / with arguments ``(str[k]=='a')``, `str`, and `k`, the function should
1838- // / return `k`.
1839- // / If two different such indexes exist, an invariant will fail.
1836+ // / Find indexes of `str` used in `expr` that contains `qvar`, for instance
1837+ // / with arguments ``(str[k+1]=='a')``, `str`, and `k`, the function should
1838+ // / return `k+1`.
18401839// / \param [in] expr: the expression to search
18411840// / \param [in] str: the string which must be indexed
18421841// / \param [in] qvar: the universal variable that must be in the index
1843- // / \return an index expression in `expr` on `str` containing `qvar`. Returns
1844- // / an empty optional when `expr` does not contain `str`.
1845- static optionalt<exprt>
1846- find_index (const exprt &expr, const exprt &str, const symbol_exprt &qvar)
1842+ // / \return index expressions in `expr` on `str` containing `qvar`.
1843+ static std::unordered_set<exprt, irep_hash>
1844+ find_indexes (const exprt &expr, const exprt &str, const symbol_exprt &qvar)
18471845{
1846+ decltype (find_indexes (expr, str, qvar)) result;
18481847 auto index_str_containing_qvar = [&](const exprt &e) {
18491848 if (auto index_expr = expr_try_dynamic_cast<index_exprt>(e))
18501849 {
@@ -1855,28 +1854,12 @@ find_index(const exprt &expr, const exprt &str, const symbol_exprt &qvar)
18551854 return false ;
18561855 };
18571856
1858- auto it = std::find_if (
1859- expr.depth_begin (), expr.depth_end (), index_str_containing_qvar);
1860- if (it == expr.depth_end ())
1861- return {};
1862- const exprt &index = to_index_expr (*it).index ();
1863-
1864- // Check that there are no two such indexes
1865- it.next_sibling_or_parent ();
1866- while (it != expr.depth_end ())
1857+ for (auto it = expr.depth_begin (); it != expr.depth_end (); ++it)
18671858 {
18681859 if (index_str_containing_qvar (*it))
1869- {
1870- INVARIANT (
1871- to_index_expr (*it).index () == index,
1872- " string should always be indexed by same value in a given formula" );
1873- it.next_sibling_or_parent ();
1874- }
1875- else
1876- ++it;
1860+ result.insert (to_index_expr (*it).index ());
18771861 }
1878-
1879- return index;
1862+ return result;
18801863}
18811864
18821865// / Instantiates a string constraint by substituting the quantifiers.
@@ -1897,18 +1880,24 @@ static exprt instantiate(
18971880 const exprt &str,
18981881 const exprt &val)
18991882{
1900- const optionalt<exprt> idx = find_index (axiom.body , str, axiom.univ_var );
1901- if (!idx.has_value ())
1902- return true_exprt ();
1903-
1904- const exprt r = compute_inverse_function (stream, axiom.univ_var , val, *idx);
1905- implies_exprt instance (
1906- and_exprt (
1907- binary_relation_exprt (axiom.univ_var , ID_ge, axiom.lower_bound ),
1908- binary_relation_exprt (axiom.univ_var , ID_lt, axiom.upper_bound )),
1909- axiom.body );
1910- replace_expr (axiom.univ_var , r, instance);
1911- return instance;
1883+ const auto indexes = find_indexes (axiom.body , str, axiom.univ_var );
1884+ INVARIANT (
1885+ str.id () == ID_array || indexes.size () <= 1 ,
1886+ " non constant array should always be accessed at the same index" );
1887+ exprt::operandst conjuncts;
1888+ for (const auto &index : indexes)
1889+ {
1890+ const exprt univ_var_value =
1891+ compute_inverse_function (stream, axiom.univ_var , val, index);
1892+ implies_exprt instance (
1893+ and_exprt (
1894+ binary_relation_exprt (axiom.univ_var , ID_ge, axiom.lower_bound ),
1895+ binary_relation_exprt (axiom.univ_var , ID_lt, axiom.upper_bound )),
1896+ axiom.body );
1897+ replace_expr (axiom.univ_var , univ_var_value, instance);
1898+ conjuncts.push_back (instance);
1899+ }
1900+ return conjunction (conjuncts);
19121901}
19131902
19141903// / Instantiates a quantified formula representing `not_contains` by
0 commit comments