Skip to content

Commit 3caa1c8

Browse files
Implement context-based solver on top of prop_conv_solvert
and carry over the current, partial support in smt2_convt.
1 parent 08b07ad commit 3caa1c8

14 files changed

+146
-91
lines changed

src/goto-checker/goto_symex_fault_localizer.cpp

Lines changed: 9 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -11,13 +11,11 @@ Author: Peter Schrammel
1111

1212
#include "goto_symex_fault_localizer.h"
1313

14-
#include <solvers/prop/prop_conv.h>
15-
1614
goto_symex_fault_localizert::goto_symex_fault_localizert(
1715
const optionst &options,
1816
ui_message_handlert &ui_message_handler,
1917
const symex_target_equationt &equation,
20-
prop_convt &solver)
18+
stack_decision_proceduret &solver)
2119
: options(options),
2220
ui_message_handler(ui_message_handler),
2321
equation(equation),
@@ -58,7 +56,7 @@ const SSA_stept &goto_symex_fault_localizert::collect_guards(
5856
step.assignment_type == symex_targett::assignment_typet::STATE &&
5957
!step.ignore)
6058
{
61-
literalt l = solver.convert(step.guard_handle);
59+
exprt l = solver.handle(step.guard_handle);
6260
if(!l.is_constant())
6361
{
6462
auto emplace_result = fault_location.scores.emplace(step.source.pc, 0);
@@ -79,21 +77,21 @@ bool goto_symex_fault_localizert::check(
7977
const localization_points_valuet &value)
8078
{
8179
PRECONDITION(value.size() == localization_points.size());
82-
bvt assumptions;
80+
std::vector<exprt> assumptions;
8381
localization_points_valuet::const_iterator v_it = value.begin();
8482
for(const auto &l : localization_points)
8583
{
8684
if(v_it->is_true())
8785
assumptions.push_back(l.first);
8886
else if(v_it->is_false())
89-
assumptions.push_back(!l.first);
87+
assumptions.push_back(solver.handle(not_exprt(l.first)));
9088
++v_it;
9189
}
9290

9391
// lock the failed assertion
94-
assumptions.push_back(!solver.convert(failed_step.cond_handle));
92+
assumptions.push_back(solver.handle(not_exprt(failed_step.cond_handle)));
9593

96-
solver.set_assumptions(assumptions);
94+
solver.push(assumptions);
9795

9896
return solver() != decision_proceduret::resultt::D_SATISFIABLE;
9997
}
@@ -104,11 +102,11 @@ void goto_symex_fault_localizert::update_scores(
104102
for(auto &l : localization_points)
105103
{
106104
auto &score = l.second->second;
107-
if(solver.l_get(l.first).is_true())
105+
if(solver.get(l.first).is_true())
108106
{
109107
score++;
110108
}
111-
else if(solver.l_get(l.first).is_false() && score > 0)
109+
else if(solver.get(l.first).is_false() && score > 0)
112110
{
113111
score--;
114112
}
@@ -135,6 +133,5 @@ void goto_symex_fault_localizert::localize_linear(
135133
}
136134

137135
// clear assumptions
138-
bvt assumptions;
139-
solver.set_assumptions(assumptions);
136+
solver.pop();
140137
}

src/goto-checker/goto_symex_fault_localizer.h

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ Author: Peter Schrammel
1818

1919
#include <goto-symex/symex_target_equation.h>
2020

21-
#include <solvers/prop/prop_conv.h>
21+
#include <solvers/stack_decision_procedure.h>
2222

2323
#include "fault_localization_provider.h"
2424

@@ -29,18 +29,18 @@ class goto_symex_fault_localizert
2929
const optionst &options,
3030
ui_message_handlert &ui_message_handler,
3131
const symex_target_equationt &equation,
32-
prop_convt &solver);
32+
stack_decision_proceduret &solver);
3333

3434
fault_location_infot operator()(const irep_idt &failed_property_id);
3535

3636
protected:
3737
const optionst &options;
3838
ui_message_handlert &ui_message_handler;
3939
const symex_target_equationt &equation;
40-
prop_convt &solver;
40+
stack_decision_proceduret &solver;
4141

4242
/// A localization point is a goto instruction that is potentially at fault
43-
typedef std::map<literalt, fault_location_infot::score_mapt::iterator>
43+
typedef std::map<exprt, fault_location_infot::score_mapt::iterator>
4444
localization_pointst;
4545

4646
/// Collects the guards as \p localization_points up to \p failed_property_id

src/solvers/prop/prop_conv.cpp

Lines changed: 0 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -7,14 +7,3 @@ Author: Daniel Kroening, [email protected]
77
\*******************************************************************/
88

99
#include "prop_conv.h"
10-
11-
#include "literal_expr.h"
12-
13-
#include <util/std_expr.h>
14-
15-
#include <algorithm>
16-
17-
void prop_convt::set_assumptions(const bvt &)
18-
{
19-
UNREACHABLE;
20-
}

src/solvers/prop/prop_conv.h

Lines changed: 3 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -10,32 +10,25 @@ Author: Daniel Kroening, [email protected]
1010
#ifndef CPROVER_SOLVERS_PROP_PROP_CONV_H
1111
#define CPROVER_SOLVERS_PROP_PROP_CONV_H
1212

13-
#include <solvers/decision_procedure.h>
14-
15-
#include "literal.h"
13+
#include <solvers/stack_decision_procedure.h>
1614

15+
class literalt;
1716
class tvt;
1817

1918
// API that provides a "handle" in the form of a literalt
2019
// for expressions.
2120

22-
class prop_convt:public decision_proceduret
21+
class prop_convt : public stack_decision_proceduret
2322
{
2423
public:
2524
virtual ~prop_convt() { }
2625

27-
using decision_proceduret::operator();
28-
2926
/// Convert a Boolean expression and return the corresponding literal
3027
virtual literalt convert(const exprt &expr) = 0;
3128

3229
/// Return value of literal \p l from satisfying assignment.
3330
/// Return tvt::UNKNOWN if not available
3431
virtual tvt l_get(literalt l) const = 0;
35-
36-
// incremental solving
37-
virtual void set_assumptions(const bvt &_assumptions);
38-
virtual bool has_set_assumptions() const { return false; }
3932
};
4033

4134
#endif // CPROVER_SOLVERS_PROP_PROP_CONV_H

src/solvers/prop/prop_conv_solver.cpp

Lines changed: 55 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -365,7 +365,7 @@ bool prop_conv_solvert::set_equality_to_true(const equal_exprt &expr)
365365
return true;
366366
}
367367

