Skip to content

Commit 705959e

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 a8de0b7 commit 705959e

File tree

8 files changed

+210
-11
lines changed

8 files changed

+210
-11
lines changed

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

+55
Original file line numberDiff line numberDiff line change
@@ -267,6 +267,61 @@ jobs:
267267
exit 1
268268
fi
269269
270+
# This job takes approximately 29 to 42 minutes
271+
check-ubuntu-20_04-cmake-gcc-mergesat:
272+
runs-on: ubuntu-20.04
273+
steps:
274+
- uses: actions/checkout@v3
275+
with:
276+
submodules: recursive
277+
- name: Fetch dependencies
278+
env:
279+
# This is needed in addition to -yq to prevent apt-get from asking for
280+
# user input
281+
DEBIAN_FRONTEND: noninteractive
282+
run: |
283+
sudo apt-get update
284+
sudo apt-get install --no-install-recommends -yq cmake ninja-build gcc gdb g++ maven flex bison libxml2-utils dpkg-dev ccache doxygen z3
285+
- name: Confirm z3 solver is available and log the version installed
286+
run: z3 --version
287+
- name: Download cvc-5 from the releases page and make sure it can be deployed
288+
run: |
289+
wget -O cvc5 https://github.com/cvc5/cvc5/releases/download/cvc5-${{env.cvc5-version}}/cvc5-Linux
290+
chmod u+x cvc5
291+
mv cvc5 /usr/local/bin
292+
cvc5 --version
293+
- name: Prepare ccache
294+
uses: actions/cache@v3
295+
with:
296+
path: .ccache
297+
key: ${{ runner.os }}-20.04-Release-mergesat-${{ github.ref }}-${{ github.sha }}-PR
298+
restore-keys: |
299+
${{ runner.os }}-20.04-Release-mergesat-${{ github.ref }}
300+
${{ runner.os }}-20.04-Release-mergesat
301+
- name: ccache environment
302+
run: |
303+
echo "CCACHE_BASEDIR=$PWD" >> $GITHUB_ENV
304+
echo "CCACHE_DIR=$PWD/.ccache" >> $GITHUB_ENV
305+
- name: Configure using CMake
306+
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"
307+
- name: Check that doc task works
308+
run: ninja -C build doc
309+
- name: Zero ccache stats and limit in size
310+
run: ccache -z --max-size=500M
311+
- name: Build with Ninja
312+
run: ninja -C build -j2
313+
- name: Print ccache stats
314+
run: ccache -s
315+
- name: Checking completeness of help output
316+
run: scripts/check_help.sh build/bin
317+
- name: Check if package building works
318+
run: |
319+
cd build
320+
ninja package
321+
ls *.deb
322+
- name: Run tests
323+
run: cd build; ctest . -V -L CORE -j2
324+
270325
# This job takes approximately 34 to 38 minutes
271326
check-ubuntu-22_04-make-clang:
272327
runs-on: ubuntu-22.04

scripts/mergesat_CMakeLists.txt

+29
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
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 17
17+
CXX_STANDARD_REQUIRED true
18+
CXX_EXTENSIONS OFF
19+
XCODE_ATTRIBUTE_CODE_SIGN_IDENTITY "Developer ID Application: Daniel Kroening"
20+
)
21+
22+
if("${CMAKE_CXX_COMPILER_ID}" STREQUAL "MSVC")
23+
target_compile_options(mergesat-condensed PUBLIC /w)
24+
endif()
25+
26+
target_include_directories(mergesat-condensed
27+
PUBLIC
28+
${CMAKE_CURRENT_SOURCE_DIR}
29+
)

src/Makefile

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

170+
mergesat_version = v4.0-rc4
171+
mergesat-download:
172+
@echo "Downloading MergeSat $(mergesat_version)"
173+
@$(DOWNLOADER) https://github.com/conp-solutions/mergesat/archive/$(mergesat_version).tar.gz
174+
@$(TAR) xfz $(mergesat_version).tar.gz
175+
@rm -Rf ../mergesat
176+
@mv mergesat-$(mergesat_version) ../mergesat
177+
@$(RM) $(mergesat_version).tar.gz
178+
170179
cudd-download:
171180
@echo "Downloading Cudd 3.0.0"
172181
@$(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,7 +81,7 @@ 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)
8787
elseif("${SOLVER}" STREQUAL "system-minisat2")
@@ -98,6 +98,25 @@ foreach(SOLVER ${sat_impl})
9898
else()
9999
message(FATAL_ERROR "Unable to find header file for preinstalled minisat2")
100100
endif()
101+
elseif("${SOLVER}" STREQUAL "mergesat")
102+
message(STATUS "Building solvers with MergeSat")
103+
104+
download_project(PROJ mergesat
105+
URL https://github.com/conp-solutions/mergesat/archive/v4.0-rc4.tar.gz
106+
PATCH_COMMAND true
107+
COMMAND cmake -E copy ${CBMC_SOURCE_DIR}/../scripts/mergesat_CMakeLists.txt CMakeLists.txt
108+
URL_MD5 aba2a8d6867d0b77f9cefac8515c2d72
109+
)
110+
111+
add_subdirectory(${mergesat_SOURCE_DIR} ${mergesat_BINARY_DIR})
112+
113+
target_compile_definitions(solvers PUBLIC
114+
SATCHECK_MERGESAT HAVE_MERGESAT __STDC_FORMAT_MACROS __STDC_LIMIT_MACROS
115+
)
116+
117+
target_sources(solvers PRIVATE ${minisat2_mergesat_source})
118+
119+
target_link_libraries(solvers mergesat-condensed)
101120
elseif("${SOLVER}" STREQUAL "glucose")
102121
message(STATUS "Building solvers with glucose")
103122

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) \
@@ -232,6 +248,31 @@ $(MINISAT2)/minisat/core/Solver$(OBJEXT): $(MINISAT2)/minisat/core/Solver.cc
232248
endif
233249
endif
234250

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

