Skip to content

Commit bf17dab

Browse files
committed
Add CaDiCaL support to CMake
Add CMake configuration to build using CaDiCaL, which was already supported with Makefiles. Also bump the version of CaDiCaL to rel-1.3.0 and fix the use of the cnf_solvert interface. Fixes: diffblue#5348
1 parent 0fe9b5c commit bf17dab

File tree

8 files changed

+192
-43
lines changed

8 files changed

+192
-43
lines changed

CMakeLists.txt

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -58,7 +58,8 @@ endif()
5858
set(enable_cbmc_tests on CACHE BOOL "Whether CBMC tests should be enabled")
5959

6060
set(sat_impl "minisat2" CACHE STRING
61-
"This setting controls the SAT library which is used. Valid values are 'minisat2' and 'glucose'"
61+
"This setting controls the SAT library which is used. Valid values are
62+
'minisat2', 'glucose', or 'cadical'"
6263
)
6364

6465
if(${enable_cbmc_tests})

scripts/cadical-patch

Lines changed: 0 additions & 10 deletions
This file was deleted.

src/Makefile

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -151,13 +151,12 @@ glucose-download:
151151
@(cd ../glucose-syrup; patch -p1 < ../scripts/glucose-syrup-patch)
152152
@rm glucose-syrup.tgz
153153

154-
cadical_release = rel-06w
154+
cadical_release = rel-1.3.0
155155
cadical-download:
156156
@echo "Downloading CaDiCaL $(cadical_release)"
157157
@curl -L https://github.com/arminbiere/cadical/archive/$(cadical_release).tar.gz | tar xz
158158
@rm -Rf ../cadical
159159
@mv cadical-$(cadical_release) ../cadical
160-
@(cd ../cadical; patch -p1 < ../scripts/cadical-patch)
161160
@cd ../cadical && CXX=$(CXX) CXXFLAGS=-O3 ./configure --debug && make
162161

163162
doc :

src/solvers/CMakeLists.txt

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -98,6 +98,36 @@ elseif("${sat_impl}" STREQUAL "glucose")
9898
target_sources(solvers PRIVATE ${glucose_source})
9999

100100
target_link_libraries(solvers glucose-condensed)
101+
elseif("${sat_impl}" STREQUAL "cadical")
102+
message(STATUS "Building solvers with cadical")
103+
104+
download_project(PROJ cadical
105+
URL https://github.com/arminbiere/cadical/archive/rel-1.3.0.tar.gz
106+
PATCH_COMMAND true
107+
COMMAND CXX=${CMAKE_CXX_COMPILER} CXXFLAGS=-O3 ./configure --debug
108+
URL_MD5 5bd15d1e198d2e904a8af8b7873dd341
109+
)
110+
111+
message(STATUS "Building CaDiCaL")
112+
execute_process(COMMAND make WORKING_DIRECTORY ${cadical_SOURCE_DIR})
113+
114+
target_compile_definitions(solvers PUBLIC
115+
SATCHECK_CADICAL HAVE_CADICAL
116+
)
117+
118+
add_library(cadical STATIC IMPORTED)
119+
120+
set_target_properties(
121+
cadical
122+
PROPERTIES IMPORTED_LOCATION ${cadical_SOURCE_DIR}/build/libcadical.a
123+
)
124+
125+
target_include_directories(solvers
126+
PUBLIC
127+
${cadical_SOURCE_DIR}/src
128+
)
129+
130+
target_link_libraries(solvers cadical)
101131
endif()
102132

103133
if(CMAKE_USE_CUDD)

src/solvers/sat/satcheck_cadical.cpp

Lines changed: 42 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ tvt satcheck_cadicalt::l_get(literalt a) const
2323

2424
tvt result;
2525

26-
if(a.var_no() > static_cast<unsigned>(solver->max()))
26+
if(a.var_no() > static_cast<unsigned>(solver->vars()))
2727
return tvt(tvt::tv_enumt::TV_UNKNOWN);
2828

2929
const int val = solver->val(a.dimacs());
@@ -62,6 +62,9 @@ void satcheck_cadicalt::lcnf(const bvt &bv)
6262
}
6363
solver->add(0); // terminate clause
6464

65+
with_solver_hardness(
66+
[&bv](solver_hardnesst &hardness) { hardness.register_clause(bv); });
67+
6568
clause_counter++;
6669
}
6770

@@ -72,31 +75,37 @@ propt::resultt satcheck_cadicalt::do_prop_solve()
7275
log.statistics() << (no_variables() - 1) << " variables, " << clause_counter
7376
<< " clauses" << messaget::eom;
7477

