Skip to content

Commit 58e83d6

Browse files
conp-solutionstautschnig
authored andcommitted
Add support for MergeSat
MergeSat is a recent SAT solver that fits the MiniSat2 interface. Run the check-ubuntu-20_04-cmake-gcc CI job with MergeSat to continuously confirm that this configuration actually works. To use MergeSat as a proper SAT backend, some extensions might be dropped. Especially being able to print memory usage is not helpful for CBMC, but requires pulling in a new dependency. Signed-off-by: Norbert Manthey <[email protected]>
1 parent 92b4580 commit 58e83d6

File tree

8 files changed

+209
-11
lines changed

8 files changed

+209
-11
lines changed

.github/workflows/pull-request-checks.yaml

+55
Original file line numberDiff line numberDiff line change
@@ -242,6 +242,61 @@ jobs:
242242
- name: Run tests
243243
run: cd build; ctest . -V -L CORE -j2
244244

245+
# This job takes approximately 29 to 42 minutes
246+
check-ubuntu-20_04-cmake-gcc-mergesat:
247+
runs-on: ubuntu-20.04
248+
steps:
249+
- uses: actions/checkout@v3
250+
with:
251+
submodules: recursive
252+
- name: Fetch dependencies
253+
env:
254+
# This is needed in addition to -yq to prevent apt-get from asking for
255+
# user input
256+
DEBIAN_FRONTEND: noninteractive
257+
run: |
258+
sudo apt-get update
259+
sudo apt-get install --no-install-recommends -yq cmake ninja-build gcc gdb g++ maven flex bison libxml2-utils dpkg-dev ccache doxygen z3
260+
- name: Confirm z3 solver is available and log the version installed
261+
run: z3 --version
262+
- name: Download cvc-5 from the releases page and make sure it can be deployed
263+
run: |
264+
wget -O cvc5 https://github.com/cvc5/cvc5/releases/download/cvc5-${{env.cvc5-version}}/cvc5-Linux
265+
chmod u+x cvc5
266+
mv cvc5 /usr/local/bin
267+
cvc5 --version
268+
- name: Prepare ccache
269+
uses: actions/cache@v3
270+
with:
271+
path: .ccache
272+
key: ${{ runner.os }}-20.04-Release-mergesat-${{ github.ref }}-${{ github.sha }}-PR
273+
restore-keys: |
274+
${{ runner.os }}-20.04-Release-mergesat-${{ github.ref }}
275+
${{ runner.os }}-20.04-Release-mergesat
276+
- name: ccache environment
277+
run: |
278+
echo "CCACHE_BASEDIR=$PWD" >> $GITHUB_ENV
279+
echo "CCACHE_DIR=$PWD/.ccache" >> $GITHUB_ENV
280+
- name: Configure using CMake
281+
run: cmake -S . -B build -G Ninja -DCMAKE_BUILD_TYPE=Release -DCMAKE_C_COMPILER=/usr/bin/gcc -DCMAKE_CXX_COMPILER=/usr/bin/g++ -Dsat_impl="mergesat;cadical"
282+
- name: Check that doc task works
283+
run: ninja -C build doc
284+
- name: Zero ccache stats and limit in size
285+
run: ccache -z --max-size=500M
286+
- name: Build with Ninja
287+
run: ninja -C build -j2
288+
- name: Print ccache stats
289+
run: ccache -s
290+
- name: Checking completeness of help output
291+
run: scripts/check_help.sh build/bin
292+
- name: Check if package building works
293+
run: |
294+
cd build
295+
ninja package
296+
ls *.deb
297+
- name: Run tests
298+
run: cd build; ctest . -V -L CORE -j2
299+
245300
# This job takes approximately 34 to 38 minutes
246301
check-ubuntu-22_04-make-clang:
247302
runs-on: ubuntu-22.04

scripts/mergesat_CMakeLists.txt

