Skip to content

Commit 22fec4c

Browse files
Merge pull request #7004 from thomasspriggs/tas/smt_array_exprt
Add support for array_exprt to incremental smt2 decision procedure
2 parents 9a0dec1 + 4d5d529 commit 22fec4c

File tree

5 files changed

+134
-5
lines changed

5 files changed

+134
-5
lines changed
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
int main()
2+
{
3+
int example_array[] = {5, 4, 3, 2, 1};
4+
unsigned int index;
5+
__CPROVER_assume(index < 5);
6+
__CPROVER_assert(example_array[index] != 42, "Non-existent element");
7+
__CPROVER_assert(example_array[index] != 5, "Index 0");
8+
__CPROVER_assert(example_array[index] != 4, "Index 1");
9+
__CPROVER_assert(example_array[index] != 3, "Index 2");
10+
__CPROVER_assert(example_array[index] != 2, "Index 3");
11+
__CPROVER_assert(example_array[index] != 1, "Index 4");
12+
__CPROVER_assert(example_array[index] == 5 - index, "Index value relation");
13+
}
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
CORE
2+
array_literal.c
3+
4+
Passing problem to incremental SMT2 solving
5+
line \d+ Non-existent element: SUCCESS
6+
line \d+ Index 0: FAILURE
7+
line \d+ Index 1: FAILURE
8+
line \d+ Index 2: FAILURE
9+
line \d+ Index 3: FAILURE
10+
line \d+ Index 4: FAILURE
11+
line \d+ Index value relation: SUCCESS
12+
^EXIT=10$
13+
^SIGNAL=0$
14+
--
15+
--
16+
Test of reading an array which is initialised using an array literal.

src/solvers/smt2_incremental/smt2_incremental_decision_procedure.cpp

Lines changed: 56 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
#include "smt2_incremental_decision_procedure.h"
44

5+
#include <util/arith_tools.h>
56
#include <util/expr.h>
67
#include <util/namespace.h>
78
#include <util/nodiscard.h>
@@ -12,6 +13,7 @@
1213

1314
#include <solvers/smt2_incremental/construct_value_expr_from_smt.h>
1415
#include <solvers/smt2_incremental/convert_expr_to_smt.h>
16+
#include <solvers/smt2_incremental/smt_array_theory.h>
1517
#include <solvers/smt2_incremental/smt_commands.h>
1618
#include <solvers/smt2_incremental/smt_core_theory.h>
1719
#include <solvers/smt2_incremental/smt_responses.h>
@@ -64,14 +66,40 @@ static std::vector<exprt> gather_dependent_expressions(const exprt &expr)
6466
{
6567
std::vector<exprt> dependent_expressions;
6668
expr.visit_pre([&](const exprt &expr_node) {
67-
if(can_cast_expr<symbol_exprt>(expr_node))
69+
if(
70+
can_cast_expr<symbol_exprt>(expr_node) ||
71+
can_cast_expr<array_exprt>(expr_node))
6872
{
6973
dependent_expressions.push_back(expr_node);
7074
}
7175
});
7276
return dependent_expressions;
7377
}
7478

79+
void smt2_incremental_decision_proceduret::define_array_function(
80+
const array_exprt &array)
81+
{
82+
const smt_sortt array_sort = convert_type_to_smt_sort(array.type());
83+
INVARIANT(
84+
array_sort.cast<smt_array_sortt>(),
85+
"Converting array typed expression to SMT should result in a term of array "
86+
"sort.");
87+
const smt_identifier_termt array_identifier = smt_identifier_termt{
88+
"array_" + std::to_string(array_sequence()), array_sort};
89+
solver_process->send(smt_declare_function_commandt{array_identifier, {}});
90+
const std::vector<exprt> &elements = array.operands();
91+
const typet &index_type = array.type().index_type();
92+
for(std::size_t i = 0; i < elements.size(); ++i)
93+
{
94+
const smt_termt index = convert_expr_to_smt(from_integer(i, index_type));
95+
const smt_assert_commandt element_definition{smt_core_theoryt::equal(
96+
smt_array_theoryt::select(array_identifier, index),
97+
convert_expr_to_smt(elements.at(i)))};
98+
solver_process->send(element_definition);
99+
}
100+
expression_identifiers.emplace(array, array_identifier);
101+
}
102+
75103
/// \brief Defines any functions which \p expr depends on, which have not yet
76104
/// been defined, along with their dependencies in turn.
77105
void smt2_incremental_decision_proceduret::define_dependent_functions(
@@ -123,10 +151,29 @@ void smt2_incremental_decision_proceduret::define_dependent_functions(
123151
solver_process->send(function);
124152
}
125153
}
154+
if(const auto array_expr = expr_try_dynamic_cast<array_exprt>(current))
155+
define_array_function(*array_expr);
126156
to_be_defined.pop();
127157
}
128158
}
129159

