Skip to content

Commit fa810f5

Browse files
committed
new decision_proceduret API
This changes the API offered by decision_proceduret to solving under assumptions. Solving under assumptions has been popularised by MiniSat, and is a state-less alternative to context stacks. This change mimics the transition from check-sat to check-sat-assuming that SMT-LIB is undergoing.
1 parent aed4d77 commit fa810f5

18 files changed

+121
-28
lines changed

src/solvers/decision_procedure.cpp

+9-1
Original file line numberDiff line numberDiff line change
@@ -11,13 +11,21 @@ Author: Daniel Kroening, [email protected]
1111

1212
#include "decision_procedure.h"
1313

14+
#include <util/std_expr.h>
15+
1416
decision_proceduret::~decision_proceduret()
1517
{
1618
}
1719

1820
decision_proceduret::resultt decision_proceduret::operator()()
1921
{
20-
return dec_solve();
22+
return dec_solve(nil_exprt());
23+
}
24+
25+
decision_proceduret::resultt
26+
decision_proceduret::operator()(const exprt &assumption)
27+
{
28+
return dec_solve(assumption);
2129
}
2230

2331
void decision_proceduret::set_to_true(const exprt &expr)

src/solvers/decision_procedure.h

+14-7
Original file line numberDiff line numberDiff line change
@@ -17,18 +17,19 @@ Author: Daniel Kroening, [email protected]
1717

1818
class exprt;
1919

20+
/// An interface for a decision procedure for satisfiability problems.
2021
class decision_proceduret
2122
{
2223
public:
2324
/// For a Boolean expression \p expr, add the constraint 'expr' if \p value
2425
/// is `true`, otherwise add 'not expr'
25-
virtual void set_to(const exprt &expr, bool value) = 0;
26+
virtual void set_to(const exprt &, bool value) = 0;
2627

2728
/// For a Boolean expression \p expr, add the constraint 'expr'
28-
void set_to_true(const exprt &expr);
29+
void set_to_true(const exprt &);
2930

3031
/// For a Boolean expression \p expr, add the constraint 'not expr'
31-
void set_to_false(const exprt &expr);
32+
void set_to_false(const exprt &);
3233

3334
/// Generate a handle, which is an expression that
3435
/// has the same value as the argument in any model
@@ -37,7 +38,7 @@ class decision_proceduret
3738
/// \ref set_to.
3839
/// The returned expression may be the expression itself or a more compact
3940
/// but solver-specific representation.
40-
virtual exprt handle(const exprt &expr) = 0;
41+
virtual exprt handle(const exprt &) = 0;
4142

4243
/// Result of running the decision procedure
4344
enum class resultt
@@ -48,12 +49,18 @@ class decision_proceduret
4849
};
4950

5051
/// Run the decision procedure to solve the problem
52+
/// This corresponds to SMT-LIB's check-sat.
5153
resultt operator()();
5254

55+
/// Run the decision procedure to solve the problem under
56+
/// the given assumption.
57+
/// This corresponds to SMT-LIB's check-sat-assuming.
58+
resultt operator()(const exprt &assumption);
59+
5360
/// Return \p expr with variables replaced by values from satisfying
5461
/// assignment if available.
5562
/// Return `nil` if not available
56-
virtual exprt get(const exprt &expr) const = 0;
63+
virtual exprt get(const exprt &) const = 0;
5764

5865
/// Print satisfying assignment to \p out
5966
virtual void print_assignment(std::ostream &out) const = 0;
@@ -67,8 +74,8 @@ class decision_proceduret
6774
virtual ~decision_proceduret();
6875

6976
protected:
70-
/// Run the decision procedure to solve the problem
71-
virtual resultt dec_solve() = 0;
77+
/// Implementation of the decision procedure.
78+
virtual resultt dec_solve(const exprt &assumption) = 0;
7279
};
7380

7481
/// Add Boolean constraint \p src to decision procedure \p dest

src/solvers/prop/prop_conv_solver.cpp

+12-2
Original file line numberDiff line numberDiff line change
@@ -439,7 +439,8 @@ void prop_conv_solvert::finish_eager_conversion()
439439
{
440440
}
441441