75-
if(status == statust::UNSAT)
76-
{
77-
log.status() << "SAT checker inconsistent: instance is UNSATISFIABLE"
78-
<< messaget::eom;
79-
}
80-
else
78+
// if assumptions contains false, we need this to be UNSAT
79+
for(const auto &a : assumptions)
8180
{
82-
switch(solver->solve())
81+
if(a.is_false())
8382
{
84-
case 10:
85-
log.status() << "SAT checker: instance is SATISFIABLE" << messaget::eom;
86-
status = statust::SAT;
87-
return resultt::P_SATISFIABLE;
88-
case 20:
89-
log.status() << "SAT checker: instance is UNSATISFIABLE"
90-
<< messaget::eom;
91-
break;
92-
default:
93-
log.status() << "SAT checker: solving returned without solution"
94-
<< messaget::eom;
95-
throw analysis_exceptiont(
96-
"solving inside CaDiCaL SAT solver has been interrupted");
83+
log.status() << "got FALSE as assumption: instance is UNSATISFIABLE"
84+
<< messaget::eom;
85+
status = statust::UNSAT;
86+
return resultt::P_UNSATISFIABLE;
9787
}
9888
}
9989

90+
for(const auto &a : assumptions)
91+
solver->assume(a.dimacs());
92+
93+
switch(solver->solve())
94+
{
95+
case 10:
96+
log.status() << "SAT checker: instance is SATISFIABLE" << messaget::eom;
97+
status = statust::SAT;
98+
return resultt::P_SATISFIABLE;
99+
case 20:
100+
log.status() << "SAT checker: instance is UNSATISFIABLE" << messaget::eom;
101+
break;
102+
default:
103+
log.status() << "SAT checker: solving returned without solution"
104+
<< messaget::eom;
105+
throw analysis_exceptiont(
106+
"solving inside CaDiCaL SAT solver has been interrupted");
107+
}
108+
100109
status = statust::UNSAT;
101110
return resultt::P_UNSATISFIABLE;
102111
}
@@ -107,8 +116,8 @@ void satcheck_cadicalt::set_assignment(literalt a, bool value)
107116
INVARIANT(false, "method not supported");
108117
}
109118

110-
satcheck_cadicalt::satcheck_cadicalt() :
111-
solver(new CaDiCaL::Solver())
119+
satcheck_cadicalt::satcheck_cadicalt(message_handlert &message_handler)
120+
: cnf_solvert(message_handler), solver(new CaDiCaL::Solver())
112121
{
113122
solver->set("quiet", 1);
114123
}
@@ -120,13 +129,20 @@ satcheck_cadicalt::~satcheck_cadicalt()
120129

121130
void satcheck_cadicalt::set_assumptions(const bvt &bv)
122131
{
123-
INVARIANT(false, "method not supported");
132+
// We filter out 'true' assumptions which cause spurious results with CaDiCaL.
133+
assumptions.clear();
134+
for(const auto &assumption : bv)
135+
{
136+
if(!assumption.is_true())
137+
{
138+
assumptions.push_back(assumption);
139+
}
140+
}
124141
}
125142

126143
bool satcheck_cadicalt::is_in_conflict(literalt a) const
127144
{
128-
INVARIANT(false, "method not supported");
129-
return false;
145+
return solver->failed(a.dimacs());
130146
}
131147

132148
#endif

src/solvers/sat/satcheck_cadical.h

Lines changed: 24 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -12,15 +12,17 @@ Author: Michael Tautschnig
1212

1313
#include "cnf.h"
1414

15+
#include <solvers/hardness_collector.h>
16+
1517
namespace CaDiCaL // NOLINT(readability/namespace)
1618
{
1719
class Solver; // NOLINT(readability/identifiers)
1820
}
1921

20-
class satcheck_cadicalt:public cnf_solvert
22+
class satcheck_cadicalt : public cnf_solvert, public hardness_collectort
2123
{
2224
public:
23-
satcheck_cadicalt();
25+
explicit satcheck_cadicalt(message_handlert &message_handler);
2426
virtual ~satcheck_cadicalt();
2527

2628
const std::string solver_text() override;
@@ -32,19 +34,37 @@ class satcheck_cadicalt:public cnf_solvert
3234
void set_assumptions(const bvt &_assumptions) override;
3335
bool has_set_assumptions() const override
3436
{
35-
return false;
37+
return true;
3638
}
3739
bool has_is_in_conflict() const override
3840
{
39-
return false;
41+
return true;
4042
}
4143
bool is_in_conflict(literalt a) const override;
4244

45+
void
46+
with_solver_hardness(std::function<void(solver_hardnesst &)> handler) override
47+
{
48+
if(solver_hardness.has_value())
49+
{
50+
handler(solver_hardness.value());
51+
}
52+
}
53+
54+
void enable_hardness_collection() override
55+
{
56+
solver_hardness = solver_hardnesst{};
57+
}
58+
4359
protected:
4460
resultt do_prop_solve() override;
4561

4662
// NOLINTNEXTLINE(readability/identifiers)
4763
CaDiCaL::Solver * solver;
64+
65+
bvt assumptions;
66+
67+
optionalt<solver_hardnesst> solver_hardness;
4868
};
4969

