Skip to content

Commit 93cc3bb

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 2e6200a commit 93cc3bb

File tree

8 files changed

+207
-12
lines changed

8 files changed

+207
-12
lines changed

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

Lines changed: 56 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -219,7 +219,7 @@ jobs:
219219
env:
220220
# This is needed in addition to -yq to prevent apt-get from asking for
221221
# user input
222-
DEBIAN_FRONTEND: noninteractive
222+
DEBIAN_FRONTEND: nonint eractive
223223
run: |
224224
sudo apt-get update
225225
sudo apt-get install --no-install-recommends -yq cmake ninja-build gcc gdb g++ maven flex bison libxml2-utils dpkg-dev ccache doxygen graphviz z3
@@ -275,6 +275,61 @@ jobs:
275275
exit 1
276276
fi
277277
278+
# This job takes approximately 29 to 42 minutes
279+
check-ubuntu-24_04-cmake-gcc-mergesat:
280+
runs-on: ubuntu-24.04
281+
steps:
282+
- uses: actions/checkout@v4
283+
with:
284+
submodules: recursive
285+
- name: Fetch dependencies
286+
env:
287+
# This is needed in addition to -yq to prevent apt-get from asking for
288+
# user input
289+
DEBIAN_FRONTEND: noninteractive
290+
run: |
291+
sudo apt-get update
292+
sudo apt-get install --no-install-recommends -yq cmake ninja-build gcc gdb g++ maven flex bison libxml2-utils dpkg-dev ccache doxygen z3
293+
- name: Confirm z3 solver is available and log the version installed
294+
run: z3 --version
295+
- name: Download cvc-5 from the releases page and make sure it can be deployed
296+
run: |
297+
wget https://github.com/cvc5/cvc5/releases/download/cvc5-${{env.cvc5-version}}/cvc5-Linux-x86_64-static.zip
298+
unzip -j -d /usr/local/bin cvc5-Linux-x86_64-static.zip cvc5-Linux-x86_64-static/bin/cvc5
299+
rm cvc5-Linux-x86_64-static.zip
300+
cvc5 --version
301+
- name: Prepare ccache
302+
uses: actions/cache@v4
303+
with:
304+
path: .ccache
305+
key: ${{ runner.os }}-24.04-Release-mergesat-${{ github.ref }}-${{ github.sha }}-PR
306+
restore-keys: |
307+
${{ runner.os }}-24.04-Release-mergesat-${{ github.ref }}
308+
${{ runner.os }}-24.04-Release-mergesat
309+
- name: ccache environment
310+
run: |
311+
echo "CCACHE_BASEDIR=$PWD" >> $GITHUB_ENV
312+
echo "CCACHE_DIR=$PWD/.ccache" >> $GITHUB_ENV
313+
- name: Configure using CMake
314+
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"
315+
- name: Check that doc task works
316+
run: ninja -C build doc
317+
- name: Zero ccache stats and limit in size
318+
run: ccache -z --max-size=500M
319+
- name: Build with Ninja
320+
run: ninja -C build -j${{env.linux-vcpus}}
321+
- name: Print ccache stats
322+
run: ccache -s
323+
- name: Checking completeness of help output
324+
run: scripts/check_help.sh /usr/bin/g++ build/bin
325+
- name: Check if package building works
326+
run: |
327+
cd build
328+
ninja package
329+
ls *.deb
330+
- name: Run tests
331+
run: cd build; ctest . -V -L CORE -j${{env.linux-vcpus}}
332+
278333
# This job takes approximately 20 to 38 minutes
279334
check-ubuntu-22_04-make-clang:
280335
runs-on: ubuntu-22.04

scripts/mergesat_CMakeLists.txt

Lines changed: 29 additions & 0 deletions
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

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -166,6 +166,15 @@ minisat2-download:
166166
@(cd ../minisat-2.2.1; patch -p1 < ../scripts/minisat-2.2.1-patch)
167167
@rm minisat2_2.2.1.orig.tar.gz
168168

169+
mergesat_version = docker-solvers
170+
mergesat-download:
171+
@echo "Downloading MergeSat $(mergesat_version)"
172+
@$(DOWNLOADER) https://github.com/conp-solutions/mergesat/archive/$(mergesat_version).tar.gz
173+
@$(TAR) xfz $(mergesat_version).tar.gz
174+
@rm -Rf ../mergesat
175+
@mv mergesat-$(mergesat_version) ../mergesat
176+
@$(RM) $(mergesat_version).tar.gz
177+
169178
cudd-download:
170179
@echo "Downloading Cudd 3.0.0"
171180
@$(DOWNLOADER) https://sourceforge.net/projects/cudd-mirror/files/cudd-3.0.0.tar.gz/download cudd-3.0.0.tar.gz

src/config.inc

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,12 +33,13 @@ endif
3333
#BOOLEFORCE = ../../booleforce-0.4
3434
#MINISAT = ../../MiniSat-p_v1.14
3535
#MINISAT2 = ../../minisat-2.2.1
36+
#MERGESAT = ../../mergesat-4.0-rc1
3637
#IPASIR = ../../ipasir
3738
#GLUCOSE = ../../glucose-syrup
3839
#CADICAL = ../../cadical
3940

4041
# select default solver to be minisat2 if no other is specified
41-
ifeq ($(BOOLEFORCE)$(CHAFF)$(GLUCOSE)$(IPASIR)$(LINGELING)$(MINISAT)$(MINISAT2)$(PICOSAT)$(CADICAL),)
42+
ifeq ($(BOOLEFORCE)$(CHAFF)$(GLUCOSE)$(IPASIR)$(LINGELING)$(MINISAT)$(MINISAT2)$(MERGESAT)$(PICOSAT)$(CADICAL),)
4243
MINISAT2 = ../../minisat-2.2.1
4344
endif
4445