+28
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
# CBMC only uses part of MergeSat.
2+
# This CMakeLists is designed to build just the parts that are needed.
3+
4+
add_library(mergesat-condensed
5+
minisat/core/Lookahead.cc
6+
minisat/core/Solver.cc
7+
minisat/simp/SimpSolver.cc
8+
minisat/utils/ccnr.cc
9+
minisat/utils/Options.cc
10+
minisat/utils/System.cc
11+
)
12+
13+
set_target_properties(
14+
mergesat-condensed
15+
PROPERTIES
16+
CXX_STANDARD 11
17+
CXX_STANDARD_REQUIRED true
18+
XCODE_ATTRIBUTE_CODE_SIGN_IDENTITY "Developer ID Application: Daniel Kroening"
19+
)
20+
21+
if("${CMAKE_CXX_COMPILER_ID}" STREQUAL "MSVC")
22+
target_compile_options(mergesat-condensed PUBLIC /w)
23+
endif()
24+
25+
target_include_directories(mergesat-condensed
26+
PUBLIC
27+
${CMAKE_CURRENT_SOURCE_DIR}
28+
)

src/Makefile

+9
Original file line numberDiff line numberDiff line change
@@ -150,6 +150,15 @@ minisat2-download:
150150
@(cd ../minisat-2.2.1; patch -p1 < ../scripts/minisat-2.2.1-patch)
151151
@rm minisat2_2.2.1.orig.tar.gz
152152

153+
mergesat_version = 4.0-rc1
154+
mergesat-download:
155+
@echo "Downloading MergeSat $(mergesat_version)"
156+
@$(DOWNLOADER) https://github.com/conp-solutions/mergesat/archive/$(mergesat_version).tar.gz
157+
@$(TAR) xfz $(mergesat_version).tar.gz
158+
@rm -Rf ../mergesat
159+
@mv mergesat-$(mergesat_version) ../mergesat
160+
@$(RM) $(mergesat_version).tar.gz
161+
153162
cudd-download:
154163
@echo "Downloading Cudd 3.0.0"
155164
@$(DOWNLOADER) https://sourceforge.net/projects/cudd-mirror/files/cudd-3.0.0.tar.gz/download cudd-3.0.0.tar.gz

src/config.inc

+6-1
Original file line numberDiff line numberDiff line change
@@ -30,12 +30,13 @@ endif
3030
#BOOLEFORCE = ../../booleforce-0.4
3131
#MINISAT = ../../MiniSat-p_v1.14
3232
#MINISAT2 = ../../minisat-2.2.1
33+
#MERGESAT = ../../mergesat-4.0-rc1
3334
#IPASIR = ../../ipasir
3435
#GLUCOSE = ../../glucose-syrup
3536
#CADICAL = ../../cadical
3637

3738
# select default solver to be minisat2 if no other is specified
38-
ifeq ($(BOOLEFORCE)$(CHAFF)$(GLUCOSE)$(IPASIR)$(LINGELING)$(MINISAT)$(MINISAT2)$(PICOSAT)$(CADICAL),)
39+
ifeq ($(BOOLEFORCE)$(CHAFF)$(GLUCOSE)$(IPASIR)$(LINGELING)$(MINISAT)$(MINISAT2)$(MERGESAT)$(PICOSAT)$(CADICAL),)
3940
MINISAT2 = ../../minisat-2.2.1
4041
endif
4142

@@ -63,6 +64,10 @@ ifneq ($(MINISAT2),)
6364
CP_CXXFLAGS += -DSATCHECK_MINISAT2
6465
endif
6566

67+
ifneq ($(MERGESAT),)
68+
CP_CXXFLAGS += -DSATCHECK_MERGESAT
69+
endif
70+
6671
ifneq ($(GLUCOSE),)
6772
CP_CXXFLAGS += -DSATCHECK_GLUCOSE
6873
endif

src/solvers/CMakeLists.txt