5070
#endif // CPROVER_SOLVERS_SAT_SATCHECK_CADICAL_H

unit/Makefile

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,7 @@ SRC += analyses/ai/ai.cpp \
6868
solvers/lowering/byte_operators.cpp \
6969
solvers/prop/bdd_expr.cpp \
7070
solvers/sat/external_sat.cpp \
71+
solvers/sat/satcheck_cadical.cpp \
7172
solvers/sat/satcheck_minisat2.cpp \
7273
solvers/strings/array_pool/array_pool.cpp \
7374
solvers/strings/string_constraint_generator_valueof/calculate_max_string_length.cpp \
@@ -224,6 +225,12 @@ EXCLUDED_TESTS=expr_undefined_casts.cpp
224225
ifneq ($(WITH_MEMORY_ANALYZER),1)
225226
EXCLUDED_TESTS += gdb_api.cpp
226227
endif
228+
ifeq ($(MINISAT2),)
229+
EXCLUDED_TESTS += satcheck_minisat2.cpp
230+
endif
231+
ifeq ($(CADICAL),)
232+
EXCLUDED_TESTS += satcheck_cadical.cpp
233+
endif
227234

228235
N_CATCH_TESTS = $(shell \
229236
cat $$(find . -name "*.cpp" \

unit/solvers/sat/satcheck_cadical.cpp

Lines changed: 86 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,86 @@
1+
/*******************************************************************\
2+
3+
Module: Unit tests for satcheck_cadical
4+
5+
Author: Peter Schrammel, Michael Tautschnig
6+
7+
\*******************************************************************/
8+
9+
/// \file
10+
/// Unit tests for satcheck_cadical
11+
12+
#ifdef HAVE_CADICAL
13+
14+
# include <testing-utils/use_catch.h>
15+
16+
# include <solvers/prop/literal.h>
17+
# include <solvers/sat/satcheck_cadical.h>
18+
# include <util/cout_message.h>
19+
20+
SCENARIO("satcheck_cadical", "[core][solvers][sat][satcheck_cadical]")
21+
{
22+
console_message_handlert message_handler;
23+
24+
GIVEN("A satisfiable formula f")
25+
{
26+
satcheck_cadicalt satcheck(message_handler);
27+
literalt f = satcheck.new_variable();
28+
satcheck.l_set_to_true(f);
29+
30+
THEN("is indeed satisfiable")
31+
{
32+
REQUIRE(satcheck.prop_solve() == propt::resultt::P_SATISFIABLE);
33+
}
34+
THEN("is unsatisfiable under a false assumption")
35+
{
36+
bvt assumptions;
37+
assumptions.push_back(const_literal(false));
38+
satcheck.set_assumptions(assumptions);
39+
REQUIRE(satcheck.prop_solve() == propt::resultt::P_UNSATISFIABLE);
40+
}
41+
}
42+
43+
GIVEN("An unsatisfiable formula f && !f")
44+
{
45+
satcheck_cadicalt satcheck(message_handler);
46+
literalt f = satcheck.new_variable();
47+
satcheck.l_set_to_true(satcheck.land(f, !f));
48+
49+
THEN("is indeed unsatisfiable")
50+
{
51+
REQUIRE(satcheck.prop_solve() == propt::resultt::P_UNSATISFIABLE);
52+
}
53+
}
54+
55+
GIVEN("An unsatisfiable formula false implied by a")
56+
{
57+
satcheck_cadicalt satcheck(message_handler);
58+
literalt a = satcheck.new_variable();
59+
literalt a_implies_false = satcheck.lor(!a, const_literal(false));
60+
satcheck.l_set_to_true(a_implies_false);
61+
62+
THEN("is indeed unsatisfiable under assumption a")
63+
{
64+
bvt assumptions;
65+
assumptions.push_back(a);
66+
satcheck.set_assumptions(assumptions);
67+
REQUIRE(satcheck.prop_solve() == propt::resultt::P_UNSATISFIABLE);
68+
}
69+
THEN("is still unsatisfiable under assumption a and true")
70+
{
71+
bvt assumptions;
72+
assumptions.push_back(const_literal(true));
73+
assumptions.push_back(a);
74+
satcheck.set_assumptions(assumptions);
75+
REQUIRE(satcheck.prop_solve() == propt::resultt::P_UNSATISFIABLE);
76+
}
77+
THEN("becomes satisfiable when assumption a is lifted")
78+
{
79+
bvt assumptions;
80+
satcheck.set_assumptions(assumptions);
81+
REQUIRE(satcheck.prop_solve() == propt::resultt::P_SATISFIABLE);
82+
}
83+
}
84+
}
85+
86+
#endif

0 commit comments

Comments
 (0)