src/solvers/CMakeLists.txt

Lines changed: 22 additions & 3 deletions
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/docker-solvers.tar.gz
106+
PATCH_COMMAND true
107+
COMMAND cmake -E copy ${CBMC_SOURCE_DIR}/../scripts/mergesat_CMakeLists.txt CMakeLists.txt
108+
URL_MD5 1cef063f3255e86beef91f3cdd2eefb7
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

Lines changed: 43 additions & 1 deletion
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) \
@@ -234,6 +250,31 @@ $(MINISAT2)/minisat/core/Solver$(OBJEXT): $(MINISAT2)/minisat/core/Solver.cc
234250
endif
235251
endif
236252

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

250291
INCLUDES += -I .. \
251292
$(CHAFF_INCLUDE) $(BOOLEFORCE_INCLUDE) $(MINISAT_INCLUDE) $(MINISAT2_INCLUDE) \
293+
$(MERGESAT_INCLUDE) \
252294
$(IPASIR_INCLUDE) \
253295
$(SQUOLEM2_INC) $(CUDD_INCLUDE) $(GLUCOSE_INCLUDE) \
254296
$(PICOSAT_INCLUDE) $(LINGELING_INCLUDE) $(CADICAL_INCLUDE)
@@ -267,7 +309,7 @@ endif
267309
endif
268310

269311
SOLVER_LIB = $(CHAFF_LIB) $(BOOLEFORCE_LIB) $(MINISAT_LIB) \
270-
$(MINISAT2_LIB) $(SQUOLEM2_LIB) $(CUDD_LIB) \
312+
$(MINISAT2_LIB) $(MERGESAT_LIB) $(SQUOLEM2_LIB) $(CUDD_LIB) \
271313
$(PICOSAT_LIB) $(LINGELING_LIB) $(GLUCOSE_LIB) $(CADICAL_LIB)
272314

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

src/solvers/sat/satcheck.h

Lines changed: 9 additions & 2 deletions
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

Lines changed: 37 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -13,21 +13,24 @@ Author: Daniel Kroening, [email protected]
1313
# include <unistd.h>
1414
#endif
1515

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

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

22+
#include <cstdlib>
23+
#include <limits>
24+
2425
#ifndef l_False
2526
# define l_False Minisat::l_False
2627
# define l_True Minisat::l_True
2728
#endif
2829

29-
#ifndef HAVE_MINISAT2
30-
#error "Expected HAVE_MINISAT2"
30+
// MergeSat is based on MiniSat2; variations in their API are handled via
31+
// #ifdefs
32+
#if !defined(HAVE_MINISAT2) && !defined(HAVE_MERGESAT)
33+
# error "Expected HAVE_MINISAT2 or HAVE_MERGESAT"
3134
#endif
3235

3336
void convert(const bvt &bv, Minisat::vec<Minisat::Lit> &dest)
@@ -95,7 +98,11 @@ void satcheck_minisat2_baset<T>::set_polarity(literalt a, bool value)
9598
try
9699
{
97100
add_variables();
101+
#ifdef HAVE_MERGESAT
102+
solver->setPolarity(a.var_no(), value);
103+
#else
98104
solver->setPolarity(a.var_no(), value ? l_True : l_False);
105+
#endif
99106
}
100107
catch(Minisat::OutOfMemoryException)
101108
{
@@ -119,12 +126,20 @@ void satcheck_minisat2_baset<T>::clear_interrupt()
119126

120127
std::string satcheck_minisat_no_simplifiert::solver_text() const
121128
{
129+
#ifdef HAVE_MERGESAT
130+
return "MergeSat 4.0-rc without simplifier";
131+
#else
122132
return "MiniSAT 2.2.1 without simplifier";
133+
#endif
123134
}
124135

125136
std::string satcheck_minisat_simplifiert::solver_text() const
126137
{
138+
#ifdef HAVE_MERGESAT
139+
return "MergeSat 4.0-rc4 with simplifier";
140+
#else
127141
return "MiniSAT 2.2.1 with simplifier";
142+
#endif
128143
}
129144

130145
template<typename T>
@@ -275,6 +290,15 @@ propt::resultt satcheck_minisat2_baset<T>::do_prop_solve(const bvt &assumptions)
275290

276291
#endif
277292

293+
#ifdef HAVE_MERGESAT
294+
// We do not actually use MergeSat's "constrain" clauses at the moment, but
295+
// MergeSat internally still uses them to track UNSAT. To make sure we
296+
// aren't stuck with "UNSAT" in incremental calls the status needs to be
297+
// reset.
298+
// See also https://github.com/conp-solutions/mergesat/pull/124
299+
((Minisat::Solver *)solver.get())->reset_constrain_clause();
300+
#endif
301+
278302
if(solver_result == l_True)
279303
{
280304
log.status() << "SAT checker: instance is SATISFIABLE" << messaget::eom;
@@ -332,6 +356,15 @@ satcheck_minisat2_baset<T>::satcheck_minisat2_baset(
332356
solver(std::make_unique<T>()),
333357
time_limit_seconds(0)
334358
{
359+
#ifdef HAVE_MERGESAT
360+
if constexpr(std::is_same<T, Minisat::SimpSolver>::value)
361+
{
362+
solver->grow_iterations = false;
363+
// limit the amount of work spent in simplification; the optimal value needs
364+
// to be found via benchmarking
365+
solver->nr_max_simp_cls = 1000000;
366+
}
367+
#endif
335368
}
336369

337370
template <typename T>

0 commit comments

Comments
 (0)