160+
/// Replaces the sub expressions of \p expr which have been defined as separate
161+
/// functions in the smt solver, using the \p expression_identifiers map.
162+
static exprt substitute_identifiers(
163+
exprt expr,
164+
const std::unordered_map<exprt, smt_identifier_termt, irep_hash>
165+
&expression_identifiers)
166+
{
167+
expr.visit_pre([&](exprt &node) -> void {
168+
auto find_result = expression_identifiers.find(node);
169+
if(find_result == expression_identifiers.cend())
170+
return;
171+
const auto type = find_result->first.type();
172+
node = symbol_exprt{find_result->second.identifier(), type};
173+
});
174+
return expr;
175+
}
176+
130177
smt2_incremental_decision_proceduret::smt2_incremental_decision_proceduret(
131178
const namespacet &_ns,
132179
std::unique_ptr<smt_base_solver_processt> _solver_process,
@@ -164,15 +211,20 @@ void smt2_incremental_decision_proceduret::ensure_handle_for_expr_defined(
164211
smt_termt
165212
smt2_incremental_decision_proceduret::convert_expr_to_smt(const exprt &expr)
166213
{
167-
track_expression_objects(expr, ns, object_map);
214+
const exprt substituted =
215+
substitute_identifiers(expr, expression_identifiers);
216+
track_expression_objects(substituted, ns, object_map);
168217
associate_pointer_sizes(
169-
expr,
218+
substituted,
170219
ns,
171220
pointer_sizes_map,
172221
object_map,
173222
object_size_function.make_application);
174223
return ::convert_expr_to_smt(
175-
expr, object_map, pointer_sizes_map, object_size_function.make_application);
224+
substituted,
225+
object_map,
226+
pointer_sizes_map,
227+
object_size_function.make_application);
176228
}
177229

178230
exprt smt2_incremental_decision_proceduret::handle(const exprt &expr)

src/solvers/smt2_incremental/smt2_incremental_decision_procedure.h

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,11 @@ class smt2_incremental_decision_proceduret final
5555
protected:
5656
// Implementation of protected decision_proceduret member function.
5757
resultt dec_solve() override;
58+
/// \brief Defines a function of array sort and asserts the element values.
59+
/// \details
60+
/// The new array function identifier is added to the
61+
/// `expression_identifiers` map.
62+
void define_array_function(const array_exprt &array);
5863
/// \brief Defines any functions which \p expr depends on, which have not yet
5964
/// been defined, along with their dependencies in turn.
6065
void define_dependent_functions(const exprt &expr);
@@ -81,7 +86,7 @@ class smt2_incremental_decision_proceduret final
8186
{
8287
return next_id++;
8388
}
84-
} handle_sequence;
89+
} handle_sequence, array_sequence;
8590

8691
std::unordered_map<exprt, smt_identifier_termt, irep_hash>
8792
expression_handle_identifiers;

unit/solvers/smt2_incremental/smt2_incremental_decision_procedure.cpp

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
#include <util/symbol_table.h>
1010

1111
#include <solvers/smt2_incremental/smt2_incremental_decision_procedure.h>
12+
#include <solvers/smt2_incremental/smt_array_theory.h>
1213
#include <solvers/smt2_incremental/smt_commands.h>
1314
#include <solvers/smt2_incremental/smt_core_theory.h>
1415
#include <solvers/smt2_incremental/smt_responses.h>
@@ -517,3 +518,45 @@ TEST_CASE(
517518
}
518519
}
519520
}
521+
522+
TEST_CASE(
523+
"smt2_incremental_decision_proceduret array commands.",
524+
"[core][smt2_incremental]")
525+
{
526+
auto test = decision_procedure_test_environmentt::make();
527+
const auto index_type = signedbv_typet{32};
528+
const symbolt index = make_test_symbol("index", index_type);
529+
const auto value_type = signedbv_typet{8};
530+
const symbolt foo = make_test_symbol("foo", value_type);
531+
const auto array_type = array_typet{value_type, from_integer(2, index_type)};
532+
SECTION("array_exprt - list of literal array elements")
533+
{
534+
const array_exprt array_literal{
535+
{from_integer(9, value_type), from_integer(12, value_type)}, array_type};
536+
test.sent_commands.clear();
537+
test.procedure.set_to(
538+
equal_exprt{
539+
foo.symbol_expr(), index_exprt{array_literal, index.symbol_expr()}},
540+
true);
541+
const auto foo_term = smt_identifier_termt{"foo", smt_bit_vector_sortt{8}};
542+
const auto array_term = smt_identifier_termt{
543+
"array_0",
544+
smt_array_sortt{smt_bit_vector_sortt{32}, smt_bit_vector_sortt{8}}};
545+
const auto index_term =
546+
smt_identifier_termt{"index", smt_bit_vector_sortt{32}};
547+
const std::vector<smt_commandt> expected_commands{
548+
smt_declare_function_commandt{foo_term, {}},
549+
smt_declare_function_commandt{array_term, {}},
550+
smt_assert_commandt{smt_core_theoryt::equal(
551+
smt_array_theoryt::select(
552+
array_term, smt_bit_vector_constant_termt{0, 32}),
553+
smt_bit_vector_constant_termt{9, 8})},
554+
smt_assert_commandt{smt_core_theoryt::equal(
555+
smt_array_theoryt::select(
556+
array_term, smt_bit_vector_constant_termt{1, 32}),
557+
smt_bit_vector_constant_termt{12, 8})},
558+
smt_declare_function_commandt{index_term, {}},
559+
smt_assert_commandt{smt_core_theoryt::equal(
560+
foo_term, smt_array_theoryt::select(array_term, index_term))}};
561+
}
562+
}

0 commit comments

Comments
 (0)