Skip to content

Commit afb3df7

Browse files
Merge pull request #4581 from peterschrammel/stack-decision-procedure
stack_decision_proceduret for solving under assumptions/contexts
2 parents 419c372 + bc3837e commit afb3df7

16 files changed

+227
-95
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/goto-checker/goto_symex_property_decider.h

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -37,10 +37,6 @@ class goto_symex_property_decidert
3737
/// Convert the instances of a property into a goal variable
3838
void convert_goals();
3939

40-
/// Prevent the solver to optimize-away the goal variables
41-
/// (necessary for incremental solving)
42-
void freeze_goal_variables();
43-
4440
/// Add disjunction of negated selected properties to the equation
4541
void add_constraint_from_goals(
4642
std::function<bool(const irep_idt &property_id)> select_property);

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::add_constraints_to_prop(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+
add_constraints_to_prop(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+
add_constraints_to_prop(*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+
add_constraints_to_prop(implies_expr.op0(), true);
441+
add_constraints_to_prop(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+
add_constraints_to_prop(*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+
add_constraints_to_prop(expr, value);
537+
}
538+
else
539+
{
540+
// We have a child context. We add context_literal ==> expr to the formula.
541+
add_constraints_to_prop(
542+
or_exprt(literal_exprt(!assumption_stack.back()), expr), value);
543+
}
544+
}
545+
546+
void prop_conv_solvert::push(const std::vector<exprt> &assumptions)
547+
{
548+
// We push the given assumptions as a single context onto the stack.
549+
assumption_stack.reserve(assumption_stack.size() + assumptions.size());
550+
for(const auto &assumption : assumptions)
551+
assumption_stack.push_back(to_literal_expr(assumption).get_literal());
552+
context_size_stack.push_back(assumptions.size());
553+
554+
prop.set_assumptions(assumption_stack);
555+
}
556+
557+
void prop_conv_solvert::push()
558+
{
559+
// We create a new context literal.
560+
literalt context_literal = convert(symbol_exprt(
561+
context_prefix + std::to_string(context_literal_counter++), bool_typet()));
562+
563+
assumption_stack.push_back(context_literal);
564+
context_size_stack.push_back(1);
565+
566+
prop.set_assumptions(assumption_stack);
567+
}
568+
569+
void prop_conv_solvert::pop()
570+
{
571+
// We remove the context from the stack.
572+
assumption_stack.resize(assumption_stack.size() - context_size_stack.back());
573+
context_size_stack.pop_back();
574+
575+
prop.set_assumptions(assumption_stack);
576+
}

src/solvers/prop/prop_conv_solver.h

Lines changed: 29 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,26 @@ 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
128130
propt &prop;
129131

130132
messaget log;
133+
134+
static const char *context_prefix;
135+
136+
/// Assumptions on the stack
137+
bvt assumption_stack;
138+
139+
/// To generate unique literal names for contexts
140+
std::size_t context_literal_counter = 0;
141+
142+
/// `assumption_stack` is segmented in contexts;
143+
/// Number of assumptions in each context on the stack
144+
std::vector<size_t> context_size_stack;
145+
146+
private:
147+
/// Helper method used by `set_to` for adding the constraints to `prop`.
148+
/// This method is private because it must not be used by derived classes.
149+
void add_constraints_to_prop(const exprt &expr, bool value);
131150
};
132151

133152
#endif // CPROVER_SOLVERS_PROP_PROP_CONV_SOLVER_H

src/solvers/prop/prop_minimize.cpp

Lines changed: 2 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,7 @@ void prop_minimizet::operator()()
120117
{
121118
_iterations++;
122119

123-
bvt assumptions;
124-
assumptions.push_back(c);
125-
prop_conv.set_assumptions(assumptions);
120+
prop_conv.push({literal_exprt{c}});
126121
dec_result = prop_conv();
127122

128123
switch(dec_result)
@@ -150,8 +145,7 @@ void prop_minimizet::operator()()
150145
// We don't have a satisfying assignment to work with.
151146
// Run solver again to get one.
152147

153-
bvt assumptions; // no assumptions
154-
prop_conv.set_assumptions(assumptions);
148+
prop_conv.pop();
155149
(void)prop_conv();
156150
}
157151
}

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

0 commit comments

Comments
 (0)