442-
decision_proceduret::resultt prop_conv_solvert::dec_solve()
442+
decision_proceduret::resultt
443+
prop_conv_solvert::dec_solve(const exprt &assumption)
443444
{
444445
// post-processing isn't incremental yet
445446
if(!post_processing_done)
@@ -459,7 +460,16 @@ decision_proceduret::resultt prop_conv_solvert::dec_solve()
459460

460461
log.statistics() << "Solving with " << prop.solver_text() << messaget::eom;
461462

462-
switch(prop.prop_solve(assumption_stack))
463+
if(assumption.is_nil())
464+
push();
465+
else
466+
push({literal_exprt(convert(assumption))});
467+
468+
auto prop_result = prop.prop_solve(assumption_stack);
469+
470+
pop();
471+
472+
switch(prop_result)
463473
{
464474
case propt::resultt::P_SATISFIABLE:
465475
return resultt::D_SATISFIABLE;

src/solvers/prop/prop_conv_solver.h

+1-1
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@ class prop_conv_solvert : public conflict_providert,
4040
virtual void finish_eager_conversion();
4141

4242
// overloading from decision_proceduret
43-
decision_proceduret::resultt dec_solve() override;
43+
decision_proceduret::resultt dec_solve(const exprt &) override;
4444
void print_assignment(std::ostream &out) const override;
4545
std::string decision_procedure_text() const override;
4646
exprt get(const exprt &expr) const override;

src/solvers/refinement/bv_refinement.h

+1-1
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,7 @@ class bv_refinementt:public bv_pointerst
3939

4040
explicit bv_refinementt(const infot &info);
4141

42-
decision_proceduret::resultt dec_solve() override;
42+
decision_proceduret::resultt dec_solve(const exprt &) override;
4343

4444
std::string decision_procedure_text() const override
4545
{

src/solvers/refinement/bv_refinement_loop.cpp

+1-1
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ bv_refinementt::bv_refinementt(const infot &info)
2121
PRECONDITION(prop.has_is_in_conflict());
2222
}
2323

24-
decision_proceduret::resultt bv_refinementt::dec_solve()
24+
decision_proceduret::resultt bv_refinementt::dec_solve(const exprt &assumption)
2525
{
2626
// do the usual post-processing
2727
log.status() << "BV-Refinement: post-processing" << messaget::eom;

src/solvers/smt2/smt2_conv.cpp

+10-2
Original file line numberDiff line numberDiff line change
@@ -317,9 +317,17 @@ void smt2_convt::define_object_size(
317317
}
318318
}
319319

320-
decision_proceduret::resultt smt2_convt::dec_solve()
320+
decision_proceduret::resultt smt2_convt::dec_solve(const exprt &assumption)
321321
{
322-
write_footer();
322+
if(assumption.is_nil())
323+
write_footer();
324+
else
325+
{
326+
assumptions.push_back(literal_exprt(convert(assumption)));
327+
write_footer();
328+
assumptions.pop_back();
329+
}
330+
323331
out.flush();
324332
return decision_proceduret::resultt::D_ERROR;
325333
}

src/solvers/smt2/smt2_conv.h

+1-1
Original file line numberDiff line numberDiff line change
@@ -106,7 +106,7 @@ class smt2_convt : public stack_decision_proceduret
106106

107107
std::size_t number_of_solver_calls = 0;
108108

109-
resultt dec_solve() override;
109+
resultt dec_solve(const exprt &) override;
110110

111111
void write_header();
112112
/// Writes the end of the SMT file to the `smt_convt::out` stream. These parts

src/solvers/smt2/smt2_dec.cpp

+1-1
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@ std::string smt2_dect::decision_procedure_text() const
3333
// clang-format on
3434
}
3535

36-
decision_proceduret::resultt smt2_dect::dec_solve()
36+
decision_proceduret::resultt smt2_dect::dec_solve(const exprt &assumption)
3737
{
3838
++number_of_solver_calls;
3939

src/solvers/smt2/smt2_dec.h

+1-1
Original file line numberDiff line numberDiff line change
@@ -39,11 +39,11 @@ class smt2_dect : protected smt2_stringstreamt, public smt2_convt
3939
{
4040
}
4141

42-
resultt dec_solve() override;
4342
std::string decision_procedure_text() const override;
4443

4544
protected:
4645
message_handlert &message_handler;
46+
resultt dec_solve(const exprt &) override;
4747

4848
/// Everything except the footer is cached, so that output files can be
4949
/// rewritten with varying footers.

src/solvers/smt2_incremental/smt2_incremental_decision_procedure.cpp

+2-1
Original file line numberDiff line numberDiff line change
@@ -690,7 +690,8 @@ exprt smt2_incremental_decision_proceduret::lower(exprt expression) const
690690
return lowered;
691691
}
692692

693-
decision_proceduret::resultt smt2_incremental_decision_proceduret::dec_solve()
693+
decision_proceduret::resultt
694+
smt2_incremental_decision_proceduret::dec_solve(const exprt &assumption)
694695
{
695696
++number_of_solver_calls;
696697
define_object_properties();

src/solvers/smt2_incremental/smt2_incremental_decision_procedure.h

+1-1
Original file line numberDiff line numberDiff line change
@@ -64,7 +64,7 @@ class smt2_incremental_decision_proceduret final
6464

6565
protected:
6666
// Implementation of protected decision_proceduret member function.
67-
resultt dec_solve() override;
67+
resultt dec_solve(const exprt &) override;
6868
/// \brief Defines a function of array sort and asserts the element values
6969
/// from `array_exprt` or `array_of_exprt`.
7070
/// \details

src/solvers/strings/string_refinement.cpp

+6-3
Original file line numberDiff line numberDiff line change
@@ -603,7 +603,8 @@ output_equations(std::ostream &output, const std::vector<exprt> &equations)
603603
/// \return `resultt::D_SATISFIABLE` if the constraints are satisfiable,
604604
/// `resultt::D_UNSATISFIABLE` if they are unsatisfiable,
605605
/// `resultt::D_ERROR` if the limit of iteration was reached.
606-
decision_proceduret::resultt string_refinementt::dec_solve()
606+
decision_proceduret::resultt
607+
string_refinementt::dec_solve(const exprt &assumption)
607608
{
608609
#ifdef DEBUG
609610
log.debug() << "dec_solve: Initial set of equations" << messaget::eom;
@@ -781,7 +782,8 @@ decision_proceduret::resultt string_refinementt::dec_solve()
781782
// Initial try without index set
782783
const auto get = [this](const exprt &expr) { return this->get(expr); };
783784
dependencies.clean_cache();
784-
const decision_proceduret::resultt initial_result = supert::dec_solve();
785+
const decision_proceduret::resultt initial_result =
786+
supert::dec_solve(nil_exprt());
785787
if(initial_result == resultt::D_SATISFIABLE)
786788
{
787789
bool satisfied;
@@ -822,7 +824,8 @@ decision_proceduret::resultt string_refinementt::dec_solve()
822824
while((loop_bound_--) > 0)
823825
{
824826
dependencies.clean_cache();
825-
const decision_proceduret::resultt refined_result = supert::dec_solve();
827+
const decision_proceduret::resultt refined_result =
828+
supert::dec_solve(nil_exprt());
826829

827830
if(refined_result == resultt::D_SATISFIABLE)
828831
{

src/solvers/strings/string_refinement.h

+3-1
Original file line numberDiff line numberDiff line change
@@ -84,7 +84,9 @@ class string_refinementt final : public bv_refinementt
8484

8585
exprt get(const exprt &expr) const override;
8686
void set_to(const exprt &expr, bool value) override;
87-
decision_proceduret::resultt dec_solve() override;
87+
88+
protected:
89+
decision_proceduret::resultt dec_solve(const exprt &) override;
8890

8991
private:
9092
// Base class

unit/Makefile

+1
Original file line numberDiff line numberDiff line change
@@ -96,6 +96,7 @@ SRC += analyses/ai/ai.cpp \
9696
path_strategies.cpp \
9797
pointer-analysis/value_set.cpp \
9898
solvers/bdd/miniBDD/miniBDD.cpp \
99+
solvers/flattening/boolbv.cpp \
99100
solvers/floatbv/float_utils.cpp \
100101
solvers/prop/bdd_expr.cpp \
101102
solvers/sat/external_sat.cpp \

unit/solvers/flattening/boolbv.cpp

+50
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
/*******************************************************************\
2+
3+
Module: Unit tests for boolbvt
4+
5+
Author: Daniel Kroening
6+
7+
\*******************************************************************/
8+
9+
/// \file
10+
/// Unit tests for boolbvt
11+
12+
#include <util/arith_tools.h>
13+
#include <util/bitvector_types.h>
14+
#include <util/cout_message.h>
15+
#include <util/namespace.h>
16+
#include <util/std_expr.h>
17+
#include <util/symbol_table.h>
18+
19+
#include <solvers/flattening/boolbv.h>
20+
#include <solvers/sat/satcheck.h>
21+
#include <testing-utils/use_catch.h>
22+
23+
SCENARIO("boolbvt", "[core][solvers][flattening][boolbvt]")
24+
{
25+
console_message_handlert message_handler;
26+
message_handler.set_verbosity(0);
27+
28+
GIVEN("A satisfiable bit-vector formula f")
29+
{
30+
satcheckt satcheck(message_handler);
31+
symbol_tablet symbol_table;
32+
namespacet ns(symbol_table);
33+
boolbvt boolbv(ns, satcheck, message_handler);
34+
35+
unsignedbv_typet u32(32);
36+
boolbv << equal_exprt(symbol_exprt("x", u32), from_integer(10, u32));
37+
38+
THEN("is indeed satisfiable")
39+
{
40+
REQUIRE(boolbv() == decision_proceduret::resultt::D_SATISFIABLE);
41+
}
42+
THEN("is unsatisfiable under an inconsistent assumption")
43+
{
44+
auto assumption =
45+
equal_exprt(symbol_exprt("x", u32), from_integer(11, u32));
46+
REQUIRE(
47+
boolbv(assumption) == decision_proceduret::resultt::D_UNSATISFIABLE);
48+
}
49+
}
50+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
solvers/sat
2+
testing-utils
3+
util

unit/solvers/strings/string_refinement/string_refinement.cpp

+4-4
Original file line numberDiff line numberDiff line change
@@ -100,7 +100,7 @@ SCENARIO("string refinement", "[core][solvers][strings][string_refinement]")
100100
solver.set_to(
101101
equal_exprt{return_length, from_integer(15, int_type)}, true);
102102

103-
auto result = solver.dec_solve();
103+
auto result = solver();
104104
THEN("The formula is satisfiable")
105105
{
106106
REQUIRE(result == decision_proceduret::resultt::D_SATISFIABLE);
@@ -136,7 +136,7 @@ SCENARIO("string refinement", "[core][solvers][strings][string_refinement]")
136136
"The formula is satisfiable and the model of the array should have"
137137
"length 10 and end with 'b'")
138138
{
139-
auto result = solver.dec_solve();
139+
auto result = solver();
140140
REQUIRE(result == decision_proceduret::resultt::D_SATISFIABLE);
141141
const exprt array_model = solver.get(array1);
142142
REQUIRE(can_cast_expr<array_exprt>(array_model));
@@ -183,7 +183,7 @@ SCENARIO("string refinement", "[core][solvers][strings][string_refinement]")
183183
"The model for array1 has length 10 and contains 'c' at "
184184
" position 3 and b at position 9")
185185
{
186-
auto result = solver.dec_solve();
186+
auto result = solver();
187187
REQUIRE(result == decision_proceduret::resultt::D_SATISFIABLE);
188188
const exprt array_model = solver.get(array1);
189189
REQUIRE(can_cast_expr<array_exprt>(array_model));
@@ -230,7 +230,7 @@ SCENARIO("string refinement", "[core][solvers][strings][string_refinement]")
230230
true);
231231
THEN("The model for array1 has length 10 and contains 'c' at position 9")
232232
{
233-
auto result = solver.dec_solve();
233+
auto result = solver();
234234
REQUIRE(result == decision_proceduret::resultt::D_SATISFIABLE);
235235
const exprt array_model = solver.get(array1);
236236
REQUIRE(can_cast_expr<array_exprt>(array_model));

0 commit comments

Comments
 (0)