368-
void prop_conv_solvert::set_to(const exprt &expr, bool value)
368+
void prop_conv_solvert::do_set_to(const exprt &expr, bool value)
369369
{
370370
PRECONDITION(expr.type().id() == ID_bool);
371371

@@ -380,7 +380,7 @@ void prop_conv_solvert::set_to(const exprt &expr, bool value)
380380
{
381381
if(expr.operands().size() == 1)
382382
{
383-
set_to(expr.op0(), !value);
383+
do_set_to(expr.op0(), !value);
384384
return;
385385
}
386386
}
@@ -393,7 +393,7 @@ void prop_conv_solvert::set_to(const exprt &expr, bool value)
393393
if(expr.id() == ID_and)
394394
{
395395
forall_operands(it, expr)
396-
set_to_true(*it);
396+
do_set_to(*it, true);
397397

398398
return;
399399
}
@@ -437,14 +437,14 @@ void prop_conv_solvert::set_to(const exprt &expr, bool value)
437437
{
438438
const implies_exprt &implies_expr = to_implies_expr(expr);
439439

440-
set_to_true(implies_expr.op0());
441-
set_to_false(implies_expr.op1());
440+
do_set_to(implies_expr.op0(), true);
441+
do_set_to(implies_expr.op1(), false);
442442
return;
443443
}
444444
else if(expr.id() == ID_or) // !(a || b) == (!a && !b)
445445
{
446446
forall_operands(it, expr)
447-
set_to_false(*it);
447+
do_set_to(*it, false);
448448
return;
449449
}
450450
}
@@ -525,3 +525,52 @@ std::size_t prop_conv_solvert::get_number_of_solver_calls() const
525525
{
526526
return prop.get_number_of_solver_calls();
527527
}
528+
529+
const char *prop_conv_solvert::context_prefix = "prop_conv::context$";
530+
531+
void prop_conv_solvert::set_to(const exprt &expr, bool value)
532+
{
533+
if(assumption_stack.empty())
534+
{
535+
// We are in the root context.
536+
do_set_to(expr, value);
537+
}
538+
else
539+
{
540+
// We have a child context. We add context_literal ==> expr to the formula.
541+
do_set_to(or_exprt(literal_exprt(!assumption_stack.back()), expr), value);
542+
}
543+
}
544+
545+
void prop_conv_solvert::push(const std::vector<exprt> &assumptions)
546+
{
547+
// We push the given assumptions as a single context onto the stack.
548+
assumption_stack.reserve(assumption_stack.size() + assumptions.size());
549+
for(const auto &assumption : assumptions)
550+
assumption_stack.push_back(to_literal_expr(assumption).get_literal());
551+
context_size_stack.push_back(assumptions.size());
552+
553+
prop.set_assumptions(assumption_stack);
554+
}
555+
556+
void prop_conv_solvert::push()
557+
{
558+
// We create a new context literal.
559+
literalt context_literal = convert(symbol_exprt(
560+
context_prefix + std::to_string(context_literal_counter++), bool_typet()));
561+
562+
assumption_stack.push_back(context_literal);
563+
context_size_stack.push_back(1);
564+
565+
prop.set_assumptions(assumption_stack);
566+
}
567+
568+
void prop_conv_solvert::pop()
569+
{
570+
// We remove the context from the stack.
571+
for(size_t i = 0; i < context_size_stack.back(); ++i)
572+
assumption_stack.pop_back();
573+
context_size_stack.pop_back();
574+
575+
prop.set_assumptions(assumption_stack);
576+
}

