Skip to content

Commit f286c07

Browse files
committed
Add conversion of exprs to SMT2 and sending to solver process
1 parent fba0629 commit f286c07

File tree

3 files changed

+148
-3
lines changed

3 files changed

+148
-3
lines changed

regression/cbmc-incr-smt2/nondeterministic-int-assert/incremental_solver_called.desc

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,12 @@ test.c
44
Passing problem to incremental SMT2 solving via "z3 --smt2 -in"
55
Sending command to SMT2 solver - \(set-option :produce-models true\)
66
Sending command to SMT2 solver - \(set-logic QF_UFBV\)
7+
Sending command to SMT2 solver - \(define-fun |B0| \(\) Bool true\)
8+
Sending command to SMT2 solver - \(declare-fun |main::1::x!0@1#1| \(\) \(_ BitVec 32\)\)
9+
Sending command to SMT2 solver - \(define-fun |B1| \(\) Bool \(|=| |main::1::x!0@1#1| |main::1::x!0@1#1|\)\)
10+
Sending command to SMT2 solver - \(assert \(|not| \(|not| \(|=| |main::1::x!0@1#1| \(_ bv0 32\)\)\)\)\)
11+
Sending command to SMT2 solver - \(define-fun |B2| \(\) Bool \(|not| false\)\)
12+
Sending command to SMT2 solver - \(assert |B2|\)
713
^EXIT=(0|127|134|137)$
814
^SIGNAL=0$
915
identifier: main::1::x

src/solvers/smt2_incremental/smt2_incremental_decision_procedure.cpp

Lines changed: 117 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,11 +2,93 @@
22

33
#include "smt2_incremental_decision_procedure.h"
44

5+
#include <solvers/smt2_incremental/convert_expr_to_smt.h>
56
#include <solvers/smt2_incremental/smt_commands.h>
7+
#include <solvers/smt2_incremental/smt_core_theory.h>
8+
#include <solvers/smt2_incremental/smt_terms.h>
69
#include <solvers/smt2_incremental/smt_to_smt2_string.h>
710
#include <util/expr.h>
811
#include <util/namespace.h>
12+
#include <util/range.h>
13+
#include <util/std_expr.h>
914
#include <util/string_utils.h>
15+
#include <util/symbol.h>
16+
17+
#include <stack>
18+
19+
/// \brief Find all sub expressions of the given \p expr which need to be
20+
/// expressed as separate smt commands.
21+
/// \note This pass over \p expr is tightly coupled to the implementation of
22+
/// `convert_expr_to_smt`. This is because any sub expressions which
23+
/// `convert_expr_to_smt` translates into function applications, must also be
24+
/// returned by this`gather_dependent_expressions` function.
25+
static std::unordered_set<exprt, irep_hash>
26+
gather_dependent_expressions(const exprt &expr)
27+
{
28+
std::unordered_set<exprt, irep_hash> dependent_expressions;
29+
expr.visit_pre([&](const exprt &expr_node) {
30+
if(can_cast_expr<symbol_exprt>(expr_node))
31+
{
32+
dependent_expressions.insert(expr_node);
33+
}
34+
});
35+
return dependent_expressions;
36+
}
37+
38+
/// \brief Defines any functions which \p expr depends on, which have not yet
39+
/// been defined, along with their dependencies in turn.
40+
void smt2_incremental_decision_proceduret::define_dependent_functions(
41+
const exprt &expr)
42+
{
43+
std::unordered_set<exprt, irep_hash> seen_expressions =
44+
make_range(expression_identifiers)
45+
.map([](const std::pair<exprt, smt_identifier_termt> &expr_identifier) {
46+
return expr_identifier.first;
47+
});
48+
std::stack<exprt> to_be_defined;
49+
const auto dependencies_needed = [&](const exprt &expr) {
50+
bool result = false;
51+
for(const auto &dependency : gather_dependent_expressions(expr))
52+
{
53+
if(!seen_expressions.insert(dependency).second)
54+
continue;
55+
result = true;
56+
to_be_defined.push(dependency);
57+
}
58+
return result;
59+
};
60+
dependencies_needed(expr);
61+
while(!to_be_defined.empty())
62+
{
63+
const exprt current = to_be_defined.top();
64+
if(dependencies_needed(current))
65+
continue;
66+
if(const auto symbol_expr = expr_try_dynamic_cast<symbol_exprt>(current))
67+
{
68+
const irep_idt &identifier = symbol_expr->get_identifier();
69+
const symbolt *symbol = nullptr;
70+
if(!ns.lookup(identifier, symbol))
71+
{
72+
if(dependencies_needed(symbol->value))
73+
continue;
74+
const smt_define_function_commandt function{
75+
symbol->name, {}, convert_expr_to_smt(symbol->value)};
76+
expression_identifiers.emplace(*symbol_expr, function.identifier());
77+
send_to_solver(function);
78+
}
79+
else
80+
{
81+
const smt_declare_function_commandt function{
82+
smt_identifier_termt(
83+
identifier, convert_type_to_smt_sort(symbol_expr->type())),
84+
{}};
85+
expression_identifiers.emplace(*symbol_expr, function.identifier());
86+
send_to_solver(function);
87+
}
88+
}
89+
to_be_defined.pop();
90+
}
91+
}
1092

1193
smt2_incremental_decision_proceduret::smt2_incremental_decision_proceduret(
1294
const namespacet &_ns,
@@ -23,8 +105,27 @@ smt2_incremental_decision_proceduret::smt2_incremental_decision_proceduret(
23105
smt_logic_quantifier_free_uninterpreted_functions_bit_vectorst{}});
24106
}
25107

108+
void smt2_incremental_decision_proceduret::ensure_handle_for_expr_defined(
109+
const exprt &expr)
110+
{
111+
if(
112+
expression_handle_identifiers.find(expr) !=
113+
expression_handle_identifiers.cend())
114+
{
115+
return;
116+
}
117+
118+
define_dependent_functions(expr);
119+
smt_define_function_commandt function{
120+
"B" + std::to_string(handle_sequence()), {}, convert_expr_to_smt(expr)};
121+
expression_handle_identifiers.emplace(expr, function.identifier());
122+
send_to_solver(function);
123+
}
124+
26125
exprt smt2_incremental_decision_proceduret::handle(const exprt &expr)
27126
{
127+
log.debug() << "`handle` -\n " << expr.pretty(2, 0) << messaget::eom;
128+
ensure_handle_for_expr_defined(expr);
28129
return expr;
29130
}
30131

@@ -53,9 +154,22 @@ smt2_incremental_decision_proceduret::get_number_of_solver_calls() const
53154

54155
void smt2_incremental_decision_proceduret::set_to(const exprt &expr, bool value)
55156
{
56-
UNIMPLEMENTED_FEATURE(
57-
"`set_to` (" + std::string{value ? "true" : "false"} + "):\n " +
58-
expr.pretty(2, 0));
157+
PRECONDITION(can_cast_type<bool_typet>(expr.type()));
158+
log.debug() << "`set_to` (" << std::string{value ? "true" : "false"}
159+
<< ") -\n " << expr.pretty(2, 0) << messaget::eom;
160+
161+
define_dependent_functions(expr);
162+
auto converted_term = [&]() -> smt_termt {
163+
const auto expression_handle_identifier =
164+
expression_handle_identifiers.find(expr);
165+
if(expression_handle_identifier != expression_handle_identifiers.cend())
166+
return expression_handle_identifier->second;
167+
else
168+
return convert_expr_to_smt(expr);
169+
}();
170+
if(!value)
171+
converted_term = smt_core_theoryt::make_not(converted_term);
172+
send_to_solver(smt_assert_commandt{converted_term});
59173
}
60174

61175
void smt2_incremental_decision_proceduret::push(

src/solvers/smt2_incremental/smt2_incremental_decision_procedure.h

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,9 +6,14 @@
66
#ifndef CPROVER_SOLVERS_SMT2_INCREMENTAL_SMT2_INCREMENTAL_DECISION_PROCEDURE_H
77
#define CPROVER_SOLVERS_SMT2_INCREMENTAL_SMT2_INCREMENTAL_DECISION_PROCEDURE_H
88

9+
#include <solvers/smt2_incremental/smt_terms.h>
910
#include <solvers/stack_decision_procedure.h>
1011
#include <util/message.h>
1112
#include <util/piped_process.h>
13+
#include <util/std_expr.h>
14+
15+
#include <unordered_map>
16+
#include <unordered_set>
1217

1318
class smt_commandt;
1419
class message_handlert;
@@ -48,6 +53,10 @@ class smt2_incremental_decision_proceduret final
4853
/// \brief Converts given SMT2 command to SMT2 string and sends it to the
4954
/// solver process.
5055
void send_to_solver(const smt_commandt &command);
56+
/// \brief Defines any functions which \p expr depends on, which have not yet
57+
/// been defined, along with their dependencies in turn.
58+
void define_dependent_functions(const exprt &expr);
59+
void ensure_handle_for_expr_defined(const exprt &expr);
5160

5261
const namespacet &ns;
5362

@@ -57,6 +66,22 @@ class smt2_incremental_decision_proceduret final
5766

5867
piped_processt solver_process;
5968
messaget log;
69+
70+
class sequencet
71+
{
72+
size_t next_id = 0;
73+
74+
public:
75+
size_t operator()()
76+
{
77+
return next_id++;
78+
}
79+
} handle_sequence;
80+
81+
std::unordered_map<exprt, smt_identifier_termt, irep_hash>
82+
expression_handle_identifiers;
83+
std::unordered_map<exprt, smt_identifier_termt, irep_hash>
84+
expression_identifiers;
6085
};
6186

6287
#endif // CPROVER_SOLVERS_SMT2_INCREMENTAL_SMT2_INCREMENTAL_DECISION_PROCEDURE_H

0 commit comments

Comments
 (0)