├── .gitmodules ├── setup.cfg ├── scripts ├── build_scripts │ ├── build_static.sh │ ├── build_norm.sh │ ├── build_static_release.sh │ ├── build_sanitize.sh │ └── build_emscripten.sh └── cluster_scripts │ ├── create_solvetimes.sh │ ├── create_solvetime_old.sh │ ├── solvetimes_from_output_appmc2.sh │ ├── solvetimes_from_output.sh │ ├── solvetimes_from_output_old.sh │ └── solved_with_options.sh ├── .gitignore ├── MANIFEST.in ├── cmake ├── FindGMP.cmake ├── AddGTestSuite.cmake ├── cmake_uninstall.cmake.in ├── AddSTPGTest.cmake ├── GetGitRevisionDescription.cmake.in └── GetGitRevisionDescription.cmake ├── .github └── workflows │ ├── nix.yml │ ├── python-package-build.yml │ ├── python-wheel-build.yml │ └── build.yml ├── pyproject.toml ├── approxmcConfig.cmake.in ├── LICENSE ├── python ├── tests │ ├── test.py │ ├── test_pyapproxmc.py │ └── test_1.cnf ├── src │ ├── GitSHA1.cpp │ └── pyapproxmc.cpp └── README.md ├── src ├── GitSHA1.h ├── GitSHA1.cpp.in ├── appmc_constants.h ├── appmcconfig.h ├── approxmc.h ├── CMakeLists.txt ├── appmc_constants.cpp ├── counter.h ├── time_mem.h ├── approxmc.cpp └── main.cpp ├── flake.nix ├── tests ├── CMakeLists.txt ├── simpletest.cpp └── test_helper.h ├── setup.py ├── README.md ├── html └── index.html ├── flake.lock └── CMakeLists.txt /.gitmodules: -------------------------------------------------------------------------------- 1 | [submodule "utils/gtest"] 2 | path = tests/gtest 3 | url = https://github.com/google/googletest 4 | -------------------------------------------------------------------------------- /setup.cfg: -------------------------------------------------------------------------------- 1 | [metadata] 2 | url = https://github.com/meelgroup/approxmc 3 | long_description_content_type = "text/markdown" 4 | 5 | [options] 6 | python_requires = >=3.5 7 | -------------------------------------------------------------------------------- /scripts/build_scripts/build_static.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | set -e 4 | 5 | rm -rf lib* Test* tests* include tests scalmc* CM* cmake* 6 | cmake -DSTATICCOMPILE=ON .. 7 | make -j12 8 | -------------------------------------------------------------------------------- /scripts/build_scripts/build_norm.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | set -e 4 | 5 | rm -rf lib* Test* tests* include tests scalmc* CM* cmake* approxmc* apx-src 6 | cmake -DENABLE_TESTING=ON .. 7 | make -j16 8 | make test 9 | -------------------------------------------------------------------------------- /scripts/build_scripts/build_static_release.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | set -e 4 | 5 | rm -rf lib* Test* tests* include tests scalmc* CM* cmake* 6 | cmake -DCMAKE_BUILD_TYPE=Release -DSTATICCOMPILE=ON .. 7 | make -j12 8 | -------------------------------------------------------------------------------- /scripts/build_scripts/build_sanitize.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | set -e 4 | 5 | rm -rf lib* Test* tests* include tests scalmc* CM* cmake* 6 | CXX=clang++ cmake -DENABLE_TESTING=ON -DSANITIZE=ON .. 7 | make -j6 8 | make test 9 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | build/ 2 | .kdev4/ 3 | python/cryptominisat 4 | python/arjun 5 | *.kdev4 6 | .cache/ 7 | .ccls-cache/ 8 | compile_commands.json 9 | dist/pyapproxmc* 10 | compare 11 | /result 12 | html/*.js 13 | html/*.wasm 14 | -------------------------------------------------------------------------------- /MANIFEST.in: -------------------------------------------------------------------------------- 1 | include LICENSE 2 | include README.md 3 | global-exclude *.json 4 | global-exclude *.timeout 5 | global-exclude *.in 6 | global-exclude *.txt 7 | recursive-include src/ *.h 8 | recursive-include python/src/ *.h *.hpp *.cpp 9 | -------------------------------------------------------------------------------- /cmake/FindGMP.cmake: -------------------------------------------------------------------------------- 1 | find_path(GMP_INCLUDE_DIRS NAMES gmp.h) 2 | find_library(GMP_LIBRARY NAMES gmp libgmp) 3 | include(FindPackageHandleStandardArgs) 4 | find_package_handle_standard_args(GMP DEFAULT_MSG 5 | GMP_INCLUDE_DIRS 6 | GMP_LIBRARY) 7 | mark_as_advanced(GMP_INCLUDE_DIRS GMP_LIBRARY) 8 | -------------------------------------------------------------------------------- /scripts/cluster_scripts/create_solvetimes.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | module unload gcc/4.9.3 4 | module load anaconda/3 5 | module load openmpi/intel/1.10.2 6 | for x in `ls | grep $1`; do 7 | (cd $x 8 | echo At $x 9 | pwd 10 | ../solvetimes_from_output.sh 11 | ); 12 | done 13 | 14 | -------------------------------------------------------------------------------- /scripts/cluster_scripts/create_solvetime_old.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | module unload gcc/4.9.3 4 | module load anaconda/3 5 | module load openmpi/intel/1.10.2 6 | for x in `ls | grep $1`; do 7 | (cd $x 8 | echo At $x 9 | pwd 10 | ../solvetimes_from_output_old.sh 11 | ); 12 | done 13 | 14 | -------------------------------------------------------------------------------- /scripts/build_scripts/build_emscripten.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | set -e 3 | rm -rf lib* Test* tests* include tests scalmc* CM* cmake* approxmc* apx-src 4 | emcmake cmake -DCMAKE_INSTALL_PREFIX=$EMINSTALL .. 5 | emmake make -j16 6 | emmake make install 7 | cp approxmc.wasm ../html 8 | cp $EMINSTALL/bin/approxmc.js ../html 9 | -------------------------------------------------------------------------------- /scripts/cluster_scripts/solvetimes_from_output_appmc2.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | xzgrep "at least" *.out.xz | sed "s/no_w.cnf.gz.*/no_w.cnf.gz/" > solved.csv 4 | ls *.out.xz | sed "s/.cnf.*/.cnf/" > all_files.csv 5 | rm solveTimes.csv 6 | for a in `cat solved.csv`; do 7 | time=`xzgrep "User time" "$a.timeout.xz" | awk '{print $4}'` 8 | echo "$time $a" >> solveTimes.csv 9 | done 10 | -------------------------------------------------------------------------------- /.github/workflows/nix.yml: -------------------------------------------------------------------------------- 1 | name: nix build 2 | 3 | on: 4 | push: 5 | branches: [ "*" ] 6 | pull_request: 7 | branches: [ "*" ] 8 | 9 | jobs: 10 | tests: 11 | runs-on: ubuntu-latest 12 | steps: 13 | - uses: actions/checkout@v4 14 | - uses: cachix/install-nix-action@v25 15 | with: 16 | nix_path: nixpkgs=channel:nixos-unstable 17 | - uses: cachix/cachix-action@v14 18 | with: 19 | name: msoos 20 | # If you chose API tokens for write access OR if you have a private cache 21 | authToken: '${{ secrets.CACHIX_AUTH_TOKEN }}' 22 | - run: nix build 23 | -------------------------------------------------------------------------------- /scripts/cluster_scripts/solvetimes_from_output.sh: -------------------------------------------------------------------------------- 1 | xzgrep -i "terminated" *.timeout.xz | sed -e "s/.gz[^ ]*//" | awk '{print $1 " " $5}' > signals.csv 2 | ls -- *.out.xz > allFiles_xz.csv 3 | ls -- *.out.xz | sed "s/.gz.*/.gz/" > allFiles.csv 4 | xzgrep "FINISHED" *.out.xz | sed -e "s/.gz[^ ]*//" | awk '{print $6 " " $1}' > solveTimes.csv 5 | awk '{print $2}' solveTimes.csv > solved.csv 6 | grep -v -f solved.csv allFiles.csv | sed "s/.gz.*/.gz/" > unsolved.csv 7 | cat unsolved.csv | awk '{print "5000.00 " $1}' >> solveTimes.csv 8 | awk '{print $2 " " $1}' solveTimes.csv | sort > solveTimes_rev.csv 9 | awk '{if ($1=="5000.00") {x+=10000} else {x += $1};} END {printf "%d\n", x}' solveTimes.csv > PAR2score 10 | -------------------------------------------------------------------------------- /scripts/cluster_scripts/solvetimes_from_output_old.sh: -------------------------------------------------------------------------------- 1 | xzgrep -i "terminated" *.timeout.xz | sed -e "s/.gz[^ ]*//" | awk '{print $1 " " $5}' > signals.csv 2 | ls -- *.out.xz > allFiles_xz.csv 3 | ls -- *.out.xz | sed "s/.gz.*/.gz/" > allFiles.csv 4 | xzgrep "FINISHED" *.out.xz | sed -e "s/.gz[^ ]*//" | awk '{print $5 " " $1}' > solveTimes.csv 5 | awk '{print $2}' solveTimes.csv > solved.csv 6 | grep -v -f solved.csv allFiles.csv | sed "s/.gz.*/.gz/" > unsolved.csv 7 | cat unsolved.csv | awk '{print "5000.00 " $1}' >> solveTimes.csv 8 | awk '{print $2 " " $1}' solveTimes.csv | sort > solveTimes_rev.csv 9 | awk '{if ($1=="5000.00") {x+=10000} else {x += $1};} END {printf "%d\n", x}' solveTimes.csv > PAR2score 10 | -------------------------------------------------------------------------------- /pyproject.toml: -------------------------------------------------------------------------------- 1 | [build-system] 2 | requires = ["setuptools>=42", "wheel", "toml", "pathlib"] 3 | build-backend = "setuptools.build_meta" 4 | 5 | [project] 6 | name = "pyapproxmc" 7 | version = "4.2.0" 8 | description = "Bindings to ApproxMC, an approximate model counter" 9 | keywords = ["sat", "model-counting"] 10 | license = { file = "LICENSE" } 11 | maintainers = [{name="Mate Soos", email="soos.mate@gmail.com"}] 12 | authors = [{name="Mate Soos", email="soos.mate@gmail.com"}] 13 | classifiers = [ 14 | "Development Status :: 4 - Beta", 15 | "Intended Audience :: Developers", 16 | "Operating System :: OS Independent", 17 | "Programming Language :: C++", 18 | "Programming Language :: Python :: 3", 19 | "Programming Language :: Python :: 3.5", 20 | "License :: OSI Approved :: MIT License", 21 | "Topic :: Utilities" 22 | ] 23 | requires-python = ">=3.5" 24 | readme = "python/README.md" 25 | -------------------------------------------------------------------------------- /approxmcConfig.cmake.in: -------------------------------------------------------------------------------- 1 | # Config file for the @EXPORT_TYPE@ cryptominisat Package 2 | # It defines the following variables 3 | # APPROXMC_INCLUDE_DIRS - include directories for cryptominisat5 4 | # APPROXMC_LIBRARIES - libraries to link against 5 | # APPROXMC_EXECUTABLE - the cryptominisat executable 6 | 7 | # Compute paths 8 | get_filename_component(APPROXMC_CMAKE_DIR "${CMAKE_CURRENT_LIST_FILE}" PATH) 9 | set(APPROXMC_INCLUDE_DIRS "@CONF_INCLUDE_DIRS@") 10 | 11 | # Our library dependencies (contains definitions for IMPORTED targets) 12 | include("${APPROXMC_CMAKE_DIR}/@APPROXMC_TARGETS_FILENAME@") 13 | 14 | # These are IMPORTED targets created by @APPROXMC_TARGETS_FILENAME@ 15 | set(APPROXMC_LIBRARIES approxmc) 16 | set(APPROXMC_STATIC_LIBRARIES approxmc) 17 | set(APPROXMC_STATIC_LIBRARIES_DEPS @APPROXMC_STATIC_DEPS@) 18 | set(APPROXMC_VERSION_MAJOR @PROJECT_VERSION_MAJOR@) 19 | set(APPROXMC_VERSION_MINOR @PROJECT_VERSION_MINOR@) 20 | set(APPROXMC_EXECUTABLE approxmc) 21 | -------------------------------------------------------------------------------- /cmake/AddGTestSuite.cmake: -------------------------------------------------------------------------------- 1 | # Sets for the current directory (and below) the testsuite to use. 2 | # This macro should be used with the AddSTPGTest function. 3 | macro(AddGTestSuite TESTSUITENAME) 4 | set(TESTSUITE "${TESTSUITENAME}") # Unit test group name 5 | # Setup custom target 6 | add_custom_target(${TESTSUITE}) 7 | add_dependencies(check ${TESTSUITE}) 8 | 9 | if(USE_VALGRIND) 10 | set(LIT_EXTRA_FLAGS --vg --vg-leak) 11 | else() 12 | set(LIT_EXTRA_FLAGS "") 13 | endif() 14 | 15 | add_custom_command(TARGET ${TESTSUITE} 16 | POST_BUILD 17 | COMMAND ${LIT_TOOL} ${LIT_ARGS} ${LIT_EXTRA_FLAGS} ${CMAKE_CURRENT_BINARY_DIR} 18 | COMMENT "Running ${TESTSUITE}" 19 | ) 20 | 21 | # Setup lit configuration 22 | configure_file(${CMAKE_SOURCE_DIR}/tests/lit-unit-tests-common.site.cfg.in 23 | ${CMAKE_CURRENT_BINARY_DIR}/lit.site.cfg 24 | @ONLY@ 25 | ) 26 | endmacro() 27 | -------------------------------------------------------------------------------- /scripts/cluster_scripts/solved_with_options.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | check="$1" 4 | FILE="20180321_110706599_p_cnf_320_1120.cnf" 5 | FILE="001-80-12-sc2014.cnf" 6 | FILE="01A-1.cnf.gz.no_w.cnf" 7 | FILE="01A-1.cnf.gz.no_w.cnf" 8 | 9 | rm out 10 | for d in `ls | grep $check`; do 11 | echo $d; 12 | PAR2=`cat $d/PAR2score` 13 | name=`xzgrep "Command being" $d/${FILE}.gz.timeout.xz` 14 | numsolved=`wc -l $d/solved.csv | awk '{print $1}'` 15 | numALL=`wc -l $d/allFiles.csv | awk '{print $1}'` 16 | #c Arjun SHA revision 8885476de181e6efe9ab3038ded86ed0bcd9cfec 17 | revArj=`xzgrep -i "Arjun.*revision" $d/${FILE}.gz.out.xz | awk '{print $5}' | cut -c1-7` 18 | revCMS=`xzgrep -i "CMS.*revision" $d/${FILE}.gz.out.xz | awk '{print $5}' | cut -c1-7` 19 | revApp=`xzgrep -i "AppMC.*revision" $d/${FILE}.gz.out.xz | awk '{print $5}' | cut -c1-7` 20 | echo "$PAR2 $d $numsolved $numALL $revApp $revCMS $revArj $name" >> out 21 | done 22 | sed "s/${FILE}.*//" out | sed "s/Command.*time.*approxmc//" | sed "s/.solved.csv//" | sed "s/ *Command being timed.*approxmc//" | sed "s/\t/ /g" | sed "s/\t/ /g" | sort -n 23 | -------------------------------------------------------------------------------- /cmake/cmake_uninstall.cmake.in: -------------------------------------------------------------------------------- 1 | cmake_policy(SET CMP0007 NEW) # Suppress warnings see `cmake --help-policy CMP0007` 2 | 3 | if (NOT EXISTS "@CMAKE_CURRENT_BINARY_DIR@/install_manifest.txt") 4 | message(FATAL_ERROR "Cannot find install manifest: \"@CMAKE_CURRENT_BINARY_DIR@/install_manifest.txt\"") 5 | endif(NOT EXISTS "@CMAKE_CURRENT_BINARY_DIR@/install_manifest.txt") 6 | 7 | file(READ "@CMAKE_CURRENT_BINARY_DIR@/install_manifest.txt" files) 8 | string(REGEX REPLACE "\n" ";" files "${files}") 9 | list(REVERSE files) 10 | foreach (file ${files}) 11 | message(STATUS "Uninstalling \"$ENV{DESTDIR}${file}\"") 12 | if (EXISTS "$ENV{DESTDIR}${file}") 13 | execute_process( 14 | COMMAND @CMAKE_COMMAND@ -E remove "$ENV{DESTDIR}${file}" 15 | OUTPUT_VARIABLE rm_out 16 | RESULT_VARIABLE rm_retval 17 | ) 18 | if(NOT ${rm_retval} EQUAL 0) 19 | message(FATAL_ERROR "Problem when removing \"$ENV{DESTDIR}${file}\"") 20 | endif (NOT ${rm_retval} EQUAL 0) 21 | else (EXISTS "$ENV{DESTDIR}${file}") 22 | message(STATUS "File \"$ENV{DESTDIR}${file}\" does not exist.") 23 | endif (EXISTS "$ENV{DESTDIR}${file}") 24 | endforeach(file) 25 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2018 Meel Group 4 | Kuldeep Meel 5 | Mate Soos 6 | Daniel Freemont 7 | and others 8 | 9 | Permission is hereby granted, free of charge, to any person obtaining a copy 10 | of this software and associated documentation files (the "Software"), to deal 11 | in the Software without restriction, including without limitation the rights 12 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 13 | copies of the Software, and to permit persons to whom the Software is 14 | furnished to do so, subject to the following conditions: 15 | 16 | The above copyright notice and this permission notice shall be included in all 17 | copies or substantial portions of the Software. 18 | 19 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 20 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 21 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 22 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 23 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 24 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 25 | SOFTWARE. 26 | -------------------------------------------------------------------------------- /python/tests/test.py: -------------------------------------------------------------------------------- 1 | #!/bin/python3 2 | 3 | import pyapproxmc 4 | import sys 5 | 6 | fname = sys.argv[1] 7 | print("using file: ", fname) 8 | solver = pyapproxmc.Counter(verbosity=1) 9 | 10 | num_cls = 0 11 | p_found = False 12 | p = [] 13 | with open(fname, "r") as f: 14 | for line in f: 15 | line = line.strip() 16 | if len(line) == 0: continue 17 | if line[0] == "c": 18 | line = line.split(" ") 19 | if len(line) < 3: continue 20 | if line[1] != "ind": continue 21 | p_found = True 22 | for l in line[2:]: 23 | l = int(l) 24 | if l != 0: 25 | p.append(l) 26 | 27 | continue 28 | if line[0] == "p": continue 29 | # print(line) 30 | clause = [] 31 | for l in line.split(" "): 32 | # print(l) 33 | l = int(l) 34 | if l == 0: break 35 | clause.append(l) 36 | solver.add_clause(clause) 37 | num_cls+=1 38 | print("num cls: ", num_cls) 39 | if not p_found: 40 | print("ERRROR: no projection found!!") 41 | exit(-1) 42 | print("projection: " , p) 43 | 44 | ret = solver.count(projection=p) 45 | print("ret:", ret) 46 | -------------------------------------------------------------------------------- /cmake/AddSTPGTest.cmake: -------------------------------------------------------------------------------- 1 | # AddSTPGTest( [ ...]) 2 | # 3 | # Adds a GoogleTest to the current test suite (${TESTSUITE}) 4 | # with executable name with the file extension removed and 5 | # the UNIT_TEST_EXE_SUFFIX appended. 6 | # The executable will be linked with libstp. 7 | # Remaining arguments to this function are interpreted as preprocessor macros 8 | # to defines. 9 | # 10 | # e.g. 11 | # AddSTPGTest(mysimpleprogram.cpp FOO=15 BAR=\"a string\") 12 | # 13 | function(AddSTPGTest sourcefile) 14 | get_filename_component(testname ${sourcefile} NAME_WE) 15 | 16 | # testname has suffix because lit expects this 17 | set(testname "${testname}${UNIT_TEST_EXE_SUFFIX}") 18 | 19 | add_executable(${testname} EXCLUDE_FROM_ALL ${sourcefile}) 20 | 21 | # Add define flags requested by users 22 | list(LENGTH ARGN LEN_ARGN) 23 | if(LEN_ARGN GREATER 0) 24 | set_property(TARGET ${testname} APPEND PROPERTY COMPILE_DEFINITIONS ${ARGN}) 25 | #message(STATUS "Added flags to test ${testname} ${ARGN}") 26 | endif() 27 | 28 | target_link_libraries(${testname} libstp ${GTEST_BOTH_LIBRARIES}) 29 | 30 | # Add dependency so that building the testsuite 31 | # will cause this test (testname) to be built 32 | add_dependencies(${TESTSUITE} ${testname}) 33 | endfunction() 34 | -------------------------------------------------------------------------------- /cmake/GetGitRevisionDescription.cmake.in: -------------------------------------------------------------------------------- 1 | # 2 | # Internal file for GetGitRevisionDescription.cmake 3 | # 4 | # Requires CMake 2.6 or newer (uses the 'function' command) 5 | # 6 | # Original Author: 7 | # 2009-2010 Ryan Pavlik 8 | # http://academic.cleardefinition.com 9 | # Iowa State University HCI Graduate Program/VRAC 10 | # 11 | # Copyright Iowa State University 2009-2010. 12 | # Distributed under the Boost Software License, Version 1.0. 13 | # (See accompanying file LICENSE_1_0.txt or copy at 14 | # http://www.boost.org/LICENSE_1_0.txt) 15 | 16 | set(HEAD_HASH) 17 | 18 | file(READ "@HEAD_FILE@" HEAD_CONTENTS LIMIT 1024) 19 | 20 | string(STRIP "${HEAD_CONTENTS}" HEAD_CONTENTS) 21 | if(HEAD_CONTENTS MATCHES "ref") 22 | # named branch 23 | string(REPLACE "ref: " "" HEAD_REF "${HEAD_CONTENTS}") 24 | if(EXISTS "@GIT_DIR@/${HEAD_REF}") 25 | configure_file("@GIT_DIR@/${HEAD_REF}" "@GIT_DATA@/head-ref" COPYONLY) 26 | elseif(EXISTS "@GIT_DIR@/logs/${HEAD_REF}") 27 | configure_file("@GIT_DIR@/logs/${HEAD_REF}" "@GIT_DATA@/head-ref" COPYONLY) 28 | set(HEAD_HASH "${HEAD_REF}") 29 | endif() 30 | else() 31 | # detached HEAD 32 | configure_file("@GIT_DIR@/HEAD" "@GIT_DATA@/head-ref" COPYONLY) 33 | endif() 34 | 35 | if(NOT HEAD_HASH) 36 | file(READ "@GIT_DATA@/head-ref" HEAD_HASH LIMIT 1024) 37 | string(STRIP "${HEAD_HASH}" HEAD_HASH) 38 | endif() 39 | -------------------------------------------------------------------------------- /src/GitSHA1.h: -------------------------------------------------------------------------------- 1 | /****************************************** 2 | Copyright (c) 2016, Mate Soos 3 | 4 | Permission is hereby granted, free of charge, to any person obtaining a copy 5 | of this software and associated documentation files (the "Software"), to deal 6 | in the Software without restriction, including without limitation the rights 7 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8 | copies of the Software, and to permit persons to whom the Software is 9 | furnished to do so, subject to the following conditions: 10 | 11 | The above copyright notice and this permission notice shall be included in 12 | all copies or substantial portions of the Software. 13 | 14 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 20 | THE SOFTWARE. 21 | ***********************************************/ 22 | 23 | #ifndef GITSHA1_H 24 | #define GITSHA1_H 25 | 26 | namespace AppMCInt { 27 | 28 | const char* get_version_sha1(); 29 | const char* get_version_tag(); 30 | const char* get_compilation_env(); 31 | 32 | } 33 | 34 | #endif //GITSHA1_H 35 | -------------------------------------------------------------------------------- /python/src/GitSHA1.cpp: -------------------------------------------------------------------------------- 1 | /****************************************** 2 | Copyright (c) 2017, Mate Soos 3 | 4 | Permission is hereby granted, free of charge, to any person obtaining a copy 5 | of this software and associated documentation files (the "Software"), to deal 6 | in the Software without restriction, including without limitation the rights 7 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8 | copies of the Software, and to permit persons to whom the Software is 9 | furnished to do so, subject to the following conditions: 10 | 11 | The above copyright notice and this permission notice shall be included in 12 | all copies or substantial portions of the Software. 13 | 14 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 20 | THE SOFTWARE. 21 | ***********************************************/ 22 | 23 | #include "../../src/GitSHA1.h" 24 | 25 | const char* AppMCInt::get_version_sha1() 26 | { 27 | static const char myversion_sha1[] = "python-build"; 28 | return myversion_sha1; 29 | } 30 | 31 | const char* AppMCInt::get_version_tag() 32 | { 33 | static const char myversion_tag[] = "see-python-package-version"; 34 | return myversion_tag; 35 | } 36 | 37 | const char* AppMCInt::get_compilation_env() 38 | { 39 | static const char compilation_env[] = "python-build" 40 | ; 41 | return compilation_env; 42 | } 43 | -------------------------------------------------------------------------------- /src/GitSHA1.cpp.in: -------------------------------------------------------------------------------- 1 | /****************************************** 2 | Copyright (c) 2017, Mate Soos 3 | 4 | Permission is hereby granted, free of charge, to any person obtaining a copy 5 | of this software and associated documentation files (the "Software"), to deal 6 | in the Software without restriction, including without limitation the rights 7 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8 | copies of the Software, and to permit persons to whom the Software is 9 | furnished to do so, subject to the following conditions: 10 | 11 | The above copyright notice and this permission notice shall be included in 12 | all copies or substantial portions of the Software. 13 | 14 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 20 | THE SOFTWARE. 21 | ***********************************************/ 22 | 23 | #include "src/GitSHA1.h" 24 | 25 | const char* AppMCInt::get_version_sha1() 26 | { 27 | static const char myversion_sha1[] = "@GIT_SHA1@"; 28 | return myversion_sha1; 29 | } 30 | 31 | const char* AppMCInt::get_version_tag() 32 | { 33 | static const char myversion_tag[] = "@PROJECT_VERSION@"; 34 | return myversion_tag; 35 | } 36 | 37 | const char* AppMCInt::get_compilation_env() 38 | { 39 | static const char compilation_env[] = 40 | "CMAKE_CXX_COMPILER = @CMAKE_CXX_COMPILER@ | " 41 | "CMAKE_CXX_FLAGS = @CMAKE_CXX_FLAGS@ | " 42 | "COMPILE_DEFINES = @COMPILE_DEFINES@ | " 43 | "STATICCOMPILE = @STATICCOMPILE@ | " 44 | "ZLIB_FOUND = @ZLIB_FOUND@ | " 45 | "VALGRIND_FOUND = @VALGRIND_FOUND@ | " 46 | "GMP_FOUND = @GMP_FOUND@ | " 47 | "ENABLE_ASSERTIONS = @ENABLE_ASSERTIONS@ | " 48 | ; 49 | return compilation_env; 50 | } 51 | -------------------------------------------------------------------------------- /python/README.md: -------------------------------------------------------------------------------- 1 | # pyapproxmc: bindings to the ApproxMC model counter 2 | This directory provides Python bindings to ApproxMC on the C++ level, 3 | i.e. when importing pyapproxmc, the ApproxMC counter becomes part of the 4 | Python process itself. 5 | 6 | ## Installing 7 | ```plain 8 | pip install pyapproxmc 9 | ``` 10 | 11 | ## Compiling 12 | If you don't want to use the pip package, you can compile it: 13 | ```plain 14 | apt-get install python-dev 15 | cd python 16 | git clone https://github.com/msoos/cryptominisat 17 | git clone https://github.com/meelgroup/arjun 18 | cd .. 19 | python -m build 20 | ``` 21 | 22 | You will then find the files under "dist/". 23 | 24 | ## Usage 25 | ``` 26 | import pyapproxmc 27 | c = pyapproxmc.Counter() 28 | c.add_clause([1,2,3]) 29 | c.add_clause([3,20]) 30 | count = c.count() 31 | print("Approximate count is: %d*2**%d" % (count[0], count[1])) 32 | ``` 33 | 34 | The above will print that `Approximate count is: 88*2**13`. Since the largest 35 | variable in the clauses was 20, the system contained 2**20 (i.e. 1048576) 36 | potential models. However, some of these models were prohibited by the two 37 | clauses, and so only approximately 88*2**13 (i.e. 720896) models remained. 38 | 39 | If you want to count over a projection set, you need to call 40 | `count(projection_set)`, for example: 41 | ```python 42 | import pyapproxmc 43 | c = pyapproxmc.Counter() 44 | c.add_clause([1,2,3]) 45 | c.add_clause([3,20]) 46 | count = c.count(range(1,10)) 47 | print("Approximate count is: %d*2**%d" % (count[0], count[1])) 48 | ``` 49 | 50 | This now prints `Approximate count is: 56*2**3`, which corresponds to the 51 | approximate count of models, projected over variables 1..10. 52 | 53 | ## Counter Object 54 | You can give the following arguments to `Counter`: 55 | * `seed` -- sets the random seed 56 | * `verbosity` -- sets the verbosity of the system (default = 0) 57 | * `epsilon` -- Tolerance parameter, i.e. sets how approximate the returned 58 | count is. Default = 0.8 59 | * `delta` -- Confidence parameter, i.e. sets how probabilistically correct the 60 | returned count is. Default = 0.20 61 | 62 | -------------------------------------------------------------------------------- /.github/workflows/python-package-build.yml: -------------------------------------------------------------------------------- 1 | name: Python tarball build 2 | 3 | on: [push, pull_request] 4 | # release: 5 | # types: [created] 6 | 7 | jobs: 8 | deploy: 9 | runs-on: ubuntu-latest 10 | steps: 11 | - uses: actions/checkout@v2 12 | - name: Set up Python 13 | uses: actions/setup-python@v1 14 | with: 15 | python-version: 3.8 16 | - name: Install dependencies 17 | run: | 18 | python -m pip install --upgrade pip 19 | pip install twine flake8 20 | - name: Checkout CMS 21 | uses: actions/checkout@v2 22 | with: 23 | repository: msoos/cryptominisat 24 | ref: 'master' 25 | path: python/cryptominisat 26 | - name: Checkout Arjun 27 | uses: actions/checkout@v2 28 | with: 29 | repository: meelgroup/arjun 30 | path: python/arjun 31 | # - name: Lint with flake8 for syntax errors 32 | # run: | 33 | # pip install flake8 34 | # flake8 . --count --select=E9,F63,F7,F82 --show-source --statistics 35 | # flake8 . --count --exit-zero --max-complexity=10 --max-line-length=127 --statistics 36 | - name: Get Python3 37 | uses: actions/setup-python@v3 38 | with: 39 | python-version: "3.10" 40 | - name: Install pypa/build 41 | run: >- 42 | python -m 43 | pip install 44 | build 45 | --user 46 | - name: Build a source tarball 47 | run: >- 48 | python -m 49 | build 50 | --sdist 51 | --outdir dist/ 52 | - name: Build manylinux Python wheels 53 | uses: RalfG/python-wheels-manylinux-build@v0.7.1 54 | with: 55 | build-requirements: 'cython numpy' 56 | system-packages: 'zlib-devel boost-devel boost-program-options boost-serialization' 57 | - name: Upload Artifacts 58 | uses: actions/upload-artifact@v2 59 | with: 60 | name: python-wheel-artifact 61 | path: | 62 | dist/*-manylinux*.whl 63 | dist/*.tar.gz 64 | - name: Publish wheels to PyPI 65 | env: 66 | TWINE_USERNAME: "__token__" 67 | TWINE_PASSWORD: ${{ secrets.PYPI_API_TOKEN }} 68 | run: | 69 | ls dist/ 70 | twine upload --skip-existing --disable-progress-bar dist/pyapproxmc*.tar.gz 71 | -------------------------------------------------------------------------------- /flake.nix: -------------------------------------------------------------------------------- 1 | { 2 | description = "Approximate model counter"; 3 | inputs = { 4 | nixpkgs.url = "github:nixos/nixpkgs/nixpkgs-unstable"; 5 | arjun = { 6 | url = "github:meelgroup/arjun/master"; 7 | inputs.nixpkgs.follows = "nixpkgs"; 8 | }; 9 | cryptominisat = { 10 | url = "github:msoos/cryptominisat/master"; 11 | inputs.nixpkgs.follows = "nixpkgs"; 12 | }; 13 | sbva = { 14 | url = "github:meelgroup/sbva/master"; 15 | inputs.nixpkgs.follows = "nixpkgs"; 16 | }; 17 | }; 18 | outputs = 19 | { 20 | self, 21 | nixpkgs, 22 | arjun, 23 | cryptominisat, 24 | sbva, 25 | }: 26 | let 27 | inherit (nixpkgs) lib; 28 | systems = lib.intersectLists lib.systems.flakeExposed lib.platforms.linux; 29 | forAllSystems = lib.genAttrs systems; 30 | nixpkgsFor = forAllSystems (system: nixpkgs.legacyPackages.${system}); 31 | fs = lib.fileset; 32 | approxmc-package = 33 | { 34 | stdenv, 35 | cmake, 36 | autoPatchelfHook, 37 | fetchFromGitHub, 38 | gmp, 39 | mpfr, 40 | zlib, 41 | cryptominisat, 42 | arjun, 43 | sbva, 44 | }: 45 | stdenv.mkDerivation { 46 | name = "approxmc"; 47 | src = fs.toSource { 48 | root = ./.; 49 | fileset = fs.unions [ 50 | ./CMakeLists.txt 51 | ./cmake 52 | ./src 53 | ./approxmcConfig.cmake.in 54 | ]; 55 | }; 56 | nativeBuildInputs = [ 57 | cmake 58 | autoPatchelfHook 59 | ]; 60 | buildInputs = [ 61 | gmp 62 | mpfr 63 | zlib 64 | cryptominisat 65 | arjun 66 | sbva 67 | ]; 68 | }; 69 | 70 | in 71 | { 72 | packages = forAllSystems ( 73 | system: 74 | let 75 | approxmc = nixpkgsFor.${system}.callPackage approxmc-package { 76 | arjun = arjun.packages.${system}.arjun; 77 | cryptominisat = cryptominisat.packages.${system}.cryptominisat; 78 | sbva = sbva.packages.${system}.sbva; 79 | }; 80 | in 81 | { 82 | inherit approxmc; 83 | default = approxmc; 84 | } 85 | ); 86 | }; 87 | } 88 | -------------------------------------------------------------------------------- /tests/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2020, Mate Soos 2 | # 3 | # Permission is hereby granted, free of charge, to any person obtaining a copy 4 | # of this software and associated documentation files (the "Software"), to deal 5 | # in the Software without restriction, including without limitation the rights 6 | # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | # copies of the Software, and to permit persons to whom the Software is 8 | # furnished to do so, subject to the following conditions: 9 | # 10 | # The above copyright notice and this permission notice shall be included in 11 | # all copies or substantial portions of the Software. 12 | # 13 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 19 | # THE SOFTWARE. 20 | 21 | if (NOT WIN32) 22 | add_cxx_flag_if_supported("-Wno-sign-compare") 23 | endif() 24 | 25 | set(GTEST_PREFIX ${PROJECT_SOURCE_DIR}/tests/gtest) 26 | message(STATUS "NOTE: if adding the 'gtest' subdirectory fails, you need to issue 'git submodule init' and 'git submodule update'") 27 | set(GTEST_BOTH_LIBRARIES gtest gtest_main) 28 | 29 | include_directories(${gtest_SOURCE_DIR}/include ${gtest_SOURCE_DIR}) 30 | add_definitions( -DCMS_TESTING_ENABLED ) 31 | 32 | # Add handy macros/functions 33 | include(AddSTPGTest) 34 | include(AddGTestSuite) 35 | 36 | include_directories(${PROJECT_SOURCE_DIR}) 37 | include_directories(${PROJECT_SOURCE_DIR}/src/) 38 | include_directories(${PROJECT_BINARY_DIR}/apx-src) 39 | include_directories(${CRYPTOMINISAT5_INCLUDE_DIRS}) 40 | include_directories(${ARJUN_INCLUDE_DIRS}) 41 | 42 | set (MY_TESTS 43 | simpletest 44 | ) 45 | 46 | foreach(F ${MY_TESTS}) 47 | add_executable(${F} 48 | ${F}.cpp 49 | ) 50 | target_link_libraries(${F} 51 | ${GMP_LIBRARY} 52 | ${GTEST_BOTH_LIBRARIES} 53 | approxmc 54 | ${CRYPTOMINISAT5_LIBRARIES} 55 | ) 56 | add_test ( 57 | NAME ${F} 58 | COMMAND ${F} 59 | WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR} 60 | ) 61 | endforeach() 62 | -------------------------------------------------------------------------------- /python/tests/test_pyapproxmc.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | import sys 3 | from array import array 4 | from pathlib import Path 5 | 6 | import pytest 7 | 8 | from pyapproxmc import Counter 9 | 10 | 11 | def test_minimal(): 12 | counter = Counter(seed=2157, epsilon=0.8, delta=0.2) 13 | counter.add_clause(list(range(1,100))) 14 | 15 | significand, exponent = counter.count() 16 | print(f'count: {significand} * 2**{exponent}') 17 | assert significand * 2**exponent == 512 * 2**90 18 | 19 | 20 | def test_sampling_set(): 21 | counter = Counter(seed=2157, epsilon=0.8, delta=0.2) 22 | counter.add_clause(range(1,100)) 23 | assert counter.count(list(range(1,50))) == (64, 43) 24 | 25 | 26 | def test_real_example(): 27 | counter = Counter(seed=120, epsilon=0.8, delta=0.2) 28 | 29 | cnf_file = Path(__file__).parent / "test_1.cnf" 30 | with open(cnf_file) as test_cnf: 31 | # Pop sampling set and metadata lines 32 | lines = test_cnf.readlines()[2:] 33 | 34 | # Add clauses to counter 35 | for line in lines: 36 | literals = [int(i) for i in line.split()[:-1]] 37 | counter.add_clause(literals) 38 | 39 | assert counter.count(list(range(1,21))) == (64,14) 40 | 41 | 42 | def test_add_clauses_minimal(): 43 | counter = Counter(seed=2157, epsilon=0.8, delta=0.2) 44 | clauses = array('i', list(range(1,100)) + [0]) 45 | counter.add_clauses(clauses) 46 | 47 | significand, exponent = counter.count() 48 | print(f'count: {significand} * 2**{exponent}') 49 | assert significand * 2**exponent == 512 * 2**90 50 | 51 | 52 | def test_add_clauses_real_example(): 53 | counter = Counter(seed=120, epsilon=0.8, delta=0.2) 54 | clauses = [] 55 | 56 | cnf_file = Path(__file__).parent / "test_1.cnf" 57 | with open((cnf_file)) as test_cnf: 58 | # Pop sampling set and metadata lines 59 | lines = test_cnf.readlines()[2:] 60 | 61 | # Add clauses to counter 62 | for line in lines: 63 | clause = [int(i) for i in line.split()] 64 | clauses += clause 65 | 66 | counter.add_clauses(array('i', clauses)) 67 | significand, exponent = counter.count(list(range(1,21))) 68 | print(f'count: {significand} * 2**{exponent}') 69 | assert significand * 2**exponent == 64 * 2**14 70 | 71 | 72 | if __name__ == '__main__': 73 | ret = pytest.main([__file__, '-v'] + sys.argv[1:]) 74 | raise SystemExit(ret) 75 | -------------------------------------------------------------------------------- /src/appmc_constants.h: -------------------------------------------------------------------------------- 1 | /* 2 | ApproxMC 3 | 4 | Copyright (c) 2019, Mate Soos and Kuldeep S. Meel. All rights reserved 5 | Copyright (c) 2009-2018, Mate Soos. All rights reserved. 6 | Copyright (c) 2015, Supratik Chakraborty, Daniel J. Fremont, 7 | Kuldeep S. Meel, Sanjit A. Seshia, Moshe Y. Vardi 8 | Copyright (c) 2014, Supratik Chakraborty, Kuldeep S. Meel, Moshe Y. Vardi 9 | 10 | Permission is hereby granted, free of charge, to any person obtaining a copy 11 | of this software and associated documentation files (the "Software"), to deal 12 | in the Software without restriction, including without limitation the rights 13 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 14 | copies of the Software, and to permit persons to whom the Software is 15 | furnished to do so, subject to the following conditions: 16 | 17 | The above copyright notice and this permission notice shall be included in 18 | all copies or substantial portions of the Software. 19 | 20 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 21 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 22 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 23 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 24 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 25 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 26 | THE SOFTWARE. 27 | */ 28 | 29 | #pragma once 30 | 31 | #include 32 | #include 33 | #include 34 | 35 | using std::vector; 36 | using std::string; 37 | 38 | #define verb_print(a, b) do { if (conf.verb >= a) cout << "c o " << b << endl; } while (0) 39 | #define clear_toclear_seen() \ 40 | do {\ 41 | for(const auto& x: to_clear) seen[x] = 0;\ 42 | to_clear.clear();} while (0) 43 | 44 | namespace AppMCInt { 45 | 46 | struct VarMap 47 | { 48 | VarMap() {} 49 | VarMap(uint32_t _vars_to_inclusive, vector _index_var_map) : 50 | vars_to_inclusive(_vars_to_inclusive), 51 | index_var_map(_index_var_map) 52 | {} 53 | 54 | uint32_t vars_to_inclusive = 0; 55 | vector index_var_map; 56 | }; 57 | 58 | class Constants 59 | { 60 | public: 61 | Constants(); 62 | vector probval; 63 | vector index_var_maps; 64 | 65 | private: 66 | vector sparseprobvalues; 67 | void readInSparseValues(); 68 | }; 69 | 70 | } 71 | -------------------------------------------------------------------------------- /src/appmcconfig.h: -------------------------------------------------------------------------------- 1 | /* 2 | ApproxMC 3 | 4 | Copyright (c) 2019, Mate Soos and Kuldeep S. Meel. All rights reserved 5 | Copyright (c) 2009-2018, Mate Soos. All rights reserved. 6 | Copyright (c) 2014, Supratik Chakraborty, Kuldeep S. Meel, Moshe Y. Vardi 7 | Copyright (c) 2015, Supratik Chakraborty, Daniel J. Fremont, 8 | Kuldeep S. Meel, Sanjit A. Seshia, Moshe Y. Vardi 9 | 10 | Permission is hereby granted, free of charge, to any person obtaining a copy 11 | of this software and associated documentation files (the "Software"), to deal 12 | in the Software without restriction, including without limitation the rights 13 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 14 | copies of the Software, and to permit persons to whom the Software is 15 | furnished to do so, subject to the following conditions: 16 | 17 | The above copyright notice and this permission notice shall be included in 18 | all copies or substantial portions of the Software. 19 | 20 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 21 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 22 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 23 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 24 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 25 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 26 | THE SOFTWARE. 27 | */ 28 | 29 | #pragma once 30 | 31 | #include 32 | #include 33 | #include 34 | #include 35 | #include 36 | #include 37 | 38 | namespace AppMCInt { 39 | 40 | class Config { 41 | public: 42 | Config(const std::unique_ptr& _fg) : multiplier_weight(_fg->one()) {} 43 | uint32_t start_iter = 0; 44 | double epsilon = 0.80; //Tolerance. CAV-2020 paper default 45 | double delta = 0.2; //Confidence. CAV-2020 paper default 46 | int sparse = 0; 47 | unsigned verb = 0; 48 | unsigned verb_cls = 0; 49 | uint32_t seed = 1; 50 | int simplify = 1; 51 | double var_elim_ratio = 1.6; 52 | int reuse_models = 1; 53 | std::string logfilename = ""; 54 | int dump_intermediary_cnf = 0; 55 | int debug = 0; 56 | int force_sol_extension = false; 57 | 58 | std::vector sampl_vars; 59 | bool sampl_vars_set = false; 60 | std::unique_ptr multiplier_weight = nullptr; 61 | }; 62 | 63 | } 64 | -------------------------------------------------------------------------------- /.github/workflows/python-wheel-build.yml: -------------------------------------------------------------------------------- 1 | name: python wheel packages 2 | 3 | on: [push, pull_request] 4 | 5 | jobs: 6 | build_wheels: 7 | name: Build wheels on ${{ matrix.os }} 8 | runs-on: ${{ matrix.os }} 9 | strategy: 10 | matrix: 11 | os: [ubuntu-20.04] 12 | #os: [ubuntu-20.04, windows-2022, macos-13] 13 | 14 | steps: 15 | - uses: actions/checkout@v3 16 | - name: Checkout CaDiCaL 17 | uses: actions/checkout@v3 18 | with: 19 | repository: meelgroup/cadical 20 | ref: 'add_dynamic_lib' 21 | path: python/cadical 22 | 23 | - name: Checkout Cadiback 24 | uses: actions/checkout@v3 25 | with: 26 | repository: meelgroup/cadiback 27 | ref: 'mate' 28 | path: python/cadiback 29 | 30 | - name: configure and build CaDiCaL 31 | run: cd python/cadical && CXXFLAGS=-fPIC ./configure --competition && make -j4 32 | 33 | - name: Configure and build Cadiback 34 | run: cd python/cadiback && ./configure && make -j4 35 | 36 | - name: Checkout CMS 37 | uses: actions/checkout@v2 38 | with: 39 | repository: msoos/cryptominisat 40 | ref: 'master' 41 | path: python/cryptominisat 42 | 43 | - name: Checkout Arjun 44 | uses: actions/checkout@v2 45 | with: 46 | repository: meelgroup/arjun 47 | path: python/arjun 48 | 49 | # Used to host cibuildwheel 50 | - uses: actions/setup-python@v3 51 | 52 | - name: Install cibuildwheel 53 | run: python -m pip install cibuildwheel 54 | 55 | - name: Build wheels 56 | run: python -m cibuildwheel --output-dir wheelhouse 57 | # to supply options, put them in 'env', like: 58 | env: 59 | CIBW_BEFORE_ALL_LINUX: yum install -y gmp-devel 60 | CIBW_TEST_REQUIRES: pytest 61 | CIBW_TEST_COMMAND: "pytest --color=yes -v {project}/python/tests/test_pyapproxmc.py" 62 | CIBW_SKIP: "*musl*" 63 | CIBW_ARCHS: "auto64" 64 | 65 | - uses: actions/upload-artifact@v3 66 | with: 67 | path: ./wheelhouse/*.whl 68 | - name: Install twine 69 | run: python -m pip install twine 70 | - name: Publish wheels to PyPI 71 | env: 72 | TWINE_USERNAME: "__token__" 73 | TWINE_PASSWORD: ${{ secrets.PYPI_API_TOKEN }} 74 | run: | 75 | twine upload --skip-existing --disable-progress-bar ./wheelhouse/pyapproxmc-*.whl 76 | -------------------------------------------------------------------------------- /setup.py: -------------------------------------------------------------------------------- 1 | # 2 | # ApproxMC 3 | # 4 | # Copyright (c) 2009-2017, Mate Soos. All rights reserved. 5 | # Copyright (c) 2017, Pierre Vignet 6 | # 7 | # Permission is hereby granted, free of charge, to any person obtaining a copy 8 | # of this software and associated documentation files (the "Software"), to deal 9 | # in the Software without restriction, including without limitation the rights 10 | # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 11 | # copies of the Software, and to permit persons to whom the Software is 12 | # furnished to do so, subject to the following conditions: 13 | # 14 | # The above copyright notice and this permission notice shall be included in 15 | # all copies or substantial portions of the Software. 16 | # 17 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 18 | # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 19 | # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 20 | # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 21 | # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 22 | # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 23 | # THE SOFTWARE. 24 | 25 | 26 | from setuptools import Extension, setup 27 | import toml 28 | import pathlib 29 | from sys import platform 30 | 31 | def _parse_toml(pyproject_path): 32 | pyproject_text = pyproject_path.read_text() 33 | pyproject_data = toml.loads(pyproject_text) 34 | return pyproject_data['project']['version'] 35 | 36 | 37 | def gen_modules(version): 38 | define_macros_val : list[tuple[str, str | None]] | None 39 | if platform == "win32" or platform == "cygwin": 40 | extra_compile_args_val = ['/std:c++17', "/DAPPMC_FULL_VERSION=\""+version+"\""] 41 | define_macros_val = [] 42 | 43 | else: 44 | extra_compile_args_val = ['-std=c++20'] 45 | define_macros_val = [("APPMC_FULL_VERSION", "\""+version+"\"")] 46 | 47 | modules = Extension( 48 | name = "pyapproxmc", 49 | sources = [ 50 | "python/src/GitSHA1.cpp", 51 | "python/src/pyapproxmc.cpp", 52 | "src/approxmc.cpp", 53 | "src/appmc_constants.cpp", 54 | "src/counter.cpp", 55 | ], 56 | extra_compile_args = extra_compile_args_val, 57 | define_macros = define_macros_val, 58 | include_dirs = ["src/"], 59 | language = "c++", 60 | ) 61 | return modules 62 | 63 | if __name__ == '__main__': 64 | pyproject_path = pathlib.Path('pyproject.toml') 65 | version = _parse_toml(pyproject_path) 66 | modules = gen_modules(version) 67 | setup( 68 | ext_modules = [modules], 69 | ) 70 | -------------------------------------------------------------------------------- /tests/simpletest.cpp: -------------------------------------------------------------------------------- 1 | /****************************************** 2 | Copyright (c) 2020, Mate Soos 3 | 4 | Permission is hereby granted, free of charge, to any person obtaining a copy 5 | of this software and associated documentation files (the "Software"), to deal 6 | in the Software without restriction, including without limitation the rights 7 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8 | copies of the Software, and to permit persons to whom the Software is 9 | furnished to do so, subject to the following conditions: 10 | 11 | The above copyright notice and this permission notice shall be included in 12 | all copies or substantial portions of the Software. 13 | 14 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 20 | THE SOFTWARE. 21 | ***********************************************/ 22 | 23 | #include "gtest/gtest.h" 24 | 25 | #include "approxmc.h" 26 | #include "cryptominisat5/solvertypesmini.h" 27 | #include "test_helper.h" 28 | #include 29 | #include 30 | #include 31 | #include 32 | #include 33 | using std::string; 34 | using std::vector; 35 | 36 | using namespace ApproxMC; 37 | #include 38 | using std::vector; 39 | 40 | 41 | TEST(normal_interface, start) 42 | { 43 | std::unique_ptr fg = std::make_unique(); 44 | AppMC s(fg); 45 | s.set_sampl_vars({}); 46 | SolCount c = s.count(); 47 | EXPECT_EQ(1U, c.cellSolCount); 48 | EXPECT_EQ(0U, c.hashCount); 49 | } 50 | 51 | TEST(normal_interface, example1) 52 | { 53 | std::unique_ptr fg = std::make_unique(); 54 | AppMC s(fg); 55 | s.new_vars(2); 56 | s.add_clause(str_to_cl("-1, 2")); 57 | s.set_sampl_vars({0, 1}); 58 | SolCount c = s.count(); 59 | EXPECT_EQ(0U, c.hashCount); 60 | EXPECT_EQ(3U, c.cellSolCount); 61 | } 62 | 63 | TEST(normal_interface, example2) 64 | { 65 | std::unique_ptr fg = std::make_unique(); 66 | AppMC s(fg); 67 | s.new_vars(10); 68 | vector sampl; 69 | for(uint32_t i = 0; i < 10; i++) sampl.push_back(i); 70 | s.set_sampl_vars(sampl); 71 | 72 | SolCount c = s.count(); 73 | uint32_t x = std::pow(2, c.hashCount)*c.cellSolCount; 74 | EXPECT_EQ(std::pow(2, 10), x); 75 | } 76 | 77 | TEST(normal_interface, example3) 78 | { 79 | std::unique_ptr fg = std::make_unique(); 80 | AppMC s(fg); 81 | s.new_vars(10); 82 | vector sampl; 83 | for(uint32_t i = 0; i < 10; i++) sampl.push_back(i); 84 | s.set_sampl_vars(sampl); 85 | 86 | s.add_clause(str_to_cl("-3")); 87 | SolCount c = s.count(); 88 | uint32_t cnt = std::pow(2, c.hashCount)*c.cellSolCount; 89 | EXPECT_EQ(std::pow(2, 9), cnt); 90 | } 91 | 92 | TEST(normal_interface, example4) 93 | { 94 | std::unique_ptr fg = std::make_unique(); 95 | AppMC s(fg); 96 | s.new_vars(10); 97 | vector sampl; 98 | for(uint32_t i = 0; i < 10; i++) sampl.push_back(i); 99 | s.set_sampl_vars(sampl); 100 | 101 | s.add_clause(str_to_cl("-3, 4")); 102 | s.add_clause(str_to_cl("3, -4")); 103 | SolCount c = s.count(); 104 | uint32_t cnt = std::pow(2, c.hashCount)*c.cellSolCount; 105 | EXPECT_EQ(std::pow(2, 9), cnt); 106 | } 107 | 108 | int main(int argc, char **argv) { 109 | ::testing::InitGoogleTest(&argc, argv); 110 | return RUN_ALL_TESTS(); 111 | } 112 | -------------------------------------------------------------------------------- /cmake/GetGitRevisionDescription.cmake: -------------------------------------------------------------------------------- 1 | # - Returns a version string from Git 2 | # 3 | # These functions force a re-configure on each git commit so that you can 4 | # trust the values of the variables in your build system. 5 | # 6 | # get_git_head_revision( [ ...]) 7 | # 8 | # Returns the refspec and sha hash of the current head revision 9 | # 10 | # git_describe( [ ...]) 11 | # 12 | # Returns the results of git describe on the source tree, and adjusting 13 | # the output so that it tests false if an error occurs. 14 | # 15 | # git_get_exact_tag( [ ...]) 16 | # 17 | # Returns the results of git describe --exact-match on the source tree, 18 | # and adjusting the output so that it tests false if there was no exact 19 | # matching tag. 20 | # 21 | # Requires CMake 2.6 or newer (uses the 'function' command) 22 | # 23 | # Original Author: 24 | # 2009-2010 Ryan Pavlik 25 | # http://academic.cleardefinition.com 26 | # Iowa State University HCI Graduate Program/VRAC 27 | # 28 | # Copyright Iowa State University 2009-2010. 29 | # Distributed under the Boost Software License, Version 1.0. 30 | # (See accompanying file LICENSE_1_0.txt or copy at 31 | # http://www.boost.org/LICENSE_1_0.txt) 32 | 33 | if(__get_git_revision_description) 34 | return() 35 | endif() 36 | set(__get_git_revision_description YES) 37 | 38 | # We must run the following at "include" time, not at function call time, 39 | # to find the path to this module rather than the path to a calling list file 40 | get_filename_component(_gitdescmoddir ${CMAKE_CURRENT_LIST_FILE} PATH) 41 | 42 | function(get_git_head_revision _refspecvar _hashvar) 43 | set(GIT_PARENT_DIR "${CMAKE_SOURCE_DIR}") 44 | set(GIT_DIR "${GIT_PARENT_DIR}/.git") 45 | while(NOT EXISTS "${GIT_DIR}") # .git dir not found, search parent directories 46 | set(GIT_PREVIOUS_PARENT "${GIT_PARENT_DIR}") 47 | get_filename_component(GIT_PARENT_DIR ${GIT_PARENT_DIR} PATH) 48 | if(GIT_PARENT_DIR STREQUAL GIT_PREVIOUS_PARENT) 49 | # We have reached the root directory, we are not in git 50 | set(${_refspecvar} "GIT-notfound" PARENT_SCOPE) 51 | set(${_hashvar} "GIT-notfound" PARENT_SCOPE) 52 | return() 53 | endif() 54 | set(GIT_DIR "${GIT_PARENT_DIR}/.git") 55 | endwhile() 56 | set(GIT_DATA "${CMAKE_CURRENT_BINARY_DIR}/CMakeFiles/git-data") 57 | if(NOT EXISTS "${GIT_DATA}") 58 | file(MAKE_DIRECTORY "${GIT_DATA}") 59 | endif() 60 | 61 | if(NOT EXISTS "${GIT_DIR}/HEAD") 62 | return() 63 | endif() 64 | set(HEAD_FILE "${GIT_DATA}/HEAD") 65 | configure_file("${GIT_DIR}/HEAD" "${HEAD_FILE}" COPYONLY) 66 | 67 | configure_file("${_gitdescmoddir}/GetGitRevisionDescription.cmake.in" 68 | "${GIT_DATA}/grabRef.cmake" 69 | @ONLY) 70 | include("${GIT_DATA}/grabRef.cmake") 71 | 72 | set(${_refspecvar} "${HEAD_REF}" PARENT_SCOPE) 73 | set(${_hashvar} "${HEAD_HASH}" PARENT_SCOPE) 74 | endfunction() 75 | 76 | function(git_describe _var) 77 | if(NOT GIT_FOUND) 78 | find_package(Git QUIET) 79 | endif() 80 | get_git_head_revision(refspec hash) 81 | if(NOT GIT_FOUND) 82 | set(${_var} "${CPACK_PACKAGE_VERSION}-compiled-from-cmake" PARENT_SCOPE) 83 | return() 84 | endif() 85 | if(NOT hash) 86 | set(${_var} "${CPACK_PACKAGE_VERSION}-compiled-from-cmake" PARENT_SCOPE) 87 | return() 88 | endif() 89 | 90 | # TODO sanitize 91 | #if((${ARGN}" MATCHES "&&") OR 92 | # (ARGN MATCHES "||") OR 93 | # (ARGN MATCHES "\\;")) 94 | # message("Please report the following error to the project!") 95 | # message(FATAL_ERROR "Looks like someone's doing something nefarious with git_describe! Passed arguments ${ARGN}") 96 | #endif() 97 | 98 | #message(STATUS "Arguments to execute_process: ${ARGN}") 99 | 100 | execute_process(COMMAND "${GIT_EXECUTABLE}" describe ${hash} ${ARGN} 101 | WORKING_DIRECTORY "${CMAKE_SOURCE_DIR}" 102 | RESULT_VARIABLE res 103 | OUTPUT_VARIABLE out 104 | #ERROR_QUIET 105 | OUTPUT_STRIP_TRAILING_WHITESPACE) 106 | if(NOT res EQUAL 0) 107 | set(out "${CPACK_PACKAGE_VERSION} (approximate version number)") 108 | endif() 109 | 110 | set(${_var} "${out}" PARENT_SCOPE) 111 | endfunction() 112 | 113 | function(git_get_exact_tag _var) 114 | git_describe(out --exact-match ${ARGN}) 115 | set(${_var} "${out}" PARENT_SCOPE) 116 | endfunction() 117 | -------------------------------------------------------------------------------- /src/approxmc.h: -------------------------------------------------------------------------------- 1 | /* 2 | ApproxMC 3 | 4 | Copyright (c) 2019-2020, Mate Soos and Kuldeep S. Meel. All rights reserved 5 | Copyright (c) 2009-2018, Mate Soos. All rights reserved. 6 | Copyright (c) 2015, Supratik Chakraborty, Daniel J. Fremont, 7 | Kuldeep S. Meel, Sanjit A. Seshia, Moshe Y. Vardi 8 | Copyright (c) 2014, Supratik Chakraborty, Kuldeep S. Meel, Moshe Y. Vardi 9 | 10 | Permission is hereby granted, free of charge, to any person obtaining a copy 11 | of this software and associated documentation files (the "Software"), to deal 12 | in the Software without restriction, including without limitation the rights 13 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 14 | copies of the Software, and to permit persons to whom the Software is 15 | furnished to do so, subject to the following conditions: 16 | 17 | The above copyright notice and this permission notice shall be included in 18 | all copies or substantial portions of the Software. 19 | 20 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 21 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 22 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 23 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 24 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 25 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 26 | THE SOFTWARE. 27 | */ 28 | 29 | 30 | #pragma once 31 | 32 | #include 33 | #include 34 | #include 35 | #include 36 | #include 37 | #include 38 | namespace ApproxMC { 39 | 40 | #ifdef _WIN32 41 | class __declspec(dllexport) SolCount 42 | #else 43 | class SolCount 44 | #endif 45 | { 46 | public: 47 | void clear() { 48 | SolCount tmp; 49 | *this = tmp; 50 | } 51 | bool valid = false; 52 | uint32_t hashCount = 0; 53 | uint64_t cellSolCount = 0; 54 | }; 55 | 56 | struct AppMCPrivateData; 57 | #ifdef _WIN32 58 | class __declspec(dllexport) AppMC 59 | #else 60 | class AppMC 61 | #endif 62 | { 63 | public: 64 | AppMC(const std::unique_ptr& _fg); 65 | ~AppMC(); 66 | ApproxMC::SolCount count(); 67 | bool find_one_solution(); 68 | 69 | // Sampling set 70 | void set_sampl_vars(const std::vector& vars); 71 | void set_opt_sampl_vars(const std::vector& vars); 72 | bool get_sampl_vars_set() const; 73 | bool get_opt_sampl_vars_set() const { return false; } 74 | const std::vector& get_sampl_vars() const; 75 | void set_multiplier_weight(const std::unique_ptr& weight); 76 | const std::unique_ptr& get_multiplier_weight() const; 77 | void set_weighted(const bool weighted); 78 | void set_projected(const bool projected); 79 | void set_lit_weight(const CMSat::Lit& lit, const std::unique_ptr& weight); 80 | 81 | // Adding constraints 82 | void new_var(); 83 | void new_vars(uint32_t num); 84 | uint32_t nVars(); 85 | bool add_clause(const std::vector& lits); 86 | bool add_red_clause(const std::vector& lits); 87 | bool add_xor_clause(const std::vector& lits, bool rhs); 88 | bool add_xor_clause(const std::vector& vars, bool rhs); 89 | 90 | // Information about approxmc 91 | static std::string get_version_sha1(); 92 | void print_stats(const double start_time); 93 | 94 | //Main options 95 | void set_verbosity(uint32_t verb); 96 | void set_seed(uint32_t seed); 97 | void set_epsilon(double epsilon); 98 | void set_delta(double delta); 99 | CMSat::SATSolver* get_solver(); 100 | 101 | //Misc options -- do NOT to change unless you know what you are doing! 102 | void set_start_iter(uint32_t start_iter); 103 | void set_verb_cls(uint32_t verb_cls); 104 | void set_var_elim_ratio(double var_elim_ratio); 105 | void set_reuse_models(uint32_t reuse_models); 106 | void set_sparse(uint32_t sparse); 107 | void set_simplify(uint32_t simplify); 108 | void set_dump_intermediary_cnf(const int dump_intermediary_cnf); 109 | void set_debug(int debug); 110 | void set_force_sol_extension(int val); 111 | 112 | //Querying default values 113 | const std::vector& get_sampling_set() const; 114 | double get_epsilon(); 115 | uint32_t get_seed(); 116 | double get_delta(); 117 | uint32_t get_simplify(); 118 | double get_var_elim_ratio(); 119 | uint32_t get_sparse(); 120 | bool get_reuse_models(); 121 | 122 | private: 123 | //////////////////////////// 124 | // Do not bother with this, it's private 125 | //////////////////////////// 126 | std::unique_ptr data; 127 | }; 128 | 129 | } 130 | -------------------------------------------------------------------------------- /src/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2017, Mate Soos 2 | # 3 | # Permission is hereby granted, free of charge, to any person obtaining a copy 4 | # of this software and associated documentation files (the "Software"), to deal 5 | # in the Software without restriction, including without limitation the rights 6 | # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | # copies of the Software, and to permit persons to whom the Software is 8 | # furnished to do so, subject to the following conditions: 9 | # 10 | # The above copyright notice and this permission notice shall be included in 11 | # all copies or substantial portions of the Software. 12 | # 13 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 19 | # THE SOFTWARE. 20 | 21 | 22 | if (NOT WIN32) 23 | add_cxx_flag_if_supported("-Wno-bitfield-constant-conversion") 24 | #add_cxx_flag_if_supported("-Wduplicated-cond") 25 | #add_cxx_flag_if_supported("-Wduplicated-branches") 26 | add_cxx_flag_if_supported("-Wlogical-op") 27 | add_cxx_flag_if_supported("-Wrestrict") 28 | add_cxx_flag_if_supported("-Wnull-dereference") 29 | add_cxx_flag_if_supported("-Wdouble-promotion") 30 | add_cxx_flag_if_supported("-Wshadow") 31 | add_cxx_flag_if_supported("-Wformat=2") 32 | add_cxx_flag_if_supported("-Wextra-semi") 33 | add_cxx_flag_if_supported("-pedantic") 34 | #add_cxx_flag_if_supported("-Wdeprecated") 35 | endif() 36 | 37 | include_directories(${PROJECT_SOURCE_DIR}) 38 | include_directories(${CMAKE_CURRENT_SOURCE_DIR}) 39 | include_directories(${CMAKE_CURRENT_BINARY_DIR}) 40 | include_directories(${CRYPTOMINISAT5_INCLUDE_DIRS}) 41 | include_directories(${ARJUN_INCLUDE_DIRS}) 42 | include_directories(${GMP_INCLUDE_DIRS}) 43 | configure_file("${CMAKE_CURRENT_SOURCE_DIR}/GitSHA1.cpp.in" "${CMAKE_CURRENT_BINARY_DIR}/GitSHA1.cpp" @ONLY) 44 | 45 | set(approxmc_lib_files 46 | approxmc.cpp 47 | counter.cpp 48 | appmc_constants.cpp 49 | ${CMAKE_CURRENT_BINARY_DIR}/GitSHA1.cpp 50 | ) 51 | add_library(approxmc ${approxmc_lib_files}) 52 | 53 | target_link_libraries(approxmc 54 | LINK_PUBLIC ${ARJUN_LIBRARIES} 55 | LINK_PUBLIC ${CRYPTOMINISAT5_LIBRARIES} 56 | ) 57 | 58 | add_executable(approxmc-bin main.cpp ${approxmc_lib_files}) 59 | set(approxmc_exec_link_libs ${GMP_LIBRARY}) 60 | 61 | IF (ZLIB_FOUND) 62 | SET(approxmc_exec_link_libs ${approxmc_exec_link_libs} ${ZLIB_LIBRARY}) 63 | ENDIF() 64 | 65 | set_target_properties(approxmc PROPERTIES 66 | PUBLIC_HEADER "${approxmc_public_headers}" 67 | VERSION ${PROJECT_VERSION_MAJOR}.${PROJECT_VERSION_MINOR} 68 | SOVERSION ${PROJECT_VERSION_MAJOR}.${PROJECT_VERSION_MINOR} 69 | ) 70 | 71 | target_link_libraries(approxmc-bin ${approxmc_exec_link_libs} approxmc) 72 | 73 | if(CMAKE_SYSTEM_NAME STREQUAL "Emscripten") 74 | set_target_properties(approxmc-bin PROPERTIES 75 | OUTPUT_NAME approxmc 76 | RUNTIME_OUTPUT_DIRECTORY ${PROJECT_BINARY_DIR} 77 | INSTALL_RPATH_USE_LINK_PATH TRUE 78 | LINK_FLAGS "-s WASM=1 -s ALLOW_MEMORY_GROWTH=1 -s EXPORTED_RUNTIME_METHODS='[\"callMain\", \"ccall\", \"cwrap\", \"FS\", \"print\"]' -s FORCE_FILESYSTEM=1" 79 | ) 80 | else() 81 | set_target_properties(approxmc-bin PROPERTIES 82 | OUTPUT_NAME approxmc 83 | RUNTIME_OUTPUT_DIRECTORY ${PROJECT_BINARY_DIR} 84 | INSTALL_RPATH_USE_LINK_PATH TRUE 85 | ) 86 | endif() 87 | 88 | approxmc_add_public_header(approxmc ${CMAKE_CURRENT_SOURCE_DIR}/approxmc.h ) 89 | 90 | # ----------------------------------------------------------------------------- 91 | # Copy public headers into build directory include directory. 92 | # The approxmcConfig.cmake we generate in the build directory depends on 93 | # this. 94 | # ----------------------------------------------------------------------------- 95 | set(HEADER_DEST "${PROJECT_BINARY_DIR}/include/approxmc/") 96 | add_custom_target(CopyPublicHeaders ALL) 97 | get_target_property(approxmc_public_headers approxmc PUBLIC_HEADER) 98 | foreach(public_header ${approxmc_public_headers}) 99 | get_filename_component(HEADER_NAME ${public_header} NAME) 100 | add_custom_command(TARGET CopyPublicHeaders PRE_BUILD 101 | COMMAND ${CMAKE_COMMAND} -E make_directory "${HEADER_DEST}" 102 | COMMAND ${CMAKE_COMMAND} -E echo "Copying ${HEADER_NAME} to ${HEADER_DEST}" 103 | COMMAND ${CMAKE_COMMAND} -E copy_if_different ${public_header} "${HEADER_DEST}/" 104 | ) 105 | endforeach() 106 | 107 | install(TARGETS approxmc 108 | EXPORT ${APPROXMC_EXPORT_NAME} 109 | LIBRARY DESTINATION "${CMAKE_INSTALL_LIBDIR}" 110 | ARCHIVE DESTINATION "${CMAKE_INSTALL_LIBDIR}" 111 | RUNTIME DESTINATION "${CMAKE_INSTALL_BINDIR}" 112 | PUBLIC_HEADER DESTINATION "${CMAKE_INSTALL_INCLUDEDIR}/approxmc" 113 | ) 114 | 115 | install(TARGETS approxmc-bin 116 | EXPORT ${APPROXMC_EXPORT_NAME} 117 | RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR} 118 | ) 119 | SET(CPACK_PACKAGE_EXECUTABLES "approxmc-bin" "approxmc") 120 | -------------------------------------------------------------------------------- /src/appmc_constants.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | ApproxMC 3 | 4 | 5 | Copyright (c) 2019, Mate Soos and Kuldeep S. Meel. All rights reserved 6 | Copyright (c) 2009-2018, Mate Soos. All rights reserved. 7 | Copyright (c) 2015, Supratik Chakraborty, Daniel J. Fremont, 8 | Kuldeep S. Meel, Sanjit A. Seshia, Moshe Y. Vardi 9 | Copyright (c) 2014, Supratik Chakraborty, Kuldeep S. Meel, Moshe Y. Vardi 10 | 11 | Permission is hereby granted, free of charge, to any person obtaining a copy 12 | of this software and associated documentation files (the "Software"), to deal 13 | in the Software without restriction, including without limitation the rights 14 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 15 | copies of the Software, and to permit persons to whom the Software is 16 | furnished to do so, subject to the following conditions: 17 | 18 | The above copyright notice and this permission notice shall be included in 19 | all copies or substantial portions of the Software. 20 | 21 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 22 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 23 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 24 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 25 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 26 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 27 | THE SOFTWARE. 28 | */ 29 | 30 | #include "appmc_constants.h" 31 | #include 32 | #include 33 | #include 34 | 35 | using std::string; 36 | using std::vector; 37 | using namespace AppMCInt; 38 | 39 | Constants::Constants() { 40 | //So if you have 50 hashes, then between 1-6, use 0.5 prob, between 7-8 use 0.49, between 9-10 0.48 41 | sparseprobvalues = {{ 42 | "header,0.5,0.49,0.48,0.47,0.45,0.44,0.43,0.42,0.41,0.39,0.38,0.37,0.36,0.35,0.33,0.32,0.31,0.3,0.29,0.27,0.26,0.25,0.24,0.22,0.21,0.19,0.18,0.16,0.15,0.13,0.12,0.1,0.09,0.07,0.06,0.04,0.03,", 43 | "50,1,7,9,11,14,15,17,18,19,21,23,24,25,26,29,30,31,32,33,36,37,38,39,41,42,44,45,47,48,50,", 44 | "100,1,7,9,12,17,19,22,23,26,29,31,33,34,36,40,42,44,46,48,53,55,58,60,65,68,74,76,82,85,90,92,95,97,", 45 | "150,1,7,10,13,18,20,23,25,28,34,36,38,40,42,47,50,52,55,57,63,66,69,72,79,83,91,96,105,110,121,126,136,140,145,148,", 46 | "200,1,8,10,13,18,20,23,25,28,37,39,42,44,47,52,55,58,61,63,70,74,77,81,89,94,104,109,121,128,142,150,167,175,190,194,", 47 | "250,1,8,10,13,18,20,24,26,28,40,42,45,47,50,56,59,62,65,68,76,79,84,88,97,103,114,120,134,141,158,168,190,202,227,238,247,", 48 | "300,1,8,10,14,18,20,24,26,29,42,44,48,50,53,59,62,66,70,72,80,84,89,94,104,109,122,129,144,152,172,183,209,224,257,274,294,299,", 49 | "350,1,8,10,14,19,21,24,27,29,44,46,50,52,55,61,65,69,73,76,84,88,93,99,109,115,129,136,152,162,183,195,225,242,282,305,342,347,", 50 | "400,1,8,11,14,19,21,25,27,30,46,48,51,54,57,64,67,72,76,79,87,92,97,103,114,120,135,142,160,170,193,206,238,257,303,330,385,395,", 51 | "450,1,8,11,14,19,21,25,27,30,47,49,53,56,59,66,70,74,78,82,90,95,101,107,118,124,140,147,166,177,202,215,250,271,322,353,423,443,", 52 | "500,1,8,11,15,19,21,25,27,30,48,50,55,57,61,68,72,76,81,84,93,98,105,110,123,128,144,152,172,183,209,224,261,283,338,373,456,490,", 53 | "600,1,8,11,15,20,22,26,28,44,51,53,57,60,63,71,75,80,84,89,98,103,110,115,129,135,152,161,181,194,222,239,279,304,367,407,513,572,", 54 | "700,1,9,11,15,20,22,26,28,46,52,55,59,63,66,74,78,83,88,93,102,109,114,120,134,141,158,168,190,203,233,251,294,322,391,436,560,639,", 55 | "800,1,9,11,16,21,22,27,29,47,54,56,61,65,68,76,80,85,91,96,106,112,118,124,139,146,164,174,197,211,243,262,308,337,411,461,601,697,", 56 | "900,1,9,12,16,21,23,27,29,49,56,58,62,68,70,78,82,88,93,99,110,116,121,127,143,150,169,179,204,219,251,271,320,350,429,483,636,747,", 57 | "1000,1,9,12,16,21,23,28,30,50,57,59,64,69,71,81,84,90,95,101,112,118,124,131,146,154,173,184,210,225,258,279,331,362,446,502,667,791,", 58 | "1200,1,9,12,17,22,23,29,30,52,59,62,66,72,74,85,88,93,99,105,117,123,130,136,153,162,181,193,221,236,272,293,348,382,474,535,721,867,", 59 | "1400,1,9,12,17,22,24,29,48,53,61,64,68,74,76,88,90,96,102,108,121,127,134,141,158,169,188,201,229,245,284,306,363,401,497,564,766,930,", 60 | "1600,1,9,12,17,22,24,29,49,55,62,65,70,76,78,90,93,99,105,111,124,131,138,145,163,174,194,208,236,253,294,317,377,416,517,588,805,984,", 61 | "1800,1,10,13,18,23,24,30,50,56,64,67,72,78,80,93,95,101,107,114,127,134,141,148,167,178,199,214,243,260,302,327,388,429,536,609,839,1031,", 62 | "2000,1,10,13,18,23,25,30,51,57,65,68,73,80,82,94,97,103,110,116,130,137,144,152,170,182,204,219,248,266,309,335,399,440,552,629,870,1074,", 63 | "2400,1,10,13,18,23,25,50,53,59,67,71,76,82,85,98,101,107,113,120,135,142,149,157,177,189,214,227,258,277,322,350,418,461,579,662,922,1147,", 64 | "2800,1,10,13,19,24,26,52,54,60,69,73,78,85,87,100,103,110,117,124,138,146,154,162,182,195,221,234,267,286,333,362,433,478,602,689,966,1209,", 65 | "3200,1,10,13,19,24,26,53,56,62,71,78,80,87,89,103,106,112,119,127,142,149,157,166,187,199,226,240,274,294,342,372,446,495,624,714,1004,1261,", 66 | "3600,1,11,13,20,25,26,54,57,63,72,79,81,88,91,105,108,115,122,129,145,153,161,170,191,204,231,246,280,301,351,381,458,508,641,736,1039,1308,", 67 | }}; 68 | 69 | readInSparseValues(); 70 | } 71 | 72 | void Constants::readInSparseValues() 73 | { 74 | assert(index_var_maps.empty()); 75 | for (uint32_t i = 0; i < sparseprobvalues.size(); i++) 76 | { 77 | std::stringstream ss(sparseprobvalues[i]); 78 | string value; 79 | std::getline(ss, value, ','); 80 | if (value == "header") { 81 | while(std::getline(ss, value, ',')) { 82 | probval.push_back(std::stod(value)); 83 | } 84 | continue; 85 | } 86 | 87 | //non-header 88 | uint32_t numvars = std::stoul(value); 89 | vector index_var_map; 90 | while(std::getline(ss, value, ',')) { 91 | index_var_map.push_back(std::stoul(value)); 92 | } 93 | assert(index_var_map.size() <= probval.size()); 94 | VarMap vmap(numvars, index_var_map); 95 | index_var_maps.push_back(vmap); 96 | } 97 | } 98 | -------------------------------------------------------------------------------- /src/counter.h: -------------------------------------------------------------------------------- 1 | /* 2 | ApproxMC 3 | 4 | Copyright (c) 2019-2020, Mate Soos and Kuldeep S. Meel. All rights reserved 5 | Copyright (c) 2009-2018, Mate Soos. All rights reserved. 6 | Copyright (c) 2015, Supratik Chakraborty, Daniel J. Fremont, 7 | Kuldeep S. Meel, Sanjit A. Seshia, Moshe Y. Vardi 8 | Copyright (c) 2014, Supratik Chakraborty, Kuldeep S. Meel, Moshe Y. Vardi 9 | 10 | Permission is hereby granted, free of charge, to any person obtaining a copy 11 | of this software and associated documentation files (the "Software"), to deal 12 | in the Software without restriction, including without limitation the rights 13 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 14 | copies of the Software, and to permit persons to whom the Software is 15 | furnished to do so, subject to the following conditions: 16 | 17 | The above copyright notice and this permission notice shall be included in 18 | all copies or substantial portions of the Software. 19 | 20 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 21 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 22 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 23 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 24 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 25 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 26 | THE SOFTWARE. 27 | */ 28 | 29 | #include "appmcconfig.h" 30 | #include 31 | #include 32 | #include 33 | #include 34 | #include 35 | #include "approxmc.h" 36 | #include "appmc_constants.h" 37 | 38 | using std::string; 39 | using std::vector; 40 | using std::map; 41 | using std::pair; 42 | using namespace CMSat; 43 | using std::unique_ptr; 44 | 45 | namespace AppMCInt { 46 | 47 | struct SavedModel 48 | { 49 | SavedModel (const vector& _model, uint32_t _hash_num): 50 | model(_model), hash_num(_hash_num) {} 51 | const vector model; 52 | uint32_t hash_num; 53 | }; 54 | 55 | struct Hash { 56 | Hash () = default; 57 | Hash(const uint32_t _act_var, const vector& _hash_vars, const bool _rhs): 58 | act_var(_act_var), hash_vars(_hash_vars), rhs(_rhs) {} 59 | 60 | uint32_t act_var; 61 | vector hash_vars; 62 | bool rhs; 63 | }; 64 | 65 | struct HashesModels { 66 | map hashes; 67 | vector glob_model; //global table storing models 68 | 69 | void clear() { 70 | hashes.clear(); 71 | vector clean_glob_model; 72 | for(auto const& m: glob_model) { 73 | if (m.hash_num == 0) clean_glob_model.push_back(m); 74 | } 75 | std::swap(glob_model, clean_glob_model); 76 | } 77 | }; 78 | 79 | struct SolNum { 80 | SolNum (uint64_t _solutions, uint64_t _repeated): 81 | solutions(_solutions), repeated(_repeated) {} 82 | uint64_t solutions = 0; 83 | uint64_t repeated = 0; 84 | }; 85 | 86 | struct SparseData { 87 | explicit SparseData(int _table_no) : table_no(_table_no) {} 88 | 89 | uint32_t next_index = 0; 90 | double sparseprob = 0.5; 91 | int table_no = -1; 92 | }; 93 | 94 | class Counter { 95 | public: 96 | Counter(Config& _conf, const unique_ptr& _fg) : fg(_fg->dup()), conf(_conf) {} 97 | ApproxMC::SolCount solve(); 98 | string gen_rnd_bits(const uint32_t size, 99 | const uint32_t numhashes, SparseData& sparse_data); 100 | string binary(const uint32_t x, const uint32_t length); 101 | bool find_one_solution(); 102 | bool gen_rhs(); 103 | uint32_t threshold_appmcgen; 104 | unique_ptr solver = nullptr; 105 | ApproxMC::SolCount calc_est_count(); 106 | const Constants constants; 107 | bool solver_add_clause(const vector& cl); 108 | bool solver_add_xor_clause(const vector& vars, const bool rhs); 109 | bool solver_add_xor_clause(const vector& lits, const bool rhs); 110 | 111 | private: 112 | unique_ptr fg; 113 | Config& conf; 114 | ApproxMC::SolCount count(); 115 | void add_appmc_options(); 116 | Hash add_hash(uint32_t total_num_hashes, SparseData& sparse_data); 117 | SolNum bounded_sol_count( 118 | uint32_t max_sols, 119 | const vector* assumps, 120 | const uint32_t hash_cnt, 121 | const uint32_t iter, 122 | HashesModels* hm = nullptr 123 | ); 124 | vector set_num_hashes( 125 | uint32_t num_wanted, 126 | map& hashes, 127 | SparseData& sparse_data 128 | ); 129 | void simplify(); 130 | 131 | //////////////// 132 | //Helper functions 133 | //////////////// 134 | void dump_cnf_from_solver(const vector& assumps, const uint32_t iter, const lbool result); 135 | void print_xor(const vector& vars, const uint32_t rhs); 136 | void one_measurement_count( 137 | int64_t& prev_measure, 138 | const unsigned iter, 139 | SparseData sparse_data, 140 | HashesModels* hm 141 | ); 142 | void call_after_parse(); 143 | void ban_one(const uint32_t act_var, const vector& model); 144 | void check_model( 145 | const vector& model, 146 | const HashesModels* const hm, 147 | const uint32_t hash_count 148 | ); 149 | bool check_model_against_hash(const Hash& h, const vector& model); 150 | uint64_t add_glob_banning_cls( 151 | const HashesModels* glob_model = nullptr 152 | , const uint32_t act_var = std::numeric_limits::max() 153 | , const uint32_t num_hashes = std::numeric_limits::max() 154 | ); 155 | 156 | int find_best_sparse_match(); 157 | void set_up_probs_threshold_measurements(uint32_t& measurements, SparseData& sparse_data); 158 | double calc_error_bound(uint32_t t, double p); 159 | 160 | //Data so we can output temporary count when catching the signal 161 | vector num_hash_list; 162 | vector num_count_list; 163 | template T find_median(const vector& nums); 164 | template T find_min(const vector& nums); 165 | 166 | //////////////// 167 | // internal data 168 | //////////////// 169 | double start_time; 170 | std::mt19937 rnd_engine; 171 | uint32_t orig_num_vars; 172 | double total_inter_simp_time = 0; 173 | uint32_t threshold; //precision, it's computed 174 | uint32_t cnf_dump_no = 0; 175 | vector> cls_in_solver; // needed for accurate dumping 176 | vector, bool>> xors_in_solver; // needed for accurate dumping 177 | }; 178 | 179 | } 180 | -------------------------------------------------------------------------------- /src/time_mem.h: -------------------------------------------------------------------------------- 1 | /********************************************************* 2 | MiniSat -- Copyright (c) 2003-2006, Niklas Een, Niklas Sorensson 3 | CryptoMiniSat -- Copyright (C) 2009-2020 Authors of CryptoMiniSat, see AUTHORS file 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in 13 | all copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 21 | THE SOFTWARE. 22 | ***********************************************************/ 23 | 24 | #pragma once 25 | 26 | #include 27 | #include 28 | #include 29 | 30 | #include 31 | #include 32 | #include 33 | #include 34 | #include 35 | #include 36 | 37 | // note: MinGW64 defines both __MINGW32__ and __MINGW64__ 38 | #if defined (_MSC_VER) || defined (__MINGW32__) || defined(_WIN32) || defined(__EMSCRIPTEN__) 39 | #include 40 | static inline double cpu_time(void) 41 | { 42 | return (double)clock() / CLOCKS_PER_SEC; 43 | } 44 | 45 | #else //Linux or POSIX 46 | #include 47 | #include 48 | #include 49 | 50 | static inline double cpu_time(void) 51 | { 52 | struct rusage ru; 53 | [[maybe_unused]] int ret = getrusage(RUSAGE_SELF, &ru); 54 | assert(ret == 0); 55 | 56 | return (double)ru.ru_utime.tv_sec + ((double)ru.ru_utime.tv_usec / 1000000.0); 57 | } 58 | 59 | #endif 60 | 61 | #if defined(__linux__) 62 | // process_mem_usage(double &, double &) - takes two doubles by reference, 63 | // attempts to read the system-dependent data for a process' virtual memory 64 | // size and resident set size, and return the results in KB. 65 | // 66 | // On failure, returns 0.0, 0.0 67 | static inline uint64_t mem_used(double& vm_usage, std::string* max_mem_usage = nullptr) 68 | { 69 | //double& vm_usage 70 | using std::ios_base; 71 | using std::ifstream; 72 | using std::string; 73 | 74 | vm_usage = 0.0; 75 | 76 | // 'file' stat seems to give the most reliable results 77 | // 78 | ifstream stat_stream("/proc/self/stat",ios_base::in); 79 | 80 | // dummy vars for leading entries in stat that we don't care about 81 | // 82 | string pid; // The process ID. 83 | string comm; //The filename of the executable, in parentheses. 84 | string state; //One of the following characters, indicating process (see man stat(2)) 85 | string ppid; //The PID of the parent of this process. 86 | string pgrp; //The process group ID of the process. 87 | string session; //The session ID of the process. 88 | 89 | //The controlling terminal of the process. (The minor device number is contained in the combina‐ 90 | //tion of bits 31 to 20 and 7 to 0; the major device number is in bits 15 to 8.) 91 | string tty_nr; 92 | 93 | //The ID of the foreground process group of the controlling terminal of the process. 94 | string tpgid; 95 | 96 | 97 | string flags; 98 | string minflt; 99 | string cminflt; 100 | string majflt; 101 | string cmajflt; 102 | string utime; 103 | string stime; 104 | string cutime; 105 | string cstime; 106 | string priority; 107 | string nice; 108 | 109 | //Number of threads in this process (since Linux 2.6). Before kernel 2.6, this field was hard 110 | //coded to 0 as a placeholder for an earlier removed field. 111 | string num_threads; 112 | 113 | string itrealvalue; 114 | string starttime; 115 | 116 | /**** the two fields we want *****/ 117 | unsigned long vsize; //Virtual memory size in bytes. 118 | 119 | //Resident Set Size: number of pages the process has in real memory. This is just the pages which 120 | //count toward text, data, or stack space. This does not include pages which have not been demand- 121 | //loaded in, or which are swapped out. 122 | long rss; 123 | /**** the two fields we want *****/ 124 | 125 | stat_stream >> pid >> comm >> state >> ppid >> pgrp >> session >> tty_nr 126 | >> tpgid >> flags >> minflt >> cminflt >> majflt >> cmajflt 127 | >> utime >> stime >> cutime >> cstime >> priority >> nice 128 | >> num_threads >> itrealvalue >> starttime >> vsize >> rss; // don't care about the rest 129 | 130 | stat_stream.close(); 131 | 132 | long page_size_kb = sysconf(_SC_PAGE_SIZE); // in case x86-64 is configured to use 2MB pages 133 | vm_usage = vsize; 134 | double resident_set = (double)rss * (double)page_size_kb; 135 | 136 | if (max_mem_usage != nullptr) { 137 | //NOTE: we could query the MAXIMUM resident size using 138 | // /proc/self/status 139 | // as it contains: * VmHWM: Peak resident set size ("high water mark"). 140 | // but we'd need to parse it, etc. 141 | // see man(5) proc for details 142 | // This note is related to issue #629 in CryptoMiniSat 143 | ifstream stat_stream2("/proc/self/status",ios_base::in); 144 | string tp; 145 | while(getline(stat_stream2, tp)){ 146 | if (tp.size() > 7 && tp.find("VmHWM:") != std::string::npos) { 147 | tp.erase(0, 7); 148 | tp.erase(tp.begin(), 149 | std::find_if(tp.begin(), tp.end(), 150 | std::bind(std::not_equal_to(), '\t', std::placeholders::_1))); 151 | tp.erase(tp.begin(), 152 | std::find_if(tp.begin(), tp.end(), 153 | std::bind(std::not_equal_to(), ' ', std::placeholders::_1))); 154 | *max_mem_usage = tp; 155 | } 156 | } 157 | } 158 | 159 | return resident_set; 160 | } 161 | #elif defined(__FreeBSD__) 162 | #include 163 | inline uint64_t mem_used(double& vm_usage, std::string* max_mem_usage = nullptr) 164 | { 165 | vm_usage = 0; 166 | 167 | struct rusage ru; 168 | getrusage(RUSAGE_SELF, &ru); 169 | return ru.ru_maxrss*1024; 170 | } 171 | #else //Windows 172 | static inline size_t mem_used(double& vm_usage, std::string* max_mem_usage = nullptr) 173 | { 174 | vm_usage = 0; 175 | return 0; 176 | } 177 | #endif 178 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT) 2 | ![build](https://github.com/meelgroup/approxmc/workflows/build/badge.svg) 3 | 4 | # ApproxMC6: Approximate Model Counter 5 | ApproxMCv6 is a state-of-the-art approximate model counter using 6 | [Arjun](https://github.com/meelgroup/arjun) and 7 | [CryptoMiniSat](https://github.com/msoos/cryptominisat) to give probabilistic 8 | approximate model counts to problems of size and complexity that were not 9 | possible before. 10 | 11 | This work is the culmination of work by a number of people. See publication list at the end of this README for more details. 12 | 13 | ApproxMC handles CNF formulas and performs approximate counting. 14 | 1. If you are interested in exact model counting, visit our exact counter 15 | [Ganak](http://github.com/meelgroup/ganak) 16 | 2. If you need to count a weighted CNF formula, you need to preprocess your CNF 17 | using [our tool](https://github.com/meelgroup/weighted-to-unweighted) to 18 | convert it to an unweighted CNF formula. Then you can use ApproxMC to count it. 19 | 3. If you are interested in DNF formulas, visit our approximate DNF 20 | counter [Pepin](https://github.com/meelgroup/pepin). 21 | 22 | Notice that for some formula families, Ganak is faster than ApproxMC. It 23 | can be worthwhile to try both tools on your instances. 24 | 25 | ## Installation 26 | You can try out ApproxMC [from your browser](https://www.msoos.org/approxmc/). 27 | 28 | It is strongly recommended to not build, but to use the precompiled 29 | binaries as in our [release](https://github.com/meelgroup/approxmc/releases). 30 | The second best thing to use is Nix. Simply [install 31 | nix](https://nixos.org/download/) and then: 32 | ```shell 33 | nix shell github:meelgroup/approxmc#approxmc 34 | ``` 35 | 36 | Then you will have `approxmc` binary available and ready to use. 37 | 38 | If this is somehow not what you want, you can also build it. See the [GitHub 39 | Action](https://github.com/meelgroup/approxmc/actions/workflows/build.yml) for the 40 | specific set of steps. 41 | 42 | ## Providing a Projection Set 43 | For some applications, one is not interested in solutions over all the 44 | variables and instead interested in counting the number of unique solutions to 45 | a subset of variables, called sampling set (also called a "projection set"). 46 | ApproxMC allows you to specify the sampling set using the following modified 47 | version of DIMACS format: 48 | 49 | ```plain 50 | $ cat myfile.cnf 51 | c p show 1 3 4 6 7 8 10 0 52 | p cnf 500 1 53 | 3 4 0 54 | ``` 55 | Above, using the `c p show` line, we declare that only variables 1, 3, 4, 6, 7, 56 | 8 and 10 form part of the sampling set out of the CNF's 500 variables 57 | `1,2...500`. This line must end with a 0. The solution that ApproxMC will be 58 | giving is essentially answering the question: how many different combination of 59 | settings to this variables are there that satisfy this problem? Naturally, if 60 | your sampling set only contains 7 variables, then the maximum number of 61 | solutions can only be at most 2^7 = 128. This is true even if your CNF has 62 | thousands of variables. 63 | 64 | ## Running ApproxMC 65 | In our case, the maximum number of solutions could at most be 2^7=128, but our 66 | CNF should be restricting this. Let's see: 67 | 68 | ```plain 69 | $ approxmc --seed 5 myfile.cnf 70 | c ApproxMC version 3.0 71 | [...] 72 | c CryptoMiniSat SHA revision [...] 73 | c Using code from 'When Boolean Satisfiability Meets Gauss-E. in a Simplex Way' 74 | [...] 75 | [appmc] using seed: 5 76 | [appmc] Sampling set size: 7 77 | [appmc] Sampling set: 1, 3, 4, 6, 7, 8, 10, 78 | [appmc] Using start iteration 0 79 | [appmc] [ 0.00 ] bounded_sol_count looking for 73 solutions -- hashes active: 0 80 | [appmc] [ 0.01 ] bounded_sol_count looking for 73 solutions -- hashes active: 1 81 | [appmc] [ 0.01 ] bounded_sol_count looking for 73 solutions -- hashes active: 0 82 | [...] 83 | [appmc] FINISHED ApproxMC T: 0.04 s 84 | c [appmc] Number of solutions is: 48*2**1 85 | s mc 96 86 | ``` 87 | ApproxMC reports that we have approximately `96 (=48*2)` solutions to the CNF's 88 | independent support. This is because for variables 3 and 4 we have banned the 89 | `false,false` solution, so out of their 4 possible settings, one is banned. 90 | Therefore, we have `2^5 * (4-1) = 96` solutions. 91 | 92 | ## Guarantees 93 | ApproxMC provides so-called "PAC", or Probably Approximately Correct, 94 | guarantees. In less fancy words, the system guarantees that the solution found 95 | is within a certain tolerance (called "epsilon") with a certain probability 96 | (called "delta"). The default tolerance and probability, i.e. epsilon and delta 97 | values, are set to 0.8 and 0.2, respectively. Both values are configurable. 98 | 99 | ## How to use the Python interface 100 | Install using pip: 101 | ```bash 102 | pip install pyapproxmc 103 | ``` 104 | 105 | Then you can use it as: 106 | ```python 107 | import pyapproxmc 108 | c = pyapproxmc.Counter() 109 | c.add_clause([1,2,3]) 110 | c.add_clause([3,20]) 111 | count = c.count() 112 | print("Approximate count is: %d*2**%d" % (count[0], count[1])) 113 | ``` 114 | 115 | The above will print that `Approximate count is: 11*2**16`. Since the largest 116 | variable in the clauses was 20, the system contained 2\*\*20 (i.e. 1048576) 117 | potential models. However, some of these models were prohibited by the two 118 | clauses, and so only approximately 11*2\*\*16 (i.e. 720896) models remained. 119 | 120 | If you want to count over a projection set, you need to call 121 | `count(projection_set)`, for example: 122 | ```python 123 | import pyapproxmc 124 | c = pyapproxmc.Counter() 125 | c.add_clause([1,2,3]) 126 | c.add_clause([3,20]) 127 | count = c.count(range(1,10)) 128 | print("Approximate count is: %d*2**%d" % (count[0], count[1])) 129 | ``` 130 | 131 | This now prints `Approximate count is: 7*2**6`, which corresponds to the 132 | approximate count of models, projected over variables 1..10. 133 | 134 | ### Library usage 135 | The system can be used as a library: 136 | 137 | ```c++ 138 | #include 139 | #include 140 | #include 141 | 142 | using std::vector; 143 | using namespace ApproxMC; 144 | using namespace CMSat; 145 | 146 | int main() { 147 | AppMC appmc; 148 | appmc.new_vars(10); 149 | 150 | vector clause; 151 | 152 | //add "-3 4 0" 153 | clause.clear(); 154 | clause.push_back(Lit(2, true)); 155 | clause.push_back(Lit(3, false)); 156 | appmc.add_clause(clause); 157 | 158 | //add "3 -4 0" 159 | clause.clear(); 160 | clause.push_back(Lit(2, false)); 161 | clause.push_back(Lit(3, true)); 162 | appmc.add_clause(clause); 163 | 164 | SolCount c = appmc.count(); 165 | uint32_t cnt = std::pow(2, c.hashCount)*c.cellSolCount; 166 | assert(cnt == std::pow(2, 9)); 167 | 168 | return 0; 169 | } 170 | ``` 171 | 172 | ## Sparse XOR Counting 173 | You can turn on the sparse XORs using the flag `--sparse 1` but beware as reported in 174 | [LICS-20](http://www.cs.toronto.edu/~meel/Papers/lics20-ma.pdf) paper, 175 | this may slow down solving in some cases. It is likely to give a 176 | significant speedup if the number of solutions is very large. 177 | 178 | ## How to Cite 179 | If you use ApproxMC, please cite the following papers: 180 | [CAV-23](https://arxiv.org/pdf/2305.09247) 181 | , [AAAI-19](https://www.cs.toronto.edu/~meel/Papers/aaai19-sm.pdf) 182 | , [CAV-20](https://www.cs.toronto.edu/~meel/Papers/cav20-sgm.pdf) 183 | , [CAV-20](https://dblp.uni-trier.de/rec/conf/cav/SoosGM20.html?view=bibtex) 184 | , [LICS-20](https://www.cs.toronto.edu/~meel/publications/AM20.bib) 185 | , [AAAI-19](https://www.cs.toronto.edu/~meel/publications/SM19.bib) 186 | , [IJCAI-16](https://www.cs.toronto.edu/~meel/publications/CMV16.bib) 187 | , [CP-13](https://www.cs.toronto.edu/~meel/publications/CMV13b.bib) 188 | 189 | Additional related publications can be found [here](https://www.cs.toronto.edu/~meel/publications.html) 190 | 191 | ## Benchmarks Used 192 | The benchmarks used in our evaluation can be found [here](https://zenodo.org/records/10449477) 193 | -------------------------------------------------------------------------------- /.github/workflows/build.yml: -------------------------------------------------------------------------------- 1 | name: build 2 | 3 | on: 4 | pull_request: 5 | branches: [ "*" ] 6 | 7 | jobs: 8 | build: 9 | runs-on: ${{ matrix.os }} 10 | 11 | strategy: 12 | fail-fast: false 13 | 14 | matrix: 15 | os: [ubuntu-latest, macos-15, ubuntu-24.04-arm, macos-15-intel] 16 | build_type: [Release] 17 | staticcompile: [ON, OFF] 18 | 19 | steps: 20 | - uses: actions/setup-python@v5 21 | with: 22 | python-version: '3.10' 23 | 24 | - name: Install python dependencies 25 | run: | 26 | pip install numpy lit 27 | 28 | - name: Install gmp for Mac 29 | if: contains(matrix.os, 'macos') 30 | run: | 31 | wget https://ftp.gnu.org/gnu/gmp/gmp-6.3.0.tar.xz 32 | tar xf gmp-6.3.0.tar.xz 33 | cd gmp-6.3.0 34 | ./configure --enable-static -enable-cxx --enable-shared --with-pic 35 | make -j8 36 | sudo make install 37 | cd .. 38 | 39 | - name: Install zlib for Mac dynamic 40 | if: contains(matrix.os, 'macos') && matrix.staticcompile == 'OFF' 41 | run: | 42 | wget https://www.zlib.net/zlib-1.3.1.tar.gz 43 | tar xzvf zlib-1.3.1.tar.gz 44 | cd zlib-1.3.1 45 | ./configure 46 | make -j8 47 | sudo make install 48 | cd .. 49 | 50 | - name: Install zlib for Mac static 51 | if: contains(matrix.os, 'macos') && matrix.staticcompile == 'ON' 52 | run: | 53 | wget https://www.zlib.net/zlib-1.3.1.tar.gz 54 | tar xzvf zlib-1.3.1.tar.gz 55 | cd zlib-1.3.1 56 | ./configure --static 57 | make -j8 58 | sudo make install 59 | cd .. 60 | 61 | - name: Install mpfr for Mac 62 | if: contains(matrix.os, 'macos') 63 | run: | 64 | wget https://ftp.gnu.org/gnu/mpfr/mpfr-4.2.1.tar.xz 65 | tar xf mpfr-4.2.1.tar.xz 66 | cd mpfr-4.2.1 67 | ./configure --enable-static -enable-cxx --enable-shared 68 | make -j8 69 | sudo make install 70 | cd .. 71 | 72 | - name: Install dependencies for Linux 73 | if: contains(matrix.os, 'ubuntu') 74 | run: sudo apt-get update && sudo apt-get install -yq help2man libgmp-dev libmpfr-dev 75 | 76 | - name: Checkout Cadical 77 | uses: actions/checkout@v4 78 | with: 79 | repository: meelgroup/cadical 80 | ref: master 81 | path: cadical 82 | 83 | - name: Build Cadical 84 | run: | 85 | cd cadical 86 | CXXFLAGS=-fPIC ./configure --competition 87 | make -j8 88 | cd .. 89 | 90 | - name: Checkout Cadiback 91 | uses: actions/checkout@v4 92 | with: 93 | repository: meelgroup/cadiback 94 | ref: main 95 | path: cadiback 96 | - name: Build Cadiback 97 | run: | 98 | cd cadiback 99 | CXX=c++ ./configure 100 | make -j8 101 | cd .. 102 | 103 | - name: Checkout breakid 104 | uses: actions/checkout@v4 105 | with: 106 | repository: meelgroup/breakid 107 | ref: master 108 | path: breakid 109 | - name: Build Breakid 110 | run: | 111 | cd breakid 112 | mkdir build 113 | cd build 114 | cmake -DCMAKE_BUILD_TYPE=${{ matrix.build_type }} -DENABLE_TESTING=OFF -DSTATICCOMPILE=${{ matrix.staticcompile }} .. 115 | cd ../.. 116 | 117 | - name: Copy cadiback and cadical libs 118 | if: matrix.staticcompile == 'OFF' 119 | run: | 120 | sudo cp cadiback/libcadiback.so . 121 | sudo cp cadical/build/libcadical.so . 122 | 123 | - name: Copy cadiback and cadical libs 124 | if: matrix.staticcompile == 'OFF' && contains(matrix.os, 'ubuntu') 125 | run: | 126 | sudo cp cadiback/libcadiback.so /usr/lib/ 127 | sudo cp cadical/build/libcadical.so /usr/lib/ 128 | 129 | - name: Checkout CMS 130 | uses: actions/checkout@v4 131 | with: 132 | repository: msoos/cryptominisat 133 | ref: master 134 | path: cryptominisat 135 | submodules: 'true' 136 | - name: Build CMS 137 | run: | 138 | cd cryptominisat 139 | mkdir build &&cd build 140 | cmake -DCMAKE_BUILD_TYPE=${{ matrix.build_type }} -DENABLE_TESTING=OFF -DSTATICCOMPILE=${{ matrix.staticcompile }} .. 141 | cmake --build . --config ${{matrix.build_type}} 142 | cd ../.. 143 | 144 | - name: Checkout SBVA 145 | uses: actions/checkout@v4 146 | with: 147 | repository: meelgroup/SBVA 148 | ref: master 149 | path: sbva 150 | - name: Build SBVA 151 | run: | 152 | cd sbva 153 | mkdir build 154 | cd build 155 | ln -s ../scripts/*.sh . 156 | cmake -DCMAKE_BUILD_TYPE=${{ matrix.build_type }} -DENABLE_TESTING=OFF -DSTATICCOMPILE=${{ matrix.staticcompile }} .. 157 | cmake --build . --config ${{matrix.build_type}} -v 158 | cd ../.. 159 | 160 | - name: Checkout cereal 161 | run: | 162 | wget https://github.com/USCiLab/cereal/archive/v1.3.2.tar.gz 163 | - name: Build cereal 164 | run: | 165 | tar xvf v1.3.2.tar.gz 166 | # Fix cereal compilation on clang 19+; see 167 | # https://github.com/USCiLab/cereal/pull/835 168 | if sed --version >/dev/null 2>&1; then 169 | # GNU sed (Linux) 170 | sed -i 's|::template apply|::apply|' cereal-1.3.2/include/cereal/types/tuple.hpp 171 | else 172 | # BSD sed (macOS) 173 | sed -i '' 's|::template apply|::apply|' cereal-1.3.2/include/cereal/types/tuple.hpp 174 | fi 175 | cd cereal-1.3.2 176 | mkdir build 177 | cd build 178 | cmake -DJUST_INSTALL_CEREAL=ON .. 179 | make -j6 180 | sudo make install 181 | cd .. 182 | 183 | - name: Checkout armadillo 184 | run: | 185 | wget https://sourceforge.net/projects/arma/files/armadillo-14.0.2.tar.xz 186 | - name: Build armadillo 187 | run: | 188 | tar xvf armadillo-14.0.2.tar.xz 189 | cd armadillo-14.0.2/ 190 | ./configure 191 | make -j6 192 | sudo make install 193 | cd .. 194 | 195 | - name: Checkout ensmallen 196 | run: | 197 | wget https://ensmallen.org/files/ensmallen-2.22.2.tar.gz 198 | - name: Build ensmallen 199 | run: | 200 | tar xvf ensmallen-2.22.2.tar.gz 201 | cd ensmallen-2.22.2 202 | mkdir build 203 | cd build 204 | cmake -DCMAKE_POLICY_VERSION_MINIMUM=3.5 .. 205 | cmake --build . --config ${{matrix.build_type}} -v 206 | sudo make install 207 | cd ../.. 208 | 209 | - name: Checkout mlpack 210 | uses: actions/checkout@v4 211 | with: 212 | repository: mlpack/mlpack 213 | ref: 4.6.2 214 | path: mlpack 215 | - name: Build mlpack 216 | run: | 217 | cd mlpack 218 | mkdir build 219 | cd build 220 | cmake -DBUILD_SHARED_LIBS=ON -DBUILD_CLI_EXECUTABLES=OFF .. 221 | cmake --build . --config ${{matrix.build_type}} -v 222 | sudo make install 223 | cd ../.. 224 | 225 | - name: Checkout arjun 226 | uses: actions/checkout@v4 227 | with: 228 | repository: meelgroup/arjun 229 | ref: master 230 | path: arjun 231 | - name: Build arjun 232 | run: | 233 | cd arjun 234 | mkdir build 235 | cd build 236 | cmake \ 237 | -DCMAKE_BUILD_TYPE=${{ matrix.build_type }} \ 238 | -DSTATICCOMPILE=${{ matrix.staticcompile }} \ 239 | -DENABLE_TESTING=OFF \ 240 | -S .. 241 | cmake --build . --config ${{matrix.build_type}} -v 242 | cd ../.. 243 | 244 | - uses: actions/checkout@v4 245 | with: 246 | path: project 247 | submodules: 'true' 248 | - name: Build project 249 | run: | 250 | cd project 251 | mkdir -p build && cd build 252 | cmake \ 253 | -DCMAKE_BUILD_TYPE=${{ matrix.build_type }} \ 254 | -DSTATICCOMPILE=${{ matrix.staticcompile }} \ 255 | -S .. 256 | cmake --build . --config ${{matrix.build_type}} -v 257 | 258 | - name: Test 259 | run: ctest -C ${{matrix.build_type}} --verbose 260 | 261 | - name: run it to check it executes 262 | run: | 263 | echo "Running version command" 264 | ./project/build/approxmc --version 265 | echo $? 266 | echo "Running help command" 267 | ./project/build/approxmc --help 268 | echo $? 269 | 270 | 271 | - name: Upload Artifact - Linux 272 | if: matrix.os == 'ubuntu-latest' && matrix.staticcompile == 'ON' 273 | uses: actions/upload-artifact@v4 274 | with: 275 | name: approxmc-linux-amd64 276 | path: | 277 | project/build/approxmc 278 | project/build/lib/* 279 | project/build/include/* 280 | 281 | - name: Upload Artifact - Linux arm 282 | if: matrix.os == 'ubuntu-24.04-arm' && matrix.staticcompile == 'ON' 283 | uses: actions/upload-artifact@v4 284 | with: 285 | name: approxmc-linux-arm64 286 | path: | 287 | project/build/approxmc 288 | project/build/lib/* 289 | project/build/include/* 290 | 291 | - name: Upload Artifact - Mac arm 292 | if: matrix.os == 'macos-14' && matrix.staticcompile == 'ON' 293 | uses: actions/upload-artifact@v4 294 | with: 295 | name: approxmc-mac-arm64 296 | path: | 297 | project/build/approxmc 298 | project/build/lib/* 299 | project/build/include/* 300 | 301 | - name: Upload Artifact - Mac x86 302 | if: matrix.os == 'macos-15-intel' && matrix.staticcompile == 'ON' 303 | uses: actions/upload-artifact@v4 304 | with: 305 | name: approxmc-mac-x86_64 306 | path: | 307 | project/build/approxmc 308 | project/build/lib/* 309 | project/build/include/* 310 | -------------------------------------------------------------------------------- /html/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | ApproxMC in your browser 11 | 85 | 86 | 87 |
88 |