+22-3
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ set(chaff_source
99
set(minisat_source
1010
${CMAKE_CURRENT_SOURCE_DIR}/sat/satcheck_minisat.cpp
1111
)
12-
set(minisat2_source
12+
set(minisat2_mergesat_source
1313
${CMAKE_CURRENT_SOURCE_DIR}/sat/satcheck_minisat2.cpp
1414
)
1515
set(glucose_source
@@ -44,7 +44,7 @@ file(GLOB_RECURSE sources "*.cpp" "*.h")
4444
list(REMOVE_ITEM sources
4545
${chaff_source}
4646
${minisat_source}
47-
${minisat2_source}
47+
${minisat2_mergesat_source}
4848
${glucose_source}
4949
${squolem2_source}
5050
${cudd_source}
@@ -81,9 +81,28 @@ foreach(SOLVER ${sat_impl})
8181
SATCHECK_MINISAT2 HAVE_MINISAT2 __STDC_FORMAT_MACROS __STDC_LIMIT_MACROS
8282
)
8383

84-
target_sources(solvers PRIVATE ${minisat2_source})
84+
target_sources(solvers PRIVATE ${minisat2_mergesat_source})
8585

8686
target_link_libraries(solvers minisat2-condensed)
87+
elseif("${sat_impl}" STREQUAL "mergesat")
88+
message(STATUS "Building solvers with MergeSat")
89+
90+
download_project(PROJ mergesat
91+
URL https://github.com/conp-solutions/mergesat/archive/4.0-rc1.tar.gz
92+
PATCH_COMMAND true
93+
COMMAND cmake -E copy ${CBMC_SOURCE_DIR}/../scripts/mergesat_CMakeLists.txt CMakeLists.txt
94+
URL_MD5 7d38528438101775d972a597a7bf7c2c
95+
)
96+
97+
add_subdirectory(${mergesat_SOURCE_DIR} ${mergesat_BINARY_DIR})
98+
99+
target_compile_definitions(solvers PUBLIC
100+
SATCHECK_MERGESAT HAVE_MERGESAT __STDC_FORMAT_MACROS __STDC_LIMIT_MACROS
101+
)
102+
103+
target_sources(solvers PRIVATE ${minisat2_mergesat_source})
104+
105+
target_link_libraries(solvers mergesat-condensed)
87106
elseif("${SOLVER}" STREQUAL "glucose")
88107
message(STATUS "Building solvers with glucose")
89108

src/solvers/Makefile

+43-1
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,21 @@ ifneq ($(MINISAT2),)
2222
CLEANFILES += $(MINISAT2_LIB) $(patsubst %$(OBJEXT), %$(DEPEXT), $(MINISAT2_LIB))
2323
endif
2424

25+
ifneq ($(MERGESAT),)
26+
# MergeSat is based on MiniSat2 and is invoked (with suitable defines/ifdefs)
27+
# via satcheck_minisat2.{h,cpp}
28+
MERGESAT_SRC=sat/satcheck_minisat2.cpp
29+
MERGESAT_INCLUDE=-I $(MERGESAT)
30+
MERGESAT_LIB=$(MERGESAT)/minisat/core/Lookahead$(OBJEXT) \
31+
$(MERGESAT)/minisat/core/Solver$(OBJEXT) \
32+
$(MERGESAT)/minisat/simp/SimpSolver$(OBJEXT) \
33+
$(MERGESAT)/minisat/utils/ccnr$(OBJEXT) \
34+
$(MERGESAT)/minisat/utils/Options$(OBJEXT) \
35+
$(MERGESAT)/minisat/utils/System$(OBJEXT)
36+
CP_CXXFLAGS += -DHAVE_MERGESAT -D__STDC_FORMAT_MACROS -D__STDC_LIMIT_MACROS
37+
CLEANFILES += $(MERGESAT_LIB) $(patsubst %$(OBJEXT), %$(DEPEXT), $(MERGESAT_LIB))
38+
endif
39+
2540
ifneq ($(IPASIR),)
2641
IPASIR_SRC=sat/satcheck_ipasir.cpp
2742
IPASIR_INCLUDE=-I $(IPASIR)
@@ -75,6 +90,7 @@ SRC = $(BOOLEFORCE_SRC) \
7590
$(GLUCOSE_SRC) \
7691
$(LINGELING_SRC) \
7792
$(MINISAT2_SRC) \
93+
$(MERGESAT_SRC) \
7894
$(IPASIR_SRC) \
7995
$(MINISAT_SRC) \
8096
$(PICOSAT_SRC) \
@@ -230,6 +246,31 @@ $(MINISAT2)/minisat/core/Solver$(OBJEXT): $(MINISAT2)/minisat/core/Solver.cc
230246
endif
231247
endif
232248

249+
ifneq ($(MERGESAT),)
250+
ifeq ($(BUILD_ENV_),MSVC)
251+
sat/satcheck_minisat2$(OBJEXT): sat/satcheck_minisat2.cpp
252+
$(CXX) $(CP_CXXFLAGS) /w /nologo /c /EHsc $< /Fo$@
253+
254+
$(MERGESAT)/minisat/core/Lookahead$(OBJEXT): $(MERGESAT)/minisat/core/Lookahead.cc
255+
$(CXX) $(CP_CXXFLAGS) /w /nologo /c /EHsc $< /Fo$@
256+
257+
$(MERGESAT)/minisat/core/Solver$(OBJEXT): $(MERGESAT)/minisat/core/Solver.cc
258+
$(CXX) $(CP_CXXFLAGS) /w /nologo /c /EHsc $< /Fo$@
259+
260+
$(MERGESAT)/minisat/simp/SimpSolver$(OBJEXT): $(MERGESAT)/minisat/simp/SimpSolver.cc
261+
$(CXX) $(CP_CXXFLAGS) /w /nologo /c /EHsc $< /Fo$@
262+
263+
$(MERGESAT)/minisat/utils/ccnr$(OBJEXT): $(MERGESAT)/minisat/utils/ccnr.cc
264+
$(CXX) $(CP_CXXFLAGS) /w /nologo /c /EHsc $< /Fo$@
265+
266+
$(MERGESAT)/minisat/utils/Options$(OBJEXT): $(MERGESAT)/minisat/utils/Options.cc
267+
$(CXX) $(CP_CXXFLAGS) /w /nologo /c /EHsc $< /Fo$@
268+
269+
$(MERGESAT)/minisat/utils/System$(OBJEXT): $(MERGESAT)/minisat/utils/System.cc
270+
$(CXX) $(CP_CXXFLAGS) /w /nologo /c /EHsc $< /Fo$@
271+
endif
272+
endif
273+
233274
ifneq ($(GLUCOSE),)
234275
ifeq ($(BUILD_ENV_),MSVC)
235276
sat/satcheck_glucose$(OBJEXT): sat/satcheck_glucose.cpp
@@ -245,6 +286,7 @@ endif
245286

246287
INCLUDES += -I .. \
247288
$(CHAFF_INCLUDE) $(BOOLEFORCE_INCLUDE) $(MINISAT_INCLUDE) $(MINISAT2_INCLUDE) \
289+
$(MERGESAT_INCLUDE) \
248290
$(IPASIR_INCLUDE) \
249291
$(SQUOLEM2_INC) $(CUDD_INCLUDE) $(GLUCOSE_INCLUDE) \
250292
$(PICOSAT_INCLUDE) $(LINGELING_INCLUDE) $(CADICAL_INCLUDE)
@@ -263,7 +305,7 @@ endif
263305
endif
264306

265307
SOLVER_LIB = $(CHAFF_LIB) $(BOOLEFORCE_LIB) $(MINISAT_LIB) \
266-
$(MINISAT2_LIB) $(SQUOLEM2_LIB) $(CUDD_LIB) \
308+
$(MINISAT2_LIB) $(MERGESAT_LIB) $(SQUOLEM2_LIB) $(CUDD_LIB) \
267309
$(PICOSAT_LIB) $(LINGELING_LIB) $(GLUCOSE_LIB) $(CADICAL_LIB)
268310

269311
SOLVER_OBJS = $(filter %$(OBJEXT), $(SOLVER_LIB))

src/solvers/sat/satcheck.h

+9-2
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ Author: Daniel Kroening, [email protected]
1717
// #define SATCHECK_ZCHAFF
1818
// #define SATCHECK_MINISAT1
1919
// #define SATCHECK_MINISAT2
20+
// #define SATCHECK_MERGESAT
2021
// #define SATCHECK_GLUCOSE
2122
// #define SATCHECK_BOOLEFORCE
2223
// #define SATCHECK_PICOSAT
@@ -39,6 +40,10 @@ Author: Daniel Kroening, [email protected]
3940
#define SATCHECK_MINISAT2
4041
#endif
4142

43+
#if defined(HAVE_MERGESAT) && !defined(SATCHECK_MERGESAT)
44+
# define SATCHECK_MERGESAT
45+
#endif
46+
4247
#if defined(HAVE_GLUCOSE) && !defined(SATCHECK_GLUCOSE)
4348
#define SATCHECK_GLUCOSE
4449
#endif
@@ -71,7 +76,7 @@ Author: Daniel Kroening, [email protected]
7176
# include "satcheck_minisat.h"
7277
#endif
7378

74-
#if defined SATCHECK_MINISAT2
79+
#if defined(SATCHECK_MINISAT2) || defined(SATCHECK_MERGESAT)
7580
# include "satcheck_minisat2.h"
7681
#endif
7782

@@ -110,7 +115,9 @@ typedef satcheck_booleforcet satcheck_no_simplifiert;
110115
typedef satcheck_minisat1t satcheckt;
111116
typedef satcheck_minisat1t satcheck_no_simplifiert;
112117

113-
#elif defined SATCHECK_MINISAT2
118+
#elif defined SATCHECK_MINISAT2 || defined SATCHECK_MERGESAT
119+
// MergeSat is based on MiniSat2 and is invoked (with suitable defines/ifdefs)
120+
// via satcheck_minisat2.{h,cpp}
114121

115122
typedef satcheck_minisat_simplifiert satcheckt;
116123
typedef satcheck_minisat_no_simplifiert satcheck_no_simplifiert;

src/solvers/sat/satcheck_minisat2.cpp

+37-4
Original file line numberDiff line numberDiff line change
@@ -13,17 +13,20 @@ Author: Daniel Kroening, [email protected]
1313
# include <unistd.h>
1414
#endif
1515

16-
#include <limits>
17-
1816
#include <util/invariant.h>
1917
#include <util/make_unique.h>
2018
#include <util/threeval.h>
2119

2220
#include <minisat/core/Solver.h>
2321
#include <minisat/simp/SimpSolver.h>
2422

25-
#ifndef HAVE_MINISAT2
26-
#error "Expected HAVE_MINISAT2"
23+
#include <cstdlib>
24+
#include <limits>
25+
26+
// MergeSat is based on MiniSat2; variations in their API are handled via
27+
// #ifdefs
28+
#if !defined(HAVE_MINISAT2) && !defined(HAVE_MERGESAT)
29+
# error "Expected HAVE_MINISAT2 or HAVE_MERGESAT"
2730
#endif
2831

2932
void convert(const bvt &bv, Minisat::vec<Minisat::Lit> &dest)
@@ -77,7 +80,11 @@ void satcheck_minisat2_baset<T>::set_polarity(literalt a, bool value)
7780
try
7881
{
7982
add_variables();
83+
#ifdef HAVE_MERGESAT
84+
solver->setPolarity(a.var_no(), value);
85+
#else
8086
solver->setPolarity(a.var_no(), value ? l_True : l_False);
87+
#endif
8188
}
8289
catch(Minisat::OutOfMemoryException)
8390
{
@@ -101,12 +108,20 @@ void satcheck_minisat2_baset<T>::clear_interrupt()
101108

102109
std::string satcheck_minisat_no_simplifiert::solver_text() const
103110
{
111+
#ifdef HAVE_MERGESAT
112+
return "MergeSat 4.0-rc1 without simplifier";
113+
#else
104114
return "MiniSAT 2.2.1 without simplifier";
115+
#endif
105116
}
106117

107118
std::string satcheck_minisat_simplifiert::solver_text() const
108119
{
120+
#ifdef HAVE_MERGESAT
121+
return "MergeSat 4.0-rc1 with simplifier";
122+
#else
109123
return "MiniSAT 2.2.1 with simplifier";
124+
#endif
110125
}
111126

112127
template<typename T>
@@ -257,6 +272,15 @@ propt::resultt satcheck_minisat2_baset<T>::do_prop_solve()
257272

258273
#endif
259274

275+
#ifdef HAVE_MERGESAT
276+
// We do not actually use MergeSat's "constrain" clauses at the moment, but
277+
// MergeSat internally still uses them to track UNSAT. To make sure we
278+
// aren't stuck with "UNSAT" in incremental calls the status needs to be
279+
// reset.
280+
// See also https://github.com/conp-solutions/mergesat/pull/124
281+
((Minisat::Solver *)solver.get())->reset_constrain_clause();
282+
#endif
283+
260284
if(solver_result == l_True)
261285
{
262286
log.status() << "SAT checker: instance is SATISFIABLE" << messaget::eom;
@@ -314,6 +338,15 @@ satcheck_minisat2_baset<T>::satcheck_minisat2_baset(
314338
solver(util_make_unique<T>()),
315339
time_limit_seconds(0)
316340
{
341+
#ifdef HAVE_MERGESAT
342+
if constexpr(std::is_same<T, Minisat::SimpSolver>::value)
343+
{
344+
solver->grow_iterations = false;
345+
// limit the amount of work spent in simplification; the optimal value needs
346+
// to be found via benchmarking
347+
solver->nr_max_simp_cls = 1000000;
348+
}
349+
#endif
317350
}
318351

319352
template <typename T>

0 commit comments

Comments
 (0)