248289
INCLUDES += -I .. \
249290
$(CHAFF_INCLUDE) $(BOOLEFORCE_INCLUDE) $(MINISAT_INCLUDE) $(MINISAT2_INCLUDE) \
291+
$(MERGESAT_INCLUDE) \
250292
$(IPASIR_INCLUDE) \
251293
$(SQUOLEM2_INC) $(CUDD_INCLUDE) $(GLUCOSE_INCLUDE) \
252294
$(PICOSAT_INCLUDE) $(LINGELING_INCLUDE) $(CADICAL_INCLUDE)
@@ -265,7 +307,7 @@ endif
265307
endif
266308

267309
SOLVER_LIB = $(CHAFF_LIB) $(BOOLEFORCE_LIB) $(MINISAT_LIB) \
268-
$(MINISAT2_LIB) $(SQUOLEM2_LIB) $(CUDD_LIB) \
310+
$(MINISAT2_LIB) $(MERGESAT_LIB) $(SQUOLEM2_LIB) $(CUDD_LIB) \
269311
$(PICOSAT_LIB) $(LINGELING_LIB) $(GLUCOSE_LIB) $(CADICAL_LIB)
270312

271313
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)
@@ -91,7 +94,11 @@ void satcheck_minisat2_baset<T>::set_polarity(literalt a, bool value)
9194
try
9295
{
9396
add_variables();
97+
#ifdef HAVE_MERGESAT
98+
solver->setPolarity(a.var_no(), value);
99+
#else
94100
solver->setPolarity(a.var_no(), value ? l_True : l_False);
101+
#endif
95102
}
96103
catch(Minisat::OutOfMemoryException)
97104
{
@@ -115,12 +122,20 @@ void satcheck_minisat2_baset<T>::clear_interrupt()
115122

116123
std::string satcheck_minisat_no_simplifiert::solver_text() const
117124
{
125+
#ifdef HAVE_MERGESAT
126+
return "MergeSat 4.0-rc4 without simplifier";
127+
#else
118128
return "MiniSAT 2.2.1 without simplifier";
129+
#endif
119130
}
120131

121132
std::string satcheck_minisat_simplifiert::solver_text() const
122133
{
134+
#ifdef HAVE_MERGESAT
135+
return "MergeSat 4.0-rc4 with simplifier";
136+
#else
123137
return "MiniSAT 2.2.1 with simplifier";
138+
#endif
124139
}
125140

126141
template<typename T>
@@ -271,6 +286,15 @@ propt::resultt satcheck_minisat2_baset<T>::do_prop_solve(const bvt &assumptions)
271286

272287
#endif
273288

289+
#ifdef HAVE_MERGESAT
290+
// We do not actually use MergeSat's "constrain" clauses at the moment, but
291+
// MergeSat internally still uses them to track UNSAT. To make sure we
292+
// aren't stuck with "UNSAT" in incremental calls the status needs to be
293+
// reset.
294+
// See also https://github.com/conp-solutions/mergesat/pull/124
295+
((Minisat::Solver *)solver.get())->reset_constrain_clause();
296+
#endif
297+
274298
if(solver_result == l_True)
275299
{
276300
log.status() << "SAT checker: instance is SATISFIABLE" << messaget::eom;
@@ -328,6 +352,15 @@ satcheck_minisat2_baset<T>::satcheck_minisat2_baset(
328352
solver(util_make_unique<T>()),
329353
time_limit_seconds(0)
330354
{
355+
#ifdef HAVE_MERGESAT
356+
if constexpr(std::is_same<T, Minisat::SimpSolver>::value)
357+
{
358+
solver->grow_iterations = false;
359+
// limit the amount of work spent in simplification; the optimal value needs
360+
// to be found via benchmarking
361+
solver->nr_max_simp_cls = 1000000;
362+
}
363+
#endif
331364
}
332365

333366
template <typename T>

0 commit comments

Comments
 (0)