ApproxMC Approximate Model Counter in Your Browser

89 |
Copy your CNF formula in the input box below and click "Run 90 | approxmc.js" to run the counter in your browser. The output will be 91 | displayed below the input box. Format description is available here. 93 | We only support unweighted instance for approximate counting.
94 | 95 |
96 | 97 | 105 |
106 | 107 |
108 | 109 | 110 | Loading WebAssembly module... 111 |
112 |
113 |
114 |
115 | 116 |
117 | 118 |
Ready - enter your input and click "Run approxmc.js"
119 |
120 |
121 | 122 | 250 | 251 | 252 | -------------------------------------------------------------------------------- /flake.lock: -------------------------------------------------------------------------------- 1 | { 2 | "nodes": { 3 | "arjun": { 4 | "inputs": { 5 | "cadiback": "cadiback", 6 | "cadical": "cadical_2", 7 | "cryptominisat": "cryptominisat", 8 | "nixpkgs": [ 9 | "nixpkgs" 10 | ], 11 | "sbva": "sbva" 12 | }, 13 | "locked": { 14 | "lastModified": 1765713217, 15 | "narHash": "sha256-Esz4ITSyeU+3LhRFLdEByZcBkBNlZfY2LkqZ4YQdTFs=", 16 | "owner": "meelgroup", 17 | "repo": "arjun", 18 | "rev": "2334ce5fd4c08c7dfc8f5a28ac1296dc119e85db", 19 | "type": "github" 20 | }, 21 | "original": { 22 | "owner": "meelgroup", 23 | "ref": "master", 24 | "repo": "arjun", 25 | "type": "github" 26 | } 27 | }, 28 | "cadiback": { 29 | "inputs": { 30 | "cadical": "cadical", 31 | "nixpkgs": [ 32 | "arjun", 33 | "nixpkgs" 34 | ] 35 | }, 36 | "locked": { 37 | "lastModified": 1765710932, 38 | "narHash": "sha256-Xlkjg5ClEW8F9er7BcYIbsXTh7HPpr6XaQUHLP8XNRY=", 39 | "owner": "meelgroup", 40 | "repo": "cadiback", 41 | "rev": "cdebc75b308149453f1e54d0dafe084caa2fee34", 42 | "type": "github" 43 | }, 44 | "original": { 45 | "owner": "meelgroup", 46 | "ref": "main", 47 | "repo": "cadiback", 48 | "type": "github" 49 | } 50 | }, 51 | "cadiback_2": { 52 | "inputs": { 53 | "cadical": "cadical_3", 54 | "nixpkgs": [ 55 | "arjun", 56 | "cryptominisat", 57 | "nixpkgs" 58 | ] 59 | }, 60 | "locked": { 61 | "lastModified": 1765710932, 62 | "narHash": "sha256-Xlkjg5ClEW8F9er7BcYIbsXTh7HPpr6XaQUHLP8XNRY=", 63 | "owner": "meelgroup", 64 | "repo": "cadiback", 65 | "rev": "cdebc75b308149453f1e54d0dafe084caa2fee34", 66 | "type": "github" 67 | }, 68 | "original": { 69 | "owner": "meelgroup", 70 | "ref": "main", 71 | "repo": "cadiback", 72 | "type": "github" 73 | } 74 | }, 75 | "cadiback_3": { 76 | "inputs": { 77 | "cadical": "cadical_5", 78 | "nixpkgs": [ 79 | "cryptominisat", 80 | "nixpkgs" 81 | ] 82 | }, 83 | "locked": { 84 | "lastModified": 1765710932, 85 | "narHash": "sha256-Xlkjg5ClEW8F9er7BcYIbsXTh7HPpr6XaQUHLP8XNRY=", 86 | "owner": "meelgroup", 87 | "repo": "cadiback", 88 | "rev": "cdebc75b308149453f1e54d0dafe084caa2fee34", 89 | "type": "github" 90 | }, 91 | "original": { 92 | "owner": "meelgroup", 93 | "ref": "main", 94 | "repo": "cadiback", 95 | "type": "github" 96 | } 97 | }, 98 | "cadical": { 99 | "inputs": { 100 | "nixpkgs": [ 101 | "arjun", 102 | "cadiback", 103 | "nixpkgs" 104 | ] 105 | }, 106 | "locked": { 107 | "lastModified": 1765644177, 108 | "narHash": "sha256-D1R6W0aKNqDxXqPeqVMkBwbkUCZbLIkwRlLwoIReG78=", 109 | "owner": "meelgroup", 110 | "repo": "cadical", 111 | "rev": "07959ac34f139c247208c850da76087d4911b86a", 112 | "type": "github" 113 | }, 114 | "original": { 115 | "owner": "meelgroup", 116 | "ref": "master", 117 | "repo": "cadical", 118 | "type": "github" 119 | } 120 | }, 121 | "cadical_2": { 122 | "inputs": { 123 | "nixpkgs": [ 124 | "arjun", 125 | "nixpkgs" 126 | ] 127 | }, 128 | "locked": { 129 | "lastModified": 1765644177, 130 | "narHash": "sha256-D1R6W0aKNqDxXqPeqVMkBwbkUCZbLIkwRlLwoIReG78=", 131 | "owner": "meelgroup", 132 | "repo": "cadical", 133 | "rev": "07959ac34f139c247208c850da76087d4911b86a", 134 | "type": "github" 135 | }, 136 | "original": { 137 | "owner": "meelgroup", 138 | "ref": "master", 139 | "repo": "cadical", 140 | "type": "github" 141 | } 142 | }, 143 | "cadical_3": { 144 | "inputs": { 145 | "nixpkgs": [ 146 | "arjun", 147 | "cryptominisat", 148 | "cadiback", 149 | "nixpkgs" 150 | ] 151 | }, 152 | "locked": { 153 | "lastModified": 1765644177, 154 | "narHash": "sha256-D1R6W0aKNqDxXqPeqVMkBwbkUCZbLIkwRlLwoIReG78=", 155 | "owner": "meelgroup", 156 | "repo": "cadical", 157 | "rev": "07959ac34f139c247208c850da76087d4911b86a", 158 | "type": "github" 159 | }, 160 | "original": { 161 | "owner": "meelgroup", 162 | "ref": "master", 163 | "repo": "cadical", 164 | "type": "github" 165 | } 166 | }, 167 | "cadical_4": { 168 | "inputs": { 169 | "nixpkgs": [ 170 | "arjun", 171 | "cryptominisat", 172 | "nixpkgs" 173 | ] 174 | }, 175 | "locked": { 176 | "lastModified": 1765644177, 177 | "narHash": "sha256-D1R6W0aKNqDxXqPeqVMkBwbkUCZbLIkwRlLwoIReG78=", 178 | "owner": "meelgroup", 179 | "repo": "cadical", 180 | "rev": "07959ac34f139c247208c850da76087d4911b86a", 181 | "type": "github" 182 | }, 183 | "original": { 184 | "owner": "meelgroup", 185 | "ref": "master", 186 | "repo": "cadical", 187 | "type": "github" 188 | } 189 | }, 190 | "cadical_5": { 191 | "inputs": { 192 | "nixpkgs": [ 193 | "cryptominisat", 194 | "cadiback", 195 | "nixpkgs" 196 | ] 197 | }, 198 | "locked": { 199 | "lastModified": 1765644177, 200 | "narHash": "sha256-D1R6W0aKNqDxXqPeqVMkBwbkUCZbLIkwRlLwoIReG78=", 201 | "owner": "meelgroup", 202 | "repo": "cadical", 203 | "rev": "07959ac34f139c247208c850da76087d4911b86a", 204 | "type": "github" 205 | }, 206 | "original": { 207 | "owner": "meelgroup", 208 | "ref": "master", 209 | "repo": "cadical", 210 | "type": "github" 211 | } 212 | }, 213 | "cadical_6": { 214 | "inputs": { 215 | "nixpkgs": [ 216 | "cryptominisat", 217 | "nixpkgs" 218 | ] 219 | }, 220 | "locked": { 221 | "lastModified": 1765644177, 222 | "narHash": "sha256-D1R6W0aKNqDxXqPeqVMkBwbkUCZbLIkwRlLwoIReG78=", 223 | "owner": "meelgroup", 224 | "repo": "cadical", 225 | "rev": "07959ac34f139c247208c850da76087d4911b86a", 226 | "type": "github" 227 | }, 228 | "original": { 229 | "owner": "meelgroup", 230 | "ref": "master", 231 | "repo": "cadical", 232 | "type": "github" 233 | } 234 | }, 235 | "cryptominisat": { 236 | "inputs": { 237 | "cadiback": "cadiback_2", 238 | "cadical": "cadical_4", 239 | "nixpkgs": [ 240 | "arjun", 241 | "nixpkgs" 242 | ] 243 | }, 244 | "locked": { 245 | "lastModified": 1765712642, 246 | "narHash": "sha256-jVxVtk6+DEpyYcziSKK6IuJlsw8rPHeLryQXJr6ANmE=", 247 | "owner": "msoos", 248 | "repo": "cryptominisat", 249 | "rev": "4c377ecab94ca9e9d3b2348204fb0ffe27fe6dec", 250 | "type": "github" 251 | }, 252 | "original": { 253 | "owner": "msoos", 254 | "ref": "master", 255 | "repo": "cryptominisat", 256 | "type": "github" 257 | } 258 | }, 259 | "cryptominisat_2": { 260 | "inputs": { 261 | "cadiback": "cadiback_3", 262 | "cadical": "cadical_6", 263 | "nixpkgs": [ 264 | "nixpkgs" 265 | ] 266 | }, 267 | "locked": { 268 | "lastModified": 1765712642, 269 | "narHash": "sha256-jVxVtk6+DEpyYcziSKK6IuJlsw8rPHeLryQXJr6ANmE=", 270 | "owner": "msoos", 271 | "repo": "cryptominisat", 272 | "rev": "4c377ecab94ca9e9d3b2348204fb0ffe27fe6dec", 273 | "type": "github" 274 | }, 275 | "original": { 276 | "owner": "msoos", 277 | "ref": "master", 278 | "repo": "cryptominisat", 279 | "type": "github" 280 | } 281 | }, 282 | "nixpkgs": { 283 | "locked": { 284 | "lastModified": 1764230294, 285 | "narHash": "sha256-Z63xl5Scj3Y/zRBPAWq1eT68n2wBWGCIEF4waZ0bQBE=", 286 | "owner": "nixos", 287 | "repo": "nixpkgs", 288 | "rev": "0d59e0290eefe0f12512043842d7096c4070f30e", 289 | "type": "github" 290 | }, 291 | "original": { 292 | "owner": "nixos", 293 | "ref": "nixpkgs-unstable", 294 | "repo": "nixpkgs", 295 | "type": "github" 296 | } 297 | }, 298 | "root": { 299 | "inputs": { 300 | "arjun": "arjun", 301 | "cryptominisat": "cryptominisat_2", 302 | "nixpkgs": "nixpkgs", 303 | "sbva": "sbva_2" 304 | } 305 | }, 306 | "sbva": { 307 | "inputs": { 308 | "nixpkgs": [ 309 | "arjun", 310 | "nixpkgs" 311 | ] 312 | }, 313 | "locked": { 314 | "lastModified": 1764364119, 315 | "narHash": "sha256-5Wyqvo8qHCg0DqiHut/SzLGEnE0WuwbjLL9eo5ZBjd8=", 316 | "owner": "meelgroup", 317 | "repo": "sbva", 318 | "rev": "65993dbc0a802c0f1f7c83fac514339227f27b71", 319 | "type": "github" 320 | }, 321 | "original": { 322 | "owner": "meelgroup", 323 | "ref": "master", 324 | "repo": "sbva", 325 | "type": "github" 326 | } 327 | }, 328 | "sbva_2": { 329 | "inputs": { 330 | "nixpkgs": [ 331 | "nixpkgs" 332 | ] 333 | }, 334 | "locked": { 335 | "lastModified": 1764364119, 336 | "narHash": "sha256-5Wyqvo8qHCg0DqiHut/SzLGEnE0WuwbjLL9eo5ZBjd8=", 337 | "owner": "meelgroup", 338 | "repo": "sbva", 339 | "rev": "65993dbc0a802c0f1f7c83fac514339227f27b71", 340 | "type": "github" 341 | }, 342 | "original": { 343 | "owner": "meelgroup", 344 | "ref": "master", 345 | "repo": "sbva", 346 | "type": "github" 347 | } 348 | } 349 | }, 350 | "root": "root", 351 | "version": 7 352 | } 353 | -------------------------------------------------------------------------------- /src/approxmc.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | ApproxMC 3 | 4 | Copyright (c) 2019-2020, Mate Soos and Kuldeep S. Meel. All rights reserved 5 | Copyright (c) 2009-2018, Mate Soos. All rights reserved. 6 | Copyright (c) 2015, Supratik Chakraborty, Daniel J. Fremont, 7 | Kuldeep S. Meel, Sanjit A. Seshia, Moshe Y. Vardi 8 | Copyright (c) 2014, Supratik Chakraborty, Kuldeep S. Meel, Moshe Y. Vardi 9 | 10 | Permission is hereby granted, free of charge, to any person obtaining a copy 11 | of this software and associated documentation files (the "Software"), to deal 12 | in the Software without restriction, including without limitation the rights 13 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 14 | copies of the Software, and to permit persons to whom the Software is 15 | furnished to do so, subject to the following conditions: 16 | 17 | The above copyright notice and this permission notice shall be included in 18 | all copies or substantial portions of the Software. 19 | 20 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 21 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 22 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 23 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 24 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 25 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 26 | THE SOFTWARE. 27 | */ 28 | 29 | #include "approxmc.h" 30 | #include "counter.h" 31 | #include "appmc_constants.h" 32 | #include "appmcconfig.h" 33 | #include "cryptominisat5/solvertypesmini.h" 34 | #include 35 | #include 36 | #include "GitSHA1.h" 37 | 38 | using std::cout; 39 | using std::endl; 40 | using namespace AppMCInt; 41 | 42 | #if defined _WIN32 43 | #define DLL_PUBLIC __declspec(dllexport) 44 | #else 45 | #define DLL_PUBLIC __attribute__ ((visibility ("default"))) 46 | #define DLL_LOCAL __attribute__ ((visibility ("hidden"))) 47 | #endif 48 | 49 | namespace ApproxMC { 50 | struct AppMCPrivateData { 51 | AppMCPrivateData(const std::unique_ptr& fg): 52 | conf(fg), 53 | counter(conf, fg) {} 54 | Config conf; 55 | Counter counter; 56 | bool sampl_vars_declared = false; 57 | }; 58 | } 59 | 60 | using namespace ApproxMC; 61 | 62 | DLL_PUBLIC AppMC::AppMC(const std::unique_ptr& _fg) 63 | { 64 | data = std::make_unique(_fg); 65 | data->counter.solver = std::make_unique(); 66 | data->counter.solver->set_up_for_scalmc(); 67 | data->counter.solver->set_allow_otf_gauss(); 68 | } 69 | 70 | DLL_PUBLIC AppMC::~AppMC() = default; 71 | 72 | // Helper function, used only in this unit 73 | void setup_sampling_vars(unique_ptr& data) 74 | { 75 | if (data->conf.verb) { 76 | cout << "c o [appmc] Sampling set size: " << data->conf.sampl_vars.size() << endl; 77 | if (data->conf.sampl_vars.size() > 100) { 78 | cout 79 | << "c o [appmc] Sampling var set contains over 100 variables, not displaying" 80 | << endl; 81 | } else { 82 | cout << "c o [appmc] Sampling set: "; 83 | for (auto v: data->conf.sampl_vars) { 84 | cout << v+1 << " "; 85 | } 86 | cout << "0" << endl; 87 | } 88 | } 89 | 90 | data->counter.solver->set_sampl_vars(data->conf.sampl_vars); 91 | } 92 | 93 | DLL_PUBLIC string AppMC::get_version_sha1() 94 | { 95 | return AppMCInt::get_version_sha1(); 96 | } 97 | 98 | DLL_PUBLIC void AppMC::set_verbosity(uint32_t verb) 99 | { 100 | data->conf.verb = verb; 101 | data->counter.solver->set_verbosity(std::max(0, (int)data->conf.verb-2)); 102 | } 103 | 104 | DLL_PUBLIC void AppMC::set_seed(uint32_t seed) 105 | { 106 | data->conf.seed = seed; 107 | } 108 | 109 | DLL_PUBLIC void AppMC::set_epsilon(double epsilon) 110 | { 111 | data->conf.epsilon = epsilon; 112 | } 113 | 114 | DLL_PUBLIC void AppMC::set_delta(double delta) 115 | { 116 | data->conf.delta = delta; 117 | } 118 | 119 | DLL_PUBLIC void AppMC::set_debug(int debug) { data->conf.debug = debug; } 120 | DLL_PUBLIC void AppMC::set_force_sol_extension(int val) { 121 | data->conf.force_sol_extension = val; 122 | } 123 | 124 | DLL_PUBLIC void AppMC::set_start_iter(uint32_t start_iter) 125 | { 126 | data->conf.start_iter = start_iter; 127 | } 128 | 129 | DLL_PUBLIC void AppMC::set_verb_cls(uint32_t verb_cls) 130 | { 131 | data->conf.verb_cls = verb_cls; 132 | } 133 | 134 | DLL_PUBLIC void AppMC::set_simplify(uint32_t simplify) 135 | { 136 | data->conf.simplify = simplify; 137 | if (!simplify) { 138 | data->counter.solver->set_no_bve(); 139 | data->counter.solver->set_no_bva(); 140 | data->counter.solver->set_scc(0); 141 | data->counter.solver->set_simplify(0); 142 | } 143 | } 144 | 145 | DLL_PUBLIC void AppMC::set_var_elim_ratio(double var_elim_ratio) 146 | { 147 | data->conf.var_elim_ratio = var_elim_ratio; 148 | } 149 | 150 | DLL_PUBLIC void AppMC::set_reuse_models(uint32_t reuse_models) 151 | { 152 | data->conf.reuse_models = reuse_models; 153 | } 154 | 155 | DLL_PUBLIC void AppMC::set_sparse(uint32_t sparse) 156 | { 157 | data->conf.sparse = sparse; 158 | } 159 | 160 | DLL_PUBLIC double AppMC::get_epsilon() 161 | { 162 | return data->conf.epsilon; 163 | } 164 | 165 | DLL_PUBLIC double AppMC::get_delta() 166 | { 167 | return data->conf.delta; 168 | } 169 | 170 | DLL_PUBLIC uint32_t AppMC::get_simplify() 171 | { 172 | return data->conf.simplify; 173 | } 174 | 175 | DLL_PUBLIC double AppMC::get_var_elim_ratio() 176 | { 177 | return data->conf.var_elim_ratio; 178 | } 179 | 180 | DLL_PUBLIC uint32_t AppMC::get_sparse() 181 | { 182 | return data->conf.sparse; 183 | } 184 | 185 | DLL_PUBLIC uint32_t AppMC::get_seed() 186 | { 187 | return data->conf.seed; 188 | } 189 | 190 | DLL_PUBLIC bool AppMC::get_reuse_models() 191 | { 192 | return data->conf.reuse_models; 193 | } 194 | 195 | DLL_PUBLIC bool AppMC::find_one_solution() 196 | { 197 | return data->counter.find_one_solution(); 198 | } 199 | 200 | DLL_PUBLIC ApproxMC::SolCount AppMC::count() 201 | { 202 | if (!data->sampl_vars_declared) { 203 | cout << "ERROR: Sampling set was not declared!" << endl; 204 | exit(-1); 205 | } 206 | if (data->conf.verb > 2) { 207 | cout << "c o [appmc] using seed: " << data->conf.seed << endl; 208 | } 209 | 210 | if (data->conf.epsilon < 0.0) { 211 | cout << "ERROR: invalid epsilon" << endl; 212 | exit(-1); 213 | } 214 | 215 | if (data->conf.delta <= 0.0 || data->conf.delta > 1.0) { 216 | cout << "ERROR: invalid delta: " << data->conf.delta << endl; 217 | exit(-1); 218 | } 219 | 220 | setup_sampling_vars(data); 221 | SolCount sol_count = data->counter.solve(); 222 | return sol_count; 223 | } 224 | 225 | DLL_PUBLIC void AppMC::set_sampl_vars(const vector& vars) 226 | { 227 | data->sampl_vars_declared = true; 228 | data->conf.sampl_vars_set = true; 229 | for(const auto& v: vars) { 230 | if (v >= data->counter.solver->nVars()) { 231 | std::cout << "ERROR: function set_projection_set() called with variable that is larger than the number of variables inside the solver. Exiting." << endl; 232 | assert(false); 233 | exit(-1); 234 | } 235 | } 236 | data->conf.sampl_vars = vars; 237 | } 238 | 239 | DLL_PUBLIC const std::vector& AppMC::get_sampl_vars() const { 240 | return data->conf.sampl_vars; 241 | } 242 | 243 | 244 | DLL_PUBLIC uint32_t AppMC::nVars() { 245 | return data->counter.solver->nVars(); 246 | } 247 | 248 | DLL_PUBLIC void AppMC::new_vars(uint32_t num) 249 | { 250 | data->counter.solver->new_vars(num); 251 | } 252 | 253 | DLL_PUBLIC void AppMC::new_var() 254 | { 255 | data->counter.solver->new_var(); 256 | } 257 | 258 | DLL_PUBLIC bool AppMC::add_red_clause(const vector& lits) 259 | { 260 | return data->counter.solver->add_red_clause(lits); 261 | } 262 | 263 | DLL_PUBLIC bool AppMC::add_clause(const vector& lits) 264 | { 265 | return data->counter.solver_add_clause(lits); 266 | } 267 | 268 | DLL_PUBLIC bool AppMC::add_xor_clause(const vector& lits, bool rhs) 269 | { 270 | return data->counter.solver_add_xor_clause(lits, rhs); 271 | } 272 | 273 | DLL_PUBLIC bool AppMC::add_xor_clause(const vector& vars, bool rhs) 274 | { 275 | return data->counter.solver_add_xor_clause(vars, rhs); 276 | } 277 | 278 | DLL_PUBLIC CMSat::SATSolver* AppMC::get_solver() 279 | { 280 | return data->counter.solver.get(); 281 | } 282 | 283 | DLL_PUBLIC const std::vector& AppMC::get_sampling_set() const 284 | { 285 | return data->conf.sampl_vars; 286 | } 287 | 288 | DLL_PUBLIC void AppMC::set_dump_intermediary_cnf(const int dump_intermediary_cnf) 289 | { 290 | data->conf.dump_intermediary_cnf = dump_intermediary_cnf; 291 | } 292 | 293 | DLL_PUBLIC void AppMC::print_stats(const double start_time) 294 | { 295 | data->counter.solver->set_verbosity(1); 296 | data->counter.solver->print_stats(start_time); 297 | data->counter.solver->set_verbosity(0); 298 | if (data->conf.verb > 2) { 299 | data->counter.solver->set_verbosity(data->conf.verb); 300 | } 301 | } 302 | 303 | DLL_PUBLIC bool AppMC::get_sampl_vars_set() const { 304 | return data->conf.sampl_vars_set; 305 | } 306 | 307 | DLL_PUBLIC void AppMC::set_multiplier_weight(const std::unique_ptr& weight) { 308 | data->conf.multiplier_weight = weight->dup(); 309 | } 310 | 311 | DLL_PUBLIC const std::unique_ptr& AppMC::get_multiplier_weight() const { 312 | return data->conf.multiplier_weight; 313 | } 314 | 315 | DLL_PUBLIC void AppMC::set_weighted(const bool weighted) { 316 | if (weighted) { 317 | cout << "ERROR: Weighted ApproxMC not supported" << endl; 318 | exit(-1); 319 | } 320 | } 321 | 322 | DLL_PUBLIC void AppMC::set_projected(const bool) { 323 | } 324 | 325 | DLL_PUBLIC void AppMC::set_lit_weight(const Lit&, const std::unique_ptr&) { 326 | cout << "ERROR: Weighted ApproxMC is not supported" << endl; 327 | exit(-1); 328 | } 329 | 330 | DLL_PUBLIC void AppMC::set_opt_sampl_vars(const std::vector&) { 331 | // Not interesting for AppMC 332 | } 333 | -------------------------------------------------------------------------------- /src/main.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | ApproxMC 3 | 4 | Copyright (c) 2019-2020, Mate Soos and Kuldeep S. Meel. All rights reserved 5 | Copyright (c) 2009-2018, Mate Soos. All rights reserved. 6 | Copyright (c) 2015, Supratik Chakraborty, Daniel J. Fremont, 7 | Kuldeep S. Meel, Sanjit A. Seshia, Moshe Y. Vardi 8 | Copyright (c) 2014, Supratik Chakraborty, Kuldeep S. Meel, Moshe Y. Vardi 9 | 10 | Permission is hereby granted, free of charge, to any person obtaining a copy 11 | of this software and associated documentation files (the "Software"), to deal 12 | in the Software without restriction, including without limitation the rights 13 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 14 | copies of the Software, and to permit persons to whom the Software is 15 | furnished to do so, subject to the following conditions: 16 | 17 | The above copyright notice and this permission notice shall be included in 18 | all copies or substantial portions of the Software. 19 | 20 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 21 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 22 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 23 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 24 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 25 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 26 | THE SOFTWARE. 27 | */ 28 | 29 | #include 30 | #include 31 | #include 32 | #if defined(__GNUC__) && defined(__linux__) 33 | #include 34 | #endif 35 | #include 36 | #include 37 | #include 38 | 39 | #include "approxmc.h" 40 | #include "time_mem.h" 41 | #include 42 | #include 43 | #include 44 | #include 45 | #include "src/argparse.hpp" 46 | 47 | using namespace CMSat; 48 | using std::cout; 49 | using std::endl; 50 | using std::set; 51 | using std::string; 52 | using std::vector; 53 | ApproxMC::AppMC* appmc = nullptr; 54 | argparse::ArgumentParser program = argparse::ArgumentParser("approxmc", 55 | ApproxMC::AppMC::get_version_sha1(), 56 | argparse::default_arguments::help); 57 | uint32_t verb = 1; 58 | uint32_t seed; 59 | double epsilon; 60 | double delta; 61 | uint32_t start_iter = 0; 62 | uint32_t verb_cls = 0; 63 | uint32_t simplify; 64 | double var_elim_ratio; 65 | uint32_t reuse_models = 1; 66 | uint32_t force_sol_extension = 0; 67 | uint32_t sparse = 0; 68 | int dump_intermediary_cnf = 0; 69 | int arjun_gates = 0; 70 | bool debug = false; 71 | std::unique_ptr fg; 72 | 73 | //Arjun 74 | ArjunNS::SimpConf simp_conf; 75 | ArjunNS::Arjun::ElimToFileConf etof_conf; 76 | int with_e = 0; 77 | bool do_arjun = true; 78 | bool do_backbone = false; 79 | 80 | #define myopt(name, var, fun, hhelp) \ 81 | program.add_argument(name) \ 82 | .action([&](const auto& a) {var = std::fun(a.c_str());}) \ 83 | .default_value(var) \ 84 | .help(hhelp) 85 | #define myopt2(name1, name2, var, fun, hhelp) \ 86 | program.add_argument(name1, name2) \ 87 | .action([&](const auto& a) {var = std::fun(a.c_str());}) \ 88 | .default_value(var) \ 89 | .help(hhelp) 90 | 91 | 92 | void print_version() { 93 | std::stringstream ss; 94 | cout << "c o CMS SHA1: " << CMSat::SATSolver::get_version_sha1() << endl; 95 | cout << "c o Arjun SHA1: " << ArjunNS::Arjun ::get_version_sha1() << endl; 96 | cout << "c o Arjun SBVA SHA1: " << ArjunNS::Arjun::get_sbva_version_sha1() << endl; 97 | cout << "c o ApproxMC SHA1: " << ApproxMC::AppMC::get_version_sha1() << endl; 98 | cout << CMSat::SATSolver::get_thanks_info("c o ") << endl; 99 | cout << ArjunNS::Arjun::get_thanks_info("c o ") << endl; 100 | } 101 | 102 | void add_appmc_options() 103 | { 104 | ApproxMC::AppMC tmp(fg); 105 | epsilon = tmp.get_epsilon(); 106 | delta = tmp.get_delta(); 107 | simplify = tmp.get_simplify(); 108 | var_elim_ratio = tmp.get_var_elim_ratio(); 109 | sparse = tmp.get_sparse(); 110 | seed = tmp.get_seed(); 111 | 112 | myopt2("-v", "--verb", verb, atoi, "Verbosity"); 113 | myopt2("-s", "--seed", seed, atoi, "Seed"); 114 | myopt2("-e", "--epsilon", epsilon, stod, 115 | "Tolerance parameter, i.e. how close is the count from the correct count? " 116 | "Count output is within bounds of (exact_count/(1+e)) < count < (exact_count*(1+e)). " 117 | "So e=0.8 means we'll output at most 180%% of exact count and at least 55%% of exact count. " 118 | "Lower value means more precise."); 119 | myopt2("-d", "--delta", delta, stod, "Confidence parameter, i.e. how sure are we of the result? " 120 | "(1-d) = probability the count is within range as per epsilon parameter. " 121 | "So d=0.2 means we are 80%% sure the count is within range as specified by epsilon. " 122 | "The lower, the higher confidence we have in the count."); 123 | program.add_argument("-v", "--version") \ 124 | .action([&](const auto&) {print_version(); exit(0);}) \ 125 | .flag() 126 | .help("Print version and exit"); 127 | 128 | /* arjun_options.add_options() */ 129 | myopt("--arjun", do_arjun, atoi, "Use arjun to minimize sampling set"); 130 | 131 | /* improvement_options.add_options() */ 132 | myopt("--sparse", sparse, atoi, 133 | "0 = (default) Do not use sparse method. 1 = Generate sparse XORs when possible."); 134 | myopt("--reusemodels", reuse_models, atoi, "Reuse models while counting solutions"); 135 | myopt("--forcesolextension", force_sol_extension, atoi, 136 | "Use trick of not extending solutions in the SAT solver to full solution"); 137 | myopt("--withe", with_e, atoi, "Eliminate variables and simplify CNF as well"); 138 | myopt("--eiter1", simp_conf.iter1, atoi, "Num iters of E on 1st round"); 139 | myopt("--eiter2", simp_conf.iter2, atoi, "Num iters of E on 1st round"); 140 | myopt("--evivif", simp_conf.oracle_vivify, atoi, "E vivif"); 141 | myopt("--esparsif", simp_conf.oracle_sparsify, atoi, "E sparsify"); 142 | myopt("--egetreds", simp_conf.oracle_vivify_get_learnts, atoi, "Get redundant from E"); 143 | 144 | /* misc_options.add_options() */ 145 | myopt("--verbcls", verb_cls, atoi, "Print banning clause + xor clauses. Highly verbose."); 146 | myopt("--simplify", simplify, atoi, "Simplify aggressiveness"); 147 | myopt("--velimratio", var_elim_ratio, stod, "Variable elimination ratio for each simplify run"); 148 | myopt("--dumpintercnf", dump_intermediary_cnf, atoi, 149 | "Dump intermediary CNFs during solving into files cnf_dump-X.cnf. If set to 1 only UNSAT is dumped, if set to 2, all are dumped"); 150 | myopt("--debug", debug, atoi, "Turn on more heavy internal debugging"); 151 | myopt("--backbone", do_backbone, atoi, "Run backbone analysis"); 152 | 153 | program.add_argument("inputfile").remaining().help("input CNF"); 154 | } 155 | 156 | void parse_supported_options(int argc, char** argv) { 157 | add_appmc_options(); 158 | try { 159 | program.parse_args(argc, argv); 160 | if (program.is_used("--help")) { 161 | cout << "Probabilistic Approximate Counter" << endl << endl 162 | << "approxmc [options] inputfile" << endl; 163 | cout << program << endl; 164 | exit(0); 165 | } 166 | } 167 | catch (const std::exception& err) { 168 | std::cerr << err.what() << std::endl; 169 | exit(-1); 170 | } 171 | } 172 | 173 | inline double stats_line_percent(double num, double total) 174 | { 175 | if (total == 0) { return 0; 176 | } else { return num/total*100.0; 177 | } 178 | } 179 | 180 | void print_final_indep_set(const vector& indep_set, uint32_t orig_sampling_set_size) 181 | { 182 | cout << "c o ind "; 183 | for(const uint32_t s: indep_set) cout << s+1 << " "; 184 | cout << "0" << endl; 185 | 186 | cout 187 | << "c o [arjun] final set size: " << std::setw(7) << indep_set.size() 188 | << " percent of original: " 189 | << std::setw(6) << std::setprecision(4) 190 | << stats_line_percent(indep_set.size(), orig_sampling_set_size) 191 | << " %" << endl; 192 | } 193 | 194 | void print_num_solutions(uint32_t cell_sol_cnt, uint32_t hash_count, const std::unique_ptr& mult_ptr) { 195 | const CMSat::Field* ptr = mult_ptr.get(); 196 | const ArjunNS::FMpq* mult = dynamic_cast(ptr); 197 | cout << "c [appmc] Number of solutions is: " 198 | << cell_sol_cnt << "*2**" << hash_count << "*" << mult->val << endl; 199 | if (cell_sol_cnt == 0 || mult->val == 0) cout << "s UNSATISFIABLE" << endl; 200 | else cout << "s SATISFIABLE" << endl; 201 | 202 | mpz_class num_sols(2); 203 | mpz_pow_ui(num_sols.get_mpz_t(), num_sols.get_mpz_t(), hash_count); 204 | num_sols *= cell_sol_cnt; 205 | auto final = mult->val * num_sols; 206 | 207 | cout << "s mc " << final << endl; 208 | } 209 | 210 | void set_approxmc_options() 211 | { 212 | //Main options 213 | appmc->set_verbosity(verb); 214 | appmc->set_seed(seed); 215 | appmc->set_epsilon(epsilon); 216 | appmc->set_delta(delta); 217 | 218 | //Improvement options 219 | appmc->set_reuse_models(reuse_models); 220 | appmc->set_sparse(sparse); 221 | 222 | //Misc options 223 | appmc->set_start_iter(start_iter); 224 | appmc->set_verb_cls(verb_cls); 225 | appmc->set_simplify(simplify); 226 | appmc->set_var_elim_ratio(var_elim_ratio); 227 | appmc->set_dump_intermediary_cnf(dump_intermediary_cnf); 228 | appmc->set_force_sol_extension(force_sol_extension); 229 | if (debug) { 230 | appmc->set_force_sol_extension(1); 231 | appmc->set_debug(1); 232 | appmc->set_dump_intermediary_cnf(std::max(dump_intermediary_cnf, 1)); 233 | } 234 | } 235 | 236 | template void parse_file(const std::string& filename, T* reader) { 237 | #ifndef USE_ZLIB 238 | FILE * in = fopen(filename.c_str(), "rb"); 239 | DimacsParser, T> parser(reader, nullptr, 0, fg); 240 | #else 241 | gzFile in = gzopen(filename.c_str(), "rb"); 242 | DimacsParser, T> parser(reader, nullptr, 0, fg); 243 | #endif 244 | if (in == nullptr) { 245 | std::cout << "ERROR! Could not open file '" << filename 246 | << "' for reading: " << strerror(errno) << endl; 247 | std::exit(-1); 248 | } 249 | if (!parser.parse_DIMACS(in, true)) exit(-1); 250 | #ifndef USE_ZLIB 251 | fclose(in); 252 | #else 253 | gzclose(in); 254 | #endif 255 | 256 | if (!reader->get_sampl_vars_set()) { 257 | vector tmp; 258 | for(uint32_t i = 0; i < reader->nVars(); i++) tmp.push_back(i); 259 | reader->set_sampl_vars(tmp); 260 | } else { 261 | // Check if CNF has all vars as indep. Then it's all_indep 262 | set tmp; 263 | for(auto const& s: reader->get_sampl_vars()) { 264 | if (s >= reader->nVars()) { 265 | cout << "ERROR: Sampling var " << s+1 << " is larger than number of vars in formula: " 266 | << reader->nVars() << endl; 267 | exit(-1); 268 | } 269 | tmp.insert(s); 270 | } 271 | if (tmp.size() == reader->nVars()) etof_conf.all_indep = true; 272 | if (!reader->get_opt_sampl_vars_set()) { 273 | reader->set_opt_sampl_vars(reader->get_sampl_vars()); 274 | } 275 | } 276 | } 277 | 278 | int main(int argc, char** argv) 279 | { 280 | #if defined(__GNUC__) && defined(__linux__) 281 | feenableexcept(FE_INVALID | FE_DIVBYZERO | FE_OVERFLOW); 282 | #endif 283 | double start_time = cpu_time(); 284 | 285 | //Reconstruct the command line so we can emit it later if needed 286 | string command_line; 287 | for(int i = 0; i < argc; i++) { 288 | command_line += string(argv[i]); 289 | if (i+1 < argc) command_line += " "; 290 | } 291 | 292 | fg = std::make_unique(); 293 | appmc = new ApproxMC::AppMC(fg); 294 | simp_conf.appmc = true; 295 | simp_conf.oracle_sparsify = false; 296 | simp_conf.iter1 = 2; 297 | simp_conf.iter2 = 0; 298 | etof_conf.do_bce = false; 299 | etof_conf.do_extend_indep = false; 300 | parse_supported_options(argc, argv); 301 | if (verb) { 302 | print_version(); 303 | cout << "c o executed with command line: " << command_line << endl; 304 | } 305 | set_approxmc_options(); 306 | 307 | ArjunNS::SimplifiedCNF cnf(fg); 308 | if (!program.is_used("inputfile")) { 309 | cout << "ERROR: you need to provide an input file. Exiting." << endl; 310 | exit(-1); 311 | } 312 | const auto& files = program.get>("inputfile"); 313 | if (files.empty()) { 314 | cout << "ERROR: you provided --inputfile but no file. Strange. Exiting. " << endl; 315 | exit(-1); 316 | } 317 | const string fname(files[0]); 318 | if (do_arjun) { 319 | parse_file(fname, &cnf); 320 | const auto orig_sampl_vars = cnf.sampl_vars; 321 | double my_time = cpu_time(); 322 | ArjunNS::Arjun arjun; 323 | arjun.set_verb(verb); 324 | arjun.set_or_gate_based(arjun_gates); 325 | arjun.set_xor_gates_based(arjun_gates); 326 | arjun.set_ite_gate_based(arjun_gates); 327 | arjun.set_irreg_gate_based(arjun_gates); 328 | if (do_backbone) 329 | arjun.standalone_backbone(cnf); 330 | arjun.standalone_minimize_indep(cnf, etof_conf.all_indep); 331 | if (with_e) arjun.standalone_elim_to_file(cnf, etof_conf, simp_conf); 332 | appmc->new_vars(cnf.nVars()); 333 | appmc->set_sampl_vars(cnf.sampl_vars); 334 | for(const auto& c: cnf.clauses) appmc->add_clause(c); 335 | for(const auto& c: cnf.red_clauses) appmc->add_red_clause(c); 336 | appmc->set_multiplier_weight(cnf.multiplier_weight); 337 | print_final_indep_set(cnf.sampl_vars, orig_sampl_vars.size()); 338 | cout << "c o [arjun] Arjun finished. T: " << (cpu_time() - my_time) << endl; 339 | } else { 340 | parse_file(fname, appmc); 341 | print_final_indep_set(appmc->get_sampl_vars(), appmc->get_sampl_vars().size()); 342 | } 343 | 344 | ApproxMC::SolCount sol_count; 345 | sol_count = appmc->count(); 346 | appmc->print_stats(start_time); 347 | cout << "c o [appmc+arjun] Total time: " << (cpu_time() - start_time) << endl; 348 | print_num_solutions(sol_count.cellSolCount, sol_count.hashCount, appmc->get_multiplier_weight()); 349 | 350 | delete appmc; 351 | } 352 | -------------------------------------------------------------------------------- /tests/test_helper.h: -------------------------------------------------------------------------------- 1 | /****************************************** 2 | Copyright (c) 2016, Mate Soos 3 | 4 | Permission is hereby granted, free of charge, to any person obtaining a copy 5 | of this software and associated documentation files (the "Software"), to deal 6 | in the Software without restriction, including without limitation the rights 7 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8 | copies of the Software, and to permit persons to whom the Software is 9 | furnished to do so, subject to the following conditions: 10 | 11 | The above copyright notice and this permission notice shall be included in 12 | all copies or substantial portions of the Software. 13 | 14 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 20 | THE SOFTWARE. 21 | ***********************************************/ 22 | 23 | #ifndef TEST_HELPER__H 24 | #define TEST_HELPER__H 25 | 26 | #include 27 | #include 28 | #include 29 | #include 30 | #include 31 | #include 32 | #include 33 | #include 34 | #include 35 | #include 36 | #include 37 | 38 | using std::cout; 39 | using std::endl; 40 | using std::vector; 41 | using std::string; 42 | using std::istringstream; 43 | using std::stringstream; 44 | using namespace CMSat; 45 | 46 | class Xor 47 | { 48 | public: 49 | Xor() 50 | {} 51 | 52 | explicit Xor(const vector& cl, const bool _rhs, const vector& _clash_vars): 53 | rhs(_rhs) 54 | , clash_vars(_clash_vars) 55 | { 56 | for (uint32_t i = 0; i < cl.size(); i++) { 57 | vars.push_back(cl[i]); 58 | } 59 | } 60 | 61 | template 62 | explicit Xor(const T& cl, const bool _rhs, const vector& _clash_vars): 63 | rhs(_rhs) 64 | , clash_vars(_clash_vars) 65 | { 66 | for (uint32_t i = 0; i < cl.size(); i++) { 67 | vars.push_back(cl[i].var()); 68 | } 69 | } 70 | 71 | explicit Xor(const vector& cl, const bool _rhs, const uint32_t clash_var): 72 | rhs(_rhs) 73 | { 74 | clash_vars.push_back(clash_var); 75 | for (uint32_t i = 0; i < cl.size(); i++) { 76 | vars.push_back(cl[i]); 77 | } 78 | } 79 | 80 | vector::const_iterator begin() const 81 | { 82 | return vars.begin(); 83 | } 84 | 85 | vector::const_iterator end() const 86 | { 87 | return vars.end(); 88 | } 89 | 90 | vector::iterator begin() 91 | { 92 | return vars.begin(); 93 | } 94 | 95 | vector::iterator end() 96 | { 97 | return vars.end(); 98 | } 99 | 100 | bool operator<(const Xor& other) const 101 | { 102 | uint64_t i = 0; 103 | while(i < other.size() && i < size()) { 104 | if (other[i] != vars[i]) { 105 | return (vars[i] < other[i]); 106 | } 107 | i++; 108 | } 109 | 110 | if (other.size() != size()) { 111 | return size() < other.size(); 112 | } 113 | return false; 114 | } 115 | 116 | const uint32_t& operator[](const uint32_t at) const 117 | { 118 | return vars[at]; 119 | } 120 | 121 | uint32_t& operator[](const uint32_t at) 122 | { 123 | return vars[at]; 124 | } 125 | 126 | void resize(const uint32_t newsize) 127 | { 128 | vars.resize(newsize); 129 | } 130 | 131 | vector& get_vars() 132 | { 133 | return vars; 134 | } 135 | 136 | const vector& get_vars() const 137 | { 138 | return vars; 139 | } 140 | 141 | size_t size() const 142 | { 143 | return vars.size(); 144 | } 145 | 146 | bool empty() const 147 | { 148 | if (!vars.empty()) 149 | return false; 150 | 151 | if (!clash_vars.empty()) 152 | return false; 153 | 154 | if (rhs != false) { 155 | return false; 156 | } 157 | 158 | return true; 159 | } 160 | 161 | void merge_clash(const Xor& other, vector& seen) { 162 | for(const auto& v: clash_vars) { 163 | seen[v] = 1; 164 | } 165 | 166 | for(const auto& v: other.clash_vars) { 167 | if (!seen[v]) { 168 | seen[v] = 1; 169 | clash_vars.push_back(v); 170 | } 171 | } 172 | 173 | for(const auto& v: clash_vars) { 174 | seen[v] = 0; 175 | } 176 | } 177 | 178 | 179 | bool rhs = false; 180 | vector clash_vars; 181 | bool detached = false; 182 | vector vars; 183 | }; 184 | 185 | inline std::ostream& operator<<(std::ostream& os, const Xor& thisXor) 186 | { 187 | for (uint32_t i = 0; i < thisXor.size(); i++) { 188 | os << Lit(thisXor[i], false); 189 | 190 | if (i+1 < thisXor.size()) 191 | os << " + "; 192 | } 193 | os << " = " << std::boolalpha << thisXor.rhs << std::noboolalpha; 194 | 195 | os << " -- clash: "; 196 | for(const auto& c: thisXor.clash_vars) { 197 | os << c+1 << ", "; 198 | } 199 | 200 | return os; 201 | } 202 | 203 | // trim from start 204 | static inline std::string <rim(std::string &s) { 205 | s.erase(s.begin(), std::find_if(s.begin(), s.end(), std::not1(std::ptr_fun(std::isspace)))); 206 | return s; 207 | } 208 | 209 | // trim from end 210 | static inline std::string &rtrim(std::string &s) { 211 | s.erase(std::find_if(s.rbegin(), s.rend(), std::not1(std::ptr_fun(std::isspace))).base(), s.end()); 212 | return s; 213 | } 214 | 215 | // trim from both ends 216 | static inline std::string &trim(std::string &s) { 217 | return ltrim(rtrim(s)); 218 | } 219 | 220 | long int str_to_long_int(string& token) 221 | { 222 | string trimmed = trim(token); 223 | size_t endptr; 224 | long i = std::stol(trimmed, &endptr); 225 | if (endptr != trimmed.size()) { 226 | cout << "Error, input token: '" << token << "' wasn't completely used up, wrong token!" << endl; 227 | exit(-1); 228 | } 229 | return i; 230 | } 231 | 232 | vector str_to_cl(const string& data) 233 | { 234 | vector tokens; 235 | stringstream ss(data); 236 | string token; 237 | while (getline(ss,token, ',')) 238 | { 239 | tokens.push_back(token); 240 | } 241 | 242 | vector ret; 243 | for(string& token2: tokens) { 244 | long int i = str_to_long_int(token2); 245 | assert(i == (int)i); 246 | Lit lit(std::abs(i)-1, i < 0); 247 | ret.push_back(lit); 248 | } 249 | //cout << "input is: " << data << " LITs is: " << ret << endl; 250 | 251 | std::sort(ret.begin(), ret.end()); 252 | return ret; 253 | } 254 | 255 | vector str_to_vars(const string& data) 256 | { 257 | vector lits = str_to_cl(data); 258 | vector vars; 259 | for(Lit lit: lits) { 260 | assert(lit.sign() == false); 261 | vars.push_back(lit.var()); 262 | } 263 | return vars; 264 | } 265 | 266 | vector str_to_xors(const string& data) 267 | { 268 | vector ret; 269 | stringstream ss(data); 270 | string token; 271 | while (getline(ss,token, ';')) 272 | { 273 | stringstream ss2(token); 274 | string token2; 275 | int at = 0; 276 | bool rhs = false; 277 | vector vars; 278 | vector clashes; 279 | while (getline(ss2,token2, '=')) 280 | { 281 | //cout << "Token is: " << token2 << endl; 282 | if (at == 0) { 283 | vars = str_to_vars(token2); 284 | } 285 | if (at == 1) { 286 | uint32_t at2 = 0; 287 | stringstream ss3(token2); 288 | string token3; 289 | //cout << "parsing token2:" << token2 << endl; 290 | while (getline(ss3,token3, 'c')) { 291 | if (at2 == 0) { 292 | long r = str_to_long_int(token3); 293 | assert(r >= 0 && r <= 1); 294 | rhs = r; 295 | } else if (at2 == 1) { 296 | clashes = str_to_vars(token3); 297 | } 298 | assert(at2 < 2 && "We can have only at most one 'c' sign in an XOR"); 299 | at2++; 300 | } 301 | } 302 | assert(at < 2 && "We can only have one '=' sign in an XOR"); 303 | at++; 304 | } 305 | 306 | assert(at == 2 && "You forgot the =0/1 from the XOR"); 307 | ret.push_back(Xor(vars, rhs, clashes)); 308 | } 309 | 310 | return ret; 311 | } 312 | 313 | vector > str_to_vecs(const string& data) 314 | { 315 | vector > ret; 316 | stringstream ss(data); 317 | string token; 318 | while (getline(ss,token, ';')) 319 | { 320 | ret.push_back(str_to_cl(token)); 321 | } 322 | 323 | return ret; 324 | } 325 | 326 | struct VecVecSorter 327 | { 328 | bool operator()(const vector&a, const vector& b) const 329 | { 330 | if (a.size() != b.size()) { 331 | return a.size() < b.size(); 332 | } 333 | 334 | for(size_t i = 0; i < a.size(); i++) { 335 | if (a[i] != b[i]) { 336 | return a[i] < b[i]; 337 | } 338 | } 339 | return false; 340 | } 341 | }; 342 | 343 | void check_fuzzy_equal( 344 | vector >& cls_expected, 345 | vector >& cls_actual) 346 | { 347 | for(vector& x: cls_actual) { 348 | std::sort(x.begin(), x.end()); 349 | } 350 | for(vector& x: cls_expected) { 351 | std::sort(x.begin(), x.end()); 352 | } 353 | 354 | VecVecSorter sorter; 355 | std::sort(cls_actual.begin(), cls_actual.end(), sorter); 356 | std::sort(cls_expected.begin(), cls_expected.end(), sorter); 357 | 358 | EXPECT_EQ(cls_expected, cls_actual); 359 | } 360 | 361 | string print(const vector >& cls) 362 | { 363 | std::stringstream ss; 364 | for(auto cl: cls) { 365 | ss << cl << endl; 366 | } 367 | return ss.str(); 368 | } 369 | 370 | struct XorSorter 371 | { 372 | bool operator()(const Xor& a, const Xor& b) const 373 | { 374 | if (a.size() != b.size()) 375 | return a.size() < b.size(); 376 | 377 | if (a.rhs != b.rhs) { 378 | return a.rhs < b.rhs; 379 | } 380 | 381 | for(size_t i = 0; i < a.size(); i++) { 382 | if (a[i] != b[i]) { 383 | return a[i] < b[i]; 384 | } 385 | } 386 | 387 | return false; 388 | } 389 | }; 390 | 391 | 392 | void sort_xor(Xor& x) 393 | { 394 | std::sort(x.vars.begin(), x.vars.end()); 395 | std::sort(x.clash_vars.begin(), x.clash_vars.end()); 396 | } 397 | 398 | void check_xors_eq(const vector& got_data, const std::string& expected) 399 | { 400 | XorSorter xorsort; 401 | 402 | vector expected_sorted = str_to_xors(expected); 403 | for(auto t: expected_sorted) { 404 | std::sort(t.begin(), t.end()); 405 | } 406 | std::sort(expected_sorted.begin(), expected_sorted.end(), xorsort); 407 | 408 | vector got_data_sorted = got_data; 409 | for(Xor& t: got_data_sorted) { 410 | sort_xor(t); 411 | } 412 | 413 | std::sort(got_data_sorted.begin(), got_data_sorted.end(), xorsort); 414 | EXPECT_EQ(expected_sorted.size(), got_data_sorted.size()); 415 | for(size_t i = 0; i < expected_sorted.size(); i++) { 416 | EXPECT_EQ(expected_sorted[i].vars, got_data_sorted[i].vars); 417 | EXPECT_EQ(expected_sorted[i].rhs, got_data_sorted[i].rhs); 418 | EXPECT_EQ(expected_sorted[i].clash_vars, got_data_sorted[i].clash_vars); 419 | } 420 | } 421 | 422 | void check_xors_contains(const vector& got_data, const std::string& expected) 423 | { 424 | vector expected_sorted = str_to_xors(expected); 425 | assert(expected_sorted.size() == 1); 426 | Xor expectedX = expected_sorted[0]; 427 | std::sort(expectedX.begin(), expectedX.end()); 428 | 429 | vector got_data_sorted = got_data; 430 | for(auto& t: got_data_sorted) { 431 | sort_xor(t); 432 | } 433 | 434 | bool found = false; 435 | for(const Xor& x: got_data_sorted) { 436 | if (x.vars == expectedX.vars && 437 | x.rhs == expectedX.rhs && 438 | x.clash_vars == expectedX.clash_vars 439 | ) { 440 | found = true; 441 | break; 442 | } 443 | } 444 | EXPECT_TRUE(found); 445 | } 446 | 447 | struct cnfdata { 448 | int64_t num_cls_per_header = -1; 449 | int64_t num_vars_per_header = -1; 450 | vector> cls; 451 | uint64_t num_vars = 0; 452 | }; 453 | 454 | template 455 | void split(const std::string &s, char delim, Out result) { 456 | std::stringstream ss(s); 457 | std::string item; 458 | while (std::getline(ss, item, delim)) { 459 | *(result++) = item; 460 | } 461 | } 462 | 463 | std::vector split(const std::string &s, char delim) { 464 | std::vector elems; 465 | split(s, delim, std::back_inserter(elems)); 466 | return elems; 467 | } 468 | 469 | cnfdata cnf_file_read(std::string fname) 470 | { 471 | cnfdata cnfdat; 472 | 473 | std::ifstream file(fname); 474 | std::string str; 475 | std::string file_contents; 476 | vector cl; 477 | while (std::getline(file, str)) 478 | { 479 | //cout << "CNF LINE: " << str << endl; 480 | if (str.find("cnf") != string::npos) { 481 | str.erase(0,5); 482 | vector s = split(rtrim(ltrim(str)), ' '); 483 | assert(s.size() == 2); 484 | cnfdat.num_vars_per_header = std::stoi(s[0]); 485 | cnfdat.num_cls_per_header = std::stoi(s[1]); 486 | continue; 487 | } 488 | 489 | if (str.find("c ") == 0) { 490 | continue; 491 | } 492 | 493 | cl.clear(); 494 | vector s = split(rtrim(ltrim(str)), ' '); 495 | for(string& l: s) { 496 | if (l.length() == 0) 497 | continue; 498 | 499 | int x = std::stoi(l); 500 | if (x == 0) { 501 | break; 502 | } 503 | uint64_t var = std::abs(x)-1; 504 | cnfdat.num_vars = std::max(cnfdat.num_vars, var+1); 505 | bool sign = x < 0; 506 | cl.push_back(Lit(var, sign)); 507 | } 508 | cnfdat.cls.push_back(cl); 509 | } 510 | return cnfdat; 511 | } 512 | 513 | bool cl_eq(const vector& lits1, const vector& lits2) 514 | { 515 | if (lits1.size() != lits2.size()) 516 | return false; 517 | 518 | 519 | 520 | vector cl1_s = lits1; 521 | std::sort(cl1_s.begin(), cl1_s.end()); 522 | 523 | vector cl2_s = lits2; 524 | std::sort(cl2_s.begin(), cl2_s.end()); 525 | for(size_t i = 0; i < cl1_s.size(); i++) { 526 | if (cl1_s[i] != cl2_s[i]) 527 | return false; 528 | } 529 | return true; 530 | } 531 | 532 | bool cl_exists(const vector >& cls, const vector& cl) { 533 | for(const vector& cli: cls) { 534 | if (cl_eq(cli, cl)) { 535 | return true; 536 | } 537 | } 538 | return false; 539 | } 540 | 541 | // string print(const vector& dat) { 542 | // std::stringstream m; 543 | // for(size_t i = 0; i < dat.size();) { 544 | // m << dat[i]; 545 | // i++; 546 | // if (i < dat.size()) { 547 | // m << ", "; 548 | // } 549 | // } 550 | // return m.str(); 551 | // } 552 | 553 | #endif //TEST_HELPER__H 554 | -------------------------------------------------------------------------------- /CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2017, Mate Soos 2 | # 3 | # Permission is hereby granted, free of charge, to any person obtaining a copy 4 | # of this software and associated documentation files (the "Software"), to deal 5 | # in the Software without restriction, including without limitation the rights 6 | # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | # copies of the Software, and to permit persons to whom the Software is 8 | # furnished to do so, subject to the following conditions: 9 | # 10 | # The above copyright notice and this permission notice shall be included in 11 | # all copies or substantial portions of the Software. 12 | # 13 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 19 | # THE SOFTWARE. 20 | 21 | cmake_minimum_required(VERSION 3.12 FATAL_ERROR) 22 | 23 | message(STATUS "LIB directory is '${CMAKE_INSTALL_LIBDIR}'") 24 | message(STATUS "BIN directory is '${CMAKE_INSTALL_BINDIR}'") 25 | 26 | if(POLICY CMP0022) 27 | cmake_policy(SET CMP0022 NEW) 28 | endif() 29 | 30 | if(POLICY CMP0048) 31 | cmake_policy(SET CMP0048 NEW) 32 | endif() 33 | 34 | if(POLICY CMP0046) 35 | cmake_policy(SET CMP0046 NEW) 36 | endif() 37 | 38 | if(POLICY CMP0026) 39 | cmake_policy(SET CMP0026 NEW) 40 | endif() 41 | 42 | # ----------------------------------------------------------------------------- 43 | # Make RelWithDebInfo the default build type if otherwise not set 44 | # ----------------------------------------------------------------------------- 45 | set(build_types Debug Release RelWithDebInfo MinSizeRel) 46 | if(NOT CMAKE_BUILD_TYPE) 47 | message(STATUS "You can choose the type of build, options are:${build_types}") 48 | set(CMAKE_BUILD_TYPE RelWithDebInfo CACHE STRING 49 | "Options are ${build_types}" 50 | FORCE 51 | ) 52 | 53 | # Provide drop down menu options in cmake-gui 54 | set_property(CACHE CMAKE_BUILD_TYPE PROPERTY STRINGS ${build_types}) 55 | endif() 56 | message(STATUS "Doing a ${CMAKE_BUILD_TYPE} build") 57 | 58 | # ----------------------------------------------------------------------------- 59 | # Option to enable/disable assertions 60 | # ----------------------------------------------------------------------------- 61 | 62 | # Filter out definition of NDEBUG from the default build configuration flags. 63 | # We will add this ourselves if we want to disable assertions 64 | foreach (build_config ${build_types}) 65 | string(TOUPPER ${build_config} upper_case_build_config) 66 | foreach (language CXX C) 67 | set(VAR_TO_MODIFY "CMAKE_${language}_FLAGS_${upper_case_build_config}") 68 | string(REGEX REPLACE "(^| )[/-]D *NDEBUG($| )" 69 | " " 70 | replacement 71 | "${${VAR_TO_MODIFY}}") 72 | #message("Original (${VAR_TO_MODIFY}) is ${${VAR_TO_MODIFY}} replacement is ${replacement}") 73 | set(${VAR_TO_MODIFY} "${replacement}" CACHE STRING "Default flags for ${build_config} configuration" FORCE) 74 | endforeach() 75 | endforeach() 76 | 77 | PROJECT(approxmc) 78 | set(CMAKE_CXX_EXTENSIONS OFF) 79 | set(CMAKE_C_STANDARD 99) 80 | set(CMAKE_CXX_STANDARD 20) 81 | set(CMAKE_POSITION_INDEPENDENT_CODE ON) 82 | enable_language( CXX ) 83 | enable_language( C ) 84 | include (GNUInstallDirs) 85 | include (GenerateExportHeader) 86 | 87 | # contains some library search cmake scripts 88 | SET(CMAKE_MODULE_PATH ${PROJECT_SOURCE_DIR}/cmake) 89 | 90 | # generate JSON file of compile commands -- useful for code extension 91 | set(CMAKE_EXPORT_COMPILE_COMMANDS 1) 92 | 93 | # static compilation 94 | option(BUILD_SHARED_LIBS "Build the shared library" ON) 95 | option(STATICCOMPILE "Compile to static executable" OFF) 96 | if (STATICCOMPILE) 97 | set(BUILD_SHARED_LIBS OFF) 98 | endif() 99 | 100 | if ((${CMAKE_SYSTEM_NAME} MATCHES "Linux") OR (${CMAKE_SYSTEM_NAME} MATCHES "Darwin")) 101 | if(NOT BUILD_SHARED_LIBS) 102 | MESSAGE(STATUS "Compiling statically") 103 | if (${CMAKE_SYSTEM_NAME} MATCHES "Linux") 104 | set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -static") 105 | endif() 106 | SET(CMAKE_FIND_LIBRARY_SUFFIXES ".a") 107 | else() 108 | MESSAGE(STATUS "Compiling for dynamic library use") 109 | endif() 110 | endif() 111 | 112 | set(THREADS_PREFER_PTHREAD_FLAG ON) 113 | find_package (Threads REQUIRED) 114 | 115 | option(SANITIZE "Use Clang sanitizers. You MUST use clang++ as the compiler for this to work" OFF) 116 | if (SANITIZE) 117 | MESSAGE(WARNING " --Using clang sanitizers -- you MUST use clang++ or the compile WILL fail") 118 | SET( CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -lasan -lubsan " ) 119 | SET( CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} -lasan -lubsan ") 120 | add_compile_options("-fsanitize=address") 121 | # below warns on overflows EVEN when that's OK, because it's well-defined, disabling 122 | # add_compile_options("-fsanitize=integer") 123 | add_compile_options("-fsanitize=undefined") 124 | 125 | add_compile_options("-fsanitize=null") 126 | add_compile_options("-fsanitize=alignment") 127 | #add_compile_options("-fno-sanitize-recover") 128 | 129 | add_compile_options("-fsanitize=return") 130 | add_compile_options("-fsanitize=bounds") 131 | add_compile_options("-fsanitize=float-divide-by-zero") 132 | add_compile_options("-fsanitize=integer-divide-by-zero") 133 | #add_compile_options("-fsanitize=unsigned-integer-overflow") 134 | add_compile_options("-fsanitize=signed-integer-overflow") 135 | add_compile_options("-fsanitize=bool") 136 | add_compile_options("-fsanitize=enum") 137 | add_compile_options("-fsanitize=float-cast-overflow") 138 | 139 | #add_compile_options("-Weverything") 140 | #add_compile_options("-Wshorten-64-to-32") 141 | #add_compile_options("-Wweak-vtables") 142 | #add_compile_options("-Wsign-conversion") 143 | #add_compile_options("-Wconversion") 144 | endif() 145 | 146 | include(CheckCXXCompilerFlag) 147 | macro(add_cxx_flag_if_supported flagname) 148 | check_cxx_compiler_flag("${flagname}" HAVE_FLAG_${flagname}) 149 | 150 | if(HAVE_FLAG_${flagname}) 151 | SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${flagname}" ) 152 | endif() 153 | endmacro() 154 | 155 | option(ENABLE_ASSERTIONS "Build with assertions enabled" ON) 156 | message(STATUS "build type is ${CMAKE_BUILD_TYPE}") 157 | if(CMAKE_BUILD_TYPE STREQUAL "Release") 158 | set(ENABLE_ASSERTIONS OFF) 159 | endif() 160 | 161 | if (ENABLE_ASSERTIONS) 162 | # NDEBUG was already removed. 163 | else() 164 | # Note this definition doesn't appear in the cache variables. 165 | add_definitions(-DNDEBUG) 166 | add_cxx_flag_if_supported("-fno-stack-protector") 167 | add_definitions(-D_FORTIFY_SOURCE=0) 168 | endif() 169 | 170 | 171 | # Note: O3 gives slight speed increase, 1 more solved from SAT Comp'14 @ 3600s 172 | if (NOT MSVC) 173 | add_compile_options( -g) 174 | 175 | add_compile_options("$<$:-O3>") 176 | 177 | add_compile_options("$<$:-O3>") 178 | add_compile_options("$<$:-g0>") 179 | add_compile_options("$<$:-DNDEBUG>") 180 | 181 | add_compile_options("$<$:-O0>") 182 | 183 | else() 184 | # see https://msdn.microsoft.com/en-us/library/fwkeyyhe.aspx for details 185 | # /ZI = include debug info 186 | # /Wall = all warnings 187 | 188 | add_compile_options("$<$:/Ox>") 189 | add_compile_options("$<$:/ZI>") 190 | 191 | add_compile_options("$<$:/Ox>") 192 | add_compile_options("$<$:/D>") 193 | add_compile_options("$<$:/NDEBUG>") 194 | add_compile_options("$<$:/ZI>") 195 | 196 | add_compile_options("$<$:/Od>") 197 | 198 | if (STATICCOMPILE) 199 | # We statically link to reduce dependencies 200 | foreach(flag_var CMAKE_CXX_FLAGS CMAKE_CXX_FLAGS_DEBUG CMAKE_CXX_FLAGS_RELEASE CMAKE_CXX_FLAGS_MINSIZEREL CMAKE_CXX_FLAGS_RELWITHDEBINFO) 201 | # /MD -- Causes the application to use the multithread-specific and DLL-specific version of the run-time library. 202 | # Defines _MT and _DLL and causes the compiler to place the library name MSVCRT.lib into the .obj file. 203 | if(${flag_var} MATCHES "/MD") 204 | string(REGEX REPLACE "/MD" "/MT" ${flag_var} "${${flag_var}}") 205 | endif(${flag_var} MATCHES "/MD") 206 | 207 | # /MDd -- Defines _DEBUG, _MT, and _DLL and causes the application to use the debug multithread-specific and DLL-specific version of the run-time library. 208 | # It also causes the compiler to place the library name MSVCRTD.lib into the .obj file. 209 | if(${flag_var} MATCHES "/MDd") 210 | string(REGEX REPLACE "/MDd" "/MTd" ${flag_var} "${${flag_var}}") 211 | endif(${flag_var} MATCHES "/MDd") 212 | endforeach(flag_var) 213 | 214 | # Creates a multithreaded executable (static) file using LIBCMT.lib. 215 | add_compile_options(/MT) 216 | endif() 217 | 218 | # buffers security check 219 | add_compile_options(/GS) 220 | 221 | # Proper warning level 222 | add_compile_options(/W1) 223 | 224 | # Disable STL used in DLL-boundary warning 225 | add_compile_options(/wd4251) 226 | add_compile_options(/D_CRT_SECURE_NO_WARNINGS) 227 | 228 | # Wall is MSVC's Weverything, so annoying unless used from the start 229 | # and with judiciously used warning disables 230 | # add_compile_options(/Wall) 231 | 232 | # /Za = only ansi C98 & C++11 233 | # /Za is not recommended for use, not tested, etc. 234 | # see: http://stackoverflow.com/questions/5489326/za-compiler-directive-does-not-compile-system-headers-in-vs2010 235 | # add_compile_options(/Za) 236 | 237 | add_compile_options(/fp:precise) 238 | 239 | # exception handling. s = The exception-handling model that catches C++ exceptions only and tells the compiler to assume that functions declared as extern "C" may throw an exception. 240 | # exception handling. c = If used with s (/EHsc), catches C++ exceptions only and tells the compiler to assume that functions declared as extern "C" never throw a C++ exception. 241 | add_compile_options(/EHsc) 242 | 243 | 244 | set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} /INCREMENTAL:NO") 245 | set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} /PDBCOMPRESS") 246 | set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} /STACK:1572864") 247 | 248 | #what does this do? 249 | set(DEF_INSTALL_CMAKE_DIR CMake) 250 | endif() 251 | 252 | option(ENABLE_TESTING "Enable testing" OFF) 253 | 254 | if (NOT WIN32) 255 | add_cxx_flag_if_supported("-Wall") 256 | add_cxx_flag_if_supported("-Wextra") 257 | add_cxx_flag_if_supported("-Wunused") 258 | add_cxx_flag_if_supported("-Wsign-compare") 259 | if (NOT CMAKE_BUILD_TYPE STREQUAL "Release") 260 | add_cxx_flag_if_supported("-fno-omit-frame-pointer") 261 | add_cxx_flag_if_supported("-g") 262 | endif() 263 | add_cxx_flag_if_supported("-Wtype-limits") 264 | add_cxx_flag_if_supported("-Wuninitialized") 265 | add_cxx_flag_if_supported("-Wno-deprecated") 266 | add_cxx_flag_if_supported("-Wstrict-aliasing") 267 | add_cxx_flag_if_supported("-Wpointer-arith") 268 | add_cxx_flag_if_supported("-Wheader-guard") 269 | add_cxx_flag_if_supported("-msse4.2") 270 | if(NOT ENABLE_TESTING AND ${CMAKE_SYSTEM_NAME} MATCHES "Linux") 271 | add_cxx_flag_if_supported("-fvisibility=hidden") 272 | endif() 273 | add_cxx_flag_if_supported("-Wpointer-arith") 274 | add_cxx_flag_if_supported("-Wformat-nonliteral") 275 | add_cxx_flag_if_supported("-Winit-self") 276 | add_cxx_flag_if_supported("-Wparentheses") 277 | add_cxx_flag_if_supported("-Wunreachable-code") 278 | endif() 279 | 280 | if ((NOT WIN32) AND (NOT ENABLE_TESTING)) 281 | add_cxx_flag_if_supported("-fvisibility=hidden") 282 | endif() 283 | 284 | set(DEF_INSTALL_CMAKE_DIR lib/cmake/approxmc) 285 | set(APPROXMC_INSTALL_CMAKE_DIR ${DEF_INSTALL_CMAKE_DIR} CACHE PATH 286 | "Installation directory for approxmc CMake files") 287 | 288 | # ----------------------------------------------------------------------------- 289 | # Add GIT version 290 | # ----------------------------------------------------------------------------- 291 | function(SetVersionNumber PREFIX VERSION_MAJOR VERSION_MINOR VERSION_PATCH) 292 | set(${PREFIX}_VERSION_MAJOR ${VERSION_MAJOR} PARENT_SCOPE) 293 | set(${PREFIX}_VERSION_MINOR ${VERSION_MINOR} PARENT_SCOPE) 294 | set(${PREFIX}_VERSION_PATCH ${VERSION_PATCH} PARENT_SCOPE) 295 | set(${PREFIX}_VERSION 296 | "${VERSION_MAJOR}.${VERSION_MINOR}.${VERSION_PATCH}" 297 | PARENT_SCOPE) 298 | endfunction() 299 | 300 | find_program (GIT_EXECUTABLE git) 301 | if (GIT_EXECUTABLE) 302 | include(GetGitRevisionDescription) 303 | get_git_head_revision(GIT_REFSPEC GIT_SHA1) 304 | MESSAGE(STATUS "GIT hash found: ${GIT_SHA1}") 305 | else() 306 | set(GIT_SHA "GIT-hash-notfound") 307 | endif() 308 | set(APPROXMC_FULL_VERSION "4.2.0") 309 | 310 | string(REPLACE "." ";" APPROXMC_FULL_VERSION_LIST ${APPROXMC_FULL_VERSION}) 311 | SetVersionNumber("PROJECT" ${APPROXMC_FULL_VERSION_LIST}) 312 | MESSAGE(STATUS "PROJECT_VERSION: ${PROJECT_VERSION}") 313 | MESSAGE(STATUS "PROJECT_VERSION_MAJOR: ${PROJECT_VERSION_MAJOR}") 314 | MESSAGE(STATUS "PROJECT_VERSION_MINOR: ${PROJECT_VERSION_MINOR}") 315 | MESSAGE(STATUS "PROJECT_VERSION_PATCH: ${PROJECT_VERSION_PATCH}") 316 | 317 | # ---------- 318 | # manpage 319 | # ---------- 320 | if (${CMAKE_SYSTEM_NAME} MATCHES "Linux" AND NOT EMSCRIPTEN) 321 | find_program(HELP2MAN_FOUND help2man) 322 | if (HELP2MAN_FOUND) 323 | ADD_CUSTOM_TARGET(man_approxmc 324 | ALL 325 | DEPENDS approxmc-bin 326 | ) 327 | 328 | ADD_CUSTOM_COMMAND( 329 | TARGET man_approxmc 330 | COMMAND help2man 331 | ARGS --version-string=${APPROXMC_FULL_VERSION} --help-option="-h" $ -o ${CMAKE_CURRENT_BINARY_DIR}/approxmc.1 332 | ) 333 | 334 | INSTALL( 335 | FILES ${CMAKE_CURRENT_BINARY_DIR}/approxmc.1 336 | DESTINATION ${CMAKE_INSTALL_PREFIX}/man/man1) 337 | 338 | message(STATUS "Manpage will be created and installed") 339 | else() 340 | MESSAGE(STATUS "Cannot find help2man, not creating manpage") 341 | endif() 342 | else() 343 | MESSAGE(STATUS "Not on Linux, not creating manpage") 344 | endif() 345 | 346 | 347 | #query definitions 348 | get_directory_property( DirDefs DIRECTORY ${CMAKE_SOURCE_DIR} COMPILE_DEFINITIONS ) 349 | set(COMPILE_DEFINES) 350 | foreach( d ${DirDefs} ) 351 | # message( STATUS "Found Define: " ${d} ) 352 | set(COMPILE_DEFINES "${COMPILE_DEFINES} -D${d}") 353 | endforeach() 354 | message(STATUS "All defines at startup: ${COMPILE_DEFINES}") 355 | 356 | set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/lib) 357 | set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/lib) 358 | 359 | macro(approxmc_add_public_header LIBTARGET HEADER) 360 | get_target_property(EXISTING_PUBLIC_HEADERS ${LIBTARGET} PUBLIC_HEADER) 361 | if(EXISTING_PUBLIC_HEADERS) 362 | list(APPEND EXISTING_PUBLIC_HEADERS "${HEADER}") 363 | else() 364 | # Do not append to empty list 365 | set(EXISTING_PUBLIC_HEADERS "${HEADER}") 366 | endif() 367 | set_target_properties( 368 | ${LIBTARGET} 369 | PROPERTIES 370 | PUBLIC_HEADER "${EXISTING_PUBLIC_HEADERS}" 371 | ) 372 | endmacro() 373 | 374 | # ----------------------------------------------------------------------------- 375 | # Dependencies 376 | # ----------------------------------------------------------------------------- 377 | option(NOZLIB "Don't use zlib" OFF) 378 | if (NOT NOZLIB AND NOT (STATICCOMPILE AND WIN32)) 379 | find_package(ZLIB) 380 | IF (ZLIB_FOUND) 381 | MESSAGE(STATUS "OK, Found ZLIB!") 382 | include_directories(${ZLIB_INCLUDE_DIR}) 383 | link_directories(${ZLIB_LIB_DIR}) 384 | add_definitions( -DUSE_ZLIB ) 385 | ELSE (ZLIB_FOUND) 386 | MESSAGE(STATUS "WARNING: Did not find ZLIB, gzipped file support will be disabled") 387 | ENDIF (ZLIB_FOUND) 388 | endif() 389 | 390 | find_package(GMP REQUIRED) 391 | 392 | find_package(cryptominisat5 CONFIG REQUIRED) 393 | message(STATUS "CryptoMiniSat5 dynamic lib: ${CRYPTOMINISAT5_LIBRARIES}") 394 | message(STATUS "CryptoMiniSat5 static lib: ${CRYPTOMINISAT5_STATIC_LIBRARIES}") 395 | message(STATUS "CryptoMiniSat5 static lib deps: ${CRYPTOMINISAT5_STATIC_LIBRARIES_DEPS}") 396 | message(STATUS "CryptoMiniSat5 include dirs: ${CRYPTOMINISAT5_INCLUDE_DIRS}") 397 | 398 | find_package(arjun CONFIG REQUIRED) 399 | message(STATUS "Arjun dynamic lib : ${ARJUN_LIBRARIES}") 400 | message(STATUS "Arjun include dirs: ${ARJUN_INCLUDE_DIRS}") 401 | find_package(sbva CONFIG REQUIRED) 402 | 403 | # ----------------------------------------------------------------------------- 404 | # Provide an export name to be used by targets that wish to export themselves. 405 | # ----------------------------------------------------------------------------- 406 | set(APPROXMC_EXPORT_NAME "approxmcTargets") 407 | 408 | if (ENABLE_TESTING) 409 | add_subdirectory(tests/gtest) 410 | endif() 411 | add_subdirectory(src apx-src) 412 | 413 | # ----------------------------------------------------------------------------- 414 | # Add uninstall target for makefiles 415 | # ----------------------------------------------------------------------------- 416 | configure_file( 417 | "${CMAKE_CURRENT_SOURCE_DIR}/cmake/cmake_uninstall.cmake.in" 418 | "${CMAKE_CURRENT_BINARY_DIR}/cmake_uninstall.cmake" 419 | IMMEDIATE @ONLY 420 | ) 421 | 422 | add_custom_target(uninstall 423 | COMMAND ${CMAKE_COMMAND} -P ${CMAKE_CURRENT_BINARY_DIR}/cmake_uninstall.cmake 424 | ) 425 | 426 | # ----------------------------------------------------------------------------- 427 | # Testing 428 | # ----------------------------------------------------------------------------- 429 | if (ENABLE_TESTING) 430 | enable_testing() 431 | 432 | message(STATUS "Testing is enabled") 433 | set(UNIT_TEST_EXE_SUFFIX "Tests" CACHE STRING "Suffix for Unit test executable") 434 | add_subdirectory(tests) 435 | 436 | else() 437 | message(WARNING "Testing is disabled") 438 | endif() 439 | 440 | # ----------------------------------------------------------------------------- 441 | # Export our targets so that other CMake based projects can interface with 442 | # the build of approxmc in the build-tree 443 | # ----------------------------------------------------------------------------- 444 | set(APPROXMC_TARGETS_FILENAME "approxmcTargets.cmake") 445 | set(APPROXMC_CONFIG_FILENAME "approxmcConfig.cmake") 446 | 447 | # Export targets 448 | export( 449 | TARGETS approxmc 450 | FILE "${CMAKE_CURRENT_BINARY_DIR}/${APPROXMC_TARGETS_FILENAME}" 451 | ) 452 | 453 | # Create approxmcConfig file 454 | set(EXPORT_TYPE "Build-tree") 455 | set(CONF_INCLUDE_DIRS "${CMAKE_CURRENT_BINARY_DIR}/include") 456 | configure_file(approxmcConfig.cmake.in 457 | "${CMAKE_CURRENT_BINARY_DIR}/${APPROXMC_CONFIG_FILENAME}" @ONLY 458 | ) 459 | 460 | # Export this package to the CMake user package registry 461 | # Now the user can just use find_package(approxmc) on their system 462 | export(PACKAGE approxmc) 463 | 464 | set(DEF_INSTALL_CMAKE_DIR lib/cmake/approxmc) 465 | set(APPROXMC_INSTALL_CMAKE_DIR ${DEF_INSTALL_CMAKE_DIR} CACHE PATH 466 | "Installation directory for approxmc CMake files") 467 | 468 | # Create approxmcConfig file 469 | set(EXPORT_TYPE "installed") 470 | set(CONF_INCLUDE_DIRS "${CMAKE_INSTALL_PREFIX}/include") 471 | configure_file(approxmcConfig.cmake.in 472 | "${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_FILES_DIRECTORY}/${APPROXMC_CONFIG_FILENAME}" @ONLY 473 | ) 474 | 475 | install(FILES 476 | "${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_FILES_DIRECTORY}/${APPROXMC_CONFIG_FILENAME}" 477 | DESTINATION "${APPROXMC_INSTALL_CMAKE_DIR}" 478 | ) 479 | 480 | # Install the export set for use with the install-tree 481 | install( 482 | EXPORT ${APPROXMC_EXPORT_NAME} 483 | DESTINATION "${APPROXMC_INSTALL_CMAKE_DIR}" 484 | ) 485 | -------------------------------------------------------------------------------- /python/tests/test_1.cnf: -------------------------------------------------------------------------------- 1 | c ind 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 0 2 | p cnf 400 1700 3 | 329 -142 -192 0 4 | -391 -76 350 0 5 | 305 380 -359 0 6 | 260 16 383 0 7 | 119 71 388 0 8 | 106 171 398 0 9 | -387 -91 -237 0 10 | 322 -202 -32 0 11 | -136 -106 380 0 12 | 91 -70 267 0 13 | -237 69 -232 0 14 | -347 304 22 0 15 | 187 -113 -73 0 16 | -183 -79 -24 0 17 | 358 -190 -395 0 18 | 284 -8 -26 0 19 | 398 -92 198 0 20 | -338 -13 53 0 21 | -280 317 -27 0 22 | 276 -387 268 0 23 | 180 398 -46 0 24 | -99 -14 -281 0 25 | -189 -321 -71 0 26 | 189 161 121 0 27 | -294 243 -137 0 28 | 199 244 400 0 29 | -180 -314 297 0 30 | 84 -42 -278 0 31 | -30 318 -233 0 32 | -238 -204 239 0 33 | 97 -156 233 0 34 | -145 -101 83 0 35 | 78 -298 400 0 36 | -373 -196 -115 0 37 | -283 381 -337 0 38 | 109 331 97 0 39 | 62 171 -118 0 40 | -103 -241 278 0 41 | -251 120 -191 0 42 | -147 158 313 0 43 | -377 291 29 0 44 | -42 -245 -176 0 45 | 90 -395 -132 0 46 | 362 -347 -302 0 47 | -37 362 -287 0 48 | 47 373 6 0 49 | 81 -38 -385 0 50 | 147 -190 -271 0 51 | -60 -22 -216 0 52 | -89 113 41 0 53 | 91 60 10 0 54 | -188 -167 396 0 55 | 352 120 236 0 56 | -92 360 317 0 57 | 386 -361 -106 0 58 | -14 -377 130 0 59 | -333 -164 -334 0 60 | 374 -191 379 0 61 | 105 56 191 0 62 | -365 299 -375 0 63 | 92 290 190 0 64 | 389 196 -329 0 65 | 134 49 311 0 66 | -295 -314 -330 0 67 | 52 250 -190 0 68 | -238 -315 -306 0 69 | 192 -77 269 0 70 | -192 -388 -296 0 71 | -328 346 18 0 72 | 148 34 104 0 73 | -305 -248 194 0 74 | -284 370 309 0 75 | -399 -186 -198 0 76 | -350 -167 -146 0 77 | 173 -74 -113 0 78 | 107 -219 322 0 79 | 181 -216 70 0 80 | 252 -318 -248 0 81 | -201 -65 157 0 82 | 25 156 205 0 83 | 211 394 336 0 84 | 184 26 83 0 85 | 316 317 -271 0 86 | 105 -118 49 0 87 | 344 -40 139 0 88 | 169 291 19 0 89 | 324 159 -289 0 90 | 360 230 271 0 91 | -166 1 -258 0 92 | 198 -61 -264 0 93 | -313 -280 283 0 94 | 195 212 -319 0 95 | -37 -81 111 0 96 | 399 -27 312 0 97 | 128 -38 137 0 98 | 335 189 -79 0 99 | -378 266 130 0 100 | 177 -337 379 0 101 | -150 194 -266 0 102 | 137 129 -48 0 103 | -72 -359 113 0 104 | -69 -104 -49 0 105 | -96 128 -333 0 106 | 217 69 -273 0 107 | -92 -218 3 0 108 | 16 -66 384 0 109 | -312 -236 -214 0 110 | -308 -80 -245 0 111 | 271 -273 183 0 112 | 17 -398 33 0 113 | 397 104 43 0 114 | 90 94 397 0 115 | -372 -265 60 0 116 | -331 -279 388 0 117 | -280 -343 -291 0 118 | -290 -261 82 0 119 | 142 -282 358 0 120 | -119 61 -179 0 121 | 246 110 -66 0 122 | -126 54 -333 0 123 | -346 207 -58 0 124 | 243 -231 -132 0 125 | 114 -39 -280 0 126 | 79 -13 -217 0 127 | 38 -323 -349 0 128 | 120 -188 -72 0 129 | 379 -361 -392 0 130 | 281 177 -350 0 131 | -220 50 82 0 132 | -331 135 -153 0 133 | 96 128 -135 0 134 | 279 186 -165 0 135 | 181 -80 -356 0 136 | -151 -11 -377 0 137 | -14 232 207 0 138 | 113 -157 390 0 139 | 3 106 -335 0 140 | -346 -108 -261 0 141 | 227 243 -14 0 142 | -276 391 147 0 143 | 297 221 -317 0 144 | -387 -21 -248 0 145 | 55 36 234 0 146 | 270 -66 -169 0 147 | 149 96 -137 0 148 | -55 -377 65 0 149 | 65 153 55 0 150 | 391 -80 -228 0 151 | 101 215 -132 0 152 | -319 -198 399 0 153 | -251 98 8 0 154 | -301 37 279 0 155 | -147 291 384 0 156 | -344 118 -96 0 157 | -379 209 341 0 158 | 56 -17 -82 0 159 | 189 -183 -90 0 160 | 323 -235 232 0 161 | 186 -55 -366 0 162 | 377 107 16 0 163 | 253 43 -246 0 164 | -340 247 -262 0 165 | -370 -139 184 0 166 | 353 -134 -349 0 167 | 126 -294 88 0 168 | -323 15 -118 0 169 | -200 -192 373 0 170 | 11 -93 280 0 171 | 89 -149 -361 0 172 | 370 -96 172 0 173 | 84 -110 -300 0 174 | 376 -381 344 0 175 | 89 51 112 0 176 | 196 285 -57 0 177 | -337 -147 -122 0 178 | 393 -191 371 0 179 | -397 319 -84 0 180 | 359 259 -127 0 181 | -331 326 159 0 182 | -366 -321 82 0 183 | -300 373 331 0 184 | -374 213 192 0 185 | 86 15 -172 0 186 | 87 367 -179 0 187 | -180 -223 -83 0 188 | -353 -161 388 0 189 | -157 -308 17 0 190 | 214 2 87 0 191 | 238 252 90 0 192 | -130 228 121 0 193 | -227 345 94 0 194 | 369 -336 -287 0 195 | -9 49 -157 0 196 | -219 -174 125 0 197 | -159 318 352 0 198 | 212 260 -239 0 199 | 236 345 354 0 200 | -278 290 -142 0 201 | -308 107 300 0 202 | 156 -77 -310 0 203 | 2 -119 -154 0 204 | -258 163 -74 0 205 | -303 -162 197 0 206 | 122 -6 192 0 207 | 364 -145 186 0 208 | 167 205 -162 0 209 | 1 -205 -251 0 210 | 381 222 -248 0 211 | 166 290 352 0 212 | 370 -178 -389 0 213 | -198 -121 -348 0 214 | 400 393 -100 0 215 | 336 351 240 0 216 | -32 149 298 0 217 | 227 -26 -240 0 218 | 359 281 -362 0 219 | -154 239 -297 0 220 | 271 327 170 0 221 | 22 -45 301 0 222 | 381 158 334 0 223 | -14 -283 297 0 224 | 279 -294 128 0 225 | 369 197 115 0 226 | -52 -206 -119 0 227 | 254 293 -312 0 228 | -39 -52 225 0 229 | -196 -38 -143 0 230 | 220 -104 -210 0 231 | 105 137 128 0 232 | 250 -216 108 0 233 | 41 -232 -279 0 234 | 81 -343 -60 0 235 | -188 389 298 0 236 | -271 379 -120 0 237 | 213 -356 -297 0 238 | 99 61 -320 0 239 | 400 310 -362 0 240 | -205 -225 -71 0 241 | 85 396 275 0 242 | 238 -109 -384 0 243 | -174 -383 -64 0 244 | 113 -311 -203 0 245 | -108 125 -63 0 246 | -74 -263 135 0 247 | 329 -160 140 0 248 | 267 18 -5 0 249 | 271 -127 226 0 250 | 263 -212 222 0 251 | 65 15 214 0 252 | -181 -243 295 0 253 | 295 324 -108 0 254 | -215 76 -201 0 255 | -90 362 -69 0 256 | 214 303 -376 0 257 | 114 -234 -37 0 258 | 98 351 18 0 259 | -232 -16 298 0 260 | 241 48 -311 0 261 | 222 76 4 0 262 | 391 -120 241 0 263 | -122 -177 248 0 264 | -314 -117 -64 0 265 | 112 341 22 0 266 | 74 -374 -264 0 267 | 85 -161 -389 0 268 | 174 -261 197 0 269 | 22 -264 -199 0 270 | -12 138 143 0 271 | -221 136 316 0 272 | 305 249 149 0 273 | -265 299 100 0 274 | 142 -245 -266 0 275 | -142 245 -333 0 276 | -178 -354 131 0 277 | -34 245 143 0 278 | -22 257 117 0 279 | 123 -363 -137 0 280 | 184 -348 -167 0 281 | -63 -361 -253 0 282 | 87 390 -389 0 283 | -48 145 -238 0 284 | -8 292 -68 0 285 | 65 367 -221 0 286 | 34 98 -363 0 287 | -30 -329 -309 0 288 | -399 108 -128 0 289 | -293 -231 -188 0 290 | 138 -342 -289 0 291 | -360 -158 21 0 292 | 194 25 -190 0 293 | -134 345 -358 0 294 | 109 376 363 0 295 | -218 -377 -230 0 296 | 382 -246 15 0 297 | 263 -313 -387 0 298 | -255 -99 277 0 299 | 393 372 -287 0 300 | -195 389 -55 0 301 | 281 28 -186 0 302 | 257 196 169 0 303 | 127 54 185 0 304 | -314 -209 371 0 305 | -278 310 131 0 306 | 273 165 -109 0 307 | -314 267 -284 0 308 | -167 187 -88 0 309 | 350 358 65 0 310 | 62 -339 -41 0 311 | -273 -95 393 0 312 | -21 -321 270 0 313 | -291 73 -21 0 314 | -235 277 71 0 315 | -31 -210 -71 0 316 | 300 178 -340 0 317 | -295 -82 -316 0 318 | 399 133 341 0 319 | -132 249 144 0 320 | 286 129 -53 0 321 | -249 -51 -87 0 322 | -134 189 230 0 323 | -270 303 203 0 324 | -29 -357 65 0 325 | -367 -348 244 0 326 | 329 104 -397 0 327 | 163 -376 -79 0 328 | 15 246 189 0 329 | 338 388 -17 0 330 | 117 -30 27 0 331 | 259 -329 385 0 332 | 98 -59 106 0 333 | -62 320 -279 0 334 | 262 -378 225 0 335 | 309 -48 -268 0 336 | 216 170 149 0 337 | 330 74 -54 0 338 | -117 214 -279 0 339 | 185 277 296 0 340 | 199 -367 -226 0 341 | -286 -69 -306 0 342 | -30 -150 -356 0 343 | -394 -254 322 0 344 | -143 289 -165 0 345 | -217 -399 141 0 346 | 82 -255 -63 0 347 | -221 -173 384 0 348 | -237 -153 -326 0 349 | 398 120 -318 0 350 | -336 -278 -68 0 351 | 70 -304 243 0 352 | -318 -63 207 0 353 | 374 379 118 0 354 | -328 86 -214 0 355 | -314 -87 -152 0 356 | -17 184 -277 0 357 | -245 185 -132 0 358 | 368 -11 204 0 359 | 131 -140 -329 0 360 | -218 249 165 0 361 | 294 -150 -63 0 362 | 192 -157 -66 0 363 | -149 78 66 0 364 | -195 245 -66 0 365 | -154 -358 -202 0 366 | -197 -76 133 0 367 | -92 340 201 0 368 | 164 315 -388 0 369 | -156 13 -345 0 370 | 174 -240 42 0 371 | -310 -306 346 0 372 | -86 111 -34 0 373 | 148 383 -114 0 374 | -236 -319 344 0 375 | -264 217 -222 0 376 | 128 53 236 0 377 | -119 -132 365 0 378 | 304 117 -370 0 379 | 39 -198 196 0 380 | 34 57 -46 0 381 | -369 252 163 0 382 | -64 30 -333 0 383 | -24 19 -136 0 384 | 245 -212 165 0 385 | -216 367 -13 0 386 | -141 129 16 0 387 | -272 -89 -294 0 388 | 224 184 -215 0 389 | 326 -372 200 0 390 | -399 130 99 0 391 | 127 84 386 0 392 | 359 -162 -100 0 393 | -400 -141 91 0 394 | -153 -329 -93 0 395 | 36 322 184 0 396 | -392 -363 -162 0 397 | 388 15 213 0 398 | 346 169 -223 0 399 | 157 -39 -107 0 400 | -255 -330 350 0 401 | -68 -54 149 0 402 | -232 -370 171 0 403 | -127 305 -61 0 404 | -175 400 -336 0 405 | -261 54 159 0 406 | -348 -111 -179 0 407 | -204 -123 -82 0 408 | 218 -245 -345 0 409 | -175 -319 -235 0 410 | 292 -364 -87 0 411 | 174 -73 191 0 412 | -64 -228 -156 0 413 | 137 -323 70 0 414 | 268 -326 -133 0 415 | 87 231 198 0 416 | 206 358 348 0 417 | -29 -325 199 0 418 | -57 -158 -274 0 419 | -340 58 -303 0 420 | -210 150 73 0 421 | -234 31 -213 0 422 | 104 -7 -350 0 423 | 206 199 31 0 424 | 8 -168 -230 0 425 | -152 352 41 0 426 | -31 -97 249 0 427 | -221 285 186 0 428 | 43 392 -126 0 429 | 246 31 -121 0 430 | -366 -395 167 0 431 | -225 -201 77 0 432 | 252 -216 142 0 433 | 364 -331 -223 0 434 | -43 153 -180 0 435 | 378 97 66 0 436 | -76 231 -387 0 437 | 362 -106 -101 0 438 | -334 -57 -272 0 439 | -305 92 -284 0 440 | -155 -183 110 0 441 | -358 -306 394 0 442 | -230 -371 -306 0 443 | 271 310 360 0 444 | 321 -322 -148 0 445 | -217 -63 -88 0 446 | 394 -144 223 0 447 | 188 173 202 0 448 | 396 -326 -87 0 449 | 364 339 -328 0 450 | -17 -263 -347 0 451 | -373 -134 228 0 452 | -26 212 391 0 453 | 356 -204 -323 0 454 | -49 75 232 0 455 | -212 106 187 0 456 | -195 134 -13 0 457 | -192 258 249 0 458 | -179 392 -260 0 459 | 394 385 -45 0 460 | 101 76 -239 0 461 | -118 -284 -84 0 462 | -167 48 173 0 463 | 71 312 151 0 464 | 300 -358 24 0 465 | -29 234 364 0 466 | 170 191 -337 0 467 | -120 390 241 0 468 | -4 -26 285 0 469 | 193 -159 -158 0 470 | -104 35 -77 0 471 | 72 23 243 0 472 | 152 299 -56 0 473 | -317 -145 389 0 474 | -354 -395 -55 0 475 | 354 219 -95 0 476 | 35 -260 370 0 477 | -343 -371 47 0 478 | 362 231 285 0 479 | -198 -289 -81 0 480 | -264 258 62 0 481 | 306 -273 -110 0 482 | 375 -396 250 0 483 | 161 -259 346 0 484 | -83 -358 169 0 485 | 6 -376 -330 0 486 | -269 -190 393 0 487 | 257 -391 -89 0 488 | 270 -76 245 0 489 | -47 154 -314 0 490 | -239 -226 -1 0 491 | -288 112 -75 0 492 | 325 298 -34 0 493 | -351 273 24 0 494 | -152 -37 200 0 495 | 91 346 -292 0 496 | 329 352 -247 0 497 | 46 59 185 0 498 | 379 326 364 0 499 | -48 177 -390 0 500 | 313 284 -41 0 501 | 292 -207 -9 0 502 | -329 159 202 0 503 | 204 119 -55 0 504 | -120 -167 255 0 505 | -157 277 -284 0 506 | 254 -276 321 0 507 | 6 -294 -192 0 508 | -336 -114 -2 0 509 | -68 352 239 0 510 | -322 121 -31 0 511 | 367 75 339 0 512 | 272 246 -102 0 513 | -298 339 125 0 514 | 371 -348 -309 0 515 | 363 -143 -393 0 516 | 56 266 239 0 517 | 154 -327 -324 0 518 | 218 -238 -295 0 519 | -58 -45 -111 0 520 | -180 8 327 0 521 | 180 -124 330 0 522 | 231 -105 284 0 523 | 255 -186 381 0 524 | 352 330 74 0 525 | -349 -278 -298 0 526 | 318 -181 280 0 527 | 160 -40 115 0 528 | 206 332 -249 0 529 | -167 383 -3 0 530 | 178 -393 -379 0 531 | 231 89 -112 0 532 | -73 47 -361 0 533 | 250 198 -320 0 534 | -172 -53 334 0 535 | 275 21 274 0 536 | 185 -230 -85 0 537 | -217 316 370 0 538 | 118 304 160 0 539 | -292 173 99 0 540 | 107 173 -315 0 541 | 329 163 143 0 542 | -336 -227 -302 0 543 | -266 -25 260 0 544 | 23 257 386 0 545 | -14 92 8 0 546 | 241 -304 100 0 547 | 322 203 240 0 548 | -83 277 171 0 549 | 106 275 392 0 550 | -278 -361 -68 0 551 | -223 81 -347 0 552 | -335 337 369 0 553 | -321 145 -256 0 554 | -130 144 -335 0 555 | -49 64 193 0 556 | 160 -123 -113 0 557 | -272 330 64 0 558 | 220 327 -271 0 559 | -134 -51 -68 0 560 | 124 -300 -93 0 561 | 351 322 237 0 562 | 280 198 379 0 563 | -243 131 375 0 564 | 51 102 -285 0 565 | -370 -301 -372 0 566 | 187 91 44 0 567 | -291 -330 -61 0 568 | 326 196 394 0 569 | 85 -67 -147 0 570 | 41 -106 175 0 571 | -134 306 -357 0 572 | 40 -124 336 0 573 | 364 -270 -37 0 574 | 354 205 119 0 575 | 326 -118 311 0 576 | -367 -215 288 0 577 | 281 335 -195 0 578 | 9 350 360 0 579 | -49 -163 -189 0 580 | 372 92 383 0 581 | -264 110 -231 0 582 | 223 264 60 0 583 | 60 -391 -395 0 584 | -355 -35 -319 0 585 | -8 77 -176 0 586 | 6 -174 380 0 587 | -361 -51 -226 0 588 | 66 30 -199 0 589 | -216 355 172 0 590 | -171 8 -400 0 591 | -216 -354 36 0 592 | -109 101 -314 0 593 | -141 138 314 0 594 | 76 317 -172 0 595 | 122 -173 -179 0 596 | 335 237 -33 0 597 | -185 -91 -226 0 598 | 286 116 -387 0 599 | 16 34 51 0 600 | 310 353 225 0 601 | -118 -265 82 0 602 | -227 -323 106 0 603 | 301 -209 149 0 604 | -373 374 140 0 605 | -380 373 275 0 606 | 2 -130 -69 0 607 | -99 57 128 0 608 | 237 -312 260 0 609 | 91 -75 144 0 610 | -104 381 132 0 611 | 135 91 225 0 612 | -8 -224 16 0 613 | -187 217 -339 0 614 | -168 -196 -162 0 615 | -23 -33 -144 0 616 | -249 -49 322 0 617 | -384 -210 223 0 618 | -25 -83 -370 0 619 | -51 200 -270 0 620 | 279 -85 182 0 621 | 205 391 -96 0 622 | -173 -351 108 0 623 | -149 -373 -87 0 624 | 144 338 -270 0 625 | -163 -331 -321 0 626 | -392 109 -102 0 627 | 385 -359 19 0 628 | 47 -54 -291 0 629 | -155 267 -67 0 630 | 261 -393 2 0 631 | 244 328 -14 0 632 | -365 -350 158 0 633 | 253 40 -68 0 634 | 273 -231 -9 0 635 | -362 -19 184 0 636 | -221 394 399 0 637 | 385 -206 266 0 638 | -157 -344 -249 0 639 | -14 -263 -107 0 640 | -165 -67 -331 0 641 | -19 154 -75 0 642 | -284 -323 -74 0 643 | -359 -172 -109 0 644 | 83 313 361 0 645 | 53 -51 35 0 646 | -16 121 42 0 647 | 267 -333 382 0 648 | -278 72 -207 0 649 | -71 332 -217 0 650 | -216 -220 150 0 651 | 136 308 110 0 652 | 289 251 -352 0 653 | -133 -174 208 0 654 | -191 -76 232 0 655 | -216 16 -236 0 656 | 34 271 -329 0 657 | 114 229 -97 0 658 | -67 121 372 0 659 | 242 79 -191 0 660 | 89 -247 354 0 661 | 298 -198 311 0 662 | -376 -6 384 0 663 | -222 -40 140 0 664 | 309 -59 11 0 665 | 390 -172 -241 0 666 | -336 248 153 0 667 | 1 353 50 0 668 | 355 -198 63 0 669 | 379 252 290 0 670 | -335 244 -144 0 671 | 130 75 342 0 672 | 327 225 -271 0 673 | 352 -67 -45 0 674 | -198 395 190 0 675 | -59 -270 -192 0 676 | -248 173 -356 0 677 | 107 334 357 0 678 | 224 117 -87 0 679 | 158 231 -146 0 680 | -247 280 302 0 681 | -368 233 -70 0 682 | -7 79 -361 0 683 | -383 230 -290 0 684 | 172 111 -106 0 685 | 350 -208 255 0 686 | 148 -165 -72 0 687 | 245 397 122 0 688 | -331 245 -358 0 689 | -47 -37 -372 0 690 | 127 208 93 0 691 | 172 -158 6 0 692 | 286 123 345 0 693 | -135 161 -52 0 694 | 353 331 -325 0 695 | 162 -18 -301 0 696 | 266 185 147 0 697 | 394 -185 39 0 698 | 86 224 248 0 699 | -34 39 -21 0 700 | -118 234 248 0 701 | 112 97 11 0 702 | 353 -149 210 0 703 | 187 -138 49 0 704 | 102 -252 146 0 705 | -304 230 356 0 706 | -329 216 331 0 707 | 317 -378 187 0 708 | -303 -106 -377 0 709 | 58 146 -398 0 710 | 326 123 291 0 711 | -68 106 210 0 712 | 84 -265 164 0 713 | -61 -244 -140 0 714 | 135 156 -329 0 715 | 193 188 -173 0 716 | -78 135 -7 0 717 | 73 -120 -219 0 718 | 270 355 308 0 719 | -192 -30 208 0 720 | 123 -258 305 0 721 | -244 -322 -11 0 722 | -156 232 -215 0 723 | -38 336 110 0 724 | 397 40 386 0 725 | -226 185 -307 0 726 | -7 275 72 0 727 | 64 184 62 0 728 | 385 -147 -367 0 729 | -51 -391 254 0 730 | 85 373 -53 0 731 | -94 13 310 0 732 | -348 44 -122 0 733 | -393 -258 281 0 734 | -126 306 313 0 735 | 198 329 -336 0 736 | 237 -366 354 0 737 | 388 -30 282 0 738 | 243 384 363 0 739 | -45 -20 -75 0 740 | 273 51 -248 0 741 | -149 41 -36 0 742 | 339 -79 148 0 743 | -326 382 -73 0 744 | -10 -101 290 0 745 | -355 -234 242 0 746 | 272 141 -86 0 747 | -25 36 -255 0 748 | -214 85 -374 0 749 | 157 285 82 0 750 | -189 -227 276 0 751 | 27 -299 -360 0 752 | 192 -183 92 0 753 | -391 71 -287 0 754 | -297 -369 -399 0 755 | -20 -106 -145 0 756 | -66 -65 -375 0 757 | 33 224 314 0 758 | 327 212 -194 0 759 | -328 376 -22 0 760 | 197 325 45 0 761 | 369 189 -100 0 762 | -74 -198 -4 0 763 | -63 104 388 0 764 | 262 148 -345 0 765 | -174 222 -126 0 766 | -302 34 -388 0 767 | -133 2 -302 0 768 | -264 -355 -182 0 769 | -172 -23 150 0 770 | -318 -383 -396 0 771 | -242 54 47 0 772 | -286 139 -376 0 773 | 265 -393 -222 0 774 | 400 318 -358 0 775 | -324 -303 149 0 776 | -333 -91 355 0 777 | -305 -157 51 0 778 | 147 111 -220 0 779 | 351 -60 284 0 780 | -26 132 -124 0 781 | -27 -287 -62 0 782 | 294 122 393 0 783 | -172 -148 -349 0 784 | 309 18 20 0 785 | 365 254 -359 0 786 | 59 -358 -248 0 787 | -5 -184 -139 0 788 | -188 300 239 0 789 | -97 103 323 0 790 | -295 -163 -308 0 791 | 166 -308 -148 0 792 | 382 -337 221 0 793 | 211 -73 -200 0 794 | -355 209 48 0 795 | -332 -170 360 0 796 | -30 92 -69 0 797 | 214 391 336 0 798 | 286 225 294 0 799 | 382 132 -215 0 800 | -179 -197 212 0 801 | 347 -17 229 0 802 | 15 -358 -228 0 803 | 123 -181 65 0 804 | 373 151 -374 0 805 | -181 310 82 0 806 | -81 -347 37 0 807 | 146 -279 -90 0 808 | -166 255 -117 0 809 | -24 146 -35 0 810 | 282 17 -380 0 811 | -384 40 -277 0 812 | -153 -398 20 0 813 | -179 -39 6 0 814 | -179 -196 325 0 815 | 235 -25 177 0 816 | 145 276 -79 0 817 | -162 400 375 0 818 | -285 372 239 0 819 | -21 -349 -206 0 820 | 105 -348 -374 0 821 | -320 258 -140 0 822 | 328 392 339 0 823 | 54 -9 8 0 824 | -351 272 -173 0 825 | 105 225 138 0 826 | -343 329 60 0 827 | -373 157 -328 0 828 | -346 -64 13 0 829 | 178 -259 38 0 830 | 140 -23 -382 0 831 | -79 347 318 0 832 | -26 352 304 0 833 | -357 112 -282 0 834 | -136 193 399 0 835 | 330 186 340 0 836 | -301 -92 242 0 837 | 269 -206 125 0 838 | -390 -68 353 0 839 | 12 75 161 0 840 | 327 -81 -392 0 841 | -113 244 -400 0 842 | 126 234 386 0 843 | -44 347 115 0 844 | 12 -133 81 0 845 | -331 -20 -313 0 846 | 231 301 99 0 847 | 10 332 296 0 848 | -395 128 152 0 849 | 115 -87 -5 0 850 | 379 142 -118 0 851 | -146 198 111 0 852 | -307 390 199 0 853 | -7 -282 11 0 854 | 382 57 -173 0 855 | 35 -135 -124 0 856 | 314 -171 289 0 857 | 291 -272 -209 0 858 | -373 384 330 0 859 | 21 -378 -281 0 860 | 127 -349 170 0 861 | -293 -318 269 0 862 | -353 183 -58 0 863 | -209 -196 18 0 864 | 362 103 -391 0 865 | -230 373 -205 0 866 | -49 -68 78 0 867 | 103 104 -153 0 868 | -194 -377 172 0 869 | -176 29 308 0 870 | 22 3 -126 0 871 | -387 -354 320 0 872 | 386 -373 127 0 873 | -65 -277 319 0 874 | -41 -166 -366 0 875 | 53 -304 -94 0 876 | 79 67 352 0 877 | -20 -98 146 0 878 | 77 -9 359 0 879 | -257 164 -261 0 880 | 209 -349 44 0 881 | 17 -96 346 0 882 | 386 101 -169 0 883 | -219 -190 262 0 884 | 24 -262 376 0 885 | 186 -131 322 0 886 | 175 -86 350 0 887 | -95 36 132 0 888 | -115 -337 -386 0 889 | 188 -88 204 0 890 | -87 -60 -256 0 891 | -262 320 361 0 892 | -243 -85 -47 0 893 | -170 366 101 0 894 | -49 -32 -204 0 895 | -330 -233 -90 0 896 | -60 -6 153 0 897 | -384 -59 -132 0 898 | 147 154 -300 0 899 | 316 -261 -224 0 900 | -101 -394 105 0 901 | 375 -141 -254 0 902 | 175 -96 128 0 903 | -240 -176 216 0 904 | -331 193 -240 0 905 | -378 -316 249 0 906 | 331 -31 70 0 907 | 205 236 278 0 908 | -394 381 -34 0 909 | -141 -2 152 0 910 | 187 36 -282 0 911 | 364 -400 273 0 912 | 167 -387 170 0 913 | -255 -216 -243 0 914 | 200 -21 -315 0 915 | 318 138 -361 0 916 | -41 -39 30 0 917 | 198 142 151 0 918 | 277 -296 -187 0 919 | 385 -335 87 0 920 | -176 155 -127 0 921 | 166 249 240 0 922 | 358 311 -308 0 923 | 32 106 -244 0 924 | -237 -113 266 0 925 | -265 -92 -257 0 926 | -145 -344 -314 0 927 | -102 -48 -337 0 928 | -309 90 -270 0 929 | -36 -48 111 0 930 | 4 186 -117 0 931 | -325 -225 -191 0 932 | 217 -214 328 0 933 | 317 35 76 0 934 | 184 126 -286 0 935 | 272 381 345 0 936 | 235 -69 201 0 937 | 306 123 125 0 938 | -170 144 -237 0 939 | -83 -65 52 0 940 | -127 -182 -362 0 941 | 47 -356 -222 0 942 | -110 238 -155 0 943 | 37 -143 77 0 944 | -151 -374 326 0 945 | -182 20 -369 0 946 | 248 40 -397 0 947 | -102 -347 118 0 948 | 141 -121 -185 0 949 | -78 -95 -50 0 950 | -239 382 -362 0 951 | 249 276 394 0 952 | 77 -398 129 0 953 | 236 298 286 0 954 | -48 144 277 0 955 | 39 289 -10 0 956 | -354 296 312 0 957 | -81 -120 157 0 958 | 374 52 -163 0 959 | -42 71 323 0 960 | 346 157 -262 0 961 | 344 -13 -157 0 962 | 15 -343 320 0 963 | 36 -125 -236 0 964 | 378 -377 -281 0 965 | 273 144 -107 0 966 | -394 -345 130 0 967 | 350 214 -334 0 968 | -4 372 160 0 969 | 1 98 23 0 970 | 183 222 -364 0 971 | 6 -300 -310 0 972 | 78 -351 274 0 973 | -95 126 -180 0 974 | -253 269 398 0 975 | 95 188 -120 0 976 | 23 -386 -230 0 977 | -392 -150 -133 0 978 | 73 -207 -380 0 979 | 105 -216 -69 0 980 | -353 -137 -261 0 981 | -2 169 -227 0 982 | -13 -43 352 0 983 | -351 331 222 0 984 | 130 -191 -1 0 985 | 175 -149 -180 0 986 | 228 -125 94 0 987 | -256 -271 139 0 988 | -223 -269 -327 0 989 | -229 280 -204 0 990 | -176 107 -100 0 991 | 184 320 300 0 992 | -373 84 381 0 993 | -107 -65 -168 0 994 | 47 241 149 0 995 | -202 149 187 0 996 | -28 -239 151 0 997 | 38 -392 -111 0 998 | -221 113 -369 0 999 | 210 -144 -221 0 1000 | -------------------------------------------------------------------------------- /python/src/pyapproxmc.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | ApproxMC 3 | 4 | Copyright (c) 2019-2020, Mate Soos and Kuldeep S. Meel. All rights reserved 5 | Copyright (c) 2009-2018, Mate Soos. All rights reserved. 6 | Copyright (c) 2015, Supratik Chakraborty, Daniel J. Fremont, 7 | Kuldeep S. Meel, Sanjit A. Seshia, Moshe Y. Vardi 8 | Copyright (c) 2014, Supratik Chakraborty, Kuldeep S. Meel, Moshe Y. Vardi 9 | 10 | Permission is hereby granted, free of charge, to any person obtaining a copy 11 | of this software and associated documentation files (the "Software"), to deal 12 | in the Software without restriction, including without limitation the rights 13 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 14 | copies of the Software, and to permit persons to whom the Software is 15 | furnished to do so, subject to the following conditions: 16 | 17 | The above copyright notice and this permission notice shall be included in 18 | all copies or substantial portions of the Software. 19 | 20 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 21 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 22 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 23 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 24 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 25 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 26 | THE SOFTWARE. 27 | */ 28 | 29 | #include 30 | #include 31 | #include "../../src/approxmc.h" 32 | #include "../arjun/src/arjun.h" 33 | 34 | #include 35 | #include 36 | #include 37 | 38 | #define MODULE_NAME "pyapproxmc" 39 | #define MODULE_DOC "ApproxMC approximate model counter." 40 | 41 | typedef struct { 42 | PyObject_HEAD 43 | ApproxMC::AppMC* appmc = NULL; 44 | ArjunNS::Arjun* arjun = NULL; 45 | std::vector tmp_cl_lits; 46 | bool count_called = false; 47 | 48 | int verbosity; 49 | uint32_t seed; 50 | double epsilon; 51 | double delta; 52 | } Counter; 53 | 54 | static const char counter_create_docstring[] = \ 55 | "Counter(verbosity=0, seed=1, epsilon=0.8, delta=0.2)\n\ 56 | Create Counter object.\n\ 57 | \n\ 58 | :param verbosity: Verbosity level: 0: nothing printed; 15: very verbose.\n\ 59 | :param seed: Random seed\n\ 60 | :param epsilon: epsilon parameter as per PAC guarantees\n\ 61 | :param delta: delta parameter as per PAC guarantees"; 62 | 63 | /********** Internal Functions **********/ 64 | 65 | /* Helper functions */ 66 | 67 | static void setup_counter(Counter *self, PyObject *args, PyObject *kwds) 68 | { 69 | static char const* kwlist[] = {"verbosity", "seed", "epsilon", "delta", NULL}; 70 | 71 | // All parameters have the same default as the command line defaults 72 | // except for verbosity which is 0 by default. 73 | self->verbosity = 0; 74 | self->seed = 1; 75 | self->epsilon = 0.8; 76 | self->delta = 0.2; 77 | 78 | if (!PyArg_ParseTupleAndKeywords(args, kwds, "|iIdd", const_cast(kwlist), 79 | &self->verbosity, &self->seed, &self->epsilon, &self->delta)) 80 | { 81 | return; 82 | } 83 | 84 | if (self->verbosity < 0) { 85 | PyErr_SetString(PyExc_ValueError, "verbosity must be at least 0"); 86 | return; 87 | } 88 | if (self->epsilon <= 0) { 89 | PyErr_SetString(PyExc_ValueError, "epsilon must be greater than 0"); 90 | return; 91 | } 92 | if (self->delta < 0 || self->delta >= 1) { 93 | PyErr_SetString(PyExc_ValueError, "delta must be greater or equal to 0, and less than 1"); 94 | return; 95 | } 96 | 97 | self->appmc = new ApproxMC::AppMC; 98 | self->appmc->set_verbosity(self->verbosity); 99 | self->appmc->set_seed(self->seed); 100 | self->appmc->set_epsilon(self->epsilon); 101 | self->appmc->set_delta(self->delta); 102 | 103 | self->arjun = new ArjunNS::Arjun; 104 | self->arjun->set_seed(self->seed); 105 | self->arjun->set_verbosity(self->verbosity); 106 | 107 | return; 108 | } 109 | 110 | static int convert_lit_to_sign_and_var(PyObject* lit, long& var, bool& sign) 111 | { 112 | if (!PyLong_Check(lit)) { 113 | PyErr_SetString(PyExc_TypeError, "integer expected !"); 114 | return 0; 115 | } 116 | 117 | long val = PyLong_AsLong(lit); 118 | if (val == 0) { 119 | PyErr_SetString(PyExc_ValueError, "non-zero integer expected"); 120 | return 0; 121 | } 122 | if (val > std::numeric_limits::max()/2 123 | || val < std::numeric_limits::min()/2 124 | ) { 125 | PyErr_Format(PyExc_ValueError, "integer %ld is too small or too large", val); 126 | return 0; 127 | } 128 | 129 | sign = (val < 0); 130 | var = std::abs(val) - 1; 131 | 132 | return 1; 133 | } 134 | 135 | static int parse_clause(Counter *self, PyObject *clause, std::vector& lits, bool allow_more_vars = true) 136 | { 137 | PyObject *iterator = PyObject_GetIter(clause); 138 | if (iterator == NULL) { 139 | PyErr_SetString(PyExc_TypeError, "iterable object expected"); 140 | return 0; 141 | } 142 | 143 | PyObject *lit; 144 | long int max_var = 0; 145 | while ((lit = PyIter_Next(iterator)) != NULL) { 146 | long var; 147 | bool sign; 148 | int ret = convert_lit_to_sign_and_var(lit, var, sign); 149 | Py_DECREF(lit); 150 | if (!ret) { 151 | Py_DECREF(iterator); 152 | return 0; 153 | } 154 | max_var = std::max(var, max_var); 155 | 156 | lits.push_back(CMSat::Lit(var, sign)); 157 | } 158 | 159 | if (!lits.empty() && max_var >= (long int)self->arjun->nVars()) { 160 | if (allow_more_vars) 161 | self->arjun->new_vars(max_var-(long int)self->arjun->nVars()+1); 162 | else { 163 | PyErr_SetString(PyExc_ValueError, 164 | "ERROR: Sampling vars contain variables that are not in the original clauses!"); 165 | return 0; 166 | } 167 | } 168 | 169 | Py_DECREF(iterator); 170 | if (PyErr_Occurred()) return 0; 171 | return 1; 172 | } 173 | 174 | static int _add_clause(Counter *self, PyObject *clause) 175 | { 176 | self->tmp_cl_lits.clear(); 177 | if (!parse_clause(self, clause, self->tmp_cl_lits)) { 178 | return 0; 179 | } 180 | self->arjun->add_clause(self->tmp_cl_lits); 181 | 182 | return 1; 183 | } 184 | 185 | 186 | /* add_clause function */ 187 | 188 | PyDoc_STRVAR(add_clause_doc, 189 | "add_clause(clause)\n\ 190 | Add a clause to the solver.\n\ 191 | \n\ 192 | :param clause: An iterator contains literals (ints)"); 193 | 194 | static PyObject* add_clause(Counter *self, PyObject *args, PyObject *kwds) 195 | { 196 | static char const* kwlist[] = {"clause", NULL}; 197 | PyObject *clause; 198 | if (!PyArg_ParseTupleAndKeywords(args, kwds, "O", const_cast(kwlist), &clause)) { 199 | return NULL; 200 | } 201 | 202 | if (_add_clause(self, clause) == 0 ) { 203 | return NULL; 204 | } 205 | 206 | Py_INCREF(Py_None); 207 | return Py_None; 208 | 209 | } 210 | 211 | template 212 | static int _add_clauses_from_array(Counter *self, const size_t array_length, const T *array) 213 | { 214 | if (array_length == 0) { 215 | return 1; 216 | } 217 | if (array[array_length - 1] != 0) { 218 | PyErr_SetString(PyExc_ValueError, "last clause not terminated by zero"); 219 | return 0; 220 | } 221 | size_t k = 0; 222 | long val = 0; 223 | std::vector& lits = self->tmp_cl_lits; 224 | for (val = (long) array[k]; k < array_length; val = (long) array[++k]) { 225 | lits.clear(); 226 | long int max_var = 0; 227 | for (; k < array_length && val != 0; val = (long) array[++k]) { 228 | long var; 229 | bool sign; 230 | if (val > std::numeric_limits::max()/2 231 | || val < std::numeric_limits::min()/2 232 | ) { 233 | PyErr_Format(PyExc_ValueError, "integer %ld is too small or too large", val); 234 | return 0; 235 | } 236 | 237 | sign = (val < 0); 238 | var = std::abs(val) - 1; 239 | max_var = std::max(var, max_var); 240 | 241 | lits.push_back(CMSat::Lit(var, sign)); 242 | } 243 | if (!lits.empty()) { 244 | if (max_var >= (long int)self->arjun->nVars()) { 245 | self->arjun->new_vars(max_var-(long int)self->arjun->nVars()+1); 246 | } 247 | self->arjun->add_clause(lits); 248 | } 249 | } 250 | return 1; 251 | } 252 | 253 | static int _add_clauses_from_buffer(Counter *self, Py_buffer *view) 254 | { 255 | if (view->ndim != 1) { 256 | PyErr_Format(PyExc_ValueError, "invalid clause array: expected 1-D array, got %d-D", view->ndim); 257 | return 0; 258 | } 259 | if (strcmp(view->format, "i") != 0 && strcmp(view->format, "l") != 0 && strcmp(view->format, "q") != 0) { 260 | PyErr_Format(PyExc_ValueError, "invalid clause array: invalid format '%s'", view->format); 261 | return 0; 262 | } 263 | 264 | void * array_address = view->buf; 265 | size_t itemsize = view->itemsize; 266 | size_t array_length = view->len / itemsize; 267 | 268 | if (itemsize == sizeof(int)) { 269 | return _add_clauses_from_array(self, array_length, (const int *) array_address); 270 | } 271 | if (itemsize == sizeof(long)) { 272 | return _add_clauses_from_array(self, array_length, (const long *) array_address); 273 | } 274 | if (itemsize == sizeof(long long)) { 275 | return _add_clauses_from_array(self, array_length, (const long long *) array_address); 276 | } 277 | PyErr_Format(PyExc_ValueError, "invalid clause array: invalid itemsize '%ld'", itemsize); 278 | return 0; 279 | } 280 | 281 | PyDoc_STRVAR(add_clauses_doc, 282 | "add_clauses(clauses)\n\ 283 | Add iterable of clauses to the solver.\n\ 284 | \n\ 285 | :param clauses: List of clauses. Each clause contains literals (ints)\n\ 286 | Alternatively, this can be a flat array.array or other contiguous\n\ 287 | buffer (format 'i', 'l', or 'q') of zero separated and terminated\n\ 288 | clauses of literals (ints).\n\ 289 | :type clauses: or \n\ 290 | :return: None\n\ 291 | :rtype: " 292 | ); 293 | 294 | static PyObject* add_clauses(Counter *self, PyObject *args, PyObject *kwds) 295 | { 296 | static char const* kwlist[] = {"clauses", NULL}; 297 | PyObject *clauses; 298 | if (!PyArg_ParseTupleAndKeywords(args, kwds, "O", const_cast(kwlist), &clauses)) { 299 | return NULL; 300 | } 301 | 302 | if (PyObject_CheckBuffer(clauses)) { 303 | Py_buffer view; 304 | memset(&view, 0, sizeof(view)); 305 | if (PyObject_GetBuffer(clauses, &view, PyBUF_CONTIG_RO | PyBUF_FORMAT) != 0) { 306 | return NULL; 307 | } 308 | 309 | int ret = _add_clauses_from_buffer(self, &view); 310 | PyBuffer_Release(&view); 311 | 312 | if (ret == 0 || PyErr_Occurred()) { 313 | return 0; 314 | } 315 | Py_INCREF(Py_None); 316 | return Py_None; 317 | } 318 | 319 | PyObject *iterator = PyObject_GetIter(clauses); 320 | if (iterator == NULL) { 321 | PyErr_SetString(PyExc_TypeError, "iterable object expected"); 322 | return NULL; 323 | } 324 | 325 | PyObject *clause; 326 | while ((clause = PyIter_Next(iterator)) != NULL) { 327 | _add_clause(self, clause); 328 | /* release reference when done */ 329 | Py_DECREF(clause); 330 | } 331 | 332 | /* release reference when done */ 333 | Py_DECREF(iterator); 334 | if (PyErr_Occurred()) { 335 | return NULL; 336 | } 337 | 338 | Py_INCREF(Py_None); 339 | return Py_None; 340 | } 341 | 342 | 343 | static void get_cnf_from_arjun(Counter* self) 344 | { 345 | const uint32_t orig_num_vars = self->arjun->get_orig_num_vars(); 346 | self->appmc->new_vars(orig_num_vars); 347 | self->arjun->start_getting_constraints(false, false); 348 | std::vector clause; 349 | bool is_xor, rhs; 350 | 351 | bool ret = true; 352 | while (ret) { 353 | ret = self->arjun->get_next_constraint(clause, is_xor, rhs); 354 | assert(!is_xor); assert(rhs); 355 | if (!ret) break; 356 | bool ok = true; 357 | for(auto l: clause) { 358 | if (l.var() >= orig_num_vars) { 359 | ok = false; 360 | break; 361 | } 362 | } 363 | 364 | if (ok) self->appmc->add_clause(clause); 365 | } 366 | self->arjun->end_getting_constraints(); 367 | } 368 | 369 | static void transfer_unit_clauses_from_arjun(Counter* self) 370 | { 371 | std::vector cl(1); 372 | auto units = self->arjun->get_zero_assigned_lits(); 373 | for(const auto& unit: units) { 374 | if (unit.var() < self->appmc->nVars()) { 375 | cl[0] = unit; 376 | self->appmc->add_clause(cl); 377 | } 378 | } 379 | } 380 | 381 | static uint32_t set_up_sampling_set(Counter* self, const std::vector& sampling_vars) 382 | { 383 | uint32_t orig_sampling_set_size; 384 | orig_sampling_set_size = self->arjun->set_sampl_vars(sampling_vars); 385 | return orig_sampling_set_size; 386 | } 387 | 388 | /* count function */ 389 | 390 | PyDoc_STRVAR(count_doc, 391 | "count(projection)\n\ 392 | Approximately count the number of solutions to the formula. It can only be called ONCE.\n\ 393 | \n\ 394 | :param projection: the projection over which to count the solutions over\n\ 395 | \n\ 396 | :return: A tuple. The first part of the tuple is the cell solution count and\n\ 397 | the second part is the hash count." 398 | ); 399 | 400 | static PyObject* count(Counter *self, PyObject *args, PyObject *kwds) 401 | { 402 | if (self->count_called) { 403 | PyErr_SetString(PyExc_ValueError, "ERROR: Counter.count() may only be called once!"); 404 | return NULL; 405 | } else { 406 | self->count_called = true; 407 | } 408 | static char const* kwlist[] = {"projection", NULL}; 409 | PyObject *py_sampling_vars = NULL; 410 | if (!PyArg_ParseTupleAndKeywords(args, kwds, "|O", const_cast(kwlist), &py_sampling_vars)) { 411 | return NULL; 412 | } 413 | 414 | // Get sampling vars from user 415 | std::vector sampling_vars; 416 | if (py_sampling_vars == NULL) { 417 | for(uint32_t i = 0; i < self->arjun->nVars(); i++) sampling_vars.push_back(i); 418 | } else { 419 | std::vector sampling_lits; 420 | if (parse_clause(self, py_sampling_vars, sampling_lits, false) == 0 ) { 421 | return NULL; 422 | } 423 | for(const auto& l: sampling_lits) { 424 | if (l.var() > self->arjun->nVars()) { 425 | PyErr_SetString(PyExc_ValueError, 426 | "ERROR: Sampling vars contain variables that are not in the original clauses!"); 427 | return NULL; 428 | } 429 | sampling_vars.push_back(l.var()); 430 | } 431 | } 432 | set_up_sampling_set(self, sampling_vars); 433 | sampling_vars = self->arjun->run_backwards(); 434 | 435 | // Now do ApproxMC 436 | get_cnf_from_arjun(self); 437 | transfer_unit_clauses_from_arjun(self); 438 | ApproxMC::SolCount sol_count; 439 | if (!sampling_vars.empty()) { 440 | self->appmc->set_sampl_vars(sampling_vars); 441 | sol_count = self->appmc->count(); 442 | } else { 443 | bool ret = self->appmc->find_one_solution(); 444 | sol_count.hashCount = 0; 445 | if (ret) sol_count.cellSolCount = 1; 446 | else sol_count.cellSolCount = 0; 447 | } 448 | 449 | // Fill return value 450 | PyObject *result = PyTuple_New((Py_ssize_t) 2); 451 | if (result == NULL) { 452 | PyErr_SetString(PyExc_SystemError, "failed to create a tuple"); 453 | return NULL; 454 | } 455 | PyTuple_SET_ITEM(result, 0, PyLong_FromLong((long)sol_count.cellSolCount)); 456 | PyTuple_SET_ITEM(result, 1, PyLong_FromLong((long)sol_count.hashCount+self->arjun->get_empty_sampl_vars().size())); 457 | return result; 458 | } 459 | 460 | /********** Python Bindings **********/ 461 | static PyMethodDef Counter_methods[] = { 462 | {"count", (PyCFunction) count, METH_VARARGS | METH_KEYWORDS, count_doc}, 463 | {"add_clause",(PyCFunction) add_clause, METH_VARARGS | METH_KEYWORDS, add_clause_doc}, 464 | {"add_clauses", (PyCFunction) add_clauses, METH_VARARGS | METH_KEYWORDS, add_clauses_doc}, 465 | {NULL, NULL} // Sentinel 466 | }; 467 | 468 | static void Counter_dealloc(Counter* self) 469 | { 470 | delete self->appmc; 471 | delete self->arjun; 472 | Py_TYPE(self)->tp_free ((PyObject*) self); 473 | } 474 | 475 | static int Counter_init(Counter *self, PyObject *args, PyObject *kwds) 476 | { 477 | if (self->appmc != NULL) delete self->appmc; 478 | if (self->arjun != NULL) delete self->arjun; 479 | 480 | setup_counter(self, args, kwds); 481 | 482 | if (!self->appmc) return -1; 483 | 484 | return 0; 485 | } 486 | 487 | static PyTypeObject pyapproxmc_CounterType = 488 | { 489 | PyVarObject_HEAD_INIT(NULL, 0) /*ob_size*/ 490 | "pyapproxmc.Counter", /*tp_name*/ 491 | sizeof(Counter), /*tp_basicsize*/ 492 | 0, /*tp_itemsize*/ 493 | (destructor)Counter_dealloc, /*tp_dealloc*/ 494 | 0, /*tp_print*/ 495 | 0, /*tp_getattr*/ 496 | 0, /*tp_setattr*/ 497 | 0, /*tp_compare*/ 498 | 0, /*tp_repr*/ 499 | 0, /*tp_as_number*/ 500 | 0, /*tp_as_sequence*/ 501 | 0, /*tp_as_mapping*/ 502 | 0, /*tp_hash */ 503 | 0, /*tp_call*/ 504 | 0, /*tp_str*/ 505 | 0, /*tp_getattro*/ 506 | 0, /*tp_setattro*/ 507 | 0, /*tp_as_buffer*/ 508 | Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /*tp_flags*/ 509 | counter_create_docstring, /* tp_doc */ 510 | 0, /* tp_traverse */ 511 | 0, /* tp_clear */ 512 | 0, /* tp_richcompare */ 513 | 0, /* tp_weaklistoffset */ 514 | 0, /* tp_iter */ 515 | 0, /* tp_iternext */ 516 | Counter_methods, /* tp_methods */ 517 | 0, /* tp_members */ 518 | 0, /* tp_getset */ 519 | 0, /* tp_base */ 520 | 0, /* tp_dict */ 521 | 0, /* tp_descr_get */ 522 | 0, /* tp_descr_set */ 523 | 0, /* tp_dictoffset */ 524 | (initproc)Counter_init, /* tp_init */ 525 | }; 526 | 527 | PyMODINIT_FUNC PyInit_pyapproxmc(void) 528 | { 529 | PyObject* m; 530 | 531 | pyapproxmc_CounterType.tp_new = PyType_GenericNew; 532 | if (PyType_Ready(&pyapproxmc_CounterType) < 0) { 533 | // Return NULL on Python3 and on Python2 with MODULE_INIT_FUNC macro 534 | // In pure Python2: return nothing. 535 | return NULL; 536 | } 537 | 538 | static struct PyModuleDef moduledef = { 539 | PyModuleDef_HEAD_INIT, /* m_base */ 540 | MODULE_NAME, /* m_name */ 541 | MODULE_DOC, /* m_doc */ 542 | -1, /* m_size */ 543 | NULL, /* m_methods */ 544 | NULL, /* m_reload */ 545 | NULL, /* m_traverse */ 546 | NULL, /* m_clear */ 547 | NULL, /* m_free */ 548 | }; 549 | 550 | m = PyModule_Create(&moduledef); 551 | 552 | if (!m) { 553 | return NULL; 554 | } 555 | 556 | // Add the version string 557 | // they're using. 558 | #if defined(_MSC_VER) 559 | #else 560 | if (PyModule_AddStringConstant(m, "__version__", APPMC_FULL_VERSION) == -1) { 561 | Py_DECREF(m); 562 | return NULL; 563 | } 564 | if (PyModule_AddStringConstant(m, "VERSION", APPMC_FULL_VERSION) == -1) { 565 | Py_DECREF(m); 566 | return NULL; 567 | } 568 | #endif 569 | 570 | // Add the Counter type 571 | Py_INCREF(&pyapproxmc_CounterType); 572 | if (PyModule_AddObject(m, "Counter", (PyObject *)&pyapproxmc_CounterType)) { 573 | Py_DECREF(m); 574 | return NULL; 575 | } 576 | 577 | return m; 578 | } 579 | --------------------------------------------------------------------------------