src/solvers/prop/prop_conv_solver.h

Lines changed: 27 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,6 @@ class prop_conv_solvert : public conflict_providert,
3737
virtual ~prop_conv_solvert() = default;
3838

3939
// overloading from decision_proceduret
40-
void set_to(const exprt &expr, bool value) override;
4140
decision_proceduret::resultt dec_solve() override;
4241
void print_assignment(std::ostream &out) const override;
4342
std::string decision_procedure_text() const override
@@ -50,14 +49,6 @@ class prop_conv_solvert : public conflict_providert,
5049
{
5150
return prop.l_get(a);
5251
}
53-
void set_assumptions(const bvt &_assumptions) override
54-
{
55-
prop.set_assumptions(_assumptions);
56-
}
57-
bool has_set_assumptions() const override
58-
{
59-
return prop.has_set_assumptions();
60-
}
6152

6253
exprt handle(const exprt &expr) override;
6354

@@ -68,6 +59,18 @@ class prop_conv_solvert : public conflict_providert,
6859
literalt convert(const exprt &expr) override;
6960
bool is_in_conflict(const exprt &expr) const override;
7061

62+
/// For a Boolean expression \p expr, add the constraint
63+
/// 'current_context => expr' if \p value is `true`,
64+
/// otherwise add 'current_context => not expr'
65+
void set_to(const exprt &expr, bool value) override;
66+
67+
void push() override;
68+
69+
/// Push \p assumptions in form of `literal_exprt`
70+
void push(const std::vector<exprt> &assumptions) override;
71+
72+
void pop() override;
73+
7174
// get literal for expression, if available
7275
bool literal(const symbol_exprt &expr, literalt &literal) const;
7376

@@ -124,10 +127,24 @@ class prop_conv_solvert : public conflict_providert,
124127

125128
virtual void ignoring(const exprt &expr);
126129

127-
// deliberately protected now to protect lower-level API
130+
/// Actually adds the constraints to `prop`
131+
void do_set_to(const exprt &expr, bool value);
132+
128133
propt &prop;
129134

130135
messaget log;
136+
137+
static const char *context_prefix;
138+
139+
/// Assumptions on the stack
140+
bvt assumption_stack;
141+
142+
/// To generate unique literal names for contexts
143+
std::size_t context_literal_counter = 0;
144+
145+
/// `assumption_stack` is segmented in contexts;
146+
/// Number of assumptions in each context on the stack
147+
std::vector<size_t> context_size_stack;
131148
};
132149

133150
#endif // CPROVER_SOLVERS_PROP_PROP_CONV_SOLVER_H

src/solvers/prop/prop_minimize.cpp

Lines changed: 4 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -95,9 +95,6 @@ literalt prop_minimizet::constraint()
9595
/// Try to cover all objectives
9696
void prop_minimizet::operator()()
9797
{
98-
// we need to use assumptions
99-
PRECONDITION(prop_conv.has_set_assumptions());
100-
10198
_iterations = 0;
10299
_number_satisfied = 0;
103100
_value = 0;
@@ -120,9 +117,9 @@ void prop_minimizet::operator()()
120117
{
121118
_iterations++;
122119

123-
bvt assumptions;
124-
assumptions.push_back(c);
125-
prop_conv.set_assumptions(assumptions);
120+
exprt::operandst assumptions;
121+
assumptions.push_back(literal_exprt(c));
122+
prop_conv.push(assumptions);
126123
dec_result = prop_conv();
127124

128125
switch(dec_result)
@@ -150,8 +147,7 @@ void prop_minimizet::operator()()
150147
// We don't have a satisfying assignment to work with.
151148
// Run solver again to get one.
152149

153-
bvt assumptions; // no assumptions
154-
prop_conv.set_assumptions(assumptions);
150+
prop_conv.pop();
155151
(void)prop_conv();
156152
}
157153
}

src/solvers/prop/prop_minimize.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ Author: Daniel Kroening, [email protected]
1616

1717
#include <util/message.h>
1818

19+
#include "literal.h"
1920
#include "prop_conv.h"
2021

2122
/// Computes a satisfying assignment of minimal cost according to a const

src/solvers/refinement/bv_refinement.h

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -57,8 +57,6 @@ class bv_refinementt:public bv_pointerst
5757
bvt convert_mod(const mod_exprt &expr) override;
5858
bvt convert_floatbv_op(const exprt &expr) override;
5959

60-
void set_assumptions(const bvt &_assumptions) override;
61-
6260
private:
6361
// the list of operator approximations
6462
struct approximationt final
@@ -78,8 +76,8 @@ class bv_refinementt:public bv_pointerst
7876
bvt op0_bv, op1_bv, op2_bv, result_bv;
7977
mp_integer op0_value, op1_value, op2_value, result_value;
8078

81-
bvt under_assumptions;
82-
bvt over_assumptions;
79+
std::vector<exprt> under_assumptions;
80+
std::vector<exprt> over_assumptions;
8381

8482
// the kind of under- or over-approximation
8583
unsigned under_state, over_state;
@@ -108,7 +106,7 @@ class bv_refinementt:public bv_pointerst
108106

109107
bool progress;
110108
std::list<approximationt> approximations;
111-
bvt parent_assumptions;
109+
112110
protected:
113111
// use gui format
114112
configt config_;

0 commit comments

Comments
 (0)