diff --git a/.config/names.dic b/.config/names.dic index 2eb4b2cf..ab3b7787 100644 --- a/.config/names.dic +++ b/.config/names.dic @@ -1,4 +1,4 @@ -58 +59 Argelich Armin Audemard @@ -12,6 +12,7 @@ Boufkhad bzip2 CaDiCaL CaDiCaL's +CryptoMiniSat Eén Fazekas Fleury diff --git a/Cargo.lock b/Cargo.lock index d9670612..185d1f65 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1294,6 +1294,21 @@ dependencies = [ "rustsat", ] +[[package]] +name = "rustsat-cryptominisat" +version = "0.1.0" +dependencies = [ + "anyhow", + "bindgen", + "clap", + "cmake", + "cpu-time", + "rustsat", + "rustsat-solvertests", + "signal-hook", + "thiserror", +] + [[package]] name = "rustsat-glucose" version = "0.3.6" diff --git a/Cargo.toml b/Cargo.toml index c63cd812..486ec953 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -10,6 +10,7 @@ members = [ "capi", "pyapi", "batsat", + "cryptominisat", ] resolver = "2" diff --git a/clippy.toml b/clippy.toml index 1cec5ff5..0625d39b 100644 --- a/clippy.toml +++ b/clippy.toml @@ -1,6 +1,7 @@ doc-valid-idents = [ "RustSAT", "CaDiCaL", + "CryptoMiniSat", "MaxSAT", "BatSat", "AllDifferent", diff --git a/cryptominisat/CHANGELOG.md b/cryptominisat/CHANGELOG.md new file mode 100644 index 00000000..9ccb5b8f --- /dev/null +++ b/cryptominisat/CHANGELOG.md @@ -0,0 +1,133 @@ +# Changelog + +All notable changes to this project will be documented in this file. + +## [0.4.4] - 2025-02-18 + +### Miscellaneous Tasks + +- Update Cargo.toml dependencies + + +## [0.4.3] - 2024-12-20 + +### Miscellaneous Tasks + +- Exclude unnecessary files from release + + +## [0.4.2] - 2024-12-13 + +### Documentation + +- Spellchecking + + +## [0.4.1] - 2024-10-16 + +### Documentation + +- Fix docsrs build + + +## [0.4.0] - 2024-10-16 + +### Features + +- `Propagate` trait + +### Miscellaneous Tasks + +- Pedantic clippy + +### Refactor + +- [**breaking**] Make reading functions take reader by reference +- Use bindgen to generate solver bindings + + +## [0.3.1] - 2024-06-12 + +### Miscellaneous Tasks + +- Updated the following local packages: rustsat + + +## [0.3.0] - 2024-04-30 + +The corresponding RustSAT release contains breaking changes. For detailed +instructions on how to handle migration, please refer to the [migration +guide](https://github.com/chrjabs/rustsat/blob/main/docs/0-5-0-migration-guide.md). + +### Bug Fixes + +- Variable freezing and return value for `var_eliminated` +- Segfault in minisat + +### Documentation + +- Add missing documentation + +### Features + +- `quiet` feature to disable stdout printing +- Migrate error handling to `anyhow` create +- `FreezeVar` trait +- Return error when assumption is eliminated +- Add `add_clause_ref` method to `Solve` trait +- `Extend<&Clause>` for solvers +- Catch memory out in solvers +- Catch memory outs in clause collector + +### Refactor + +- Clean up control flow in solver methods +- Factor out solver integration tests +- Factor out solver unit tests +- Solver build system + +### Testing + +- Minisat segfault tests + +### Example + +- `minisat-cli` tool + + +## [0.2.4] - 2024-02-22 + +### Bug Fixes + +- Remove zlib dependency from minisat and glucose + + + +## [0.2.3] - 2024-01-11 + +### Documentation + +- Fix [docs.rs](https://docs.rs/rustsat-minisat) build + +## [0.2.2] - 2024-01-11 + +### Bug Fixes + +- Build on non-linux + +### Documentation + +- Add shields to READMEs + +### Features + +- Debug feature + + +## [0.2.1] - 2023-12-18 + +### Miscellaneous Tasks + +- Updated the following local packages: rustsat + + diff --git a/cryptominisat/Cargo.toml b/cryptominisat/Cargo.toml new file mode 100644 index 00000000..e0b651a1 --- /dev/null +++ b/cryptominisat/Cargo.toml @@ -0,0 +1,45 @@ +[package] +name = "rustsat-cryptominisat" +version = "0.1.0" +edition.workspace = true +authors = ["Christoph Jabs "] +license.workspace = true +description = "Interface to the SAT solver CryptoMiniSat for the RustSAT library." +keywords = ["sat-solver", "rustsat"] +repository = "https://github.com/chrjabs/rustsat" +readme = "README.md" +include = [ + "build.rs", + "CHANGELOG.md", + "README.md", + "/src/", + "/examples/", + "/cppsrc/src/", + "/cppsrc/README.markdown", + "/cppsrc/LICENSE.txt", + "/cppsrc/AUTHORS", + "/cppsrc/CMakeLists.txt", + "/cppsrc/cryptominisat5Config.cmake.in", +] + +build = "build.rs" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[features] +debug = [] + +[dependencies] +anyhow.workspace = true +cpu-time.workspace = true +thiserror.workspace = true +rustsat.workspace = true + +[build-dependencies] +bindgen.workspace = true +cmake.workspace = true + +[dev-dependencies] +clap.workspace = true +signal-hook.workspace = true +rustsat-solvertests.workspace = true diff --git a/cryptominisat/README.md b/cryptominisat/README.md new file mode 100644 index 00000000..569caab0 --- /dev/null +++ b/cryptominisat/README.md @@ -0,0 +1,22 @@ +[![Check & Test](https://github.com/chrjabs/rustsat/actions/workflows/minisat.yml/badge.svg)](https://github.com/chrjabs/rustsat/actions/workflows/minisat.yml) +[![crates.io](https://img.shields.io/crates/v/rustsat-minisat)](https://crates.io/crates/rustsat-minisat) +[![docs.rs](https://img.shields.io/docsrs/rustsat-minisat)](https://docs.rs/rustsat-minisat) +[![License](https://img.shields.io/crates/l/rustsat-minisat)](../LICENSE) + + + +# rustsat-minisat - Interface to the Minisat SAT Solver for RustSAT + +The Minisat SAT solver to be used with the [RustSAT](https://github.com/chrjabs/rustsat) library. + +## Features + +- `debug`: if this feature is enables, the Cpp library will be built with debug and check functionality if the Rust project is built in debug mode +- `quiet`: disable all glucose-internal printing to `stdout` during solving (on by default) + +## Minisat Version + +The version of Minisat in this crate is Version 2.2.0. +The used Cpp source repository can be found [here](https://github.com/chrjabs/minisat). + + diff --git a/cryptominisat/build.rs b/cryptominisat/build.rs new file mode 100644 index 00000000..e2032f64 --- /dev/null +++ b/cryptominisat/build.rs @@ -0,0 +1,64 @@ +#![warn(clippy::pedantic)] + +use std::{ + env, + path::{Path, PathBuf}, +}; + +fn main() { + // Build C++ library + build(); + + let out_dir = env::var("OUT_DIR").unwrap(); + + println!("cargo:rerun-if-changed=cppsrc/"); + + // Built solver is in out_dir + println!("cargo:rustc-link-search={out_dir}/build/lib"); + println!("cargo:rustc-link-lib=static=cryptominisat5"); + + // Link c++ std lib + // Note: this should be _after_ linking the solver itself so that it is actually pulled in + #[cfg(target_os = "macos")] + println!("cargo:rustc-link-lib=dylib=c++"); + #[cfg(not(any(target_os = "macos", target_os = "windows")))] + println!("cargo:rustc-link-lib=dylib=stdc++"); + + // Generate Rust FFI bindings + let bindings = bindgen::Builder::default() + .rust_target("1.66.1".parse().unwrap()) // Set MSRV of RustSAT + .header("cppsrc/src/cryptominisat_c.h") + .allowlist_file("cppsrc/src/cryptominisat_c.h") + .blocklist_function("cmsat_print_stats") + .blocklist_function("cmsat_set_up_for_scalmc") + .blocklist_function("set_up_for_arjun") + .blocklist_function("cmsat_set_yes_comphandler") + .blocklist_function("cmsat_simplify") + .blocklist_function("cmsat_set_polarity_auto") + .parse_callbacks(Box::new(bindgen::CargoCallbacks::new())) + .generate() + .expect("Unable to generate ffi bindings"); + bindings + .write_to_file(PathBuf::from(out_dir).join("bindings.rs")) + .expect("Could not write ffi bindings"); +} + +fn build() { + let crate_dir = env::var("CARGO_MANIFEST_DIR").unwrap(); + let mut cms_dir_str = crate_dir.clone(); + cms_dir_str.push_str("/cppsrc"); + let cms_dir = Path::new(&cms_dir_str); + let mut conf = cmake::Config::new(cms_dir); + conf.build_target("cryptominisat5") + .define("STATICCOMPILE", "ON") + .define("ENABLE_PYTHON_INTERFACE", "OFF") + .define("ONLY_SIMPLE", "ON") + .define("NOZLIB", "ON") + .define("NOM4RI", "ON") + .define("STATS", "OFF") + .define("NOVALGRIND", "ON") + .define("ENABLE_TESTING", "OFF"); + #[cfg(not(feature = "debug"))] + conf.profile("Release"); + conf.build(); +} diff --git a/cryptominisat/cppsrc/.clang-format b/cryptominisat/cppsrc/.clang-format new file mode 100644 index 00000000..411cce28 --- /dev/null +++ b/cryptominisat/cppsrc/.clang-format @@ -0,0 +1,100 @@ +--- +Language: Cpp +# BasedOnStyle: Google +AccessModifierOffset: -1 +AlignAfterOpenBracket: Align +AlignConsecutiveAssignments: false +AlignConsecutiveDeclarations: false +AlignEscapedNewlinesLeft: true +AlignOperands: true +AlignTrailingComments: true +AllowAllParametersOfDeclarationOnNextLine: true +AllowShortBlocksOnASingleLine: true +AllowShortCaseLabelsOnASingleLine: true +AllowShortFunctionsOnASingleLine: true +AllowShortIfStatementsOnASingleLine: true +AllowShortLoopsOnASingleLine: true +AllowShortIfStatementsOnASingleLine: true +AlwaysBreakAfterDefinitionReturnType: None +AlwaysBreakAfterReturnType: None +AlwaysBreakBeforeMultilineStrings: true +AlwaysBreakTemplateDeclarations: true +BinPackArguments: true +BinPackParameters: true +BreakBeforeBraces: Custom +BraceWrapping: + AfterClass: false + AfterStruct: false + AfterControlStatement: false + AfterEnum: false + AfterFunction: false + AfterNamespace: false + AfterObjCDeclaration: false + AfterStruct: false + AfterUnion: false + BeforeCatch: false + BeforeElse: false + IndentBraces: false +BreakBeforeBinaryOperators: None +BreakBeforeTernaryOperators: true +BreakConstructorInitializersBeforeComma: false +BreakAfterJavaFieldAnnotations: false +BreakStringLiterals: true +ColumnLimit: 100 +CommentPragmas: '^ IWYU pragma:' +ConstructorInitializerAllOnOneLineOrOnePerLine: true +ConstructorInitializerIndentWidth: 4 +ContinuationIndentWidth: 4 +Cpp11BracedListStyle: true +DerivePointerAlignment: true +DisableFormat: false +ExperimentalAutoDetectBinPacking: false +ForEachMacros: [ foreach, Q_FOREACH, BOOST_FOREACH ] +IncludeCategories: + - Regex: '^<.*\.h>' + Priority: 1 + - Regex: '^<.*' + Priority: 2 + - Regex: '.*' + Priority: 3 +IncludeIsMainRegex: '([-_](test|unittest))?$' +IndentCaseLabels: true +IndentWidth: 4 +IndentWrappedFunctionNames: false +JavaScriptQuotes: Leave +JavaScriptWrapImports: true +KeepEmptyLinesAtTheStartOfBlocks: false +MacroBlockBegin: '' +MacroBlockEnd: '' +MaxEmptyLinesToKeep: 1 +NamespaceIndentation: None +ObjCBlockIndentWidth: 4 +ObjCSpaceAfterProperty: false +ObjCSpaceBeforeProtocolList: false +PenaltyBreakBeforeFirstCallParameter: 1 +PenaltyBreakComment: 300 +PenaltyBreakFirstLessLess: 120 +PenaltyBreakString: 1000 +PenaltyExcessCharacter: 1000000 +PenaltyReturnTypeOnItsOwnLine: 200 +PointerAlignment: Left +ReflowComments: false +SortIncludes: true +SpaceAfterCStyleCast: false +SpaceAfterTemplateKeyword: true +SpaceBeforeAssignmentOperators: true +SpaceBeforeParens: ControlStatements +SpaceBeforeRangeBasedForLoopColon: false +SpaceInEmptyParentheses: false +SpaceInEmptyParentheses: false +SpacesBeforeTrailingComments: 1 +SpacesInAngles: false +SpacesInContainerLiterals: false +SpacesInCStyleCastParentheses: false +SpacesInParentheses: false +SpacesInSquareBrackets: false +Standard: Auto +TabWidth: 8 +UseTab: Never +... + diff --git a/cryptominisat/cppsrc/.dockerignore b/cryptominisat/cppsrc/.dockerignore new file mode 100644 index 00000000..7bcebb41 --- /dev/null +++ b/cryptominisat/cppsrc/.dockerignore @@ -0,0 +1,30 @@ +# files and dirs to ignore +scripts/fuzz +scripts/reconf +scripts/aws +.git/ +debian + +appveyor.yml +AUTHORS +build +.clang-format +cryptominisat.kdev4 +debian +.directory +Dockerfile +.dockerignore +docs +.git +.gitignore +.gitmodules +jni +.kdev4 +LICENSE.txt +python +README.markdown +sql_* +tests +.travis.yml +utils +web/dygraphs/node_modules diff --git a/cryptominisat/cppsrc/.github/workflows/binary-build.yml b/cryptominisat/cppsrc/.github/workflows/binary-build.yml new file mode 100644 index 00000000..8a22dfa7 --- /dev/null +++ b/cryptominisat/cppsrc/.github/workflows/binary-build.yml @@ -0,0 +1,91 @@ +name: binary build + +on: + push: + branches: + - master + + +jobs: + build: + # The CMake configure and build commands are platform agnostic and should work equally + # well on Windows or Mac. You can convert this to a matrix build if you need + # cross-platform coverage. + # See: https://docs.github.com/en/actions/configuring-and-managing-workflows/configuring-a-workflow#configuring-a-build-matrix + runs-on: ${{ matrix.os }} + + + strategy: + matrix: + os: [ubuntu-20.04, windows-2022, macos-13] + build_type: ['Release'] + staticcompile: ['ON', 'OFF'] + + steps: + - uses: actions/checkout@v4.1.1 + + # install dependencies + - name: Install boost & help2man for Linux + if: matrix.os == 'ubuntu-20.04' + run: sudo apt-get update && sudo apt-get install -yq libboost-dev libboost-serialization-dev libboost-program-options-dev help2man + + - name: Installing Numpy + run: | + pip install pip --upgrade + pip install numpy lit + + - name: Add git submodules for Linux only (not needed for non-testing) + if: matrix.os == 'ubuntu-20.04' + run: git submodule update --init + + - name: Configure CMake for linux + if: matrix.os == 'ubuntu-20.04' + # Use a bash shell so we can use the same syntax for environment variable + # access regardless of the host operating system + #working-directory: ${{runner.workspace}}/build + # Note the current convention is to use the -S and -B options here to specify source + # and build directories, but this is only available with CMake 3.13 and higher. + # The CMake binaries on the Github Actions machines are (as of this writing) 3.12 + run: cmake $GITHUB_WORKSPACE -DCMAKE_BUILD_TYPE=${{ matrix.build_type }} -DENABLE_TESTING=ON -DSTATICCOMPILE=${{ matrix.staticcompile }} + + - name: Configure CMake for non-linux + if: matrix.os != 'ubuntu-20.04' + # Use a bash shell so we can use the same syntax for environment variable + # access regardless of the host operating system + #working-directory: ${{runner.workspace}}/build + # Note the current convention is to use the -S and -B options here to specify source + # and build directories, but this is only available with CMake 3.13 and higher. + # The CMake binaries on the Github Actions machines are (as of this writing) 3.12 + run: cmake $GITHUB_WORKSPACE -DCMAKE_BUILD_TYPE=${{ matrix.build_type }} -DENABLE_TESTING=OFF -DSTATICCOMPILE=${{ matrix.staticcompile }} + + - name: Build + #working-directory: ${{runner.workspace}}/build + # Execute the build. You can specify a specific target with "--target " + run: cmake --build . --config ${{ matrix.build_type }} + + - name: Test + #working-directory: ${{runner.workspace}}/build + # Execute tests defined by the CMake configuration. + # See https://cmake.org/cmake/help/latest/manual/ctest.1.html for more detail + run: ctest -C ${{ matrix.build_type }} + + - name: Upload Artifact - Linux + if: matrix.os == 'ubuntu-20.04' && matrix.staticcompile == 'ON' + uses: actions/upload-artifact@v3 + with: + name: cryptominisat5-linux-amd64 + path: cryptominisat5 + + - name: Upload Artifact - Mac + if: matrix.os == 'macos-13' && matrix.staticcompile == 'ON' + uses: actions/upload-artifact@v3 + with: + name: cryptominisat5-mac-amd64 + path: cryptominisat5 + + - name: Upload Artifact - Windows + if: matrix.os == 'windows-2022' && matrix.staticcompile == 'ON' + uses: actions/upload-artifact@v3 + with: + name: cryptominisat5-win64.exe + path: Release\cryptominisat5.exe diff --git a/cryptominisat/cppsrc/.github/workflows/python-src-pkg-build.yml b/cryptominisat/cppsrc/.github/workflows/python-src-pkg-build.yml new file mode 100644 index 00000000..25f1e991 --- /dev/null +++ b/cryptominisat/cppsrc/.github/workflows/python-src-pkg-build.yml @@ -0,0 +1,57 @@ +name: Python source package build + +on: + push: + branches: + - master + +jobs: + deploy: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v2 + - name: Set up Python + uses: actions/setup-python@v1 + with: + python-version: 3.8 + - name: Install dependencies + run: | + python -m pip install --upgrade pip + pip install twine flake8 +# - name: Lint with flake8 for syntax errors +# run: | +# pip install flake8 +# flake8 . --count --select=E9,F63,F7,F82 --show-source --statistics +# flake8 . --count --exit-zero --max-complexity=10 --max-line-length=127 --statistics + - name: Get Python3 + uses: actions/setup-python@v3 + with: + python-version: "3.10" + - name: Install pypa/build + run: >- + python -m + pip install + build + --user + - name: Build a source tarball + run: >- + python -m + build + --sdist + --outdir dist/ + - name: Build manylinux Python wheels + uses: RalfG/python-wheels-manylinux-build@v0.7.1 + with: + build-requirements: 'cython numpy' + system-packages: 'zlib-devel boost-devel boost-program-options boost-serialization' + - name: Upload Artifacts + uses: actions/upload-artifact@v2 + with: + name: python-wheel-artifact + path: dist/* + - name: Publish wheels to PyPI + env: + TWINE_USERNAME: "__token__" + TWINE_PASSWORD: ${{ secrets.PYPI_API_TOKEN }} + run: | + twine upload --skip-existing --disable-progress-bar dist/pycryptosat-*.tar.gz diff --git a/cryptominisat/cppsrc/.github/workflows/python-wheel-build.yml b/cryptominisat/cppsrc/.github/workflows/python-wheel-build.yml new file mode 100644 index 00000000..c634e13b --- /dev/null +++ b/cryptominisat/cppsrc/.github/workflows/python-wheel-build.yml @@ -0,0 +1,43 @@ +name: python wheel package build + +on: + push: + branches: + - master + +jobs: + build_wheels: + name: Build wheels on ${{ matrix.os }} + runs-on: ${{ matrix.os }} + strategy: + matrix: + os: [ubuntu-20.04, windows-2022, macos-13] + + steps: + - uses: actions/checkout@v3 + + # Used to host cibuildwheel + - uses: actions/setup-python@v3 + + - name: Install cibuildwheel + run: python -m pip install cibuildwheel==2.16.2 + + - name: Build wheels + run: python -m cibuildwheel --output-dir wheelhouse + # to supply options, put them in 'env', like: + env: + CIBW_BEFORE_ALL_LINUX: yum install -y boost-devel zlib-devel + CIBW_SKIP: "*musl*" + CIBW_ARCHS: "auto64" + + - uses: actions/upload-artifact@v3 + with: + path: ./wheelhouse/*.whl + - name: Install twine + run: python -m pip install twine + - name: Publish wheels to PyPI + env: + TWINE_USERNAME: "__token__" + TWINE_PASSWORD: ${{ secrets.PYPI_API_TOKEN }} + run: | + twine upload --skip-existing --disable-progress-bar ./wheelhouse/pycryptosat-*.whl diff --git a/cryptominisat/cppsrc/.gitignore b/cryptominisat/cppsrc/.gitignore new file mode 100644 index 00000000..91045e58 --- /dev/null +++ b/cryptominisat/cppsrc/.gitignore @@ -0,0 +1,27 @@ +*.kdev4 +*.pyc +*.aux +*.bbl +*.blg +*.log +*.pdf +*.out +.gdb_history +.directory +build/ +scripts/fuzz/out/ +scripts/reconf/outs +tests/cnf-files/*.sqlite +scripts/fuzz/fuzzTest_* +scripts/fuzz/tmp_for_xor_to_cnf_* +scripts/reconf/outfile* +.vscode +web/jquery-1.11.3.min.js +*.pdf +*.aux +*.blg +*.log +*.bbl +*.bak +/.vs +tags diff --git a/cryptominisat/cppsrc/.gitmodules b/cryptominisat/cppsrc/.gitmodules new file mode 100644 index 00000000..4e0785a6 --- /dev/null +++ b/cryptominisat/cppsrc/.gitmodules @@ -0,0 +1,38 @@ +[submodule "utils/OutputCheck"] + path = utils/OutputCheck + url = https://github.com/stp/OutputCheck.git +[submodule "utils/gtest"] + path = utils/gtest + url = https://github.com/stp/googletest.git +[submodule "utils/cnf-utils"] + path = utils/cnf-utils + url = https://github.com/msoos/cnf-utils.git +[submodule "utils/sha1-sat"] + path = utils/sha1-sat + url = https://github.com/msoos/sha1-sat.git +[submodule "utils/licensecheck"] + path = utils/licensecheck + url = https://github.com/msoos/licensecheck.git +[submodule "scripts/build_scripts"] + path = scripts/build_scripts + url = https://github.com/msoos/cryptominisat_build.git +[submodule "utils/minisat_only_elim_and_subsume"] + path = utils/minisat_only_elim_and_subsume + url = https://github.com/msoos/minisat + branch = only_elim_and_subsume +[submodule "tests/simp-checks/simplifiy_testfiles"] + path = tests/simp-checks/simplifiy_testfiles + url = https://github.com/msoos/simplifiy_testfiles +[submodule "minisat-fuzz"] + path = utils/minisat + url = https://github.com/msoos/minisat + branch = fuzzer +[submodule "tests/xor_cnf_tests"] + path = tests/xor_cnf_tests + url = https://github.com/msoos/xor_testfiles.git +[submodule "tests/pbsugar"] + path = tests/pbsugar + url = https://github.com/msoos/pbsugar +[submodule "utils/lingeling-ala"] + path = utils/lingeling-ala + url = https://github.com/msoos/lingeling-ala/ diff --git a/cryptominisat/cppsrc/AUTHORS b/cryptominisat/cppsrc/AUTHORS new file mode 100644 index 00000000..596dae62 --- /dev/null +++ b/cryptominisat/cppsrc/AUTHORS @@ -0,0 +1,49 @@ +Mate Soos +ysard (Pierre) from GitHub +Arijit Shaw +Martin Hořeňovský +Alexander Scheel +Marcel Bargull +Andres Notzli +Simon Felix +Julian Rüth +Martin Maurer +Vegard Nossum +Sami Liedes +Alex Odinayev +Martin Albrecht +Kuleep S. Meel +Jan Mazak +Finn Haedicke +Erik M. Bray +Davin Choo +Yevgeny Kazakov +Rui Chen +Robert Grosse +Martin Nowack +Jörg Thalheim +Gleb Popov +Dennis Yurichev +Dan Liew +Yuri Pirola +Sudhanshu Mishra +Storyyeller +Rion Snow +Reuven Peleg +Lars Schmertmann +David E. Narváez +Daniel Fremont +Curtis Bright +Marie Maurer +Brian Mastenbrook +Andrew V. Jones +Andrew Ross +Andrew Johnson +Shaowei Cai (CCANR solver) + +Acknowledgements: +The author would like to thank in no particular order Horst Samulowitz, +Marius T. Lindauer, Martin Maurer, Martin Albrecht, Vegard Nossum, +Valentin Mayer-Eichberger, George Katsirelos, Karsten Nohl, +Luca Melette, Marijn Heule, Vijay Ganesh, Trevor Hansen and Robert +Aston for their help. diff --git a/cryptominisat/cppsrc/CMakeLists.txt b/cryptominisat/cppsrc/CMakeLists.txt new file mode 100644 index 00000000..65c7deff --- /dev/null +++ b/cryptominisat/cppsrc/CMakeLists.txt @@ -0,0 +1,777 @@ +# Copyright (C) 2009-2020 Authors of CryptoMiniSat, see AUTHORS file +# +# Permission is hereby granted, free of charge, to any person obtaining a copy +# of this software and associated documentation files (the "Software"), to deal +# in the Software without restriction, including without limitation the rights +# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +# copies of the Software, and to permit persons to whom the Software is +# furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in +# all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +# THE SOFTWARE. + +cmake_minimum_required(VERSION 3.12 FATAL_ERROR) +set(CMAKE_C_STANDARD 99) +set(CMAKE_CXX_STANDARD 17) + +enable_language( CXX ) + +message(STATUS "LIB directory is '${CMAKE_INSTALL_LIBDIR}'") +message(STATUS "BIN directory is '${CMAKE_INSTALL_BINDIR}'") + +if(POLICY CMP0092) + # Disable passing /W3 by default on MSVC + cmake_policy(SET CMP0092 NEW) +endif() + +if(POLICY CMP0048) + #policy for VERSION in cmake 3.0 + cmake_policy(SET CMP0048 NEW) +endif() + + +if(POLICY CMP0022) + cmake_policy(SET CMP0022 NEW) +endif() + +if(POLICY CMP0046) + cmake_policy(SET CMP0046 NEW) +endif() + +if(POLICY CMP0026) + cmake_policy(SET CMP0026 NEW) +endif() + +if(POLICY CMP0104) + cmake_policy(SET CMP0104 NEW) +endif() + + +# ----------------------------------------------------------------------------- +# Provide scripts dir for included cmakes to use +# ----------------------------------------------------------------------------- +set(CRYPTOMS_SCRIPTS_DIR ${CMAKE_CURRENT_SOURCE_DIR}/scripts) + +include (GenerateExportHeader) +include (GNUInstallDirs) + +# ----------------------------------------------------------------------------- +# Make RelWithDebInfo the default build type if otherwise not set +# ----------------------------------------------------------------------------- +set(build_types Debug Release RelWithDebInfo MinSizeRel) +if(NOT CMAKE_BUILD_TYPE) + message(STATUS "You can choose the type of build, options are:${build_types}") + set(CMAKE_BUILD_TYPE RelWithDebInfo CACHE STRING + "Options are ${build_types}" + FORCE + ) + + # Provide drop down menu options in cmake-gui + set_property(CACHE CMAKE_BUILD_TYPE PROPERTY STRINGS ${build_types}) +endif() +message(STATUS "Doing a ${CMAKE_BUILD_TYPE} build") + +# ----------------------------------------------------------------------------- +# Option to enable/disable assertions +# ----------------------------------------------------------------------------- + +# Filter out definition of NDEBUG from the default build configuration flags. +# We will add this ourselves if we want to disable assertions +foreach (build_config ${build_types}) + string(TOUPPER ${build_config} upper_case_build_config) + foreach (language CXX C) + set(VAR_TO_MODIFY "CMAKE_${language}_FLAGS_${upper_case_build_config}") + string(REGEX REPLACE "(^| )[/-]D *NDEBUG($| )" + " " + replacement + "${${VAR_TO_MODIFY}}") + #message("Original (${VAR_TO_MODIFY}) is ${${VAR_TO_MODIFY}} replacement is ${replacement}") + set(${VAR_TO_MODIFY} "${replacement}" CACHE STRING "Default flags for ${build_config} configuration" FORCE) + endforeach() +endforeach() + +PROJECT(cryptominisat5) + +# contains some library search cmake scripts +SET(CMAKE_MODULE_PATH ${PROJECT_SOURCE_DIR}/cmake) + +# generate JSON file of compile commands -- useful for code extension +set(CMAKE_EXPORT_COMPILE_COMMANDS 1) + +# static compilation +option(BUILD_SHARED_LIBS "Build the shared library" ON) +option(STATICCOMPILE "Compile to static executable" OFF) +if (STATICCOMPILE) + set(BUILD_SHARED_LIBS OFF) +# if (IPASIR) +# if ( ${CMAKE_SYSTEM_NAME} MATCHES "Linux") +# set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -static -Wl,--whole-archive -ldl -lpthread -Wl,--no-whole-archive -static ") +# SET(CMAKE_FIND_LIBRARY_SUFFIXES ".a") +# add_compile_options( -static-libstdc++) +# endif() +# endif() +endif() + +option(GPU "Use GPU based setup" OFF) +if (GPU) + add_definitions( -DUSE_GPU ) + enable_language( CUDA ) +endif() + +option(NOTBUDDY "Disable the use of tbuddy, even if installed" OFF) +option(FORCETBUDDY "For the use of tbuddy" OFF) +if (NOT NOTBUDDY) + find_package(tbuddy CONFIG) + if (tbuddy_FOUND) + MESSAGE(STATUS "OK, found tbuddy: ${TBUDDY}") + add_definitions(-DUSE_TBUDDY) + else() + MESSAGE(STATUS "tbuddy not found, not compiling with tbuddy-based GJ FRAT proofs") + endif() +endif() + +if (FORCETBUDDY AND NOT tbuddy_FOUND) + MESSAGE(FATAL_ERROR "tbuddy was required but not found. Please install tbuddy.") +endif () + +option(EMSCRIPTEN "Generate only emscripten JS" OFF) +if (EMSCRIPTEN) + set(BUILD_SHARED_LIBS ON) + set(NOZLIB ON) +else() + set(THREADS_PREFER_PTHREAD_FLAG ON) + find_package (Threads REQUIRED) +endif() + +option(SANITIZE "Use Clang sanitizers. You MUST use clang++ as the compiler for this to work" OFF) +option(FEEDBACKFUZZ "Use Clang coverage sanitizers" OFF) +if (FEEDBACKFUZZ) + set(SANITIZE ON) +endif() + +option(LARGEMEM "Allow memory usage to grow to Terabyte values -- uses 64b offsets. Slower, but allows the solver to run for much longer." OFF) +if (LARGEMEM) + add_definitions(-DLARGE_OFFSETS) +endif() + +option(RDB0ONLY "Use only RDB0 features only" ON) +if (RDB0ONLY) + add_definitions(-DRDB0_ONLY_FEATURES) +endif() + +option(EXTFEAT "Use extended features" OFF) +if (EXTFEAT) + add_definitions(-DEXTENDED_FEATURES) +endif() + +macro(add_sanitize_option flagname) + SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${flagname}" ) +endmacro() + +include(CheckCXXCompilerFlag) +macro(add_cxx_flag_if_supported flagname) + check_cxx_compiler_flag("${flagname}" HAVE_FLAG_${flagname}) + + if(HAVE_FLAG_${flagname}) + SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${flagname}" ) + endif() +endmacro() + +include(CheckCCompilerFlag) +macro(add_c_flag_if_supported flagname) + check_c_compiler_flag("${flagname}" HAVE_FLAG_${flagname}) + + if(HAVE_FLAG_${flagname}) + SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${flagname}" ) + endif() +endmacro() + +macro(add_sanitize_flags) +if (SANITIZE) + MESSAGE(WARNING " --Using clang sanitizers -- you MUST use clang++ or the compile WILL fail") + SET( CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -lasan -lubsan " ) + SET( CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} -lasan -lubsan ") + add_compile_options("-fsanitize=address") + # below warns on overflows EVEN when that's OK, because it's well-defined, disabling + # add_compile_options("-fsanitize=integer") + add_compile_options("-fsanitize=undefined") + add_compile_options("-fsanitize=null") + add_compile_options("-fsanitize=alignment") + #add_compile_options("-fno-sanitize-recover") + add_compile_options("-fsanitize=return") + add_compile_options("-fsanitize=bounds") + add_compile_options("-fsanitize=float-divide-by-zero") + add_compile_options("-fsanitize=integer-divide-by-zero") + # add_compile_options("-fsanitize=unsigned-integer-overflow") + add_compile_options("-fsanitize=signed-integer-overflow") + add_compile_options("-fsanitize=bool") + add_compile_options("-fsanitize=enum") + add_compile_options("-fsanitize=float-cast-overflow") + add_compile_options("$<$:-D_GLIBCXX_ASSERTIONS>") +endif() +endmacro() + +option(ENABLE_ASSERTIONS "Build with assertions enabled" ON) +message(STATUS "build type is ${CMAKE_BUILD_TYPE}") +if(CMAKE_BUILD_TYPE STREQUAL "Release") + set(ENABLE_ASSERTIONS OFF) +endif() + +if (ENABLE_ASSERTIONS) + # NDEBUG was already removed. +else() + # Note this definition doesn't appear in the cache variables. + add_definitions(-DNDEBUG) + add_cxx_flag_if_supported("-fno-stack-protector") + add_definitions(-D_FORTIFY_SOURCE=0) +endif() + +# Note: O3 gives slight speed increase, 1 more solved from SAT Comp'14 @ 3600s +if (NOT MSVC) + add_compile_options( -g) + add_compile_options( -pthread ) + + #NOTE: out-satrace19-8373595 has confirmed that O3+flto only hurts compared to O2 + # on gcc version 7.3.0 + add_compile_options("$<$:-O2>") + + add_compile_options("$<$:-O2>") + add_compile_options("$<$:-g0>") + + add_compile_options("$<$:-O0>") + + if(NOT CMAKE_BUILD_TYPE STREQUAL "Debug") + set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} -O2") + set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -O2") + endif() + +else() + # see https://msdn.microsoft.com/en-us/library/fwkeyyhe.aspx for details + # /ZI = include debug info + # /Wall = all warnings + + add_compile_options("$<$:/O2>") + add_compile_options("$<$:/ZI>") + + add_compile_options("$<$:/O2>") + add_compile_options("$<$:/D>") + add_compile_options("$<$:/NDEBUG>") + + add_compile_options("$<$:/Od>") + + if (STATICCOMPILE) + # We statically link to reduce dependencies + foreach(flag_var CMAKE_CXX_FLAGS CMAKE_CXX_FLAGS_DEBUG CMAKE_CXX_FLAGS_RELEASE CMAKE_CXX_FLAGS_MINSIZEREL CMAKE_CXX_FLAGS_RELWITHDEBINFO) + # /MD -- Causes the application to use the multithread-specific + # and DLL-specific version of the run-time library. + # Defines _MT and _DLL and causes the compiler to place + # the library name MSVCRT.lib into the .obj file. + if(${flag_var} MATCHES "/MD") + string(REGEX REPLACE "/MD" "/MT" ${flag_var} "${${flag_var}}") + endif(${flag_var} MATCHES "/MD") + + # /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. + # It also causes the compiler to place the library name MSVCRTD.lib into the .obj file. + if(${flag_var} MATCHES "/MDd") + string(REGEX REPLACE "/MDd" "/MTd" ${flag_var} "${${flag_var}}") + endif(${flag_var} MATCHES "/MDd") + endforeach(flag_var) + + # Creates a multithreaded executable (static) file using LIBCMT.lib. + add_compile_options(/MT) + endif() + + # buffers security check + add_compile_options(/GS) + + # Proper warning level + add_compile_options(/W1) + + # Disable STL used in DLL-boundary warning + add_compile_options(/wd4251) + add_compile_options(/D_CRT_SECURE_NO_WARNINGS) + + # Wall is MSVC's Weverything, so annoying unless used from the start + # and with judiciously used warning disables + # add_compile_options(/Wall) + + # /Za = only ansi C98 & C++11 + # /Za is not recommended for use, not tested, etc. + # see: http://stackoverflow.com/questions/5489326/za-compiler-directive-does-not-compile-system-headers-in-vs2010 + # add_compile_options(/Za) + + add_compile_options(/fp:precise) + + # 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. + # 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. + add_compile_options(/EHsc) + + + # set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} /INCREMENTAL:NO") + # set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} /PDBCOMPRESS") + set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} /STACK:1572864") + + #what does this do? + set(DEF_INSTALL_CMAKE_DIR CMake) +endif() + +option(ENABLE_TESTING "Enable testing" OFF) +option(COVERAGE "Build with coverage check" OFF) + +if (COVERAGE AND BUILD_SHARED_LIBS) + MESSAGE(FATAL_ERROR "Coverage can only be computed on static compilation") +endif() + +if (NOT WIN32) + if(NOT ENABLE_TESTING AND ${CMAKE_SYSTEM_NAME} MATCHES "Linux" AND NOT COVERAGE) + add_cxx_flag_if_supported("-fvisibility=hidden") + endif() + add_compile_options("-fPIC") + #add_cxx_flag_if_supported("-mtune=native") + + if(CMAKE_BUILD_TYPE STREQUAL "Release") + #NOTE: out-satrace19-8373595 has confirmed that O3+flto only hurts compared to O2 + # on gcc version 7.3.0 + #add_cxx_flag_if_supported("-flto") + else() + add_cxx_flag_if_supported("-Wall") + add_cxx_flag_if_supported("-Wextra") + add_cxx_flag_if_supported("-Wunused") + add_cxx_flag_if_supported("-Wsign-compare") + if (NOT CMAKE_BUILD_TYPE STREQUAL "Release") + add_cxx_flag_if_supported("-fno-omit-frame-pointer") + endif() + add_cxx_flag_if_supported("-Wtype-limits") + add_cxx_flag_if_supported("-Wuninitialized") + add_cxx_flag_if_supported("-Wno-deprecated") + add_cxx_flag_if_supported("-Wstrict-aliasing") + add_cxx_flag_if_supported("-Wpointer-arith") + add_cxx_flag_if_supported("-Wheader-guard") + add_cxx_flag_if_supported("-Wpointer-arith") + add_cxx_flag_if_supported("-Wformat-nonliteral") + add_cxx_flag_if_supported("-Winit-self") + add_cxx_flag_if_supported("-Wparentheses") + add_cxx_flag_if_supported("-Wunreachable-code") + add_cxx_flag_if_supported("-g") + add_cxx_flag_if_supported("-Wno-class-memaccess") + add_cxx_flag_if_supported("-mpopcnt") + add_cxx_flag_if_supported("-msse4.2") + add_cxx_flag_if_supported("-Wextra-semi-stmt") + add_cxx_flag_if_supported("-Wnoweak-vtables") + add_cxx_flag_if_supported("-ggdb3") + + # Apparently needed before OS X Maverics (2013) + #add_c_flag_if_supported("-stdlib=libc++") + endif() +endif() + +if (COVERAGE) + add_compile_options("--coverage") + SET(CMAKE_EXE_LINKER_FLAGS "--coverage") +endif() + + +option(IPASIR "Also build IPASIR" OFF) + +option(LIMITMEM "*Only used for testing*. Limit memory used by CMS through number of variables" OFF) +if (LIMITMEM) + add_definitions(-DLIMITMEM) +endif() + +# ----------------------------------------------------------------------------- +# Uncomment these for static compilation under Linux (messes up Valgrind) +# ----------------------------------------------------------------------------- +if (${CMAKE_SYSTEM_NAME} MATCHES "Linux" AND NOT SANITIZE) + set(CMAKE_EXE_LINKER_FLAGS " ${CMAKE_EXE_LINKER_FLAGS} -Wl,--discard-all -Wl,--build-id=sha1") +endif() + +if ((${CMAKE_SYSTEM_NAME} MATCHES "Linux") OR (${CMAKE_SYSTEM_NAME} MATCHES "Darwin")) + if(NOT BUILD_SHARED_LIBS) + MESSAGE(STATUS "Compiling for static library use") + if (${CMAKE_SYSTEM_NAME} MATCHES "Linux") + set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -static -Wl,--whole-archive -ldl -lpthread -Wl,--no-whole-archive -static ") + endif() + + SET(CMAKE_FIND_LIBRARY_SUFFIXES ".a") + + # removing -rdynamic that's automatically added + foreach (language CXX C) + set(VAR_TO_MODIFY "CMAKE_SHARED_LIBRARY_LINK_${language}_FLAGS") + string(REGEX REPLACE "(^| )-rdynamic($| )" + " " + replacement + "${${VAR_TO_MODIFY}}") + #message("Original (${VAR_TO_MODIFY}) is ${${VAR_TO_MODIFY}} replacement is ${replacement}") + set(${VAR_TO_MODIFY} "${replacement}" CACHE STRING "Default flags for ${build_config} configuration" FORCE) + endforeach() + else() + MESSAGE(STATUS "Compiling for dynamic library use") + endif() +endif() + +if(NOT MSVC) + set(DEF_INSTALL_CMAKE_DIR lib/cmake/cryptominisat5) +endif() + +option(SLOW_DEBUG "Use more debug flags" OFF) +IF(SLOW_DEBUG) + add_definitions(-DSLOW_DEBUG) +endif() + +# ----------------------------------------------------------------------------- +# Add GIT version +# ----------------------------------------------------------------------------- +function(SetVersionNumber PREFIX VERSION_MAJOR VERSION_MINOR VERSION_PATCH) + set(${PREFIX}_VERSION_MAJOR ${VERSION_MAJOR} PARENT_SCOPE) + set(${PREFIX}_VERSION_MINOR ${VERSION_MINOR} PARENT_SCOPE) + set(${PREFIX}_VERSION_PATCH ${VERSION_PATCH} PARENT_SCOPE) + set(${PREFIX}_VERSION + "${VERSION_MAJOR}.${VERSION_MINOR}.${VERSION_PATCH}" + PARENT_SCOPE) +endfunction() + +find_program (GIT_EXECUTABLE git) +if (GIT_EXECUTABLE) + include(GetGitRevisionDescription) + get_git_head_revision(GIT_REFSPEC GIT_SHA1) + MESSAGE(STATUS "GIT hash found: ${GIT_SHA1}") +else() + set(GIT_SHA "GIT-hash-notfound") +endif() + +set(CMS_FULL_VERSION "5.11.21") + +string(REPLACE "." ";" CMS_FULL_VERSION_LIST ${CMS_FULL_VERSION}) +SetVersionNumber("PROJECT" ${CMS_FULL_VERSION_LIST}) +MESSAGE(STATUS "PROJECT_VERSION: ${PROJECT_VERSION}") +MESSAGE(STATUS "PROJECT_VERSION_MAJOR: ${PROJECT_VERSION_MAJOR}") +MESSAGE(STATUS "PROJECT_VERSION_MINOR: ${PROJECT_VERSION_MINOR}") +MESSAGE(STATUS "PROJECT_VERSION_PATCH: ${PROJECT_VERSION_PATCH}") + +option(FINAL_PREDICTOR "Use final predictor" OFF) +if (FINAL_PREDICTOR) + message(STATUS "You HAVE to build xgboost and LightGBM with 'cmake -DBUILD_STATIC_LIB=ON -DUSE_OPENMP=OFF ..' for static linking") + find_package(dmlc REQUIRED) + find_package(rabit REQUIRED) + find_package(xgboost REQUIRED) + find_library(lightgbm + NAMES _lightgbm lightgbm LightGBM + REQUIRED) + add_definitions( -DFINAL_PREDICTOR ) +endif() + +if (STATS) + find_package (SQLITE3 REQUIRED) + find_package(louvain_communities CONFIG REQUIRED) + MESSAGE(STATUS "OK, Found SQLITE3!") + include_directories(${SQLITE3_INCLUDE_DIR}) + add_definitions( -DUSE_SQLITE3 ) +endif() + +option(NORMAL_CL_USE_STATS "Only prop and uip stats for NORM" OFF) +if (NORMAL_CL_USE_STATS) + add_definitions( -DNORMAL_CL_USE_STATS ) + MESSAGE(STATUS "Adding uip + props to normal run") +endif() + +option(STATS "Don't use statistics at all" OFF) +if (STATS) + if (FINAL_PREDICTOR) + message(FATAL_ERROR "Cannot have stats and final predictor on both") + endif() + set(STATS_NEEDED ON) + add_definitions( -DSTATS_NEEDED ) + if (NOT SQLITE3_FOUND) + message(FATAL_ERROR "SQLite needed for STATS") + endif() +ELSE () + MESSAGE(STATUS "Not compiling detailed statistics. The system is faster without them") +ENDIF () + +if (STATS_NEEDED) + find_package(louvain_communities CONFIG) + if (louvain_communities_FOUND) + message(STATUS "Found Community Louvain library") + message(STATUS "Community Louvain dynamic lib: ${COMMLOUVAIN_LIBRARIES}") + message(STATUS "Community Louvain include dirs: ${COMMLOUVAIN_INCLUDE_DIRS}") + else() + message(STATUS "Cannot find Community Louvain. Please install it!") + if (STATS_NEEDED OR FINAL_PREDICTOR) + message(FATAL_ERROR "For STATS we must have louvain communities installed!") + endif() + endif() +endif() + +# ---------- +# manpage +# ---------- +if (${CMAKE_SYSTEM_NAME} MATCHES "Linux" AND NOT EMSCRIPTEN) + find_program(HELP2MAN_FOUND help2man) + if (HELP2MAN_FOUND) + ADD_CUSTOM_TARGET(man_cryptominisat5 + ALL + DEPENDS cryptominisat5-bin + ) + + ADD_CUSTOM_COMMAND( + TARGET man_cryptominisat5 + COMMAND help2man + ARGS --version-string=${CMS_FULL_VERSION} --help-option="-h" $ -o ${CMAKE_CURRENT_BINARY_DIR}/cryptominisat5.1 + ) + + INSTALL( + FILES ${CMAKE_CURRENT_BINARY_DIR}/cryptominisat5.1 + DESTINATION ${CMAKE_INSTALL_PREFIX}/share/man/man1) + + message(STATUS "Manpage will be created and installed") + else() + MESSAGE(STATUS "Cannot find help2man, not creating manpage") + endif() +else() + MESSAGE(STATUS "Not on Linux, not creating manpage") +endif() + +# ----------------------------------------------------------------------------- +# Look for ZLIB (For reading zipped CNFs) +# ----------------------------------------------------------------------------- +option(NOZLIB "Don't use zlib" OFF) + +# cannot currently compile static zlib under Windows +if (NOT NOZLIB AND NOT ((NOT BUILD_SHARED_LIBS) AND WIN32)) + find_package(ZLIB) + IF (ZLIB_FOUND) + MESSAGE(STATUS "OK, Found ZLIB!") + include_directories(${ZLIB_INCLUDE_DIR}) + link_directories(${ZLIB_LIB_DIR}) + add_definitions( -DUSE_ZLIB ) + ELSE (ZLIB_FOUND) + MESSAGE(STATUS "WARNING: Did not find ZLIB, gzipped file support will be disabled") + ENDIF (ZLIB_FOUND) +endif() + + +include(CheckFloatPrecision) +check_float_precision() +if (HAVE__FPU_SETCW) + add_definitions(-DYALSAT_FPU) + message(STATUS "Found FPU code for yalsat: fpu_control.h, _FPU_SINGLE, _FPU_DOUBLE") +endif() + +option(WEIGHTED_SAMPLING "Allow for weighted sampling" OFF) +if (WEIGHTED_SAMPLING) + add_definitions( -DWEIGHTED_SAMPLING ) +endif() + + +# ----------------------------------------------------------------------------- +# MIT option +# ----------------------------------------------------------------------------- +option(MIT "Build with only MIT licensed components" OFF) +# NOTE: everything is MIT, bosphorus is now disabled + +# ----------------------------------------------------------------------------- +# Look for BreakID +# ----------------------------------------------------------------------------- +option(NOBREAKID "Disable BreakID" ON) +option(NOMPI "Disable MPI" ON) +if (NOT NOMPI) + find_package(MPI) + if (MPI_FOUND) + add_definitions( -DUSE_MPI ) + set(NOBREAKID ON) + #set( CMAKE_CXX_COMPILER ${MPI_CXX_COMPILER} ) + else (MPI_FOUND) + MESSAGE(STATUS "No suitable C++ MPI implementation found. CryptoMiniSat will not be distributed.") + endif(MPI_FOUND) +endif() + +# ----------------------------------------------------------------------------- +# Look for BreakID +# ----------------------------------------------------------------------------- +if (NOT NOBREAKID) + find_package(breakid) + if (NOT BREAKID_LIBRARIES) + message(WARNING "BreakID NOT found") + else() + message(STATUS "BreakID -- found version ${BREAKID_VERSION_MAJOR}.${BREAKID_VERSION_MINOR}") + message(STATUS "BreakID -- libraries: ${BREAKID_LIBRARIES}") + message(STATUS "BreakID -- include dirs: ${BREAKID_INCLUDE_DIRS}") + add_definitions(-DUSE_BREAKID) + endif() +endif() + + +set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/lib) +set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/lib) + +macro(cmsat_add_public_header LIBTARGET HEADER) + get_target_property(EXISTING_PUBLIC_HEADERS ${LIBTARGET} PUBLIC_HEADER) + if(EXISTING_PUBLIC_HEADERS) + list(APPEND EXISTING_PUBLIC_HEADERS "${HEADER}") + else() + # Do not append to empty list + set(EXISTING_PUBLIC_HEADERS "${HEADER}") + endif() + set_target_properties( + ${LIBTARGET} + PROPERTIES + PUBLIC_HEADER "${EXISTING_PUBLIC_HEADERS}" + ) +endmacro() + +# ----------------------------------------------------------------------------- +# Look for MPI +# ----------------------------------------------------------------------------- +option(NOMPI "Disable MPI" ON) +if (NOT NOMPI) + find_package(MPI) + if (MPI_FOUND) + add_definitions( -DUSE_MPI ) + set(NOBREAKID ON) + #set( CMAKE_CXX_COMPILER ${MPI_CXX_COMPILER} ) + else (MPI_FOUND) + MESSAGE(STATUS "No suitable C++ MPI implementation found. CryptoMiniSat will not be distributed.") + endif(MPI_FOUND) +endif() + +if (FINAL_PREDICTOR OR STATS OR ENABLE_TESTING) + find_package(Python3 COMPONENTS NumPy Interpreter Development REQUIRED) + if (Python3_FOUND AND Python3_Interpreter_FOUND AND Python3_NumPy_FOUND) + message(STATUS "Python 3 -- Python3_EXECUTABLE=${Python3_EXECUTABLE}") + message(STATUS "Python 3 -- Python3_LIBRARIES=${Python3_LIBRARIES}") + message(STATUS "Python 3 -- Python3_INCLUDE_DIRS=${Python3_INCLUDE_DIRS}") + message(STATUS "Python 3 -- Python3_VERSION=${Python3_VERSION}") + message(STATUS "Python 3 -- Python3_NumPy_INCLUDE_DIRS=${Python3_NumPy_INCLUDE_DIRS}") + message(STATUS "Python 3 -- Python3_NumPy_VERSION=${Python3_NumPy_VERSION}") + endif() +endif() + +# ----------------------------------------------------------------------------- +# Provide an export name to be used by targets that wish to export themselves. +# ----------------------------------------------------------------------------- +set(CRYPTOMINISAT5_EXPORT_NAME "cryptominisat5Targets") + +#query definitions +get_directory_property( DirDefs DIRECTORY ${CMAKE_SOURCE_DIR} COMPILE_DEFINITIONS ) +set(COMPILE_DEFINES) +foreach( d ${DirDefs} ) + # message( STATUS "Found Define: " ${d} ) + set(COMPILE_DEFINES "${COMPILE_DEFINES} -D${d}") +endforeach() +message(STATUS "All defines at startup: ${COMPILE_DEFINES}") + +add_subdirectory(src cmsat5-src) + +# ----------------------------------------------------------------------------- +# Add uninstall target for makefiles +# ----------------------------------------------------------------------------- +configure_file( + "${CMAKE_CURRENT_SOURCE_DIR}/cmake/cmake_uninstall.cmake.in" + "${CMAKE_CURRENT_BINARY_DIR}/cmake_uninstall.cmake" + IMMEDIATE @ONLY +) + +add_custom_target(uninstall + COMMAND ${CMAKE_COMMAND} -P ${CMAKE_CURRENT_BINARY_DIR}/cmake_uninstall.cmake +) + +# ----------------------------------------------------------------------------- +# Testing +# ----------------------------------------------------------------------------- +if (ENABLE_TESTING) + enable_testing() + + #use valgrind + find_program(MEMORYCHECK_COMMAND valgrind) + if(MEMORYCHECK_COMMAND-NOTFOUND) + message(WARNING "Valgrind not found. Test will be run without valgrind.") + else() + message(STATUS "Valgrind found: ${MEMORYCHECK_COMMAND}. Running test using it.") + set(MEMORYCHECK_COMMAND_OPTIONS "--trace-children=yes --leak-check=full") + endif() + + # too unstable to add (depends on CPU) + #if (NOT STATS AND NOT SLOW_DEBUG) + #add_test (NAME library_speed_test COMMAND tests/library_speed_test) + #endif() + + message(STATUS "Testing is enabled") + set(UNIT_TEST_EXE_SUFFIX "Tests" CACHE STRING "Suffix for Unit test executable") + add_subdirectory(tests) + add_subdirectory(scripts/fuzz) + add_subdirectory(utils/minimal_cms) + add_subdirectory(utils/lingeling-ala) + +else() + message(WARNING "Testing is disabled") +endif() + +# ----------------------------------------------------------------------------- +# Export our targets so that other CMake based projects can interface with +# the build of cryptominisat5 in the build-tree +# ----------------------------------------------------------------------------- +set(CRYPTOMINISAT5_TARGETS_FILENAME "cryptominisat5Targets.cmake") +set(CRYPTOMINISAT5_CONFIG_FILENAME "cryptominisat5Config.cmake") +set(CRYPTOMINISAT5_VERSION_FILENAME "cryptominisat5ConfigVersion.cmake") +set(CRYPTOMINISAT5_STATIC_DEPS ${SQLITE3_LIBRARIES}) + +# Export targets +set(MY_TARGETS cryptominisat5) +if (IPASIR) + set(MY_TARGETS ${MY_TARGETS} ipasircryptominisat5) +endif() +export( + TARGETS ${MY_TARGETS} + FILE "${CMAKE_CURRENT_BINARY_DIR}/${CRYPTOMINISAT5_TARGETS_FILENAME}" +) + +# Create cryptominisat5Config file +set(EXPORT_TYPE "Build-tree") +set(CONF_INCLUDE_DIRS "${CMAKE_CURRENT_BINARY_DIR}/include") +configure_file(cryptominisat5Config.cmake.in + "${CMAKE_CURRENT_BINARY_DIR}/${CRYPTOMINISAT5_CONFIG_FILENAME}" @ONLY +) + +# Export this package to the CMake user package registry +# Now the user can just use find_package(cryptominisat5) on their system +export(PACKAGE cryptominisat5) + +set(DEF_INSTALL_CMAKE_DIR lib/cmake/cryptominisat5) +set(CRYPTOMINISAT5_INSTALL_CMAKE_DIR ${DEF_INSTALL_CMAKE_DIR} CACHE PATH + "Installation directory for cryptominisat5 CMake files") + +# Create cryptominisat5Config file +set(EXPORT_TYPE "installed") +set(CONF_INCLUDE_DIRS "${CMAKE_INSTALL_PREFIX}/include") +configure_file(cryptominisat5Config.cmake.in + "${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_FILES_DIRECTORY}/${CRYPTOMINISAT5_CONFIG_FILENAME}" @ONLY +) + +include(CMakePackageConfigHelpers) +write_basic_package_version_file( + "${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_FILES_DIRECTORY}/${CRYPTOMINISAT5_VERSION_FILENAME}" + COMPATIBILITY SameMajorVersion) + +install(FILES + "${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_FILES_DIRECTORY}/${CRYPTOMINISAT5_VERSION_FILENAME}" + DESTINATION "${CRYPTOMINISAT5_INSTALL_CMAKE_DIR}" +) + +install(FILES + "${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_FILES_DIRECTORY}/${CRYPTOMINISAT5_CONFIG_FILENAME}" + DESTINATION "${CRYPTOMINISAT5_INSTALL_CMAKE_DIR}" +) + +# Install the export set for use with the install-tree +install( + EXPORT ${CRYPTOMINISAT5_EXPORT_NAME} + DESTINATION "${CRYPTOMINISAT5_INSTALL_CMAKE_DIR}" +) diff --git a/cryptominisat/cppsrc/Dockerfile b/cryptominisat/cppsrc/Dockerfile new file mode 100644 index 00000000..6297afaf --- /dev/null +++ b/cryptominisat/cppsrc/Dockerfile @@ -0,0 +1,48 @@ +FROM ubuntu:16.04 as builder + +LABEL maintainer="Mate Soos" +LABEL version="5.0" +LABEL Description="An advanced SAT solver" + +# get curl, etc +RUN apt-get update && apt-get install --no-install-recommends -y software-properties-common && rm -rf /var/lib/apt/lists/* +RUN add-apt-repository -y ppa:ubuntu-toolchain-r/test && rm -rf /var/lib/apt/lists/* +RUN apt-get update && apt-get install --no-install-recommends -y libboost-program-options-dev gcc g++ make cmake zlib1g-dev wget && rm -rf /var/lib/apt/lists/* + +# set up build env +RUN groupadd -r solver -g 433 +RUN useradd -u 431 -r -g solver -d /home/solver -s /sbin/nologin -c "Docker image user" solver +RUN mkdir -p /home/solver/cms +RUN chown -R solver:solver /home/solver + +# build CMS +USER root +COPY . /home/solver/cms +WORKDIR /home/solver/cms +RUN mkdir build +WORKDIR /home/solver/cms/build +RUN cmake -DSTATICCOMPILE=ON .. \ + && make -j6 \ + && make install \ + && rm -rf * + +# set up for running +FROM alpine:latest +COPY --from=builder /usr/local/bin/cryptominisat5 /usr/local/bin/ +ENTRYPOINT ["/usr/local/bin/cryptominisat5"] + +# -------------------- +# HOW TO USE +# -------------------- +# on file through STDIN: +# zcat mizh-md5-47-3.cnf.gz | docker run --rm -i -a stdin -a stdout cms + +# on a file: +# docker run --rm -v `pwd`/myfile.cnf.gz:/in cms in + +# echo through STDIN: +# echo "1 2 0" | docker run --rm -i -a stdin -a stdout cms + +# hand-written CNF: +# docker run --rm -ti -a stdin -a stdout cms + diff --git a/cryptominisat/cppsrc/LICENSE.txt b/cryptominisat/cppsrc/LICENSE.txt new file mode 100644 index 00000000..47f5872a --- /dev/null +++ b/cryptominisat/cppsrc/LICENSE.txt @@ -0,0 +1,57 @@ +Copyright (C) 2009-2020 Authors of CryptoMiniSat, see AUTHORS file +All rights reserved. + +The general priciple of the licensing is as follows. Everything that's +needed to run/build/install/link the system is MIT licensed. This allows +easy distribution and running of the system everywhere. Files that +have no copyright header are also MIT licensed. Note that in case you +compile with Bliss, then Bliss's GPL license affects the final executable +and library. + +Everything else that's not needed to run/build/install/link is usually GPLv2 +licensed or compatible (see the copyright headers.) The only exceptions are the +following files in docs/: +* `splncs03.bat` which is under the LPPL +* `ieee.cls` which is covered by the IEEE Copyright Policy + + +MIT License +=================== + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + + + +GPL License v2 +=================== + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; version 2 +of the License. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301, USA. diff --git a/cryptominisat/cppsrc/MANIFEST.in b/cryptominisat/cppsrc/MANIFEST.in new file mode 100644 index 00000000..9a6ffa7e --- /dev/null +++ b/cryptominisat/cppsrc/MANIFEST.in @@ -0,0 +1,7 @@ +global-exclude *.json +global-exclude *.timeout +global-exclude *.in +global-exclude *.txt +recursive-include src/ *.h *.hpp +recursive-include src/picosat/ *.h *.hpp +recursive-include src/oracle/ *.h *.hpp diff --git a/cryptominisat/cppsrc/README.markdown b/cryptominisat/cppsrc/README.markdown new file mode 100644 index 00000000..c466a319 --- /dev/null +++ b/cryptominisat/cppsrc/README.markdown @@ -0,0 +1,492 @@ +[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT) +[![Windows build](https://ci.appveyor.com/api/projects/status/8d000iy63xu7eau5?svg=true)](https://ci.appveyor.com/project/msoos/cryptominisat) +![build](https://github.com/msoos/cryptominisat/workflows/build/badge.svg) + + +CryptoMiniSat SAT solver +=========================================== + +This system provides CryptoMiniSat, an advanced incremental SAT solver. The system has 3 +interfaces: command-line, C++ library and python. The command-line interface +takes a [cnf](http://en.wikipedia.org/wiki/Conjunctive_normal_form) as an +input in the [DIMACS](http://www.satcompetition.org/2009/format-benchmarks2009.html) +format with the extension of XOR clauses. The C++ and python interface mimics this and also +allows for incremental use: assumptions and multiple `solve` calls. +A C compatible wrapper is also provided. + +When citing, always reference our [SAT 2009 conference paper](https://link.springer.com/chapter/10.1007%2F978-3-642-02777-2_24), bibtex record is [here](http://dblp.uni-trier.de/rec/bibtex/conf/sat/SoosNC09). + +License +----- + +Everything that is needed to build by default is MIT licensed. If you specifically instruct the system it can build with Bliss, which are both GPL. However, by default CryptoMiniSat will not build with these. + + +Compiling in Linux +----- + +To build and install, issue: + +``` +sudo apt-get install build-essential cmake +# not required but very useful +sudo apt-get install zlib1g-dev +tar xzvf cryptominisat-version.tar.gz +cd cryptominisat-version +mkdir build && cd build +cmake .. +make +sudo make install +sudo ldconfig +``` + +Compiling in Mac OSX +----- + +First, you must get Homebrew from https://brew.sh/ then: + +``` +brew install cmake +tar xzvf cryptominisat-version.tar.gz +cd cryptominisat-version +mkdir build && cd build +cmake .. +make +sudo make install +``` + +Compiling in Windows +----- + +``` +C:\> [ download and unzip cryptominisat-version.zip ] +C:\> cd cryptominisat +C:\cryptominisat> mkdir build +C:\cryptominisat> cd build +C:\cryptominisat\build> cmake -G "Visual Studio 17 2022" -DCMAKE_BUILD_TYPE=Release -DSTATICCOMPILE=ON .. +C:\cryptominisat\build> cmake --build --config Release . +``` + +You now have the static binary under `C:\cryptominisat\build\Release\cryptominisat5.exe` + +Command-line usage +----- + +Let's take the file: +``` +p cnf 3 3 +1 0 +-2 0 +-1 2 3 0 +``` + +The file has 3 variables and 3 clauses, this is reflected in the header +`p cnf 3 3` which gives the number of variables as the first number and the number of clauses as the second. +Every clause is ended by '0'. The clauses say: 1 must be True, 2 +must be False, and either 1 has to be False, 2 has to be True or 3 has to be +True. The only solution to this problem is: +``` +cryptominisat5 --verb 0 file.cnf +s SATISFIABLE +v 1 -2 3 0 +``` + +Which means, that setting variable 1 True, variable 2 False and variable 3 True satisfies the set of constraints (clauses) in the CNF. If the file had contained: +``` +p cnf 3 4 +1 0 +-2 0 +-3 0 +-1 2 3 0 +``` + +Then there is no solution and the solver returns `s UNSATISFIABLE`. + +Incremental Python Usage +----- +The python module works with both Python 3. Just execute: + +``` +pip3 install pycryptosat +``` + +You can then use it in incremental mode as: + +``` +>>> from pycryptosat import Solver +>>> s = Solver() +>>> s.add_clause([1]) +>>> s.add_clause([-2]) +>>> s.add_clause([-1, 2, 3]) +>>> sat, solution = s.solve() +>>> print sat +True +>>> print solution +(None, True, False, True) +>>> sat, solution = s.solve([-3]) +>> print sat +False +>>> sat, solution = s.solve() +>>> print sat +True +>>> s.add_clause([-3]) +>>> sat, solution = s.solve() +>>> print sat +False +``` + +We can also try to assume any variable values for a single solver run: +``` +>>> sat, solution = s.solve([-3]) +>>> print sat +False +>>> print solution +None +>>> sat, solution = s.solve() +>>> print sat +True +>>> print solution +(None, True, False, True) +``` +If you want to build the python module, you can do this: + +``` +sudo apt-get install build-essential +sudo apt-get install python3-setuptools python3-dev +git clone https://github.com/msoos/cryptominisat +python -m build +pip install dist/pycryptosat-*.whl +``` + +Incremental Library Usage +----- +The library uses a variable numbering scheme that starts from 0. Since 0 cannot +be negated, the class `Lit` is used as: `Lit(variable_number, is_negated)`. As +such, the 1st CNF above would become: + +``` +#include +#include +#include +using std::vector; +using namespace CMSat; + +int main() +{ + SATSolver solver; + vector clause; + + //Let's use 4 threads + solver.set_num_threads(4); + + //We need 3 variables. They will be: 0,1,2 + //Variable numbers are always trivially increasing + solver.new_vars(3); + + //add "1 0" + clause.push_back(Lit(0, false)); + solver.add_clause(clause); + + //add "-2 0" + clause.clear(); + clause.push_back(Lit(1, true)); + solver.add_clause(clause); + + //add "-1 2 3 0" + clause.clear(); + clause.push_back(Lit(0, true)); + clause.push_back(Lit(1, false)); + clause.push_back(Lit(2, false)); + solver.add_clause(clause); + + lbool ret = solver.solve(); + assert(ret == l_True); + std::cout + << "Solution is: " + << solver.get_model()[0] + << ", " << solver.get_model()[1] + << ", " << solver.get_model()[2] + << std::endl; + + //assumes 3 = FALSE, no solutions left + vector assumptions; + assumptions.push_back(Lit(2, true)); + ret = solver.solve(&assumptions); + assert(ret == l_False); + + //without assumptions we still have a solution + ret = solver.solve(); + assert(ret == l_True); + + //add "-3 0" + //No solutions left, UNSATISFIABLE returned + clause.clear(); + clause.push_back(Lit(2, true)); + solver.add_clause(clause); + ret = solver.solve(); + assert(ret == l_False); + + return 0; +} +``` + +The library usage also allows for assumptions. We can add these lines just +before the `return 0;` above: +``` +vector assumptions; +assumptions.push_back(Lit(2, true)); +lbool ret = solver.solve(&assumptions); +assert(ret == l_False); + +lbool ret = solver.solve(); +assert(ret == l_True); +``` + +Since we assume that variable 2 must be false, there is no solution. However, +if we solve again, without the assumption, we get back the original solution. +Assumptions allow us to assume certain literal values for a _specific run_ but +not all runs -- for all runs, we can simply add these assumptions as 1-long +clauses. + +Multiple solutions +----- + +To find multiple solutions to your problem, just run the solver in a loop +and ban the previous solution found: + +``` +while(true) { + lbool ret = solver->solve(); + if (ret != l_True) { + assert(ret == l_False); + //All solutions found. + exit(0); + } + + //Use solution here. print it, for example. + + //Banning found solution + vector ban_solution; + for (uint32_t var = 0; var < solver->nVars(); var++) { + if (solver->get_model()[var] != l_Undef) { + ban_solution.push_back( + Lit(var, (solver->get_model()[var] == l_True)? true : false)); + } + } + solver->add_clause(ban_solution); +} +``` + +The above loop will run as long as there are solutions. It is __highly__ +suggested to __only__ add into the new clause(`bad_solutions` above) the +variables that are "important" or "main" to your problem. Variables that were +only used to translate the original problem into CNF should not be added. +This way, you will not get spurious solutions that don't differ in the main, +important variables. + +Rust bindings +----- + +To build the Rust bindings: + +``` +git clone https://github.com/msoos/cryptominisat-rs/ +cd cryptominisat-rs +cargo build --release +cargo test +``` + +You can use it as per the [README](https://github.com/msoos/cryptominisat-rs/blob/master/README.markdown) in that repository. To include CryptoMiniSat in your Rust project, add the dependency to your `Cargo.toml` file: + +``` +cryptominisat = { git = "https://github.com/msoos/cryptominisat-rs", branch= "master" } +``` + +You can see an example project using CryptoMiniSat in Rust [here](https://github.com/msoos/caqe/). + +Preprocessing +----- +If you wish to use CryptoMiniSat as a preprocessor, we encourage you +to try out our model counting preprocessing framework +(Arjun)[https://www.github.com/meelgroup/arjun]. Arjun was conceived to +minimize input formulas for model counting, but it can also be used for +non-model-counting purposes. However, it cannot produce a solution to the +original CNF given a solution to the simplified CNF. This current limitation +will eventually be lifted for Arjun. + +Please see the README of Arjun for more details. The basic usage of Arjun is: +`./arjun --renumber 0 original.cnf simplified.cnf` + +Gauss-Jordan elimination +----- +Since CryptoMiniSat 5.8, Gauss-Jordan elimination is compiled into the solver by default. However, it will turn off automatically in case the solver observes GJ not to perform too well. To use Gaussian elimination, provide a CNF with xors in it (either in CNF or XOR+CNF form) and either run with default setup, or, tune it to your heart's desire: + +``` +Gauss options: + --iterreduce arg (=1) Reduce iteratively the matrix that is updated.We + effectively are moving the start to the last + column updated + --maxmatrixrows arg (=3000) Set maximum no. of rows for gaussian matrix. Too + large matrixes should be discarded for reasons of + efficiency + --autodisablegauss arg (=1) Automatically disable gauss when performing badly + --minmatrixrows arg (=5) Set minimum no. of rows for gaussian matrix. + Normally, too small matrixes are discarded for + reasons of efficiency + --savematrix arg (=2) Save matrix every Nth decision level + --maxnummatrixes arg (=3) Maximum number of matrixes to treat. +``` + +In particular, you may want to set `--autodisablegauss 0` in case you are sure it'll help. + +Testing +----- +For testing you will need the GIT checkout and build as per: + +``` +sudo apt-get install build-essential cmake git +sudo apt-get install zlib1g-dev libboost-program-options-dev libsqlite3-dev +sudo apt-get install git python3-pip python3-setuptools python3-dev +sudo pip3 install --upgrade pip +sudo pip3 install lit +git clone https://github.com/msoos/cryptominisat.git +cd cryptominisat +git submodule update --init +mkdir build && cd build +cmake -DENABLE_TESTING=ON .. +make -j4 +make test +sudo make install +sudo ldconfig +``` + +Fuzzing +----- +Build for test as per above, then: + +``` +cd ../cryptominisat/scripts/fuzz/ +./fuzz_test.py +``` + + +CrystalBall +----- + +Build and use instructions below. Please see the [associated blog post](https://www.msoos.org/2019/06/crystalball-sat-solving-data-gathering-and-machine-learning/) for more information. + +``` +# prerequisites on a modern Debian/Ubuntu installation +sudo apt-get install build-essential cmake git +sudo apt-get install zlib1g-dev libsqlite3-dev +sudo apt-get install libboost-program-options-dev libboost-serialization-dev +sudo apt-get install python3-pip +sudo pip3 install sklearn pandas numpy lit matplotlib + +# build and install Louvain Communities +git clone https://github.com/meelgroup/louvain-community +cd louvain-community +mkdir build && cd build +cmake .. +make -j10 +sudo make install +cd ../.. + +# build and install XGBoost +git clone https://github.com/dmlc/xgboost +cd xgboost +mkdir build && cd build +cmake .. +make -j10 +sudo make install +cd ../.. + +# build and install LightGBM +git clone https://github.com/microsoft/LightGBM +cd LightGBM +mkdir build && cd build +cmake .. +make -j10 +sudo make install +cd ../.. + +# getting the code +git clone https://github.com/msoos/cryptominisat +cd cryptominisat +git checkout crystalball +git submodule update --init +mkdir build && cd build +ln -s ../scripts/crystal/* . +ln -s ../scripts/build_scripts/* . + +# Let's get an unsatisfiable CNF +wget https://www.msoos.org/largefiles/goldb-heqc-i10mul.cnf.gz +gunzip goldb-heqc-i10mul.cnf.gz + +# Gather the data, denormalize, label, +# create the classifier, generate C++, +# and build the final SAT solver +./ballofcrystal.sh goldb-heqc-i10mul.cnf +[...compilations and the full data pipeline...] + +# let's use our newly built tool +./cryptominisat5 goldb-heqc-i10mul.cnf +[ ... ] +s UNSATISFIABLE + +# Let's look at the data +cd goldb-heqc-i10mul.cnf-dir +sqlite3 mydata.db +sqlite> select count() from sum_cl_use; +94507 +``` + +Configuring a build for a minimal binary&library +----- +The following configures the system to build a bare minimal binary&library. It needs a compiler, but nothing much else: + +``` +cmake -DONLY_SIMPLE=ON -DNOZLIB=ON -DSTATS=OFF -DENABLE_TESTING=OFF . +``` + +CMake Arguments +----- +The following arguments to cmake configure the generated build artifacts. To use, specify options prior to running make in a clean subdirectory: `cmake ..` + +- `-DSTATICCOMPILE=` -- statically linked library and binary. You must build&link `BreakID` with the same `DSTATICCOMPILE=` setting as well. You can get the BreakID library from [our GitHub repository](https://github.com/meelgroup/breakid) +- `-DSTATS=` -- advanced statistics (slower). Needs [louvain communities](https://github.com/meelgroup/louvain-community) installed. +- `-DENABLE_TESTING=` -- test suite support +- `-DMIT=` -- MIT licensed components only +- `-DNOMPI=` -- without MPI support +- `-DNOZLIB=` -- no gzip DIMACS input support +- `-DONLY_SIMPLE=` -- only the simple binary is built +- `-DLARGEMEM=` -- more memory available for clauses (but slower on most problems) +- `-DIPASIR=` -- Build `libipasircryptominisat.so` for [IPASIR](https://www.cs.utexas.edu/users/moore/acl2/manuals/current/manual/index-seo.php/IPASIR____IPASIR) interface support + +Getting learnt clauses +----- +As an experimental feature, you can get the learnt clauses from the system with the following code, where `lits` is filled with learnt clauses every time `get_next_small_clause` is called. The example below will eventually return all clauses of size 4 or less. You can call `end_getting_small_clauses` at any time. + +``` +SATSolver s; +//fill the solver, run solve, etc. + +//Get all clauses of size 4 or less + +s->start_getting_small_clauses(4); + +vector lits; +bool ret = true; +while (ret) { + bool ret = s->get_next_small_clause(lits); + if (ret) { + //deal with clause in "lits" + add_to_my_db(lits); + } +} +s->end_getting_small_clauses(); +``` + +C usage +----- +See src/cryptominisat_c.h.in for details. This is an experimental feature. diff --git a/cryptominisat/cppsrc/cmake/AddGTestSuite.cmake b/cryptominisat/cppsrc/cmake/AddGTestSuite.cmake new file mode 100644 index 00000000..0dbe1ec0 --- /dev/null +++ b/cryptominisat/cppsrc/cmake/AddGTestSuite.cmake @@ -0,0 +1,26 @@ +# Sets for the current directory (and below) the testsuite to use. +# This macro should be used with the AddSTPGTest function. +macro(AddGTestSuite TESTSUITENAME) + set(TESTSUITE "${TESTSUITENAME}") # Unit test group name + # Setup custom target + add_custom_target(${TESTSUITE}) + add_dependencies(check ${TESTSUITE}) + + if(USE_VALGRIND) + set(LIT_EXTRA_FLAGS --vg --vg-leak) + else() + set(LIT_EXTRA_FLAGS "") + endif() + + add_custom_command(TARGET ${TESTSUITE} + POST_BUILD + COMMAND ${LIT_TOOL} ${LIT_ARGS} ${LIT_EXTRA_FLAGS} ${CMAKE_CURRENT_BINARY_DIR} + COMMENT "Running ${TESTSUITE}" + ) + + # Setup lit configuration + configure_file(${CMAKE_SOURCE_DIR}/tests/lit-unit-tests-common.site.cfg.in + ${CMAKE_CURRENT_BINARY_DIR}/lit.site.cfg + @ONLY@ + ) +endmacro() diff --git a/cryptominisat/cppsrc/cmake/AddSTPGTest.cmake b/cryptominisat/cppsrc/cmake/AddSTPGTest.cmake new file mode 100644 index 00000000..25dc7401 --- /dev/null +++ b/cryptominisat/cppsrc/cmake/AddSTPGTest.cmake @@ -0,0 +1,33 @@ +# AddSTPGTest( [ ...]) +# +# Adds a GoogleTest to the current test suite (${TESTSUITE}) +# with executable name with the file extension removed and +# the UNIT_TEST_EXE_SUFFIX appended. +# The executable will be linked with libstp. +# Remaining arguments to this function are interpreted as preprocessor macros +# to defines. +# +# e.g. +# AddSTPGTest(mysimpleprogram.cpp FOO=15 BAR=\"a string\") +# +function(AddSTPGTest sourcefile) + get_filename_component(testname ${sourcefile} NAME_WE) + + # testname has suffix because lit expects this + set(testname "${testname}${UNIT_TEST_EXE_SUFFIX}") + + add_executable(${testname} EXCLUDE_FROM_ALL ${sourcefile}) + + # Add define flags requested by users + list(LENGTH ARGN LEN_ARGN) + if(LEN_ARGN GREATER 0) + set_property(TARGET ${testname} APPEND PROPERTY COMPILE_DEFINITIONS ${ARGN}) + #message(STATUS "Added flags to test ${testname} ${ARGN}") + endif() + + target_link_libraries(${testname} libstp ${GTEST_BOTH_LIBRARIES}) + + # Add dependency so that building the testsuite + # will cause this test (testname) to be built + add_dependencies(${TESTSUITE} ${testname}) +endfunction() diff --git a/cryptominisat/cppsrc/cmake/CheckFloatPrecision.cmake b/cryptominisat/cppsrc/cmake/CheckFloatPrecision.cmake new file mode 100644 index 00000000..6e8e3d58 --- /dev/null +++ b/cryptominisat/cppsrc/cmake/CheckFloatPrecision.cmake @@ -0,0 +1,51 @@ +# Floating point precision checks +# +# This file contains floating point precision checks +# +# This file is released under public domain - or - in countries where this is +# not possible under the following license: +# +# Permission is hereby granted, free of charge, to any person obtaining a +# copy of this software, to deal in the software without restriction, +# including without limitation the rights to use, copy, modify, merge, +# publish, distribute, sublicense, and/or sell copies of the software, +# and to permit persons to whom the software is furnished to do so, subject +# to no condition whatsoever. +# +# This software is provided AS IS, without warranty of any kind, express or +# implied. + +# FIXME: +# This file was only built for x86 and x86_64 platforms but it does not check +# for the platform since CMake does not provide a viable variable. + +include(CheckCSourceRuns) + +macro(check_float_precision) + check_c_source_runs(" + #include + #include + #include + + double div (double a, double b) { + fpu_control_t fpu_oldcw, fpu_cw; + volatile double result; + + _FPU_GETCW(fpu_oldcw); + fpu_cw = (fpu_oldcw & ~_FPU_EXTENDED & ~_FPU_SINGLE) | _FPU_DOUBLE; + _FPU_SETCW(fpu_cw); + result = a / b; + _FPU_SETCW(fpu_oldcw); + return result; + } + + int main (int argc, char **argv) { + double d = div (2877.0, 1000000.0); + char buf[255]; + sprintf(buf, \"%.30f\", d); + // see if the result is actually in double precision + return strncmp(buf, \"0.00287699\", 10) == 0 ? 0 : 1; + } + " HAVE__FPU_SETCW) + +endmacro(check_float_precision) diff --git a/cryptominisat/cppsrc/cmake/FindPerftools.cmake b/cryptominisat/cppsrc/cmake/FindPerftools.cmake new file mode 100644 index 00000000..f40ace7c --- /dev/null +++ b/cryptominisat/cppsrc/cmake/FindPerftools.cmake @@ -0,0 +1,139 @@ +# - Try to find Google perftools include dirs and libraries +# +# Usage of this module as follows: +# +# find_package(Perftools) +# +# Variables used by this module, they can change the default behaviour and need +# to be set before calling find_package: +# +# PERFTOOLS_ROOT Preferred installation prefix for searching for +# Perftools, set this if the module has problems +# finding the proper installation path. +# PERFTOOLS_INCLUDEDIR Set this to the include directory of the Google +# perftools, if the module has problems finding the +# installation path. +# PERFTOOLS_LIBRARYDIR Set this to the library directory of the Google +# perftools if the module has problems finding the +# proper installation path. +# +# Variables defined by this module: +# +# Perftools_FOUND System has Google perftools, this means the +# include dir and all the libraries were found. +# Perftools_INCLUDE_DIRS Google perftools include directories. +# Perftools_LIBRARIES Link these to use the Google perftools libraries. +# +# Perftools_TCMALLOC_LIBRARY Path to the tcmalloc library. +# Perftools_STACKTRACE_LIBRARY Path to the stacktrace library. +# Perftools_PROFILER_LIBRARY Path to the profiler library. + +if (PERFTOOLS_ROOT) + set(Perftools_ADDITIONAL_INCLUDE_SEARCH_DIRS ${PERFTOOLS_ROOT}/include) + set(Perftools_ADDITIONAL_LIBRARY_SEARCH_DIRS ${PERFTOOLS_ROOT}/lib) +endif () + +if (PERFTOOLS_INCLUDEDIR) + set(Perftools_ADDITIONAL_INCLUDE_SEARCH_DIRS ${PERFTOOLS_ROOT}/include) +endif () + +if (PERFTOOLS_LIBRARYDIR) + set(Perftools_ADDITIONAL_LIBRARY_SEARCH_DIRS ${PERFTOOLS_ROOT}/lib) +endif () + + +if (Perftools_LIBRARIES AND Perftools_INCLUDE_DIRS) + # In cache already. + set(Perftools_FOUND true) +else () + find_path(Perftools_INCLUDE_DIRS + NAMES + google/heap-profiler.h + PATHS + ${Perftools_ADDITIONAL_INCLUDE_SEARCH_DIRS} + /usr/local/include + /opt/local/include + /sw/include + /usr/include + ) + + # tcmalloc + set(tcmalloc_names ${tcmalloc_names} tcmalloc) + find_library(perftools_tcmalloc_library + NAMES + ${tcmalloc_names} + PATHS + ${Perftools_ADDITIONAL_LIBRARY_SEARCH_DIRS} + /usr/local/lib + /opt/local/lib + /sw/lib + /usr/lib + ) + + if (perftools_tcmalloc_library AND Perftools_INCLUDE_DIRS) + set(Perftools_TCMALLOC_LIBRARY ${perftools_tcmalloc_library}) + set(Perftools_LIBRARIES + ${Perftools_LIBRARIES} ${perftools_tcmalloc_library}) + set(Perftools_FOUND true) + else () + set(Perftools_FOUND false) + endif () + + + # stacktrace + set(stacktrace_names ${stacktrace_names} stacktrace) + find_library(perftools_stacktrace_library + NAMES + ${stacktrace_names} + PATHS + ${Perftools_ADDITIONAL_LIBRARY_SEARCH_DIRS} + /usr/local/lib + /opt/local/lib + /sw/lib + /usr/lib + ) + + if (perftools_stacktrace_library AND Perftools_INCLUDE_DIRS) + set(Perftools_STACKTRACE_LIBRARY ${perftools_stacktrace_library}) + set(Perftools_LIBRARIES + ${Perftools_LIBRARIES} ${perftools_stacktrace_library}) + endif () + + + # profiler + set(profiler_names ${profiler_names} profiler) + find_library(perftools_profiler_library + NAMES + ${profiler_names} + PATHS + ${Perftools_ADDITIONAL_LIBRARY_SEARCH_DIRS} + /usr/local/lib + /opt/local/lib + /sw/lib + /usr/lib + ) + + if (perftools_profiler_library AND Perftools_INCLUDE_DIRS) + set(Perftools_PROFILER_LIBRARY ${perftools_profiler_library}) + set(Perftools_LIBRARIES + ${Perftools_LIBRARIES} ${perftools_profiler_library}) + endif () + + if (Perftools_FOUND) + if (NOT Perftools_FIND_QUIETLY) + message(STATUS "Found Google perftools") + endif () + else () + if (Perftools_FIND_REQUIRED) + message(FATAL_ERROR "Could not find Google perftools") + endif () + endif () + + mark_as_advanced( + Perftools_INCLUDE_DIRS + Perftools_LIBRARIES + Perftools_TCMALLOC_LIBRARY + Perftools_STACKTRACE_LIBRARY + Perftools_PROFILER_LIBRARY + ) +endif() diff --git a/cryptominisat/cppsrc/cmake/FindPkgMacros.cmake b/cryptominisat/cppsrc/cmake/FindPkgMacros.cmake new file mode 100644 index 00000000..59686232 --- /dev/null +++ b/cryptominisat/cppsrc/cmake/FindPkgMacros.cmake @@ -0,0 +1,163 @@ +#------------------------------------------------------------------- +# This file is part of the CMake build system for OGRE +# (Object-oriented Graphics Rendering Engine) +# For the latest info, see http://www.ogre3d.org/ +# +# The contents of this file are placed in the public domain. Feel +# free to make use of it in any way you like. +#------------------------------------------------------------------- + +################################################################## +# Provides some common functionality for the FindPackage modules +################################################################## + +# Begin processing of package +macro(findpkg_begin PREFIX) + if (NOT ${PREFIX}_FIND_QUIETLY) + message(STATUS "Looking for ${PREFIX}...") + endif () +endmacro(findpkg_begin) + +# Display a status message unless FIND_QUIETLY is set +macro(pkg_message PREFIX) + if (NOT ${PREFIX}_FIND_QUIETLY) + message(STATUS ${ARGN}) + endif () +endmacro(pkg_message) + +# Get environment variable, define it as ENV_$var and make sure backslashes are converted to forward slashes +macro(getenv_path VAR) + set(ENV_${VAR} $ENV{${VAR}}) + # replace won't work if var is blank + if (ENV_${VAR}) + string( REGEX REPLACE "\\\\" "/" ENV_${VAR} ${ENV_${VAR}} ) + endif () +endmacro(getenv_path) + +# Construct search paths for includes and libraries from a PREFIX_PATH +macro(create_search_paths PREFIX) + foreach(dir ${${PREFIX}_PREFIX_PATH}) + set(${PREFIX}_INC_SEARCH_PATH ${${PREFIX}_INC_SEARCH_PATH} + ${dir}/include ${dir}/Include ${dir}/include/${PREFIX} ${dir}/Headers) + set(${PREFIX}_LIB_SEARCH_PATH ${${PREFIX}_LIB_SEARCH_PATH} + ${dir}/lib ${dir}/Lib ${dir}/lib/${PREFIX} ${dir}/Libs) + set(${PREFIX}_BIN_SEARCH_PATH ${${PREFIX}_BIN_SEARCH_PATH} + ${dir}/bin) + endforeach(dir) + if(ANDROID) + set(${PREFIX}_LIB_SEARCH_PATH ${${PREFIX}_LIB_SEARCH_PATH} ${OGRE_DEPENDENCIES_DIR}/lib/${ANDROID_ABI}) + endif() + set(${PREFIX}_FRAMEWORK_SEARCH_PATH ${${PREFIX}_PREFIX_PATH}) +endmacro(create_search_paths) + +# clear cache variables if a certain variable changed +macro(clear_if_changed TESTVAR) + # test against internal check variable + # HACK: Apparently, adding a variable to the cache cleans up the list + # a bit. We need to also remove any empty strings from the list, but + # at the same time ensure that we are actually dealing with a list. + list(APPEND ${TESTVAR} "") + list(REMOVE_ITEM ${TESTVAR} "") + if (NOT "${${TESTVAR}}" STREQUAL "${${TESTVAR}_INT_CHECK}") + message(STATUS "${TESTVAR} changed.") + foreach(var ${ARGN}) + set(${var} "NOTFOUND" CACHE STRING "x" FORCE) + endforeach(var) + endif () + set(${TESTVAR}_INT_CHECK ${${TESTVAR}} CACHE INTERNAL "x" FORCE) +endmacro(clear_if_changed) + +# Try to get some hints from pkg-config, if available +macro(use_pkgconfig PREFIX PKGNAME) + find_package(PkgConfig) + if (PKG_CONFIG_FOUND) + pkg_check_modules(${PREFIX} ${PKGNAME}) + endif () +endmacro (use_pkgconfig) + +# Couple a set of release AND debug libraries (or frameworks) +macro(make_library_set PREFIX) + if (${PREFIX}_FWK) + set(${PREFIX} ${${PREFIX}_FWK}) + elseif (${PREFIX}_REL AND ${PREFIX}_DBG) + set(${PREFIX} optimized ${${PREFIX}_REL} debug ${${PREFIX}_DBG}) + elseif (${PREFIX}_REL) + set(${PREFIX} ${${PREFIX}_REL}) + elseif (${PREFIX}_DBG) + set(${PREFIX} ${${PREFIX}_DBG}) + endif () +endmacro(make_library_set) + +# Generate debug names from given release names +macro(get_debug_names PREFIX) + foreach(i ${${PREFIX}}) + set(${PREFIX}_DBG ${${PREFIX}_DBG} ${i}d ${i}D ${i}_d ${i}_D ${i}_debug ${i}) + endforeach(i) +endmacro(get_debug_names) + +# Add the parent dir from DIR to VAR +macro(add_parent_dir VAR DIR) + get_filename_component(${DIR}_TEMP "${${DIR}}/.." ABSOLUTE) + set(${VAR} ${${VAR}} ${${DIR}_TEMP}) +endmacro(add_parent_dir) + +# Do the final processing for the package find. +macro(findpkg_finish PREFIX) + # skip if already processed during this run + if (NOT ${PREFIX}_FOUND) + if (${PREFIX}_INCLUDE_DIR AND ${PREFIX}_LIBRARY) + set(${PREFIX}_FOUND TRUE) + set(${PREFIX}_INCLUDE_DIRS ${${PREFIX}_INCLUDE_DIR}) + set(${PREFIX}_LIBRARIES ${${PREFIX}_LIBRARY}) + if (NOT ${PREFIX}_FIND_QUIETLY) + message(STATUS "Found ${PREFIX}: ${${PREFIX}_LIBRARIES}") + endif () + else () + if (NOT ${PREFIX}_FIND_QUIETLY) + message(STATUS "Could not locate ${PREFIX}") + endif () + if (${PREFIX}_FIND_REQUIRED) + message(FATAL_ERROR "Required library ${PREFIX} not found! Install the library (including dev packages) and try again. If the library is already installed, set the missing variables manually in cmake.") + endif () + endif () + + mark_as_advanced(${PREFIX}_INCLUDE_DIR ${PREFIX}_LIBRARY ${PREFIX}_LIBRARY_REL ${PREFIX}_LIBRARY_DBG ${PREFIX}_LIBRARY_FWK) + endif () +endmacro(findpkg_finish) + + +# Slightly customised framework finder +macro(findpkg_framework fwk) + if(APPLE) + set(${fwk}_FRAMEWORK_PATH + ${${fwk}_FRAMEWORK_SEARCH_PATH} + ${CMAKE_FRAMEWORK_PATH} + ~/Library/Frameworks + /Library/Frameworks + /System/Library/Frameworks + /Network/Library/Frameworks + ${CMAKE_CURRENT_SOURCE_DIR}/lib/macosx/Release + ${CMAKE_CURRENT_SOURCE_DIR}/lib/macosx/Debug + ) + # These could be arrays of paths, add each individually to the search paths + foreach(i ${OGRE_PREFIX_PATH}) + set(${fwk}_FRAMEWORK_PATH ${${fwk}_FRAMEWORK_PATH} ${i}/lib/macosx/Release ${i}/lib/macosx/Debug) + endforeach(i) + + foreach(i ${OGRE_PREFIX_BUILD}) + set(${fwk}_FRAMEWORK_PATH ${${fwk}_FRAMEWORK_PATH} ${i}/lib/macosx/Release ${i}/lib/macosx/Debug) + endforeach(i) + + foreach(dir ${${fwk}_FRAMEWORK_PATH}) + set(fwkpath ${dir}/${fwk}.framework) + if(EXISTS ${fwkpath}) + set(${fwk}_FRAMEWORK_INCLUDES ${${fwk}_FRAMEWORK_INCLUDES} + ${fwkpath}/Headers ${fwkpath}/PrivateHeaders) + set(${fwk}_FRAMEWORK_PATH ${dir}) + if (NOT ${fwk}_LIBRARY_FWK) + set(${fwk}_LIBRARY_FWK "-framework ${fwk}") + endif () + endif(EXISTS ${fwkpath}) + endforeach(dir) + endif(APPLE) +endmacro(findpkg_framework) diff --git a/cryptominisat/cppsrc/cmake/FindSQLITE3.cmake b/cryptominisat/cppsrc/cmake/FindSQLITE3.cmake new file mode 100644 index 00000000..096de79e --- /dev/null +++ b/cryptominisat/cppsrc/cmake/FindSQLITE3.cmake @@ -0,0 +1,31 @@ +# Copyright (C) 2007-2009 LuaDist. +# Created by Peter Kapec +# Redistribution and use of this file is allowed according to the terms of the MIT license. + +# - Find sqlite3 +# Find the native SQLITE3 headers and libraries. +# +# SQLITE3_INCLUDE_DIRS - where to find sqlite3.h, etc. +# SQLITE3_LIBRARIES - List of libraries when using sqlite. +# SQLITE3_FOUND - True if sqlite found. + +# Look for the header file. +FIND_PATH(SQLITE3_INCLUDE_DIR NAMES sqlite3.h) + +# Look for the library. +FIND_LIBRARY(SQLITE3_LIBRARY NAMES sqlite3) + +# Handle the QUIETLY and REQUIRED arguments and set SQLITE3_FOUND to TRUE if all listed variables are TRUE. +INCLUDE(FindPackageHandleStandardArgs) +FIND_PACKAGE_HANDLE_STANDARD_ARGS(SQLITE3 DEFAULT_MSG SQLITE3_LIBRARY SQLITE3_INCLUDE_DIR) + +# Copy the results to the output variables. +IF(SQLITE3_FOUND) + SET(SQLITE3_LIBRARIES ${SQLITE3_LIBRARY}) + SET(SQLITE3_INCLUDE_DIRS ${SQLITE3_INCLUDE_DIR}) +ELSE(SQLITE3_FOUND) + SET(SQLITE3_LIBRARIES) + SET(SQLITE3_INCLUDE_DIRS) +ENDIF(SQLITE3_FOUND) + +MARK_AS_ADVANCED(SQLITE3_INCLUDE_DIRS SQLITE3_LIBRARIES) diff --git a/cryptominisat/cppsrc/cmake/FindTBB.cmake b/cryptominisat/cppsrc/cmake/FindTBB.cmake new file mode 100644 index 00000000..beb7f7b8 --- /dev/null +++ b/cryptominisat/cppsrc/cmake/FindTBB.cmake @@ -0,0 +1,111 @@ +#------------------------------------------------------------------- +# This file is part of the CMake build system for OGRE +# (Object-oriented Graphics Rendering Engine) +# For the latest info, see http://www.ogre3d.org/ +# +# The contents of this file are placed in the public domain. Feel +# free to make use of it in any way you like. +#------------------------------------------------------------------- + +# - Try to find ThreadingBuildingBlocks libraries +# Once done, this will define +# +# TBB_FOUND - system has TBB +# TBB_INCLUDE_DIRS - the TBB include directories +# TBB_LIBRARIES - link these to use TBB + +include(FindPkgMacros) +findpkg_begin(TBB) + +# Get path, convert backslashes as ${ENV_${var}} +getenv_path(TBB_HOME) +getenv_path(TBB_ROOT) +getenv_path(TBB_BASE) + +# construct search paths +set(TBB_PREFIX_PATH + ${TBB_HOME} ${ENV_TBB_HOME} + ${TBB_ROOT} ${ENV_TBB_ROOT} + ${TBB_BASE} ${ENV_TBB_BASE} +) +# redo search if prefix path changed +clear_if_changed(TBB_PREFIX_PATH + TBB_LIBRARY_FWK + TBB_LIBRARY_REL + TBB_LIBRARY_DBG + TBB_INCLUDE_DIR +) + +create_search_paths(TBB) +set(TBB_INC_SEARCH_PATH ${TBB_INC_SEARCH_PATH} ${TBB_PREFIX_PATH}) + +# For Windows, let's assume that the user might be using the precompiled +# TBB packages from the main website. These use a rather awkward directory +# structure (at least for automatically finding the right files) depending +# on platform and compiler, but we'll do our best to accomodate it. +# Not adding the same effort for the precompiled linux builds, though. Those +# have different versions for CC compiler versions and linux kernels which +# will never adequately match the user's setup, so there is no feasible way +# to detect the "best" version to use. The user will have to manually +# select the right files. (Chances are the distributions are shipping their +# custom version of tbb, anyway, so the problem is probably nonexistant.) +if (WIN32) + set(COMPILER_PREFIX "vc7.1") + if (MSVC80) + set(COMPILER_PREFIX "vc8") + endif () + if (MSVC90) + set(COMPILER_PREFIX "vc9") + endif () + + # for each prefix path, add ia32/64\${COMPILER_PREFIX}\lib to the lib search path + foreach (dir ${TBB_PREFIX_PATH}) + if (CMAKE_CL_64) + list(APPEND TBB_LIB_SEARCH_PATH ${dir}/ia64/${COMPILER_PREFIX}/lib) + list(APPEND TBB_LIB_SEARCH_PATH ${dir}/intel64/${COMPILER_PREFIX}/lib) + else () + list(APPEND TBB_LIB_SEARCH_PATH ${dir}/ia32/${COMPILER_PREFIX}/lib) + endif () + endforeach () +endif () + + + +set(TBB_LIBRARY_NAMES tbb) +get_debug_names(TBB_LIBRARY_NAMES) + +# use_pkgconfig(TBB_PKGC TBB) + +findpkg_framework(TBB) + +find_path(TBB_INCLUDE_DIR NAMES tbb/tbb.h HINTS ${TBB_INC_SEARCH_PATH} ${TBB_PKGC_INCLUDE_DIRS}) +find_library(TBB_LIBRARY_REL NAMES ${TBB_LIBRARY_NAMES} HINTS ${TBB_LIB_SEARCH_PATH} ${TBB_PKGC_LIBRARY_DIRS}) +find_library(TBB_LIBRARY_DBG NAMES ${TBB_LIBRARY_NAMES_DBG} HINTS ${TBB_LIB_SEARCH_PATH} ${TBB_PKGC_LIBRARY_DIRS}) +make_library_set(TBB_LIBRARY) + +findpkg_finish(TBB) + +if (NOT TBB_FOUND) + return() +endif () + + +# Look for TBB's malloc package +findpkg_begin(TBB_MALLOC) +set(TBB_MALLOC_LIBRARY_NAMES tbbmalloc) +get_debug_names(TBB_MALLOC_LIBRARY_NAMES) +find_path(TBB_MALLOC_INCLUDE_DIR NAMES tbb/tbb.h HINTS ${TBB_INCLUDE_DIR} ${TBB_INC_SEARCH_PATH} ${TBB_PKGC_INCLUDE_DIRS} ) +find_library(TBB_MALLOC_LIBRARY_REL NAMES ${TBB_MALLOC_LIBRARY_NAMES} HINTS ${TBB_LIB_SEARCH_PATH} ${TBB_PKGC_LIBRARY_DIRS} ) +find_library(TBB_MALLOC_LIBRARY_DBG NAMES ${TBB_MALLOC_LIBRARY_NAMES_DBG} HINTS ${TBB_LIB_SEARCH_PATH} ${TBB_PKGC_LIBRARY_DIRS} ) +make_library_set(TBB_MALLOC_LIBRARY) +findpkg_finish(TBB_MALLOC) + +# Look for TBB's malloc proxy package +findpkg_begin(TBB_MALLOC_PROXY) +set(TBB_MALLOC_PROXY_LIBRARY_NAMES tbbmalloc_proxy) +get_debug_names(TBB_MALLOC_PROXY_LIBRARY_NAMES) +find_path(TBB_MALLOC_PROXY_INCLUDE_DIR NAMES tbb/tbbmalloc_proxy.h HINTS ${TBB_INCLUDE_DIR} ${TBB_INC_SEARCH_PATH} ${TBB_PKGC_INCLUDE_DIRS}) +find_library(TBB_MALLOC_PROXY_LIBRARY_REL NAMES ${TBB_MALLOC_PROXY_LIBRARY_NAMES} HINTS ${TBB_LIB_SEARCH_PATH} ${TBB_PKGC_LIBRARY_DIRS}) +find_library(TBB_MALLOC_PROXY_LIBRARY_DBG NAMES ${TBB_MALLOC_PROXY_LIBRARY_NAMES_DBG} HINTS ${TBB_LIB_SEARCH_PATH} ${TBB_PKGC_LIBRARY_DIRS}) +make_library_set(TBB_MALLOC_PROXY_LIBRARY) +findpkg_finish(TBB_MALLOC_PROXY) diff --git a/cryptominisat/cppsrc/cmake/FindValgrind.cmake b/cryptominisat/cppsrc/cmake/FindValgrind.cmake new file mode 100644 index 00000000..cafc0116 --- /dev/null +++ b/cryptominisat/cppsrc/cmake/FindValgrind.cmake @@ -0,0 +1,22 @@ +# Find Valgrind. +# +# This module defines: +# VALGRIND_INCLUDE_DIR, where to find valgrind/memcheck.h, etc. +# VALGRIND_PROGRAM, the valgrind executable. +# VALGRIND_FOUND, If false, do not try to use valgrind. +# +# If you have valgrind installed in a non-standard place, you can define +# VALGRIND_PREFIX to tell cmake where it is. + +message(STATUS "Valgrind Prefix: ${VALGRIND_PREFIX}") + +find_path(VALGRIND_INCLUDE_DIR memcheck.h + /usr/include /usr/include/valgrind /usr/local/include /usr/local/include/valgrind + ${VALGRIND_PREFIX}/include ${VALGRIND_PREFIX}/include/valgrind) +find_program(VALGRIND_PROGRAM NAMES valgrind PATH /usr/bin /usr/local/bin ${VALGRIND_PREFIX}/bin) + +find_package_handle_standard_args(VALGRIND DEFAULT_MSG + VALGRIND_INCLUDE_DIR + VALGRIND_PROGRAM) + +mark_as_advanced(VALGRIND_INCLUDE_DIR VALGRIND_PROGRAM) diff --git a/cryptominisat/cppsrc/cmake/Findcargo.cmake b/cryptominisat/cppsrc/cmake/Findcargo.cmake new file mode 100644 index 00000000..766b6072 --- /dev/null +++ b/cryptominisat/cppsrc/cmake/Findcargo.cmake @@ -0,0 +1,25 @@ +# Copyright (c) 2014 SiegeLord -- Pavel Sountsov +# +# This software is provided 'as-is', without any express or implied +# warranty. In no event will the authors be held liable for any damages +# arising from the use of this software. +# +# Permission is granted to anyone to use this software for any purpose, +# including commercial applications, and to alter it and redistribute it +# freely, subject to the following restrictions: +# +# 1. The origin of this software must not be misrepresented; you must not +# claim that you wrote the original software. If you use this software +# in a product, an acknowledgment in the product documentation would be +# appreciated but is not required. +# +# 2. Altered source versions must be plainly marked as such, and must not be +# misrepresented as being the original software. +# +# 3. This notice may not be removed or altered from any source +# distribution. + +find_program(CARGO_EXECUTABLE cargo) +include(FindPackageHandleStandardArgs) +find_package_handle_standard_args(cargo DEFAULT_MSG CARGO_EXECUTABLE) +mark_as_advanced(CARGO_EXECUTABLE) diff --git a/cryptominisat/cppsrc/cmake/Findrustc.cmake b/cryptominisat/cppsrc/cmake/Findrustc.cmake new file mode 100644 index 00000000..affc8427 --- /dev/null +++ b/cryptominisat/cppsrc/cmake/Findrustc.cmake @@ -0,0 +1,33 @@ +# Copyright (c) 2014 SiegeLord -- Pavel Sountsov +# +# This software is provided 'as-is', without any express or implied +# warranty. In no event will the authors be held liable for any damages +# arising from the use of this software. +# +# Permission is granted to anyone to use this software for any purpose, +# including commercial applications, and to alter it and redistribute it +# freely, subject to the following restrictions: +# +# 1. The origin of this software must not be misrepresented; you must not +# claim that you wrote the original software. If you use this software +# in a product, an acknowledgment in the product documentation would be +# appreciated but is not required. +# +# 2. Altered source versions must be plainly marked as such, and must not be +# misrepresented as being the original software. +# +# 3. This notice may not be removed or altered from any source +# distribution. + +find_program(RUSTC_EXECUTABLE rustc) +include(FindPackageHandleStandardArgs) +find_package_handle_standard_args(rustc DEFAULT_MSG RUSTC_EXECUTABLE) +mark_as_advanced(RUSTC_EXECUTABLE) + +execute_process(COMMAND ${RUSTC_EXECUTABLE} -Vv + OUTPUT_VARIABLE RUSTC_TARGET_TRIPLE + OUTPUT_STRIP_TRAILING_WHITESPACE) +string(REGEX MATCH "host:[ \t](.*)\n" RUSTC_TARGET_TRIPLE "${RUSTC_TARGET_TRIPLE}") +string(REGEX REPLACE "host:[ \t](.*)\n" "\\1" RUSTC_TARGET_TRIPLE "${RUSTC_TARGET_TRIPLE}") +set(RUSTC_TARGET_TRIPLE "${RUSTC_TARGET_TRIPLE}" CACHE STRING "Target triple you can pass to rustc (not passed by default)") +mark_as_advanced(RUSTC_TARGET_TRIPLE) diff --git a/cryptominisat/cppsrc/cmake/Findrustdoc.cmake b/cryptominisat/cppsrc/cmake/Findrustdoc.cmake new file mode 100644 index 00000000..8323f250 --- /dev/null +++ b/cryptominisat/cppsrc/cmake/Findrustdoc.cmake @@ -0,0 +1,25 @@ +# Copyright (c) 2014 SiegeLord -- Pavel Sountsov +# +# This software is provided 'as-is', without any express or implied +# warranty. In no event will the authors be held liable for any damages +# arising from the use of this software. +# +# Permission is granted to anyone to use this software for any purpose, +# including commercial applications, and to alter it and redistribute it +# freely, subject to the following restrictions: +# +# 1. The origin of this software must not be misrepresented; you must not +# claim that you wrote the original software. If you use this software +# in a product, an acknowledgment in the product documentation would be +# appreciated but is not required. +# +# 2. Altered source versions must be plainly marked as such, and must not be +# misrepresented as being the original software. +# +# 3. This notice may not be removed or altered from any source +# distribution. + +find_program(RUSTDOC_EXECUTABLE rustdoc) +include(FindPackageHandleStandardArgs) +find_package_handle_standard_args(rustdoc DEFAULT_MSG RUSTDOC_EXECUTABLE) +mark_as_advanced(RUSTDOC_EXECUTABLE) diff --git a/cryptominisat/cppsrc/cmake/GetGitRevisionDescription.cmake b/cryptominisat/cppsrc/cmake/GetGitRevisionDescription.cmake new file mode 100644 index 00000000..2fb24584 --- /dev/null +++ b/cryptominisat/cppsrc/cmake/GetGitRevisionDescription.cmake @@ -0,0 +1,116 @@ +# - Returns a version string from Git +# +# These functions force a re-configure on each git commit so that you can +# trust the values of the variables in your build system. +# +# get_git_head_revision( [ ...]) +# +# Returns the refspec and sha hash of the current head revision +# +# git_describe( [ ...]) +# +# Returns the results of git describe on the source tree, and adjusting +# the output so that it tests false if an error occurs. +# +# git_get_exact_tag( [ ...]) +# +# Returns the results of git describe --exact-match on the source tree, +# and adjusting the output so that it tests false if there was no exact +# matching tag. +# +# Requires CMake 2.6 or newer (uses the 'function' command) +# +# Original Author: +# 2009-2010 Ryan Pavlik +# http://academic.cleardefinition.com +# Iowa State University HCI Graduate Program/VRAC +# +# Copyright Iowa State University 2009-2010. +# Distributed under the Boost Software License, Version 1.0. +# (See accompanying file LICENSE_1_0.txt or copy at +# http://www.boost.org/LICENSE_1_0.txt) + +if(__get_git_revision_description) + return() +endif() +set(__get_git_revision_description YES) + +# We must run the following at "include" time, not at function call time, +# to find the path to this module rather than the path to a calling list file +get_filename_component(_gitdescmoddir ${CMAKE_CURRENT_LIST_FILE} PATH) + +function(get_git_head_revision _refspecvar _hashvar) + set(GIT_PARENT_DIR "${CMAKE_SOURCE_DIR}") + set(GIT_DIR "${GIT_PARENT_DIR}/.git") + while(NOT EXISTS "${GIT_DIR}") # .git dir not found, search parent directories + set(GIT_PREVIOUS_PARENT "${GIT_PARENT_DIR}") + get_filename_component(GIT_PARENT_DIR ${GIT_PARENT_DIR} PATH) + if(GIT_PARENT_DIR STREQUAL GIT_PREVIOUS_PARENT) + # We have reached the root directory, we are not in git + set(${_refspecvar} "GIT-notfound" PARENT_SCOPE) + set(${_hashvar} "GIT-notfound" PARENT_SCOPE) + return() + endif() + set(GIT_DIR "${GIT_PARENT_DIR}/.git") + endwhile() + set(GIT_DATA "${CMAKE_CURRENT_BINARY_DIR}/CMakeFiles/git-data") + if(NOT EXISTS "${GIT_DATA}") + file(MAKE_DIRECTORY "${GIT_DATA}") + endif() + + if(NOT EXISTS "${GIT_DIR}/HEAD") + return() + endif() + set(HEAD_FILE "${GIT_DATA}/HEAD") + configure_file("${GIT_DIR}/HEAD" "${HEAD_FILE}" COPYONLY) + + configure_file("${_gitdescmoddir}/GetGitRevisionDescription.cmake.in" + "${GIT_DATA}/grabRef.cmake" + @ONLY) + include("${GIT_DATA}/grabRef.cmake") + + set(${_refspecvar} "${HEAD_REF}" PARENT_SCOPE) + set(${_hashvar} "${HEAD_HASH}" PARENT_SCOPE) +endfunction() + +function(git_describe _var) + if(NOT GIT_FOUND) + find_package(Git QUIET) + endif() + get_git_head_revision(refspec hash) + if(NOT GIT_FOUND) + set(${_var} "${CPACK_PACKAGE_VERSION}-compiled-from-cmake" PARENT_SCOPE) + return() + endif() + if(NOT hash) + set(${_var} "${CPACK_PACKAGE_VERSION}-compiled-from-cmake" PARENT_SCOPE) + return() + endif() + + # TODO sanitize + #if((${ARGN}" MATCHES "&&") OR + # (ARGN MATCHES "||") OR + # (ARGN MATCHES "\\;")) + # message("Please report the following error to the project!") + # message(FATAL_ERROR "Looks like someone's doing something nefarious with git_describe! Passed arguments ${ARGN}") + #endif() + + #message(STATUS "Arguments to execute_process: ${ARGN}") + + execute_process(COMMAND "${GIT_EXECUTABLE}" describe ${hash} ${ARGN} + WORKING_DIRECTORY "${CMAKE_SOURCE_DIR}" + RESULT_VARIABLE res + OUTPUT_VARIABLE out + #ERROR_QUIET + OUTPUT_STRIP_TRAILING_WHITESPACE) + if(NOT res EQUAL 0) + set(out "${CPACK_PACKAGE_VERSION} (approximate version number)") + endif() + + set(${_var} "${out}" PARENT_SCOPE) +endfunction() + +function(git_get_exact_tag _var) + git_describe(out --exact-match ${ARGN}) + set(${_var} "${out}" PARENT_SCOPE) +endfunction() diff --git a/cryptominisat/cppsrc/cmake/GetGitRevisionDescription.cmake.in b/cryptominisat/cppsrc/cmake/GetGitRevisionDescription.cmake.in new file mode 100644 index 00000000..888ce13a --- /dev/null +++ b/cryptominisat/cppsrc/cmake/GetGitRevisionDescription.cmake.in @@ -0,0 +1,38 @@ +# +# Internal file for GetGitRevisionDescription.cmake +# +# Requires CMake 2.6 or newer (uses the 'function' command) +# +# Original Author: +# 2009-2010 Ryan Pavlik +# http://academic.cleardefinition.com +# Iowa State University HCI Graduate Program/VRAC +# +# Copyright Iowa State University 2009-2010. +# Distributed under the Boost Software License, Version 1.0. +# (See accompanying file LICENSE_1_0.txt or copy at +# http://www.boost.org/LICENSE_1_0.txt) + +set(HEAD_HASH) + +file(READ "@HEAD_FILE@" HEAD_CONTENTS LIMIT 1024) + +string(STRIP "${HEAD_CONTENTS}" HEAD_CONTENTS) +if(HEAD_CONTENTS MATCHES "ref") + # named branch + string(REPLACE "ref: " "" HEAD_REF "${HEAD_CONTENTS}") + if(EXISTS "@GIT_DIR@/${HEAD_REF}") + configure_file("@GIT_DIR@/${HEAD_REF}" "@GIT_DATA@/head-ref" COPYONLY) + elseif(EXISTS "@GIT_DIR@/logs/${HEAD_REF}") + configure_file("@GIT_DIR@/logs/${HEAD_REF}" "@GIT_DATA@/head-ref" COPYONLY) + set(HEAD_HASH "${HEAD_REF}") + endif() +else() + # detached HEAD + configure_file("@GIT_DIR@/HEAD" "@GIT_DATA@/head-ref" COPYONLY) +endif() + +if(NOT HEAD_HASH) + file(READ "@GIT_DATA@/head-ref" HEAD_HASH LIMIT 1024) + string(STRIP "${HEAD_HASH}" HEAD_HASH) +endif() diff --git a/cryptominisat/cppsrc/cmake/Rust.cmake b/cryptominisat/cppsrc/cmake/Rust.cmake new file mode 100644 index 00000000..6eb0c695 --- /dev/null +++ b/cryptominisat/cppsrc/cmake/Rust.cmake @@ -0,0 +1,354 @@ +# Copyright (c) 2014 SiegeLord -- Pavel Sountsov +# +# This software is provided 'as-is', without any express or implied +# warranty. In no event will the authors be held liable for any damages +# arising from the use of this software. +# +# Permission is granted to anyone to use this software for any purpose, +# including commercial applications, and to alter it and redistribute it +# freely, subject to the following restrictions: +# +# 1. The origin of this software must not be misrepresented; you must not +# claim that you wrote the original software. If you use this software +# in a product, an acknowledgment in the product documentation would be +# appreciated but is not required. +# +# 2. Altered source versions must be plainly marked as such, and must not be +# misrepresented as being the original software. +# +# 3. This notice may not be removed or altered from any source +# distribution. + +# Defines a few macros, variables and a function to help with compiling Rust +# programs/libraries and documentation with CMake. +# +# This file utilizes several global variables: +# +# RUSTC_EXECUTABLE - Filename of the rustc executable. You can fill it in using the Findrustc package. +# RUSTDOC_EXECUTABLE - Filename of the rustc executable. You can fill it in using the Findrustdoc package. +# RUSTC_FLAGS - These get passed to rustc. +# RUSTDOC_FLAGS - These flags get passed to rustdoc. + +include(CMakeParseArguments) + +if(NOT RUSTC_FLAGS) + set(RUSTC_FLAGS "" CACHE STRING "Flags to pass to the Rust compiler.") +endif() +mark_as_advanced(RUSTC_FLAGS) + +if(NOT RUSTDOC_FLAGS) + set(RUSTDOC_FLAGS "" CACHE STRING "Flags to pass to Rustdoc.") +endif() +mark_as_advanced(RUSTDOC_FLAGS) + +# Fetches the dependencies of a Rust crate with local crate root located at +# local_root_file and places them into out_var. Optionally also builds the crate. +# +# Optional arguments: +# OTHER_RUSTC_FLAGS flags - Other flags to pass to rustc. +# DESTINATION destination - If compiling, where to place the compilation artifacts. +# COMPILE - Whether or not to produce artifacts (it won't by default). +# NOTE! This will force the compillation of this crate every time the +# project is reconfigured, so use with care! +# +# NOTE: Only the first target's dependencies are fetched! +function(get_rust_deps local_root_file out_var) + cmake_parse_arguments("OPT" "COMPILE" "DESTINATION" "OTHER_RUSTC_FLAGS" ${ARGN}) + + set(root_file "${CMAKE_CURRENT_SOURCE_DIR}/${local_root_file}") + + set(dep_dir "${CMAKE_CURRENT_BINARY_DIR}/CMakeFiles/.cmake_rust_dependencies") + file(MAKE_DIRECTORY "${dep_dir}") + + if(OPT_COMPILE) + file(MAKE_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/${OPT_DESTINATION}") + set(flags --out-dir "${CMAKE_CURRENT_BINARY_DIR}/${OPT_DESTINATION}") + message(STATUS "Compiling Rust dependency info for crate root ${local_root_file}") + # XXX: It'd be nice if this wasn't a separate operation (need to handle the dep file location being different, or rewrite this macro thing) + execute_process(COMMAND ${RUSTC_EXECUTABLE} ${RUSTC_FLAGS} ${OPT_OTHER_RUSTC_FLAGS} ${flags} "${root_file}") + endif() + + set(flags "-Zno-analysis") + message(STATUS "Getting Rust dependency info for crate root ${local_root_file}") + + execute_process(COMMAND ${RUSTC_EXECUTABLE} ${RUSTC_FLAGS} ${OPT_OTHER_RUSTC_FLAGS} ${flags} --emit dep-info -o "${dep_dir}/deps.d" "${root_file}") + + # Read and parse the dependency information + file(STRINGS "${dep_dir}/deps.d" crate_deps LIMIT_COUNT 1) + file(REMOVE "${dep_dir}/deps.d") + string(REGEX REPLACE ".*: (.*)" "\\1" crate_deps "${crate_deps}") + string(STRIP "${crate_deps}" crate_deps) + string(REPLACE " " ";" crate_deps "${crate_deps}") + + # Make the dependencies be relative to the source directory + set(crate_deps_relative "") + foreach(var IN ITEMS ${crate_deps}) + file(TO_CMAKE_PATH "${var}" var) + file(RELATIVE_PATH var "${CMAKE_CURRENT_SOURCE_DIR}" "${var}") + list(APPEND crate_deps_relative "${var}") + # Hack to re-run CMake if the file changes + configure_file("${var}" "${dep_dir}/${var}" COPYONLY) + endforeach() + + set(${out_var} "${crate_deps_relative}" PARENT_SCOPE) +endfunction() + +# Adds a target to build a rust crate with the crate root located at local_root_file. +# The compilation output is placed inside DESTINATION within the build directory. +# +# Please pass the crate dependencies obtained through get_rust_deps to the dependencies argument in +# addition to other targets/files you want this target to depend on. +# +# Optional arguments: +# +# ALL - Pass this to make this crate be built by default. +# DESTINATION dest - Where to place the compilation artifacts. +# TARGET_NAME target - Target name for the command to build this crate. +# DEPENDS depends - List of dependencies of this crate. +# OTHER_RUSTC_FLAGS flags - Other flags to pass to rustc. +# +# This function sets two variables: +# +# ${target_name}_FULL_TARGET - This is what you would use as a set of dependencies +# for other targets when you want them to depend on the +# output of this target. +# +# ${target_name}_ARTIFACTS - The actual files generated by this command. +# You'd use this as a set of files to install/copy elsewhere. +function(rust_crate local_root_file) + cmake_parse_arguments("OPT" "ALL" "DESTINATION;TARGET_NAME" "DEPENDS;OTHER_RUSTC_FLAGS" ${ARGN}) + + if(NOT OPT_TARGET_NAME) + set(OPT_TARGET_NAME CRATE) + endif() + + if(OPT_ALL) + set(ALL_ARG "ALL") + else() + set(ALL_ARG "") + endif() + + set(root_file "${CMAKE_CURRENT_SOURCE_DIR}/${local_root_file}") + + execute_process(COMMAND ${RUSTC_EXECUTABLE} ${RUSTC_FLAGS} ${OPT_OTHER_RUSTC_FLAGS} --print file-names "${root_file}" + OUTPUT_VARIABLE rel_crate_filenames + OUTPUT_STRIP_TRAILING_WHITESPACE) + + # Split up the names into a list + string(REGEX MATCHALL "[^\n\r]+" rel_crate_filenames "${rel_crate_filenames}") + + set(comment "Building ") + set(crate_filenames "") + set(first TRUE) + foreach(name IN ITEMS ${rel_crate_filenames}) + if(${first}) + set(first FALSE) + else() + set(comment "${comment}, ") + endif() + set(comment "${comment}${OPT_DESTINATION}/${name}") + list(APPEND crate_filenames "${CMAKE_CURRENT_BINARY_DIR}/${OPT_DESTINATION}/${name}") + endforeach() + file(MAKE_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/${OPT_DESTINATION}") + + add_custom_command(OUTPUT ${crate_filenames} + COMMAND ${RUSTC_EXECUTABLE} ${RUSTC_FLAGS} ${OPT_OTHER_RUSTC_FLAGS} --out-dir "${CMAKE_CURRENT_BINARY_DIR}/${OPT_DESTINATION}" "${root_file}" + DEPENDS ${crate_deps_list} + DEPENDS ${OPT_DEPENDS} + COMMENT "${comment}") + + add_custom_target("${OPT_TARGET_NAME}" + ${ALL_ARG} + DEPENDS ${crate_filenames}) + + set("${OPT_TARGET_NAME}_ARTIFACTS" "${crate_filenames}" PARENT_SCOPE) + # CMake Bug #10082 + set("${OPT_TARGET_NAME}_FULL_TARGET" "${OPT_TARGET_NAME};${crate_filenames}" PARENT_SCOPE) +endfunction() + +# Like rust_crate, but fetches the crate dependencies for you. This is convenient +# but inefficient if you want to compile the crate several times with different +# configurations (e.g. with --test and without) or if you want to build documentation. +# +# Optional arguments: +# +# ALL - Pass this to make this crate be built by default. +# DESTINATION dest - Where to place the compilation artifacts. +# TARGET_NAME target - Target name for the command to build this crate. +# DEPENDS depends - List of dependencies of this crate. +# OTHER_RUSTC_FLAGS flags - Other flags to pass to rustc. +# +# This function sets two variables: +# +# ${target_name}_FULL_TARGET - This is what you would use as a set of dependencies +# for other targets when you want them to depend on the +# output of this target. +# +# ${target_name}_ARTIFACTS - The actual files generated by this command. +# You'd use this as a set of files to install/copy elsewhere. +function(rust_crate_auto local_root_file) + cmake_parse_arguments("OPT" "ALL" "DESTINATION;TARGET_NAME" "DEPENDS;OTHER_RUSTC_FLAGS" ${ARGN}) + + if(NOT OPT_TARGET_NAME) + set(OPT_TARGET_NAME CRATE) + endif() + + if(OPT_ALL) + set(ALL_ARG "ALL") + else() + set(ALL_ARG "") + endif() + + get_rust_deps(${local_root_file} crate_deps_list + OTHER_RUSTC_FLAGS ${OPT_OTHER_RUSTC_FLAGS}) + + rust_crate("${local_root_file}" + ${ALL_ARG} + TARGET_NAME "${OPT_TARGET_NAME}" + DESTINATION "${OPT_DESTINATION}" + DEPENDS "${crate_deps_list};${OPT_DEPENDS}" + OTHER_RUSTC_FLAGS ${OPT_OTHER_RUSTC_FLAGS}) + set("${OPT_TARGET_NAME}_ARTIFACTS" "${${OPT_TARGET_NAME}_ARTIFACTS}" PARENT_SCOPE) + set("${OPT_TARGET_NAME}_FULL_TARGET" "${${OPT_TARGET_NAME}_FULL_TARGET}" PARENT_SCOPE) +endfunction(rust_crate_auto) + +# Like rust_crate, but this time it generates documentation using rust_doc. +# +# Optional arguments: +# +# ALL - Pass this to make this crate be built by default. +# DESTINATION dest - Where to place the compilation artifacts. +# TARGET_NAME target - Target name for the command to build this crate. +# DEPENDS depends - List of dependencies of this crate. +# OTHER_RUSTC_FLAGS flags - Other flags to pass to rustc. +# OTHER_RUSTDOC_FLAGS flags - Other flags to pass to rustdoc. +# +# This function sets two variables: +# +# ${target_name}_FULL_TARGET - This is what you would use as a set of dependencies +# for other targets when you want them to depend on the +# output of this target. +# +# ${target_name}_ARTIFACTS - The actual files generated by this command. +# You'd use this as a set of files to install/copy elsewhere. +function(rust_doc local_root_file) + cmake_parse_arguments("OPT" "ALL" "DESTINATION;TARGET_NAME" "DEPENDS;OTHER_RUSTDOC_FLAGS;OTHER_RUSTC_FLAGS" ${ARGN}) + + if(NOT OPT_TARGET_NAME) + set(OPT_TARGET_NAME DOC) + endif() + + if(OPT_ALL) + set(ALL_ARG "ALL") + else() + set(ALL_ARG "") + endif() + + set(root_file "${CMAKE_CURRENT_SOURCE_DIR}/${local_root_file}") + + execute_process(COMMAND ${RUSTC_EXECUTABLE} ${RUSTC_FLAGS} ${OPT_OTHER_RUSTC_FLAGS} --print crate-name "${root_file}" + OUTPUT_VARIABLE crate_name + OUTPUT_STRIP_TRAILING_WHITESPACE) + + set(doc_dir "${CMAKE_CURRENT_BINARY_DIR}/${OPT_DESTINATION}/${crate_name}") + set(src_dir "${CMAKE_CURRENT_BINARY_DIR}/${OPT_DESTINATION}/src/${crate_name}") + file(MAKE_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/${OPT_DESTINATION}") + + add_custom_command(OUTPUT "${doc_dir}/index.html" "${doc_dir}" "${src_dir}" + COMMAND ${RUSTDOC_EXECUTABLE} ${RUSTDOC_FLAGS} ${OPT_OTHER_RUSTDOC_FLAGS} -o "${CMAKE_CURRENT_BINARY_DIR}/${OPT_DESTINATION}" "${root_file}" + DEPENDS ${crate_deps_list} + DEPENDS ${OPT_DEPENDS}) + + add_custom_target("${OPT_TARGET_NAME}" + ${ALL_ARG} + DEPENDS "${doc_dir}/index.html") + + set("${OPT_TARGET_NAME}_ARTIFACTS" "${doc_dir};${src_dir}" PARENT_SCOPE) + # CMake Bug #10082 + set("${OPT_TARGET_NAME}_FULL_TARGET" "${OPT_TARGET_NAME};${doc_dir}/index.html" PARENT_SCOPE) +endfunction() + +# Like rust_crate_auto, but this time it generates documentation using rust_doc. +# +# Optional arguments: +# +# ALL - Pass this to make this crate be built by default. +# DESTINATION dest - Where to place the compilation artifacts. +# TARGET_NAME target - Target name for the command to build this crate. +# DEPENDS depends - List of dependencies of this crate. +# OTHER_RUSTC_FLAGS flags - Other flags to pass to rustc. +# OTHER_RUSTDOC_FLAGS flags - Other flags to pass to rustdoc. +# +# This function sets two variables: +# +# ${target_name}_FULL_TARGET - This is what you would use as a set of dependencies +# for other targets when you want them to depend on the +# output of this target. +# +# ${target_name}_ARTIFACTS - The actual files generated by this command. +# You'd use this as a set of files to install/copy elsewhere. +function(rust_doc_auto local_root_file) + cmake_parse_arguments("OPT" "ALL" "DESTINATION;TARGET_NAME" "DEPENDS;OTHER_RUSTC_FLAGS;OTHER_RUSTDOC_FLAGS" ${ARGN}) + + if(NOT OPT_TARGET_NAME) + set(OPT_TARGET_NAME DOC) + endif() + + if(OPT_ALL) + set(ALL_ARG "ALL") + else() + set(ALL_ARG "") + endif() + + get_rust_deps(${local_root_file} crate_deps_list + OTHER_RUSTC_FLAGS ${OPT_OTHER_RUSTC_FLAGS}) + + rust_doc("${local_root_file}" + ${ALL_ARG} + TARGET_NAME "${OPT_TARGET_NAME}" + DESTINATION "${OPT_DESTINATION}" + DEPENDS "${crate_deps_list};${OPT_DEPENDS}" + OTHER_RUSTC_FLAGS ${OPT_OTHER_RUSTC_FLAGS} + OTHER_RUSTDOC_FLAGS ${OPT_OTHER_RUSTDOC_FLAGS}) + set("${OPT_TARGET_NAME}_ARTIFACTS" "${${OPT_TARGET_NAME}_ARTIFACTS}" PARENT_SCOPE) + set("${OPT_TARGET_NAME}_FULL_TARGET" "${${OPT_TARGET_NAME}_FULL_TARGET}" PARENT_SCOPE) +endfunction() + +# Creates a dummy cargo project named ${name} to fetch crates.io dependencies. +# The package will be created in the ${CMAKE_CURRENT_BINARY_DIR}. Typically you +# would then pass "-L ${CMAKE_CURRENT_BINARY_DIR}/target/debug/deps" to rustc so +# it can pick up the dependencies. +# +# Optional arguments: +# +# OTHER_CARGO_FLAGS - Flags to pass to cargo. +# PACKAGE_NAMES - List of package names to fetch. +# PACKAGE_VERSIONS - List of package versions to fetch. +function(cargo_dependency name) + cmake_parse_arguments("OPT" "" "" "OTHER_CARGO_FLAGS;PACKAGE_NAMES;PACKAGE_VERSIONS" ${ARGN}) + + list(LENGTH OPT_PACKAGE_NAMES num_packages) + list(LENGTH OPT_PACKAGE_VERSIONS num_versions) + if(NOT ${num_packages} EQUAL ${num_versions}) + message(FATAL_ERROR "Number of cargo packages doesn't match the number of cargo versions.") + endif() + + set(cargo_dependency_dir "${CMAKE_CURRENT_BINARY_DIR}/${name}") + file(MAKE_DIRECTORY "${cargo_dependency_dir}") + file(MAKE_DIRECTORY "${cargo_dependency_dir}/src") + + set(CARGO_TOML [package] \n name = \"cargo_deps_fetcher\" \n version = \"0.0.0\" \n authors = [\"none\"] \n) + + math(EXPR num_packages "${num_packages} - 1") + foreach(pkg_idx RANGE 0 ${num_packages}) + list(GET OPT_PACKAGE_NAMES ${pkg_idx} pkg_name) + list(GET OPT_PACKAGE_VERSIONS ${pkg_idx} pkg_version) + set(CARGO_TOML ${CARGO_TOML} \n [dependencies.${pkg_name}] \n version = \"${pkg_version}\" \n) + endforeach() + + file(WRITE "${cargo_dependency_dir}/Cargo.toml" ${CARGO_TOML}) + file(WRITE "${cargo_dependency_dir}/src/lib.rs" "") + + execute_process(COMMAND ${CARGO_EXECUTABLE} build ${CARGO_FLAGS} ${OPT_OTHER_CARGO_FLAGS} + WORKING_DIRECTORY ${cargo_dependency_dir}) +endfunction() diff --git a/cryptominisat/cppsrc/cmake/cmake_uninstall.cmake.in b/cryptominisat/cppsrc/cmake/cmake_uninstall.cmake.in new file mode 100644 index 00000000..13cedcc5 --- /dev/null +++ b/cryptominisat/cppsrc/cmake/cmake_uninstall.cmake.in @@ -0,0 +1,24 @@ +cmake_policy(SET CMP0007 NEW) # Suppress warnings see `cmake --help-policy CMP0007` + +if (NOT EXISTS "@CMAKE_CURRENT_BINARY_DIR@/install_manifest.txt") + message(FATAL_ERROR "Cannot find install manifest: \"@CMAKE_CURRENT_BINARY_DIR@/install_manifest.txt\"") +endif(NOT EXISTS "@CMAKE_CURRENT_BINARY_DIR@/install_manifest.txt") + +file(READ "@CMAKE_CURRENT_BINARY_DIR@/install_manifest.txt" files) +string(REGEX REPLACE "\n" ";" files "${files}") +list(REVERSE files) +foreach (file ${files}) + message(STATUS "Uninstalling \"$ENV{DESTDIR}${file}\"") + if (EXISTS "$ENV{DESTDIR}${file}") + execute_process( + COMMAND @CMAKE_COMMAND@ -E remove "$ENV{DESTDIR}${file}" + OUTPUT_VARIABLE rm_out + RESULT_VARIABLE rm_retval + ) + if(NOT ${rm_retval} EQUAL 0) + message(FATAL_ERROR "Problem when removing \"$ENV{DESTDIR}${file}\"") + endif (NOT ${rm_retval} EQUAL 0) + else (EXISTS "$ENV{DESTDIR}${file}") + message(STATUS "File \"$ENV{DESTDIR}${file}\" does not exist.") + endif (EXISTS "$ENV{DESTDIR}${file}") +endforeach(file) diff --git a/cryptominisat/cppsrc/cmsat_tablestructure.sql b/cryptominisat/cppsrc/cmsat_tablestructure.sql new file mode 100644 index 00000000..999f7749 --- /dev/null +++ b/cryptominisat/cppsrc/cmsat_tablestructure.sql @@ -0,0 +1,486 @@ +DROP TABLE IF EXISTS `tags`; +CREATE TABLE `tags` ( + `name` varchar(500) NOT NULL, + `val` varchar(500) NOT NULL +); + +DROP TABLE IF EXISTS `timepassed`; +CREATE TABLE `timepassed` ( + `simplifications` bigint(20) NOT NULL, + `conflicts` bigint(20) NOT NULL, + `runtime` float NOT NULL, + `name` varchar(200) NOT NULL, + `elapsed` float NOT NULL, + `timeout` int(20) DEFAULT NULL, + `percenttimeremain` float DEFAULT NULL +); + +DROP TABLE IF EXISTS `memused`; +CREATE TABLE `memused` ( + `simplifications` bigint(20) NOT NULL, + `conflicts` bigint(20) NOT NULL, + `runtime` float NOT NULL, + `name` varchar(200) NOT NULL, + `MB` int(20) NOT NULL +); + +DROP TABLE IF EXISTS `solverRun`; +CREATE TABLE `solverRun` ( + `runtime` float NOT NULL, + `gitrev` varchar(100) NOT NULL +); + +DROP TABLE IF EXISTS `startup`; +CREATE TABLE `startup` ( + `startTime` datetime NOT NULL +); + +DROP TABLE IF EXISTS `finishup`; +CREATE TABLE `finishup` ( + `endTime` datetime NOT NULL, + `status` varchar(255) NOT NULL +); + +DROP TABLE IF EXISTS `reduceDB_common`; +CREATE TABLE `reduceDB_common` ( + `reduceDB_called` int(20) NOT NULL, + + `simplifications` int(20) NOT NULL, + `restarts` int(20) NOT NULL, + `conflicts` bigint(20) NOT NULL, + `latest_satzilla_feature_calc` int(20) NOT NULL, + `cur_restart_type` int(20) NOT NULL, + `runtime` float NOT NULL, + `tot_cls_in_db` int(20) NOT NULL, + + `median_act` float NOT NULL, + `median_uip1_used` int(20) NOT NULL, + `median_props` int(20) NOT NULL, + `median_sum_uip1_per_time` float NOT NULL, + `median_sum_props_per_time` float NOT NULL, + + -- `avg_glue` float NOT NULL, CANNOT do this, ternaries don't have a glue! + `avg_props` float NOT NULL, + `avg_uip1_used` float NOT NULL, + `avg_sum_uip1_per_time` float NOT NULL, + `avg_sum_props_per_time` float NOT NULL, + + num_vars int(20) NOT NULL, + num_long_irred_cls int(20) NOT NULL, + num_long_irred_cls_lits int(20) NOT NULL, + num_long_red_cls int(20) NOT NULL, + num_long_red_cls_lits int(20) NOT NULL, + num_bin_irred_cls int(20) NOT NULL, + num_bin_red_cls int(20) NOT NULL, + + trailDepthHistLT_avg float NOT NULL, + backtrackLevelHistLT_avg float NOT NULL, + conflSizeHistLT_avg float NOT NULL, + numResolutionsHistLT_avg float NOT NULL, + glueHistLT_avg float NOT NULL, + antec_data_sum_sizeHistLT_avg float NOT NULL, + overlapHistLT_avg float NOT NULL +); + +DROP TABLE IF EXISTS `reduceDB`; +CREATE TABLE `reduceDB` ( + `reduceDB_called` int(20) NOT NULL, + `conflicts` bigint(20) NOT NULL, + `introduced_at_conflict` bigint(20) NOT NULL, -- this is BAD but for ternary clauses we need this + `which_red_array` int(20) NOT NULL, + + `clauseID` int(20) NOT NULL, + `dump_no` int(20) NOT NULL, + `conflicts_made` bigint(20) NOT NULL, + `props_made` bigint(20) NOT NULL, + `sum_props_made` bigint(20) NOT NULL, + `uip1_used` bigint(20) NOT NULL, + `sum_uip1_used` int(20) NOT NULL, + + `last_touched_any_diff` bigint(20) NOT NULL, + `activity_rel` float(20) NOT NULL, + `locked` int(20) NOT NULL, + `in_xor` int(20) NOT NULL, + `glue` int(20) DEFAULT NULL, + `size` int(20) NOT NULL, + `ttl_stats` int(20) NOT NULL, + `is_ternary_resolvent` int(20) NOT NULL, + `is_decision` int(20) NOT NULL, + `is_distilled` int(20) NOT NULL, + `connects_num_communities` int(20) NOT NULL, + + -- ranking + `act_ranking` int(20) NOT NULL, + `prop_ranking` int(20) NOT NULL, + `uip1_ranking` int(20) NOT NULL, + `sum_uip1_per_time_ranking` int(20) NOT NULL, + `sum_props_per_time_ranking` int(20) NOT NULL, + + -- discounted + `discounted_uip1_used` float(20) NOT NULL, + `discounted_props_made` float(20) NOT NULL, + `discounted_uip1_used2` float(20) NOT NULL, + `discounted_props_made2` float(20) NOT NULL, + `discounted_uip1_used3` float(20) NOT NULL, + `discounted_props_made3` float(20) NOT NULL +); + +DROP TABLE IF EXISTS `restart`; +CREATE TABLE `restart` ( + `restartID` int (20) NOT NULL, + `clauseID` bigint(20) DEFAULT NULL, + `simplifications` int(20) NOT NULL, + `restarts` int(20) NOT NULL, + `conflicts` bigint(20) NOT NULL, + `conflicts_this_restart` int(20) NOT NULL, + `latest_satzilla_feature_calc` int(20) NOT NULL, + `runtime` float NOT NULL, + + `numIrredBins` int(20) NOT NULL, + `numIrredLongs` int(20) NOT NULL, + `numRedBins` int(20) NOT NULL, + `numRedLongs` int(20) NOT NULL, + + `numIrredLits` bigint(20) NOT NULL, + `numredLits` bigint(20) NOT NULL, + + -- conflict stats + `glue` float, + `glueSD` float, + `glueMin` int(20), + `glueMax` int(20), + + `size` float, + `sizeSD` float, + `sizeMin` int(20), + `sizeMax` int(20), + + `resolutions` float, + `resolutionsSD` float, + `resolutionsMin` int(20), + `resolutionsMax` int(20), + + -- search stats + `branchDepth` float, + `branchDepthSD` float, + `branchDepthMin` int(20), + `branchDepthMax` int(20), + + `branchDepthDelta` float, + `branchDepthDeltaSD` float, + `branchDepthDeltaMin` int(20), + `branchDepthDeltaMax` int(20), + + `trailDepth` float, + `trailDepthSD` float, + `trailDepthMin` int(20), + `trailDepthMax` int(20), + + `trailDepthDelta` float, + `trailDepthDeltaSD` float, + `trailDepthDeltaMin` int(20), + `trailDepthDeltaMax` int(20), + + `learntUnits` int(20) NOT NULL, + `learntBins` int(20) NOT NULL, + `learntLongs` int(20) NOT NULL, + + `resolBinIrred` bigint(20) NOT NULL, + `resolBinRed` bigint(20) NOT NULL, + `resolLIrred` bigint(20) NOT NULL, + `resolLRed` bigint(20) NOT NULL, + + `propagations` bigint(20) NOT NULL, + `decisions` bigint(20) NOT NULL, + + `flipped` bigint(20) NOT NULL, + `varSetPos` bigint(20) NOT NULL, + `varSetNeg` bigint(20) NOT NULL, + `free` int(20) NOT NULL, + `replaced` int(20) NOT NULL, + `eliminated` int(20) NOT NULL, + `set` int(20) NOT NULL, + + `branch_strategy` int NOT NULL, + `restart_type` int(20) NOT NULL +); + +DROP TABLE IF EXISTS `restart_dat_for_var`; +DROP TABLE IF EXISTS `restart_dat_for_cl`; +CREATE TABLE `restart_dat_for_var` AS SELECT * FROM `restart` WHERE 0; +CREATE TABLE `restart_dat_for_cl` AS SELECT * FROM `restart` WHERE 0; + + +DROP TABLE IF EXISTS `clause_stats`; +CREATE TABLE `clause_stats` ( + `simplifications` int(20) NOT NULL, + `restarts` int(20) NOT NULL, + `prev_restart` bigint(20) NOT NULL, + `conflicts` bigint(20) NOT NULL, + `latest_satzilla_feature_calc` int(20) NOT NULL, + `clauseID` bigint(20) NOT NULL, + `restartID` int(20) NOT NULL, + + `orig_glue` int(20) NOT NULL, + `glue_before_minim` int(20) NOT NULL, + `orig_size` int(20) NOT NULL, + `size_before_minim` int(20) NOT NULL, + `conflicts_this_restart` bigint(20) NOT NULL, + `num_overlap_literals` int(20) NOT NULL, + `num_antecedents` int(20) NOT NULL, + `num_total_lits_antecedents` int(20) NOT NULL, + `is_decision` int(20) NOT NULL, + + `backtrack_level` int(20) NOT NULL, + `decision_level` int(20) NOT NULL, + `decision_level_pre1` int(20) NOT NULL, + `decision_level_pre2` int(20) NOT NULL, + `trail_depth_level` int(20) NOT NULL, + `cur_restart_type` int(20) NOT NULL, + + `atedecents_binIrred` int(20) NOT NULL, + `atedecents_binRed` int(20) NOT NULL, + `atedecents_longIrred` int(20) NOT NULL, + `atedecents_longRed` int(20) NOT NULL, + + `decisionLevelHistLT_avg` float, + `backtrackLevelHistLT_avg` float, + `trailDepthHistLT_avg` float, + `conflSizeHistlt_avg` float, + `glueHistLT_avg` float, + `connects_num_communities_histLT_avg` float, + `numResolutionsHistLT_avg` float, + + `antec_data_sum_sizeHistLT_avg` float, + `overlapHistLT_avg` float, + + `branchDepthHistQueue_avg` float, + `trailDepthHist_avg` float, + `trailDepthHistLonger_avg` float, + `numResolutionsHist_avg` float, + `conflSizeHist_avg` float, + `trailDepthDeltaHist_avg` float, + `backtrackLevelHist_avg` float, + `glueHist_avg` float, + `glueHist_longterm_avg` float, + `orig_connects_num_communities` int(20) NOT NULL +); + +DROP TABLE IF EXISTS `satzilla_features`; +CREATE TABLE `satzilla_features` ( + `simplifications` int(20) NOT NULL, + `restarts` int(20) NOT NULL, + `conflicts` bigint(20) NOT NULL, + `latest_satzilla_feature_calc` int(20) NOT NULL, + + `numVars` int(20) NOT NULL, + `numClauses` int(20) NOT NULL, + `var_cl_ratio` double NOT NULL, + + -- Clause distribution + `binary` double NOT NULL, + `horn` double NOT NULL, + `horn_mean` double NOT NULL, + `horn_std` double NOT NULL, + `horn_min` double NOT NULL, + `horn_max` double NOT NULL, + `horn_spread` double NOT NULL, + + `vcg_var_mean` double NOT NULL, + `vcg_var_std` double NOT NULL, + `vcg_var_min` double NOT NULL, + `vcg_var_max` double NOT NULL, + `vcg_var_spread` double NOT NULL, + + `vcg_cls_mean` double NOT NULL, + `vcg_cls_std` double NOT NULL, + `vcg_cls_min` double NOT NULL, + `vcg_cls_max` double NOT NULL, + `vcg_cls_spread` double NOT NULL, + + `pnr_var_mean` double NOT NULL, + `pnr_var_std` double NOT NULL, + `pnr_var_min` double NOT NULL, + `pnr_var_max` double NOT NULL, + `pnr_var_spread` double NOT NULL, + + `pnr_cls_mean` double NOT NULL, + `pnr_cls_std` double NOT NULL, + `pnr_cls_min` double NOT NULL, + `pnr_cls_max` double NOT NULL, + `pnr_cls_spread` double NOT NULL, + + -- Conflict clauses + `avg_confl_size` double NOT NULL, + `confl_size_min` double NOT NULL, + `confl_size_max` double NOT NULL, + `avg_confl_glue` double NOT NULL, + `confl_glue_min` double NOT NULL, + `confl_glue_max` double NOT NULL, + `avg_num_resolutions` double NOT NULL, + `num_resolutions_min` double NOT NULL, + `num_resolutions_max` double NOT NULL, + `learnt_bins_per_confl` double NOT NULL, + + -- Search + `avg_branch_depth` double NOT NULL, + `branch_depth_min` double NOT NULL, + `branch_depth_max` double NOT NULL, + `avg_trail_depth_delta` double NOT NULL, + `trail_depth_delta_min` double NOT NULL, + `trail_depth_delta_max` double NOT NULL, + `avg_branch_depth_delta` double NOT NULL, + `props_per_confl` double NOT NULL, + `confl_per_restart` double NOT NULL, + `decisions_per_conflict` double NOT NULL, + + -- clause distributions + `red_glue_distr_mean` double NOT NULL, + `red_glue_distr_var` double NOT NULL, + `red_size_distr_mean` double NOT NULL, + `red_size_distr_var` double NOT NULL, + `red_activity_distr_mean` double NOT NULL, + `red_activity_distr_var` double NOT NULL, + + `irred_glue_distr_mean` double NOT NULL, + `irred_glue_distr_var` double NOT NULL, + `irred_size_distr_mean` double NOT NULL, + `irred_size_distr_var` double NOT NULL, + `irred_activity_distr_mean` double NOT NULL, + `irred_activity_distr_var` double NOT NULL +); + +DROP TABLE IF EXISTS `var_data_fintime`; +create table `var_data_fintime` ( + `var` int(20) NOT NULL + , `sumConflicts_at_picktime` int(20) NOT NULL + , `rel_activity_at_fintime` double NOT NULL + + , `inside_conflict_clause_at_fintime` int(20) NOT NULL + , `inside_conflict_clause_antecedents_at_fintime` int(20) NOT NULL + , `inside_conflict_clause_glue_at_fintime` int(20) NOT NULL + + , `sumDecisions_at_fintime` int(20) NOT NULL + , `sumConflicts_at_fintime` int(20) NOT NULL + , `sumPropagations_at_fintime` int(20) NOT NULL + , `sumAntecedents_at_fintime` int(20) NOT NULL + , `sumAntecedentsLits_at_fintime` int(20) NOT NULL + , `sumConflictClauseLits_at_fintime` int(20) NOT NULL + , `sumDecisionBasedCl_at_fintime` int(20) NOT NULL + , `sumClLBD_at_fintime` int(20) NOT NULL + , `sumClSize_at_fintime` int(20) NOT NULL +); + +DROP TABLE IF EXISTS `var_data_picktime`; +create table `var_data_picktime` ( + `var` int(20) NOT NULL + , `dec_depth` int(20) NOT NULL + , `rel_activity_at_picktime` double NOT NULL + , `latest_vardist_feature_calc` int(20) NOT NULL + + , `inside_conflict_clause_at_picktime` int(20) NOT NULL + , `inside_conflict_clause_antecedents_at_picktime` int(20) NOT NULL + , `inside_conflict_clause_glue_at_picktime` int(20) NOT NULL + + , `inside_conflict_clause_during_at_picktime` int(20) NOT NULL + , `inside_conflict_clause_antecedents_during_at_picktime` int(20) NOT NULL + , `inside_conflict_clause_glue_during_at_picktime` int(20) NOT NULL + + , `num_decided` int(20) NOT NULL + , `num_decided_pos` int(20) NOT NULL + , `num_propagated` int(20) NOT NULL + , `num_propagated_pos` int(20) NOT NULL + + , `conflicts_since_in_1uip` int(20) NOT NULL + , `conflicts_since_decided` int(20) NOT NULL + , `conflicts_since_propagated` int(20) NOT NULL + , `conflicts_since_canceled` int(20) NOT NULL + + , `sumDecisions_at_picktime` int(20) NOT NULL + , `sumConflicts_at_picktime` int(20) NOT NULL + , `sumPropagations_at_picktime` int(20) NOT NULL + , `sumAntecedents_at_picktime` int(20) NOT NULL + , `sumAntecedentsLits_at_picktime` int(20) NOT NULL + , `sumConflictClauseLits_at_picktime` int(20) NOT NULL + , `sumDecisionBasedCl_at_picktime` int(20) NOT NULL + , `sumClLBD_at_picktime` int(20) NOT NULL + , `sumClSize_at_picktime` int(20) NOT NULL + + , `sumConflicts_below_during` int(20) NOT NULL + , `sumDecisions_below_during` int(20) NOT NULL + , `sumPropagations_below_during` int(20) NOT NULL + , `sumAntecedents_below_during` int(20) NOT NULL + , `sumAntecedentsLits_below_during` int(20) NOT NULL + , `sumConflictClauseLits_below_during` int(20) NOT NULL + , `sumDecisionBasedCl_below_during` int(20) NOT NULL + , `sumClLBD_below_during` int(20) NOT NULL + , `sumClSize_below_during` int(20) NOT NULL + + , flipped_confs_ago int(20) NOT NULL +); + +DROP TABLE IF EXISTS `dec_var_clid`; +create table `dec_var_clid` ( + `var` int(20) NOT NULL + , `sumConflicts_at_picktime` bigint(20) NOT NULL + , `clauseID` int(2) DEFAULT NULL +); + +DROP TABLE IF EXISTS `var_data_use`; +create table `var_data_use` ( + `var` int(20) NOT NULL + , `sumConflicts_at_picktime` bigint(20) NOT NULL + + , `cls_marked` int(2) DEFAULT NULL + , `useful_clauses` int(20) DEFAULT NULL + , `useful_clauses_used` int(20) DEFAULT NULL +); + +DROP TABLE IF EXISTS `cl_last_in_solver`; +create table `cl_last_in_solver` ( + `conflicts` bigint(20) NOT NULL + , `clauseID` bigint(20) NOT NULL +); + +DROP TABLE IF EXISTS `update_id`; +create table `update_id` ( + `old_id` bigint(20) NOT NULL + , `new_id` bigint(20) NOT NULL +); + +DROP TABLE IF EXISTS `set_id_confl`; +create table `set_id_confl` ( + `id` bigint(20) NOT NULL + , `conflicts` bigint(20) NOT NULL +); + + +DROP TABLE IF EXISTS `var_dist`; +create table `var_dist` ( + `var` bigint(20) NOT NULL + , `latest_vardist_feature_calc` bigint(20) NOT NULL + , `conflicts` bigint(20) NOT NULL + + , `num_irred_long_cls` bigint(20) NOT NULL + , `num_red_long_cls` bigint(20) NOT NULL + , `num_irred_bin_cls` bigint(20) NOT NULL + , `num_red_bin_cls` bigint(20) NOT NULL + + , `red_num_times_in_bin_clause` bigint(20) NOT NULL + , `red_num_times_in_long_clause` bigint(20) NOT NULL + , `red_satisfies_cl` bigint(20) NOT NULL + , `red_falsifies_cl` bigint(20) NOT NULL + , `red_tot_num_lit_of_bin_it_appears_in` bigint(20) NOT NULL + , `red_tot_num_lit_of_long_cls_it_appears_in` bigint(20) NOT NULL + , `red_sum_var_act_of_cls` double NOT NULL + + , `irred_num_times_in_bin_clause` bigint(20) NOT NULL + , `irred_num_times_in_long_clause` bigint(20) NOT NULL + , `irred_satisfies_cl` bigint(20) NOT NULL + , `irred_falsifies_cl` bigint(20) NOT NULL + , `irred_tot_num_lit_of_bin_it_appears_in` bigint(20) NOT NULL + , `irred_tot_num_lit_of_long_cls_it_appears_in` bigint(20) NOT NULL + , `irred_sum_var_act_of_cls` double NOT NULL + + , `tot_act_long_red_cls` bigint(20) NOT NULL +); diff --git a/cryptominisat/cppsrc/cryptominisat5Config.cmake.in b/cryptominisat/cppsrc/cryptominisat5Config.cmake.in new file mode 100644 index 00000000..b9725665 --- /dev/null +++ b/cryptominisat/cppsrc/cryptominisat5Config.cmake.in @@ -0,0 +1,20 @@ +# Config file for the @EXPORT_TYPE@ cryptominisat Package +# It defines the following variables +# CRYPTOMINISAT5_INCLUDE_DIRS - include directories for cryptominisat5 +# CRYPTOMINISAT5_LIBRARIES - libraries to link against +# CRYPTOMINISAT5_EXECUTABLE - the cryptominisat executable + +# Compute paths +get_filename_component(CRYPTOMINISAT5_CMAKE_DIR "${CMAKE_CURRENT_LIST_FILE}" PATH) +set(CRYPTOMINISAT5_INCLUDE_DIRS "@CONF_INCLUDE_DIRS@") + +# Our library dependencies (contains definitions for IMPORTED targets) +include("${CRYPTOMINISAT5_CMAKE_DIR}/@CRYPTOMINISAT5_TARGETS_FILENAME@") + +# These are IMPORTED targets created by @CRYPTOMINISAT5_TARGETS_FILENAME@ +set(CRYPTOMINISAT5_LIBRARIES cryptominisat5) +set(CRYPTOMINISAT5_STATIC_LIBRARIES cryptominisat5) +set(CRYPTOMINISAT5_STATIC_LIBRARIES_DEPS @CRYPTOMINISAT5_STATIC_DEPS@) +set(CRYPTOMINISAT5_VERSION_MAJOR @PROJECT_VERSION_MAJOR@) +set(CRYPTOMINISAT5_VERSION_MINOR @PROJECT_VERSION_MINOR@) +set(CRYPTOMINISAT5_EXECUTABLE cryptominisat5) diff --git a/cryptominisat/cppsrc/dist/README.md b/cryptominisat/cppsrc/dist/README.md new file mode 100644 index 00000000..51aac0e8 --- /dev/null +++ b/cryptominisat/cppsrc/dist/README.md @@ -0,0 +1 @@ +To build, run `python -m build` from the main directory. To upload to pypi, run `twine upload ...`. The wheel binary should be obtained from `https://github.com/msoos/cryptominisat/actions/workflows/wheel-builder.yml` diff --git a/cryptominisat/cppsrc/docs/HOWTO_WEB b/cryptominisat/cppsrc/docs/HOWTO_WEB new file mode 100644 index 00000000..f609622d --- /dev/null +++ b/cryptominisat/cppsrc/docs/HOWTO_WEB @@ -0,0 +1,52 @@ +1) You will need: +* MySQL server +* MySQL libraries +* PHP5 +* Apache +* Chrome or Firefox, but prefer chrome, js is faster there + +2) create "cryptoms database" in mysql: + +$ mysql -u root -p PASS +$ create database cryptoms + +3) create two MySQL users: +* one "cryptomsuser" , with empty password, which can read-write to database "cryptoms" +* one "presenter", with empty password, which can read database "cryptoms" + +4) run: + +$ mysql -u cryptomsuser cryptoms < web/tablestructure.sql + +this will create the table structures needed + +4) compile and exectute cryptoms as: + +$ ./cryptominisat --sql 1 MYFILE.cnf + +and let it run for at least 20'000 conflicts. It should run without any problems. +If there is any problem with MySQL, it will print the exact error, errors are not +silently ignored. + +5) you can now play around with the data in mysql: + +$ mysql -u cryptomsuser cryptoms +$ show tables; +$ select * from restartDB; + +3) Copy everything under "web" into /var/www/cryptoms and make sure that it's +readable by apache. + +4) point your browser to + +http://localhost/cryptoms + +you should see the output of the last run. You can also refresh it, and if it's +running in the background, you will see the graphs update. Note that if your +last solving run was aborted early,and there was no data input into MySQL +then there will be no data shown. So make sure your last run of cryptominisat +with option "--sql 1" was meaningful, i.e. long enough. + + + + diff --git a/cryptominisat/cppsrc/docs/satcomp14-pdf/Makefile b/cryptominisat/cppsrc/docs/satcomp14-pdf/Makefile new file mode 100644 index 00000000..99046573 --- /dev/null +++ b/cryptominisat/cppsrc/docs/satcomp14-pdf/Makefile @@ -0,0 +1,23 @@ +TEX = pdflatex -shell-escape -interaction=nonstopmode -file-line-error +PRE = $(TEX) -ini -job-name="preamble" "&pdflatex preamble.tex\dump" +BIB = bibtex + +all: cmsv4.pdf + +view : + open cmsv4.pdf + +cmsv4.pdf : cmsv4.tex cmsv4.bbl cmsv4.blg + $(TEX) cmsv4.tex + +cmsv4.bbl cmsv4.blg : cmsv4.bib cmsv4.aux + $(BIB) cmsv4 + +cmsv4.aux : cmsv4.tex + $(TEX) cmsv4.tex + +cmsv4.bib : cmsv4.tex + $(TEX) cmsv4.tex + +clean: + rm -f *.aux *.bbl *.out cmsv4.pdf *.log *.blg diff --git a/cryptominisat/cppsrc/docs/satcomp14-pdf/cmsv4.tex b/cryptominisat/cppsrc/docs/satcomp14-pdf/cmsv4.tex new file mode 100644 index 00000000..ec9b29d2 --- /dev/null +++ b/cryptominisat/cppsrc/docs/satcomp14-pdf/cmsv4.tex @@ -0,0 +1,73 @@ +%\documentclass[runningheads]{llncs} +\documentclass[final]{ieee} + +\usepackage{microtype} %This gives MUCH better PDF results! +%\usepackage[active]{srcltx} %DVI search +\usepackage[cmex10]{amsmath} +\usepackage{amssymb} +\usepackage{fnbreak} %warn for split footnotes +\usepackage{url} +%\usepackage{qtree} %for drawing trees +%\usepackage{fancybox} % if we need rounded corners +%\usepackage{pict2e} % large circles can be drawn +%\usepackage{courier} %for using courier in texttt{} +%\usepackage{nth} %allows to \nth{4} to make 1st 2nd, etc. +%\usepackage{subfigure} %allows to have side-by-side figures +%\usepackage{booktabs} %nice tables +%\usepackage{multirow} %allow multiple cells with rows in tabular +\usepackage[utf8]{inputenc} % allows to write Faugere correctly +\usepackage[bookmarks=true, citecolor=black, linkcolor=black, colorlinks=true]{hyperref} +\hypersetup{ +pdfauthor = {Mate Soos}, +pdftitle = {CryptoMiniSat v4}, +pdfsubject = {SAT Competition 2013}, +pdfkeywords = {SAT Solver, DPLL}, +pdfcreator = {PdfLaTeX with hyperref package}, +pdfproducer = {PdfLaTex}} +%\usepackage{butterma} + +%\usepackage{pstricks} +\usepackage{graphicx,epsfig,xcolor} +\usepackage[algoruled, linesnumbered, lined]{algorithm2e} %algorithms + +\begin{document} +\title{CryptoMiniSat v4} +\author{Mate Soos\\Security Research Labs} + +\maketitle +\thispagestyle{empty} +\pagestyle{empty} + +\section{Introduction} +This paper presents the conflict-driven clause-learning SAT solver CryptoMiniSat v4 (\emph{cmsat4}). \emph{cmsat4} aims to be a modern SAT Solver that allows for multi-threaded in-processing techniques while still retaining a strong CDCL component. In this description only the features relative to \emph{forl}, the previous year's submission, are explained. Please refer to the previous years' description for details. + + +\subsection{Cleaner code} +The code has been significantly cleaned up. In particular, it has been refactored to use more descriptive names, smaller functions and uses C++11 constructs that aid in simplifying code. + +\subsection{Better data gathering} +More data is gathered into an SQL database that allows for interactive display of solving parameters. It also allows for later analysis of the solving, spotting e.g. that certain simplification steps take too long. Every simplification step is recorded and many important factors about clauses, clause cleaning, propagation and conflict analysis are dumped to the database. + +\subsection{Bounded variable addition} +As per \cite{DBLP:conf/hvc/MantheyHB12} +variables are added to simplify the formula. CryptoMiniSat allows for not only 1-literal diff as per the research paper, but also 2-literal diffs. In terms of the algorithm in the research paper this difference introduces almost no change, though makes the implementation somewhat more elaborate. + +\subsection{Tuned time-outs} +Thanks to the SQL-based query functionality, time-outs could be queried easily and checked. This allowed for fine-tuning of time-outs for weird problems. + +\subsection{Multi-threading} +An experimental multi-threading system has been added. It only exchanges unit and binary lemmas. The system works even in case of library usage: it cleanly aborts the other threads even if the other threads are solving subcomponents with subsolvers. + +\subsection{Better stability} +The API has been cleaned up and connected to a number of fuzzers, including e.g. a wrapper for python and a python-based test-suite. This allowed for more rigorious testing to be carried out. + +\section*{Acknowledgements} +The author would like to thank in no particular order Horst Samulowitz, Marius T. Lindauer, Martin Maurer, Martin Albrecht, Vegard Nossum, Valentin Mayer-Eichberger, George Katsirelos, Karsten Nohl, Luca Melette, Marijn Heule, Vijay Ganesh, Trevor Hansen and Robert Aston for their help. + +\bibliographystyle{splncs03} +\bibliography{sigproc} + +\vfill +\pagebreak + +\end{document} diff --git a/cryptominisat/cppsrc/docs/satcomp14-pdf/ieee.cls b/cryptominisat/cppsrc/docs/satcomp14-pdf/ieee.cls new file mode 100644 index 00000000..3c57bba5 --- /dev/null +++ b/cryptominisat/cppsrc/docs/satcomp14-pdf/ieee.cls @@ -0,0 +1,1497 @@ +% Copyright 2014 IEEEE +% for terms of use see https://www.ieee.org/publications_standards/publications/rights/copyrightpolicy.html + +% ========================================================================= +% ------------------------------------------------------------------------- +% XX X +% X +% XX XXX XXX XXX XXX X XXXX +% X X X X X X X X X X X +% X XXXXX XXXXX XXXXX X X XXX +% X X X X XX X X X X +% XXX XXX XXX XXX XX XXX X XXXX +% ------------------------------------------------------------------------- +% ========================================================================= +% ieee.cls --- For formatting IEEE conference & journal papers +% --- Compiled by Gregory Plett, Sept 1997 +% +% This class was inspired by one first compiled by Gerry Murray and +% Silvano Balemi for LaTeX209. It was later updated for use with +% LaTeX2e, and some bugs were fixed, all by Istvan Kollar. Lastly, +% I have tried to make the class easier to use by paper authors. +% Significant new functionality has been added. Many routines are +% "borrowed" from other people's packages and modified extensively. +% When I rembered where I got the routines from, I gave the author +% credit. +% +% After I made many changes on my own, I found a version by Peter +% N"uchter, and tried to retain some amount of compatibility with his +% version. To be completely compatible with him, you may need to +% manually: +% \usepackage{rawfonts}\usepackage{oldlfont} +% \AtBeginDocument{\parindent1.0em} (?) +% +%=========================================================================== +% +% Usage: +% \documentclass[main-mode,sub-mode,misc-options]{ieee} +% \usepackage{your own packages} +% \begin{document} +% \bibliographystyle{IEEEbib} +% \title[short]{regular} +% \author[short]{full} +% \maketitle +% \begin{abstract}...\end{abstract} +% \begin{keywords}...\end{keywords} +% \section{...} +% \PARstart ... or \PARstartCal ... +% ... +% \begin{biography}[picname.ps]{Author's name}...\end{biography} +% \end{document} +% +% The document class options are: +% +% main-mode: One of the following is required. (draft is the default) +% draft: Double-spaced, single column with date/time stamp. +% submission: Double-spaced, suitable for submission for review. +% compressed: Same as "submission", only single spaced. +% final: Double-column, for assessing page-length and +% format of final version. +% +% sub-mode: +% techreport: This can modify "final" to produce a two-col +% technical report. +% internal: This can modify "submission", "compressed" or "final". +% It changes the header to notify the reader that +% this is a version of the manuscript to be used for +% internal review processes only, and not to be +% distributed. +% submitted: This can modify "compressed" or "final". It changes +% the header to notify the reader that this +% is a preprint and not to be distributed. +% inpress: This can modify "compressed" or "final". It changes the +% header to notify the reader that this paper has +% been accepted for publishing, but it is not yet to be +% distributed. +% reprint: This can modify "final". It changes the header +% to notify the reader where the paper is reprinted from. +% +% misc-options: +% narroweqnarray: Changes the spacing around the "=" sign in +% equation arrays to make it the same as in displayed math. +% inline: Compresses the horizontal spacing of inline math equations. +% notitlepage: No separate title page. (default) +% titlepage: Separate title page. +% anonymous: Omit all author information from main part of paper. +% Author info only prints on titlepage. +% 9pt,10pt,11pt,12pt: Choose the appropriate type size. You should +% not need to do this as the "correct" size is automatically +% chosen. However, if you want, you may use these to change +% the type size of the main text. "9pt" is a bit of a hack +% to retain backward-compatibility. +% invited: If the paper is an "invited" paper, then this option +% prints "(Invited Paper)" under the authors' names. +% +% For regular IEEE submissions, define the journal name as: +% \journal{IEEE Trans. Inst. Meas.} +% +% To specify the conference place and date: +% \confplacedate{Ottawa, Canada, May 19--21, 1997} +% +% Before \maketitle, define: +% \title{Title of paper} +% \author{Author1\member{Fellow}\authorinfo{Department of +% Electrical Engineering\\ Some University, Somewhere, CA 94305 +% USA} \and Author2\member{Senior Member}\authorinfo{Deptartment of +% Measurement and Instrument Eng., Another University, ...}} +% +% Note, the contents of \authorinfo tends to vary depending on if it is +% a conference or journal paper. The amount of manual changes are +% small, and must be done by a human anyway. The example given is for an +% IMTC conference. +% +% See also IEEEbib.bst and ieeefig.sty +% Also very useful for document preparation is the style file "endfloat", +% available on all CTAN TeX archives. +% +%=========================================================================== +% modified 14 October 2002: +% - fixed bibliography listing of [#] when # < 10 and number of +% references is greater than 9. Thanks for Janos Markus for finding +% this bug and suggesting a solution. +% modified 15 January 2000: +% - "fixed" narroweqnarray. Never implemented! Now it is... +% modified 12 January 2000: +% - modified so only first \title and \author commands are recognized. +% This allows LyX to have \title and \author with full syntax in +% header, but dummy \title and \author show up in GUI. +% - added "\date" so the \date command can change "submitted" and +% "draft" date headers. +% modified 11 January 2000: +% - added PARstartLyX and PARstartCalLyX for LyX compatibility +% - added biographyLyX +% modified 1 Dec 1997: +% - fixed first page in reprint mode to be same length as other pages +% - added "invited" misc-option +% modified 5 Sept 1997: +% - added the inpress, reprint and internal sub-modes +% - removed IMTC-conf and CDC-conf to separate files +% modified 1 Sept 1997: +% - included Babel package compatibility +% - removed paper title from header on first page of draft +% manuscript +% - removed the fixed option "letterpaper" to allow a4paper (etc) +% modified 1 Aug 1997: +% - included the CDC-conf option +%=========================================================================== +% ************************************************************************** +% ****** ****************************************** +% ***** LaTeX2e INITIALIZATION ***************************************** +% ****** ****************************************** +% ************************************************************************** +\typeout{Document Class `ieee' .} +\NeedsTeXFormat{LaTeX2e}[1993/11/11] % Oldest acceptable version of LaTeX2e +\ProvidesClass{ieee}[2000/01/11] % Name of package provided, date +\def\i@@@cls{exists} + +% Initial Code & Declaration of Options +% ------------------------------------- +\newif\ifev@l \ev@lfalse % true if "final" mode. +\newif\ifsubm@t \subm@tfalse % true if "submission" mode. +\newif\ifdr@ft \dr@fttrue % true if "draft" mode. +\newif\ifc@mpress \c@mpressfalse % true if "compressed" mode. + +\newif\if@technote \@technotefalse % true if "technote" sub-mode. +\newif\ifintern@l \intern@lfalse % true if "internal" sub-mode. +\newif\ifprepr@nt \prepr@ntfalse % true if "preprint" sub-mode. +\newif\ifinpr@ss \inpr@ssfalse % true if "inpress" sub-mode. +\newif\ifrepr@nt \repr@ntfalse % true if "reprint" sub-mode. + +\newif\iftitlep@ge \titlep@gefalse % true if has own titlepage +\newif\if@non \@nonfalse % true if anonymous +\newif\ifixpt \ixptfalse % true if trying to do 9 pt +\newif\if@nvited \@nvitedfalse % true if an invited paper + +% Main options +% ------------ +\DeclareOption{draft}{\ev@lfalse\subm@tfalse\dr@fttrue% + \typeout{ieee: `Draft' mode selected.}} +\DeclareOption{submission}{\ev@lfalse\dr@ftfalse\subm@ttrue% + \typeout{ieee: `Submission' mode selected.}} +\DeclareOption{compressed}{\ev@lfalse\dr@ftfalse\subm@tfalse\c@mpresstrue% + \typeout{ieee: `Compressed' mode selected.}} +\DeclareOption{final}{\ev@ltrue\dr@ftfalse\subm@tfalse% + \typeout{ieee: `Final' mode selected.}} +\DeclareOption{evaluation}{\ev@ltrue\dr@ftfalse\subm@tfalse% + \typeout{ieee: `Final' mode selected.}} % synonym for final + +% Sub options +% ----------- +\DeclareOption{technote}{\@technotetrue% + \typeout{ieee: `Technote' sub-mode selected.}} +\DeclareOption{internal}{\intern@ltrue\prepr@ntfalse\inpr@ssfalse\repr@ntfalse% + \typeout{ieee: `Internal-Review' sub-mode selected.}} +\DeclareOption{submitted}{\intern@lfalse\prepr@nttrue\inpr@ssfalse\repr@ntfalse% + \typeout{ieee: `Submitted' sub-mode selected.}} +\DeclareOption{preprint}{\intern@lfalse\prepr@nttrue\inpr@ssfalse\repr@ntfalse% + \typeout{ieee: `Submitted' sub-mode selected.}} % synonym for submitted +\DeclareOption{inpress}{\intern@lfalse\prepr@ntfalse\inpr@sstrue\repr@ntfalse% + \typeout{ieee: `Inpress' sub-mode selected.}} +\DeclareOption{reprint}{\intern@lfalse\prepr@ntfalse\inpr@ssfalse\repr@nttrue% + \typeout{ieee: `Reprint' sub-mode selected.}} + +% Misc options +% ------------ + % regular or compressed "=" spacing in +\def\eqnarr@ysep{\arraycolsep} % eqnarray (this is the default) + % NOTE: we must use "def" and not "=" + % as arraycolsep not yet defined. +\DeclareOption{narroweqnarray}{\gdef\eqnarr@ysep{0.28em\relax}% + \typeout{ieee: Narrow equation arrays selected.}} +\DeclareOption{inline}{\everymath{\thinmuskip=2mu plus 1mu + \medmuskip=3mu plus 1mu minus 2mu + \thickmuskip=4mu plus 2mu\relax}% + \typeout{ieee: Narrower inline equations selected.}} +\DeclareOption{notitlepage}{\titlep@gefalse% + \typeout{ieee: No separate title page.}} +\DeclareOption{titlepage}{\titlep@getrue% + \typeout{ieee: Use separate title page.}} +\DeclareOption{anonymous}{\@nontrue\AtBeginDocument{\glpexclude{biography}} + \typeout{ieee: Omit author information from paper.}} +\DeclareOption{invited}{\@nvitedtrue% + \typeout{ieee: (Invited Paper).}} + +\DeclareOption{9pt}{\ixpttrue% + \typeout{ieee: Trying to emulate old `9pt' document class.}} + +\DeclareOption*{\PassOptionsToClass{\CurrentOption}{article}} + +% Execution of Options/Package Loading +% ------------------------------------ +\newlength\narrowcol +\newlength\parindentsave % recover parindent in blsone text + +\ProcessOptions +\ifev@l % if "final" mode... + \if@technote\ixpttrue\typeout{ieee: Trying to emulate old `9pt' + document class.}\fi% + \LoadClass[twoside,final,twocolumn,10pt]{article} +\else % if "draft"/"submission"/(compressed) mode... + \ifixpt + \LoadClass[oneside,final,onecolumn,10pt]{article} + \else + \LoadClass[oneside,final,onecolumn,12pt]{article} + \fi +\fi +\RequirePackage[final]{graphicx} +\RequirePackage{ifthen} + +% Re-Definitions of English words which must be done before +% the Babel package (optional) is loaded. +% --------------------------------------------------------- +\def\keywordsname{Index Terms} +\def\indexterms#1{\def\keywordsname{#1}} +\def\appendicesname{Appendices} +\def\figurename{Fig.} + +% ************************************************************************** +% ***** Check Sub-Options for Compatibility w/ Main-Options ************ +% ************************************************************************** +\if@technote\ifev@l\else\ClassError{ieee}{`technote' sub-mode may be + used only with the `final' ^^Jmain-mode. It may not be used + with either the `draft,' `submission,' or ^^J`compressed' + main-modes}{}\endinput\fi\fi +\ifintern@l\ifdr@ft\ClassError{ieee}{`internal' sub-mode may be + used only with the ^^J`submission,' `compressed,' or `final' main-modes. + It may not be used ^^Jwith the `draft' main-mode}{}\endinput\fi\fi +\ifprepr@nt\ifc@mpress\else\ifev@l\else\ClassError{ieee}{`submitted' + sub-mode may be used only with the ^^J`compressed' or `final' + main-modes. It may not be used with either the ^^J`draft' or + `submission' main-modes}{}\endinput\fi\fi\fi +\ifinpr@ss\ifc@mpress\else\ifev@l\else\ClassError{ieee}{`inpress' + sub-mode may be used only with the `compressed' ^^Jor `final' + main-modes. It may not be used with either the `draft' or + ^^J`submission' main-modes}{}\endinput\fi\fi\fi +\ifrepr@nt\ifev@l\else\ClassError{ieee}{`reprint' + sub-mode may be used only with the `final' ^^Jmain-mode. It may not be + used with either the `draft,' `submission,' or ^^J`compressed' + main-modes}{}\endinput\fi\fi + +% ************************************************************************** +% ***** Page Layout Definition ***************************************** +% ************************************************************************** +%% Layout definitions (mostly) common to all options. + +\hoffset 0in \voffset 0in +\headheight 12pt \headsep 7mm +\marginparsep 10pt \marginparwidth 20pt +\marginparpush 25pt +\columnsep 4mm +\parindent 1.0em +\lineskip 1pt +\normallineskip 1pt +\def\baselinestretch{1} + +\partopsep \z@ +\topsep 1.3ex +\parsep \z@ +\itemsep \z@ + +\setlength{\parindentsave}{\parindent} + +\ifev@l % if "evaluation" mode + % if camera-ready or A4paper ... + \ifdim\paperwidth<211mm + \oddsidemargin -11.4mm \evensidemargin -11.4mm + % for regular US Letter, not camera-ready + \else + \oddsidemargin -8.45mm \evensidemargin -8.45mm + \fi + \ifrepr@nt + \textheight 237.5mm % leave 6mm for cpyright on first page + \else + \textheight 243.5mm + \fi + \voffset -0.5in + \textwidth 182.0mm + \topmargin -12pt + \setlength{\narrowcol}{89mm} +\else % if "draft"/"submission" mode... + \ifc@mpress % and "compressed" + \oddsidemargin -0.25in \evensidemargin -0.25in + \textheight 9in \textwidth 7in + \topmargin -0.25in + \setlength{\narrowcol}{7in} + \else % and NOT "compressed" + \renewcommand\baselinestretch{1.8}\renewcommand{\arraystretch}{0.8} + \parindent=1.8\parindent + \oddsidemargin 0pt \evensidemargin 0pt + \headheight 12pt \headsep 0.375in + \topmargin 0pt + \textheight 8.5in \textwidth 6.5in + \marginparsep 0in \marginparwidth 0pt + \marginparpush 5pt + \setlength{\narrowcol}{6.5in} + \fi +\fi + +\def\normalstyle{\rmfamily} + +% ************************************************************************** +% ***** Font Definition ************************************************ +% ************************************************************************** +%% The 9-point option is being faked since it is not supported by the +%% article base class. + +%% Check if we have selected 9 points +\ifixpt +\typeout{-- This is a 9 point document} +\gdef\@ptsize{9} +\def\@normalsize{\@setsize\normalsize{10.7pt}\ixpt\@ixpt +\abovedisplayskip 1em plus2pt minus5pt\belowdisplayskip \abovedisplayskip +\abovedisplayshortskip \z@ plus3pt\belowdisplayshortskip .6em plus3pt minus3pt +\topsep \belowdisplayshortskip%!PN +} +\def\small{\@setsize\small{9.12pt}\viiipt\@viipt} +\def\footnotesize{\@setsize\footnotesize{8.15pt}\viipt\@vipt} +\def\scriptsize{\@setsize\scriptsize{8pt}\vipt\@vpt} +\def\tiny{\@setsize\tiny{5pt}\vpt\@vpt} +\def\large{\@setsize\large{12pt}\xpt\@xpt} +\def\Large{\@setsize\Large{14pt}\xiipt\@xiipt} +\def\LARGE{\@setsize\LARGE{18pt}\xivpt\@xivpt} +\def\huge{\@setsize\huge{22pt}\xviipt\@xviipt} +\def\Huge{\@setsize\Huge{25pt}\xxpt\@xxpt} +\fi +%% +%% Check if we have selected 10 points +\def\@tempa{0}\if\@ptsize\@tempa +\typeout{-- This is a 10 point document} +\def\@normalsize{\@setsize\normalsize{11.9pt}\xpt\@xpt +\abovedisplayskip 1em plus2pt minus5pt\belowdisplayskip \abovedisplayskip +\abovedisplayshortskip \z@ plus3pt\belowdisplayshortskip .6em plus3pt minus3pt +\topsep \belowdisplayshortskip%!PN +} +\def\small{\@setsize\small{9.2pt}\viiipt\@viiipt} +\def\footnotesize{\@setsize\footnotesize{8.8pt}\viiipt\@viiipt} +\def\scriptsize{\@setsize\scriptsize{8pt}\viipt\@viipt} +\def\tiny{\@setsize\tiny{6pt}\vpt\@vpt} +\def\normalsize{\@setsize\normalsize{11.9pt}\xpt\@xpt} +\def\large{\@setsize\large{14pt}\xiipt\@xiipt} +\def\Large{\@setsize\Large{18pt}\xivpt\@xivpt} +\def\LARGE{\@setsize\LARGE{22pt}\xviipt\@xviipt} +\def\huge{\@setsize\huge{22pt}\xxpt\@xxpt} +\def\Huge{\@setsize\Huge{28pt}\xxvpt\@xxvpt} +\fi +%% +%% Check if we have selected 11 points +\def\@tempa{1}\if\@ptsize\@tempa +\typeout{-- This is an 11 point document} +\def\@normalsize{\@setsize\normalsize{13.6pt}\xipt\@xipt +\abovedisplayskip 1em plus2pt minus5pt\belowdisplayskip \abovedisplayskip +\abovedisplayshortskip \z@ plus3pt\belowdisplayshortskip .6em plus3pt minus3pt +\topsep \belowdisplayshortskip%!PN +} +\def\small{\@setsize\small{12pt}\xpt\@xpt} +\def\footnotesize{\@setsize\footnotesize{11pt}\ixpt\@ixpt} +\def\scriptsize{\@setsize\scriptsize{9.5pt}\viiipt\@viiipt} +\def\tiny{\@setsize\tiny{7pt}\vipt\@vipt} +\def\normalsize{\@setsize\normalsize{13.6pt}\xipt\@xipt} +\def\large{\@setsize\large{14pt}\xiipt\@xiipt} +\def\Large{\@setsize\Large{18pt}\xivpt\@xivpt} +\def\LARGE{\@setsize\LARGE{22pt}\xviipt\@xviipt} +\def\huge{\@setsize\huge{25pt}\xxpt\@xxpt} +\def\Huge{\@setsize\Huge{30pt}\xxvpt\@xxvpt} +\fi +%% +%% Check if we have selected 12 points +\def\@tempa{2}\if\@ptsize\@tempa +\typeout{-- This is a 12 point document} +\def\@normalsize{\@setsize\normalsize{14pt}\xiipt\@xiipt +\abovedisplayskip 1em plus3pt minus6pt\belowdisplayskip \abovedisplayskip +\abovedisplayshortskip \z@ plus3pt\belowdisplayshortskip .6em plus4pt minus4pt +\topsep \belowdisplayshortskip%!PN +} +\def\small{\@setsize\small{11.4pt}\xpt\@xpt} +\def\footnotesize{\@setsize\footnotesize{10pt}\ixpt\@ixpt} +\def\scriptsize{\@setsize\scriptsize{9pt}\viiipt\@viiipt} +\def\tiny{\@setsize\tiny{8pt}\vipt\@vipt} +\def\normalsize{\@setsize\normalsize{14pt}\xiipt\@xiipt} +\def\large{\@setsize\large{18pt}\xivpt\@xivpt} +\def\Large{\@setsize\Large{22pt}\xviipt\@xviipt} +\def\LARGE{\@setsize\LARGE{25pt}\xxpt\@xxpt} +\def\huge{\@setsize\huge{30pt}\xxvpt\@xxvpt} +\let\Huge=\huge +\fi + +\AtBeginDocument{\normalsize\normalstyle\ps@headings\pagenumbering{arabic}} + +% ************************************************************************** +% ***** List Definition ************************************************ +% ************************************************************************** +%% Change aspect of lists with +%% 1) \itemindent, label indentation wrt to left list margin +%% 2) \leftmargini, the indentation of the whole list (on left, first level) +\ifev@l + \itemindent -1em + \leftmargini 2em + \leftmarginii 1em + \leftmarginiii 1.5em + \leftmarginiv 1.5em + \leftmarginv 1.0em + \leftmarginvi 1.0em +\else + \itemindent -1em + \leftmargini 3em + \leftmarginii 3em + \leftmarginiii 3em + \leftmarginiv 3em + \leftmarginv 3em + \leftmarginvi 3em +\fi +%\itemindent 2em % Alternative values: sometimes used.. +%\leftmargini 0em +\labelsep 5pt +\leftmargin\leftmargini +\labelwidth \z@ + +\def\@listI{\leftmargin\leftmargini} \@listI +\def\@listi{\leftmargin\leftmargini \topsep \z@ plus 1pt minus 1pt} +\def\@listii{\leftmargin\leftmarginii\labelwidth\leftmarginii + \advance\labelwidth-\labelsep \topsep \z@} +\def\@listiii{\leftmargin\leftmarginiii\labelwidth\leftmarginiii + \advance\labelwidth-\labelsep \topsep \z@} +\def\@listiv{\leftmargin\leftmarginiv\labelwidth\leftmarginiv + \advance\labelwidth-\labelsep \topsep \z@} +\def\@listv{\leftmargin\leftmarginv\labelwidth\leftmarginv + \advance\labelwidth-\labelsep \topsep \z@} +\def\@listvi{\leftmargin\leftmarginvi\labelwidth\leftmarginvi + \advance\labelwidth-\labelsep \topsep \z@} + +\def\labelenumi{\theenumi.} \def\theenumi{\arabic{enumi}} +\def\labelenumii{(\theenumii)} \def\theenumii{\alph{enumii}} +\def\labelenumiii{\theenumiii.} \def\theenumiii{\roman{enumiii}} +\def\labelenumiv{\theenumiv.} \def\theenumiv{\Alph{enumiv}} +\def\p@enumii{\theenumi} +\def\p@enumiii{\theenumi(\theenumii)} +\def\p@enumiv{\p@enumiii\theenumiii} + +\def\labelitemi{$\scriptstyle\bullet$} +\def\labelitemii{\bf --} +\def\labelitemiii{$\ast$} +\def\labelitemiv{$\cdot$} + +%% \itemindent is set to \z@ by list, so define new temporary variable +\newdimen\tmpitemindent +\def\verse{\let\\=\@centercr + \list{}{\itemsep\z@ \itemindent -1.5em \listparindent \itemindent + \rightmargin\leftmargin\advance\leftmargin 1.5em}\item[]} +\let\endverse\endlist +\def\quotation{\list{}{\listparindent 1.5em \itemindent\listparindent + \rightmargin\leftmargin \parsep 0pt plus 1pt}\item[]} +\let\endquotation=\endlist +\def\quote{\list{}{\rightmargin\leftmargin}\item[]} +\let\endquote=\endlist +\def\@mklab#1{#1} +\def\description{\tmpitemindent\itemindent\list{}{\itemindent\tmpitemindent + \labelwidth\z@\def\makelabel##1{\hspace\labelsep\emph{##1}}}} +\def\enddescription{\endlist\par} +\def\enumerate{\tmpitemindent\itemindent\ifnum \@enumdepth >3 \@toodeep\else + \advance\@enumdepth \@ne \edef\@enumctr{enum\romannumeral\the\@enumdepth}% + \list{\csname label\@enumctr\endcsname}{\itemindent\tmpitemindent + \usecounter{\@enumctr}\def\makelabel##1{\hspace\labelsep\hfil{##1}}}\fi} +\def\endenumerate{\endlist\par} +\def\itemize{\tmpitemindent\itemindent\ifnum \@itemdepth >3 \@toodeep\else + \advance\@itemdepth\@ne + \edef\@itemitem{labelitem\romannumeral\the\@itemdepth}% + \list{\csname\@itemitem\endcsname}{\itemindent\tmpitemindent + \def\makelabel##1{\hspace\labelsep\hfil\emph{##1}}}\fi} +\def\enditemize{\endlist\par} + +\newif\if@restonecol +\def\titlepage{\@restonecolfalse\if@twocolumn\@restonecoltrue\onecolumn + \else \newpage \fi \thispagestyle{coverpagestyle}\c@page\z@} +\def\endtitlepage{\if@restonecol\twocolumn \else \newpage \fi% +\if@twoside\mbox{}\thispagestyle{coverpagestyle}\c@page\z@\cleardoublepage\fi} + +\arraycolsep 5pt +\tabcolsep 6pt +\arrayrulewidth .4pt +\doublerulesep 2pt +\tabbingsep\labelsep + +% ************************************************************************** +% ***** Footnote Definition ******************************************** +% ************************************************************************** +\skip\footins 10pt plus 5pt minus 2pt +\footnotesep 7pt +\footskip 6mm +\skip\@mpfootins = \skip\footins +\fboxsep = 3pt \fboxrule = .4pt +\long\def\@makefntext#1{\parindent .8em\indent$^{\@thefnmark}$#1} +\def\footnoterule{} + +% Reset baselinestretch within footnotes. +% Originally stolen from Stanford University thesis style. +% -------------------------------------------------------- +\long\def\@footnotetext#1{\insert\footins{\blsone% + \footnotesize\interlinepenalty\interfootnotelinepenalty + \splittopskip\footnotesep + \splitmaxdepth \dp\strutbox \floatingpenalty \@MM + \hsize\columnwidth \@parboxrestore + \edef\@currentlabel{\csname p@footnote\endcsname\@thefnmark}\@makefntext + \let\par\\ + {\rule{\z@}{\footnotesep}\ignorespaces + #1\strut}}} + +% ************************************************************************** +% ***** Keep track of Sections ***************************************** +% ************************************************************************** +\if@technote + \setcounter{secnumdepth}{3} +\else + \setcounter{secnumdepth}{4} +\fi + +\def\thesection{\@Roman\c@section} +\def\thesubsection{\Alph{subsection}} +\def\thesubsubsection{\thesubsection.\arabic{subsubsection}} +\def\thesubsubsectiondis{\Alph{subsection}.\arabic{subsubsection}} +\def\theparagraph{\thesubsubsection.\alph{paragraph}} +\def\theparagraphdis{\thesubsubsectiondis.\alph{paragraph}} + +\def\theequation{\arabic{equation}} + +% ************************************************************************** +% ***** Table of Contents, List of Figures/Tables Definitions ********** +% ************************************************************************** +\def\@pnumwidth{1.55em} +\def\@tocrmarg {2.55em} +\def\@dotsep{4.5} +\setcounter{tocdepth}{3} + +\def\tableofcontents{\section*{\contentsname}\@starttoc{toc}} +\def\l@section#1#2{\addpenalty{\@secpenalty} \addvspace{1.0em plus 1pt} + \@tempdima 1.8em \begingroup \parindent \z@ \rightskip \@pnumwidth + \parfillskip-\@pnumwidth \bf\leavevmode #1\hfil\hbox to\@pnumwidth{\hss #2} + \par \endgroup} +\def\l@subsection{\@dottedtocline{2}{1.5em}{2.3em}} +\def\l@subsubsection{\@dottedtocline{3}{3.8em}{3.2em}} +\def\listoffigures{\section*{\listfigurename}\@starttoc{lof}} +\def\l@figure{\@dottedtocline{1}{1em}{1.8em}} +\def\listoftables{\section*{\listtablename}\@starttoc{lot}} +\let\l@table\l@figure + +% ************************************************************************** +% ***** Float Definitions ********************************************** +% ************************************************************************** +%% Normal Floats %% Double Column Floats +\floatsep 12pt plus 2pt minus 2pt \dblfloatsep 12pt plus 2pt minus 2pt +\textfloatsep 20pt plus 2pt minus 4pt \dbltextfloatsep 20pt plus 2pt minus 4pt +%\@maxsep 20pt \@dblmaxsep 20pt %!PN +\@fptop 0pt plus 1fil \@dblfptop 0pt plus 1fil +\@fpsep 8pt plus 2fil \@dblfpsep 8pt plus 2fil +\@fpbot 0pt plus 1fil \@dblfpbot 0pt plus 1fil +\def\topfraction{1.0} \def\dbltopfraction{1.0} +\def\floatpagefraction{0.8} \def\dblfloatpagefraction{0.8} +\setcounter{topnumber}{2} \setcounter{dbltopnumber}{4} +% +\intextsep 12pt plus 2pt minus 2pt +\setcounter{bottomnumber}{2} +\def\bottomfraction{.4} +\setcounter{totalnumber}{4} +\def\textfraction{.2} + +% Reset baselinestretch within floats. +% Originally stolen from Stanford University thesis style. +% -------------------------------------------------------- +\def\@xfloat#1[#2]{\ifhmode \@bsphack\@floatpenalty -\@Mii\else + \@floatpenalty-\@Miii\fi\def\@captype{#1}\ifinner + \@parmoderr\@floatpenalty\z@ + \else\@next\@currbox\@freelist{\@tempcnta\csname ftype@#1\endcsname + \multiply\@tempcnta\@xxxii\advance\@tempcnta\sixt@@n + \@tfor \@tempa :=#2\do + {\if\@tempa h\advance\@tempcnta \@ne\fi + \if\@tempa t\advance\@tempcnta \tw@\fi + \if\@tempa b\advance\@tempcnta 4\relax\fi + \if\@tempa p\advance\@tempcnta 8\relax\fi + }\global\count\@currbox\@tempcnta}\@fltovf\fi + \global\setbox\@currbox\vbox\bgroup + \def\baselinestretch{1}\small\normalsize + \hsize\columnwidth \@parboxrestore} + +% ************************************************************************** +% ***** Caption Definition ********************************************* +% ************************************************************************** +% some journals do not have centered captions for figures. +\newif\ifc@ptionleft \c@ptionlefttrue +\def\leftfigcaptions{\c@ptionlefttrue} +\def\centerfigcaptions{\c@ptionleftfalse} + +\long\def\caption{\refstepcounter\@captype \@dblarg{\@caption\@captype}} + +\long\def\@caption#1[#2]#3{\par\addcontentsline{\csname ext@#1\endcsname}{#1}{% + \protect\numberline{\csname the#1\endcsname}{\ignorespaces #2}} + \begingroup \@parboxrestore \normalsize + \@makecaption{\csname fnum@#1\endcsname}{\ignorespaces #3}{#1}\par + \endgroup} + +\def\tablestring{table} +\def\figurestring{figure} + +% changed by GLP to allow table captions to be set to a specific maximum +% width "\captionwidth", if defined. +\newlength{\captionindent} +\long\def\@makecaption#1#2#3{ +\ifx\figurestring#3 + \vskip 5pt + \setbox\@tempboxa\hbox{\small #1.~ #2} + \ifdim \wd\@tempboxa >\hsize + \setbox\@tempboxa\hbox{\small #1.~ } + %\setlength\captionindent{\wd\@tempboxa} \divide\captionindent by 2 + %\parbox[t]{\hsize}{\small \hangindent \captionindent \hangafter=1% + \parbox[t]{\hsize}{\small + \unhbox\@tempboxa#2} + \else \hbox + to\hsize{\small\ifc@ptionleft\else\hfil\fi\box\@tempboxa\hfil} + \fi +\else + \begin{center} + \ifx\captionwidth\undefined {\small #1}\\{\small\scshape #2} + \else + \begin{minipage}{\captionwidth} + \begin{center}{\small #1}\\{\small\scshape #2}\end{center} + \end{minipage} + \fi + \end{center}\vskip 4pt +\fi} + +\def\thefigure{\@arabic\c@figure} +\def\fps@figure{tbp} +\def\ftype@figure{1} +\def\ext@figure{lof} +\def\fnum@figure{\figurename\ \thefigure} +%\def\figure{\@float{figure}} % GLP +%\let\endfigure\end@float +\@namedef{figure*}{\@dblfloat{figure}} +\@namedef{endfigure*}{\end@dblfloat} + +\def\thetable{\@Roman\c@table} +\def\fps@table{tbp} +\def\ftype@table{2} +\def\ext@table{lot} +\def\fnum@table{TABLE~\thetable} +\def\table{\@float{table}} +\let\endtable\end@float +\@namedef{table*}{\@dblfloat{table}} +\@namedef{endtable*}{\end@dblfloat} + +% ************************************************************************** +% ***** Header/Footer Definition *************************************** +% ************************************************************************** +% compute the time in hours and minutes; make new vars \timehh and \timemm +\newcount\timehh\newcount\timemm\timehh=\time\divide\timehh by 60 +\timemm=\time\count255=\timehh\multiply\count255 by-60 +\advance\timemm by \count255 +\ifnum\timehh=12\def\apm{pm}\else +\ifnum\timehh>12\def\apm{pm}\advance\timehh by-12\else +\def\apm{am}\fi\fi +\def\t@me{\number\timehh\,:\,\ifnum\timemm<10 0\fi\number\timemm\,\apm} + +% default definitions +% ------------------- +\def\theevenhe@d{\footnotesize\thepage \hfil \leftmark\hbox{}} +\def\theoddhe@d{\hbox{}\footnotesize\rightmark \hfil \thepage} +\def\theevenf@@t{} +\def\theoddf@@t{} + +\def\theeventphe@d{\footnotesize\thepage \hfil \hbox{}} +\def\theoddtphe@d{\hbox{}\footnotesize \hfil \thepage} +\def\theeventpf@@t{} +\def\theoddtpf@@t{} + +\def\theevencphe@d{} +\def\theoddcphe@d{} +\def\theevencpf@@t{} +\def\theoddcpf@@t{} + +\def\internalmsg{Preliminary version for evaluation: Please do not + circulate without the permission of the author(s)} +\def\submittedmsg{SUBMITTED FOR PUBLICATION TO:} +\def\acceptedmsg{ACCEPTED FOR PUBLICATION:} +\def\inpressmsg{(IN PRESS)} +\def\reprintmsg{REPRINTED FROM:} + +% default cover page style (optional cover page) +% ---------------------------------------------- +\def\ps@coverpagestyle{ + \def\@oddhead{\theoddcphe@d} \def\@evenhead{\theevencphe@d} + \def\@oddfoot{\theoddcpf@@t} \def\@evenfoot{\theevencpf@@t} +} + +% default title page style (first page of paper) +% ---------------------------------------------- +\def\ps@titlepagestyle{ + \def\@oddhead{\theoddtphe@d} \def\@evenhead{\theeventphe@d} + \def\@oddfoot{\theoddtpf@@t} \def\@evenfoot{\theeventpf@@t} +} + +% default regular page style +% -------------------------- +\if@twoside + \def\ps@headings{ + \def\@oddhead{\theoddhe@d} + \def\@evenhead{\theevenhe@d} + \def\@oddfoot{\theoddf@@t} \def\@evenfoot{\theevenf@@t} + } +\else + \def\ps@headings{ + \def\@oddhead{\theoddhe@d} + \def\@oddfoot{\theoddf@@t} + \def\@evenhead{} \def\@evenfoot{} + } +\fi + +% For draft mode (no sub-modes allowed) +% ------------------------------------- +\ifdr@ft + \def\leftmark{\sh@rttitle}\let\rightmark\leftmark + \def\theoddf@@t{\footnotesize\today---\t@me\hfil DRAFT} + \def\theevenf@@t{\footnotesize DRAFT\hfil\today---\t@me} + \def\theoddtpf@@t{\footnotesize\today---\t@me\hfil DRAFT} + \def\theeventpf@@t{\footnotesize DRAFT\hfil\today---\t@me} +\fi + +% For submission mode (default plus internal sub-modes allowed) +% ------------------------------------------------------------- +\ifsubm@t + \def\leftmark{\sh@rttitle}\def\rightmark{\titl@line} + \ifintern@l + \def\theeventphe@d{\footnotesize\thepage \hfil \rightmark\hbox{}} + \def\theoddtphe@d{\hbox{}\footnotesize\rightmark \hfil \thepage} + \def\rightmark{\vbox to 0pt{\vss\hbox{\internalmsg} \hbox{\sh@rttitle}}} + \def\leftmark{\vbox to 0pt{\vss\hbox{\internalmsg} + \hbox{\phantom{\internalmsg}\llap{\sh@rttitle}}}} + \else % put date on first page. + \edef\TODAY{\uppercase{\today}} + \def\theeventphe@d{\footnotesize\thepage \hfil \submittedmsg\ + \@journal\@titletext, \TODAY} + \def\theoddtphe@d{\footnotesize\submittedmsg\ + \@journal\@titletext, \TODAY\hfil \thepage} + \def\theevencphe@d{\footnotesize\hbox{} \hfil \submittedmsg\ + \@journal\@titletext, \TODAY} + \def\theoddcphe@d{\footnotesize\submittedmsg\ + \@journal\@titletext, \TODAY\hfil \hbox{}} + \fi +\fi + +% For compressed mode (default, internal, submitted and +% inpress sub-modes allowed) +% ----------------------------------------------------- +\ifc@mpress + \def\leftmark{\sh@rttitle}\def\rightmark{\titl@line} + \ifintern@l + \def\theeventphe@d{\footnotesize\thepage \hfil \rightmark\hbox{}} + \def\theoddtphe@d{\hbox{}\footnotesize\rightmark \hfil \thepage} + \def\rightmark{\vbox to 0pt{\vss\hbox{\internalmsg} \hbox{\sh@rttitle}}} + \def\leftmark{\vbox to 0pt{\vss\hbox{\internalmsg} + \hbox{\phantom{\internalmsg}\llap{\sh@rttitle}}}} + \fi + \ifprepr@nt + \edef\TODAY{\uppercase{\today}} + \def\theeventphe@d{\footnotesize\thepage \hfil \submittedmsg\ + \@journal\@titletext, \TODAY} + \def\theoddtphe@d{\footnotesize\submittedmsg\ + \@journal\@titletext, \TODAY\hfil \thepage} + \def\theevencphe@d{\footnotesize\hbox{} \hfil \submittedmsg\ + \@journal\@titletext, \TODAY} + \def\theoddcphe@d{\footnotesize\submittedmsg\ + \@journal\@titletext, \TODAY\hfil \hbox{}} + \fi + \ifinpr@ss + \def\leftmark{\acceptedmsg\ \@journal\@titletext, \inpressmsg} + \def\theeventphe@d{\footnotesize\thepage \hfil \leftmark\hbox{}} + \def\theoddtphe@d{\hbox{}\footnotesize\leftmark \hfil \thepage} + \fi +\fi + +% For final (evaluate) mode (default, techreport, internal, +% submitted, inpress and reprint sub-modes allowed) +% --------------------------------------------------------- +\ifev@l + \edef\TODAY{\uppercase{\today}} + \def\leftmark{\@journal\@titletext}\def\rightmark{\titl@line} + \def\theeventphe@d{\footnotesize\thepage \hfil \leftmark\hbox{}} + \def\theoddtphe@d{\hbox{}\footnotesize\leftmark \hfil \thepage} + \if@technote % make header a little bigger + \def\theevenhe@d{\small\thepage \hfil \leftmark\hbox{}} + \def\theoddhe@d{\hbox{}\small\rightmark \hfil \thepage} + \def\theeventphe@d{\small\thepage \hfil \leftmark\hbox{}} + \def\theoddtphe@d{\hbox{}\small\leftmark \hfil \thepage} + \fi + \ifintern@l + \def\theeventphe@d{\footnotesize\thepage \hfil \rightmark\hbox{}} + \def\theoddtphe@d{\hbox{}\footnotesize\rightmark \hfil \thepage} + \def\rightmark{\vbox to 0pt{\vss\hbox{\internalmsg} \hbox{\sh@rttitle}}} + \def\leftmark{\vbox to 0pt{\vss\hbox{\internalmsg} + \hbox{\phantom{\internalmsg}\llap{\sh@rttitle}}}} + \fi + \ifprepr@nt + \def\leftmark{\submittedmsg\ \@journal\@titletext, \TODAY} + \fi + \ifinpr@ss + \def\leftmark{\acceptedmsg\ \@journal\@titletext, \inpressmsg} + \fi + \ifrepr@nt + % reset page size on second and following pages b/c no copyright info + \let\oldshipout\shipout + \gdef\shipout{\global\textheight 243.5mm\oldshipout} + \def\theeventpf@@t{\footnotesize\hfil\@ieeecopyright\hfil} + \def\theoddtpf@@t{\footnotesize\hfil\@ieeecopyright\hfil} + \def\leftmark{\reprintmsg\ \@journal\@titletext} + \fi +\fi + +%% Defines the command for putting the header. footernote{TEXT} is the same +%% as markboth{TEXT}{TEXT}. Here for compatibility with other style files. +\def\markboth#1#2{\def\leftmark{#1}\def\rightmark{#2}} +\def\footernote#1{\markboth{#1}{#1}} + +% ************************************************************************** +% ***** Citation/Bibliography Definitions ****************************** +% ************************************************************************** +%% separate citations with "], [" +\def\@citex[#1]#2{\if@filesw\immediate\write\@auxout{\string\citation{#2}}\fi +\def\@citea{}\@cite{\@for\@citeb:=#2\do {\@citea\def\@citea{], +[}\@ifundefined {b@\@citeb}{{\bf ?}\@warning {Citation `\@citeb' on +page \thepage \space undefined}}% +{\csname b@\@citeb\endcsname}}}{#1}} + +\def\@cite#1#2{[{#1\if@tempswa, #2\fi}]} + +%% Allow short (name-less) citations, when used in conjunction with a +%% bibliography style that creates labels like \citename{, } +\let\@internalcite\cite +\def\cite{\def\citename##1{##1}\@internalcite} +\def\shortcite{\def\citename##1{}\@internalcite} +\def\@biblabel#1{\def\citename##1{##1}[#1]\hfill} + +\def\thebibliography#1{\section*{\refname}\footnotesize\list + {\hss[\arabic{enumi}]}{\settowidth\labelwidth{[#1]}\leftmargin\labelwidth + \advance\leftmargin\labelsep \itemsep 0pt plus .5pt + \usecounter{enumi}} + \def\newblock{\hskip .11em plus .33em minus .07em} + \sloppy\clubpenalty4000\widowpenalty4000 + \sfcode`\.=1000\relax + \ifev@l\else\normalsize\fi %added by GLP +} +\let\endthebibliography=\endlist + +% ************************************************************************** +% ***** Appendix/Appendices Definitions ******************************** +% ************************************************************************** +\newcounter{numappendices}\setcounter{numappendices}{0} +\newif\ifappendix \appendixfalse +%% appendix command for one single appendix +\def\appendix{\par + \appendixtrue + \typeout{appendices: \arabic{numappendices}} + \setcounter{section}{0}\setcounter{subsection}{0} + \gdef\thesection{\Alph{section}} + \ifnum \value{numappendices}>1 + \section*{\appendicesname} + \else + \section*{\appendixname} + \fi + \setcounter{numappendices}{0} +} +%% appendices command for multiple appendicies +\def\appendices{\par + \appendixtrue + \typeout{appendices: \arabic{numappendices}} + \setcounter{section}{0}\setcounter{subsection}{0} + \gdef\thesection{\Alph{section}} \section*{\appendicesname} + \setcounter{numappendices}{0} +} +\AtEndDocument{\if@filesw\immediate\write\@auxout{\string\setcounter{numappendices}{\arabic{numappendices}}}\fi} + +% ************************************************************************** +% ***** Title Definitions ********************************************** +% ************************************************************************** +\def\titl@line{\sh@rttitle} %for the header at the top of the page. + +\def\@title{\typeout{ieee: Warning! No \noexpand\title given!}} +\def\title{\@ifnextchar [{\titlea}{\titleb}}%] + +\def\set@title#1{\gdef\@title{#1}\global\def\set@title##1{}} +\def\setsh@rttitle#1{\gdef\sh@rttitle{#1}\global\def\setsh@rttitle##1{}} +\def\titlea[#1]#2{\set@title{#2}\setsh@rttitle{\uppercase{#1}}} +\def\titleb#1{\set@title{#1}\setsh@rttitle{\uppercase{#1}}} + +\def\authorinfo#1{\let\\\relax\thanks{#1}} + +\ifev@l + \if@technote + \def\member#1{} + \else + \def\member#1{, \emph{#1, IEEE}} + \fi +\else + \def\member#1{} +\fi + +\def\and{\unskip% % \begin{tabular} +\end{tabular}% +\hskip 0pt plus 0.1pt% +\begin{tabular}[t]{@{}c@{}}\ }% + +\def\@author{\typeout{ieee: Warning! No \noexpand\author given!}} +\def\author{\@ifnextchar [{\authora}{\authorb}}%] +\def\set@author#1{\gdef\@author{#1}\global\def\set@author##1{}} +\def\settitl@line#1{\gdef\titl@line{#1}\global\def\settitl@line##1{}} +\def\authora[#1]#2{\set@author{#2}\if@non\else\settitl@line{#1: \sh@rttitle}\fi} +\def\authorb#1{\set@author{#1}} + +\def\date#1{\def\today{#1}\edef\TODAY{\uppercase{\today}}} + +\long\def\maketitle{% + \begingroup + \let\@thanks\@empty + \renewcommand\thefootnote{} % the \thanks{} mark type is empty + \iftitlep@ge\begin{titlepage}\@maketitlepage\@thanks\end{titlepage}% + \let\@thanks\@empty\fi + \thispagestyle{titlepagestyle} + \if@twocolumn + \if@technote + %\if@twoside\newpage\cleardoublepage\else\newpage\fi% + \newpage\global\@topnum\z@ + \ifrepr@nt + \ifx\@loginfo\undefined\typeout{ieee: Warning! No \noexpand\loginfo + given!}\else\let\\\relax\thanks{\@loginfo}\fi% + \fi + \@maketitle + \else + \ifnum \col@number=\@ne + \ifrepr@nt + \ifx\@loginfo\undefined\typeout{ieee: Warning! No \noexpand\loginfo + given!}\else\let\\\relax\thanks{\@loginfo}\fi% + \fi + \@maketitle + \else \twocolumn[% + \ifrepr@nt% + \ifx\@loginfo\undefined\typeout{ieee: Warning! No \noexpand\loginfo% + given!}\else\let\\\relax\thanks{\@loginfo}\fi% + \fi% + \@maketitle]% + \fi + \fi + \else + \newpage + \global\@topnum\z@ % Prevents figures from going at top of page. + \ifrepr@nt + \ifx\@loginfo\undefined\typeout{ieee: Warning! No \noexpand\loginfo + given!}\else\let\\\relax\thanks{\@loginfo}\fi + \fi + \@maketitle + \fi + \thispagestyle{titlepagestyle}% + \@thanks + \endgroup + \setcounter{footnote}{0}% + \global\let\thanks\relax \global\let\maketitle\relax + \global\let\@maketitle\relax \global\let\@thanks\@empty + \global\let\@author\@empty \global\let\@date\@empty + \global\let\@title\@empty \global\let\title\relax + \global\let\author\relax \global\let\date\relax + \global\let\and\relax +} + +\long\def\@maketitle{\unskip\newpage% + \begin{center}\blsone + \let \footnote \thanks + \if@technote + {\bfseries\@title\par}\if@non\else\vskip 1.3em{\lineskip .5em + \noindent\begin{tabular}[t]{@{}c@{}}\@author\end{tabular}}\fi\par + \else\unskip + \noindent{\Huge\@title\par}% + \if@non\else\vskip1.0em% + \noindent{\large\lineskip .5em% + \begin{tabular}[t]{@{}c@{}}\@author\end{tabular}}% + \fi\par% + \if@nvited\vskip1.0em\noindent\emph{\large(Invited Paper)}\par\fi + \fi + \ifrepr@nt + \ifx\@lognumber\undefined\typeout{ieee: Warning! No + \noexpand\pubitemident or \noexpand\lognumber + given!}\else\thanks{\@lognumber}\fi% + \fi + \end{center}\par\vskip 0.5em}% + +\long\def\@maketitlepage{\newpage% + \mbox{}\vfil + \begin{center}\blsone + \let \footnote \thanks + \if@technote + {\bfseries\@title\par}\vskip 1.3em{\lineskip .5em + \noindent\begin{tabular}[t]{@{}c@{}}\@author\end{tabular}\par} + \else + \vskip0.2em{\Huge\@title\par}\vskip1.0em% + \iftitlep@ge\vfil\fi + \noindent{\large\lineskip .5em% + \begin{tabular}[t]{@{}c@{}}\@author\end{tabular}\par}% + \fi + \end{center}\par\vfil\mbox{}} + +\def\@journal{\typeout{ieee: Warning! No \noexpand\journal given!}} +\def\journal#1{\def\@journal{\uppercase{#1}}} + +\def\@ieeecopyright{\typeout{ieee: Warning! No \noexpand\ieeecopyright given!}} +\def\ieeecopyright#1{\def\@ieeecopyright{#1}} + +\def\lognumber#1{\def\@lognumber{IEEE Log Number #1.}} +\def\pubitemident#1{\def\@lognumber{Publisher Item Identifier #1.}} +\long\def\loginfo#1{\long\def\@loginfo{\hbox{\vrule height 3ex width \z@}#1}} + +\def\sh@rttitle{} +\def\@titletext{} +\def\titletext#1{\def\@titletext{#1}} + +\def\firstpage#1{\setcounter{page}{#1}} + +% ************************************************************************** +% ***** Abstract Definition ******************************************** +% ************************************************************************** +\def\abstract{% + \if@twocolumn + \small\bfseries{\itshape\abstractname\/---}% + \else + \begin{center}\vspace{-0.8em}\small\bf\abstractname\end{center} + \quotation\small + \fi\ignorespaces} +\def\endabstract{\vspace{0.6em}\par\if@twocolumn\else\endquotation\fi + \normalsize\normalstyle} + +% ************************************************************************** +% ***** Keywords Definition ******************************************** +% ************************************************************************** +\def\keywords{\vspace{-.3em} + \if@twocolumn + \small\bfseries{\itshape\keywordsname\/---}% + \else + \begin{center}\small\bf\keywordsname\end{center}\quotation\small + \fi\ignorespaces} +\def\endkeywords{\vspace{0.6em}\par\if@twocolumn\else\endquotation\fi + \normalsize\normalstyle} + +% ************************************************************************** +% ***** Fix Section Numbering ****************************************** +% ************************************************************************** +\gdef\@punct{.\ \ } % Punctuation after run-in section heading +\def\@sect#1#2#3#4#5#6[#7]#8{% + \ifnum #2>\c@secnumdepth + \def\@svsec\@empty + \else + \refstepcounter{#1}% + \protected@edef\@svsec{% + %\ifnum #2=1\Roman{#1}.\fi\ifnum #2=2\Alph{#1}.\fi + \ifnum #2=1\thesection.\fi + \ifnum #2=2\thesubsection.\fi + \ifnum #2>2{\csname the#1dis\endcsname}\if@technote.\fi\fi \hskip .5em} + \ifnum #2=1\ifappendix\stepcounter{numappendices}\fi\fi + \fi + \@tempskipa #5\relax + \ifdim \@tempskipa>\z@ + \begingroup #6\relax + \@hangfrom{\hskip #3\relax\@svsec}{\interlinepenalty \@M #8\par} + \endgroup + \csname #1mark\endcsname{#7} + \addcontentsline{toc}{#1}{\ifnum #2>\c@secnumdepth\else + \protect\numberline{\csname the#1\endcsname}\fi#7} + \else + \def\@svsechd{#6\hskip #3\@svsec #8\@punct\csname #1mark\endcsname{#7} + \addcontentsline{toc}{#1}{\ifnum #2>\c@secnumdepth \else + \protect\numberline{\csname the#1\endcsname}\fi#7}} + \fi + \@xsect{#5}} + +\def\@ssect#1#2#3#4#5{\@tempskipa #3\relax + \ifdim \@tempskipa>\z@ + \begingroup #4\@hangfrom{\hskip #1}{\interlinepenalty \@M #5\par}\endgroup + \else \def\@svsechd{#4\hskip #1\relax #5\@punct}\fi + \@xsect{#3}} + +% ************************************************************************** +% ***** Section Definitions ******************************************** +% ************************************************************************** +\def\section{\@startsection{section}{1}{\z@}{2.0ex plus .5ex + minus .2ex}{1.0ex plus .2ex}{\centering\scshape}} +\def\subsection{\@startsection{subsection}{2}{\z@}{2.0ex plus .5ex + minus .2ex}{1.0ex plus .2ex}{\itshape}} +\if@technote + \def\subsubsection{\@startsection{subsubsection}{3}{\z@}{2.0ex plus .5ex + minus .1ex}{0pt}{\itshape}} +\else + \def\subsubsection{\@startsection{subsubsection}{3}{\z@}{2.0ex plus .5ex + minus .2ex}{1.0ex plus .2ex}{\normalstyle}} + \def\paragraph{\@startsection{paragraph}{4}{\z@}{1.0ex plus .5ex + minus .2ex}{0ex}{\normalstyle}} +\fi + +% ************************************************************************** +% ***** Special Environment Definitions ******************************** +% ************************************************************************** +\def\QED{\mbox{\rule[0pt]{1.5ex}{1.5ex}}} +\def\proof{\noindent\hspace{1em}{\it Proof: }} +\def\endproof{\hspace*{\fill}~\QED\par\endtrivlist\unskip} +\def\@begintheorem#1#2{\tmpitemindent\itemindent\topsep 0pt\normalstyle\trivlist + \item[\hskip \labelsep{\indent\it #1\ #2:}]\itemindent\tmpitemindent} +\def\@opargbegintheorem#1#2#3{\tmpitemindent\itemindent\topsep 0pt\normalstyle \trivlist + \item[\hskip\labelsep{\indent\it #1\ #2\ \normalstyle(#3)}]\itemindent\tmpitemindent} +\def\@endtheorem{\endtrivlist\unskip} + +% ************************************************************************** +% ***** Special Environment Definitions ******************************** +% ************************************************************************** +\if@twoside\else\raggedbottom\fi + +%% Definition for Big letter at the beginning of a paragraph +%% +\def\PARstart#1#2 {\begingroup\def\par{\endgraf\endgroup\lineskiplimit=0pt} + \setbox2=\hbox{\uppercase{#2} }\newdimen\tmpht \tmpht \ht2 + \advance\tmpht by \baselineskip\font\hhuge=cmr10 at \tmpht + \setbox1=\hbox{{\hhuge #1}} + \count7=\tmpht \count8=\ht1\divide\count8 by 1000 \divide\count7 by\count8 + \tmpht=.001\tmpht\multiply\tmpht by \count7\font\hhuge=cmr10 at \tmpht + \setbox1=\hbox{{\hhuge #1}} \noindent \hangindent1.05\wd1 + \hangafter=-2 {\hskip-\hangindent \lower1\ht1\hbox{\raise1.0\ht2\copy1}% + \kern-0\wd1}\copy2\lineskiplimit=-1000pt} + +\def\PARstartCal#1#2 {\begingroup\def\par{\endgraf\endgroup\lineskiplimit=0pt} + \setbox2=\hbox{\uppercase{#2} }\newdimen\tmpht \tmpht \ht2 + \advance\tmpht by \baselineskip\font\hhuge=cmsy10 at \tmpht + \setbox1=\hbox{{\hhuge #1\/}} + \count7=\tmpht \count8=\ht1\divide\count8 by 1000 \divide\count7 by\count8 + \tmpht=.001\tmpht\multiply\tmpht by \count7\font\hhuge=cmsy10 at \tmpht + \setbox1=\hbox{{\hhuge #1\/}} \noindent \hangindent1.05\wd1 + \hangafter=-2 {\hskip-\hangindent \lower1\ht1\hbox{\raise1.0\ht2\copy1}% + \kern-0\wd1}\copy2\lineskiplimit=-1000pt} + +\def\PARstartLyX#1{\PARstart #1} +\def\PARstartCalLyX#1{\PARstartCal #1} + +\if@technote\def\PARstart#1#2{#1#2}\fi % if technical note, disable it +\if@technote\def\PARstartCal#1#2{#1#2}\fi % if technical note, disable it +\if@technote\def\PARstartLyX#1{#1}\fi % if technical note, disable it +\if@technote\def\PARstartCalLyx#1{#1}\fi % if technical note, disable it + +% ************************************************************************** +% ***** Misc. Definitions ********************************************** +% ************************************************************************** +%Restore single spacing +\newcommand{\blsone}{\renewcommand\baselinestretch{1}% + \renewcommand\arraystretch{1.2}\setlength{\parindent}{\parindentsave}% + \normalsize} +\newcommand{\capitem}[1]{{\hspace{0.2ex}(#1)}~} +\newcommand{\insdate}{} + +% ************************************************************************** +% ***** MATH Definitions *********************************************** +% ************************************************************************** +\def\eqnarray{% + \stepcounter{equation}% + \def\@currentlabel{\p@equation\theequation}% + \global\@eqnswtrue + \m@th + \global\@eqcnt\z@ + \tabskip\@centering + \let\\\@eqncr + $$\everycr{}\halign to\displaywidth\bgroup + \hskip\@centering$\displaystyle\tabskip\z@skip{##}$\@eqnsel + &\global\@eqcnt\@ne\hskip \eqnarr@ysep\hfil${##}$\hfil + &\global\@eqcnt\tw@ \hskip \eqnarr@ysep + $\displaystyle{##}$\hfil\tabskip\@centering + &\global\@eqcnt\thr@@ \hb@xt@\z@\bgroup\hss##\egroup + \tabskip\z@skip + \cr +} +\def\endeqnarray{% + \@@eqncr + \egroup + \global\advance\c@equation\m@ne + $$\@ignoretrue +} + +% ************************************************************************** +% ***** Biography Definitions ****************************************** +% ************************************************************************** +% This is the main code for the biography environment of the IEEE +% transactions class. The previous biography code had some known +% problems which were difficult to fix. The crux of the issue was that +% the photo frame was overlaid by text when \baselinestretch>1 or when +% the biography consisted of multiple short paragraphs. +% +% The fix was done by extracting code from the excellent package: +% 'picinpar.sty' version 1.2a as of july 13, 1993 +% by Friedhelm Sowa +% +% (At least most of) The bugs you find in this code were introduced +% unwittingly by myself. +% +%---------------- +% Known problems: +% +% - Don't use multiple blank lines to separate paragraphs. A single +% blank line works well, but multiple blank lines will confuse +% the code. This has something to do with the \def\par{\\\indent} +% line, but I can't think of an appropriate fix. Similarly, make +% sure the environment doesn't end with an extra blank line. +% - Don't use \samepage +% - Use \footnotemark within and \footnotetext outside the +% window-environment instead of \footnote +% - When using the epic-package load picinpar before epic +% like \documentstyle[...,picinpar,epic]{...} +% +% Counts +\newcount\br \newcount\nb \newcount\tcdsav \newcount\tcl \newcount\tcd +\newcount\tcn \newcount\cumtcl +% Dimens +\newdimen\rtside \newdimen\hpic \newdimen\vpic \newdimen\strutilg +\newdimen\picwd \newdimen\topheight \newdimen\ilg \newdimen\lpic +\newdimen\lwindowsep \newdimen\rwindowsep % VK 10 Feb 93 +\lwindowsep0.5\baselineskip % " +\rwindowsep0.5\baselineskip % " +\newdimen\cumpar +% Tokens +\newtoks\twa \newtoks\la \newtoks\ra \newtoks\ha \newtoks\pictoc +% Boxes +\newbox\rawtext \newbox\holder \newbox\windowbox \newbox\wartext +\newbox\finaltext \newbox\aslice \newbox\bslice \newbox\wbox +\newbox\wstrutbox \newbox\picbox \newbox\waslice \newbox\wbslice +\newbox\fslice + % Another strut +\def\wstrut{\relax\ifmmode\copy\wstrutbox\else\unhcopy\wstrutbox\fi} +% + +\def\getpic#1{\sbox{\@tempboxa}{\includegraphics{#1}}% +\newcount\tmpcta \tmpcta=\ht\@tempboxa% +\newcount\tmpctb \tmpctb=\wd\@tempboxa% +\divide\tmpctb by 100% +\divide\tmpcta by\tmpctb% +\ifnum\tmpcta>133% +\typeout{ieee: Biography picture `#1' too tall.}% +\frame{\hbox to 25mm{\hfil\resizebox{!}{32mm}{\usebox{\@tempboxa}}\hfil}}% +\else \ifnum\tmpcta<123% +\typeout{ieee: Biography picture `#1' too wide.}% +\frame{\vbox to 32mm{\vss\hbox{\resizebox{25mm}{!}{\usebox{\@tempboxa}}}\vss}}% +\else% +\resizebox{25mm}{32mm}{\usebox{\@tempboxa}} +\fi\fi} + +\long\def\biographyLyX#1{\if@non\else\begin{biography} #1\end{biography}\fi} + +\if@non + \long\def\biography{} +\else + \long\def\biography{\@ifnextchar [{\@biographyb}{\@biographya[{\unitlength + 1mm\hbox{\framebox(25,32){}}}]}} +\fi + +\long\def\@biographyb[#1]{\@biographya[\getpic{#1}]} + +\long\def\@biographya[#1]#2{\bgroup +\footnotesize\bigskip\bigskip\bigskip\parskip=0pt\par% +\rule{0pt}{35mm}\vspace*{-35mm}\par% garantees correct page breaking +\begin{main@bio}[{#1}]% +\noindent{\bf #2}% +} +\def\endbiography{\if@non\else\end{main@bio}\egroup\fi} + +\long\def\main@bio[#1]{% #1 is the material for setting a graphic box +\vskip\parskip\everypar{} +\global\cumpar=0pt +\global\cumtcl=0 + \tcd=0 + \rtside=0pt +% \hpic=\linewidth + \twa={} \la={} \ra={} \ha={} +\setbox\wbox=\hbox{(} +\computeilg +\pictoc={#1} +\setbox\windowbox=\vbox{\hbox{#1}} +\picwd=\wd\windowbox +\hpic=\picwd +\vpic=\ht\windowbox\advance\vpic\dp\windowbox +\rtside=\linewidth\advance\rtside-\picwd +\setbox\picbox=\vbox{\hsize=\hpic\vbox to\vpic{\box\windowbox}}% \vfill}}% + +\vpic=\ht\picbox\advance\vpic\dp\picbox +\ifdim\rtside>0pt\advance\rtside-\rwindowsep\fi % " +\global\br=\rtside +\ifnum\picwd=0 +\ifdim\vpic>0pt\picwd=\hpic +\else\vpic=\ht\picbox\advance\vpic\dp\picbox +\fi +\fi + \global\tcl=0 \lpic=0pt + \loop\global\advance\tcl by 1 \lpic=\tcl\baselineskip + \ifdim\lpic<\vpic\repeat + \vpic=\lpic + \global\cumtcl=\tcl +% +% Here we know exactly the number of indented lines and +% are able to generate the tokens for the \parshape list +% + \ifnum\br>0\ra={ 0pt \rtside}\fi + \ifnum\tcd>0\ha={ 0pt \linewidth}\fi + \ifnum\tcl<1\global\tcl=1\fi + \createparshapespec + \tcd=0 % restore the lintel + \global\tcdsav=0 +% +% This is a very tricky part of the package. Some day there +% will exist a detailed documentation. +% +\def\par{\\\indent} +% +% This is where we start to pick up the paragraph(s) +% + \setbox\rawtext=\vbox\bgroup\unvbox\rawtext\unskip + \clubpenalty=0\widowpenalty=0 + \ifnum\brokenpenalty<\maxdimen\else\brokenpenalty=9999\fi + \tolerance=1000 + \parshape=\tcn \the\twa } +% +\def\endmain@bio{% + %\par + \global\tcd=\tcdsav + \egroup\vskip\parskip\parshape=0 % reset parshape; end \box\rawtext + \vbadness=10000 + \splittopskip=0pt +% +% Now we build the boxes beside the window +% +\global\topheight=\tcl\baselineskip +\ifnum\br>0\setbox\holder=\vsplit\rawtext to\topheight\fi +\tcn=\tcl \nb=0 +\ifnum\br>0\nb=\tcn\fi +% +% text on the right side +% +\ifnum\nb>0 + \loop\advance\nb -1 + \setbox\bslice=\vsplit\holder to\baselineskip + \prune\bslice\rtside + \setbox\wbslice=\vbox{\unvbox\wbslice\hbox + to\rtside{\box\bslice\hfil}} + \ifdim\ht\holder>0pt\repeat +\fi +%GLP add fix to make sure bio starts at top of picture +\setbox\wbslice=\vbox to\topheight{\unvbox\wbslice\vfill\vss} +% +% fixing the dimensions of the window part +% +\topheight=\ht\wbslice +% +% ship out the window material to the main vertical list +% +\setbox\windowbox=\vbox{\hbox to\linewidth{% +\vbox to\topheight{\hrule width\picwd height0pt depth0pt\vskip0pt% +\vfill\unvbox\picbox% +\ifnum\picwd>0\vfill\fi% +\vss}\ifnum\br>0\hfill\vbox{\box\wbslice}\fi}}% +% +\unvbox\windowbox% +\loop% lines below picture.... + \setbox\bslice=\vsplit\rawtext to\baselineskip + \prune\bslice\linewidth + \setbox\wbslice=\vbox{\hbox to\linewidth{\box\bslice\hfil}} + \unvbox\wbslice + \ifdim\ht\rawtext>0pt +\repeat +%GLP +%\ifnum\nb>0\topheight=\nb\baselineskip %\advance\topheight by\ilg +%\vspace*{\topheight} +%\fi +}% FINITO +% +% What else do we need? +% +\def\prune#1#2{ +% take a \vbox containing a single \hbox, +% \unvbox it, and cancel the \lastskip +% put in a \hbox of width #2 + \unvbox#1 \setbox#1=\lastbox % \box#1 now is an \hbox + \ifdim\ht#1=\parskip + \setbox#1=\hbox to#2{\vrule height\parskip depth0pt width0pt\hfill} + \else\ifdim\ht#1=0pt\relax + \else\setbox#1=\hbox to#2{\wstrut\unhbox#1\unskip}\fi\fi} +% +% Here the token \twa is generated. +% It's not so difficult as it looks like. +% +\def\createparshapespec{% +\global\tcn=0 +\ifnum\br>0\global\tcn=\tcl\fi +\nb=0 +\ifnum\br>0\nb=\tcn\fi +\global\advance\tcn by\tcd \global\advance\tcn by1 +\ifnum\tcd>0 +\loop\twa=\expandafter{\the\twa\the\ha}\advance\tcd -1 +\ifnum\tcd>0\repeat +\fi +\ifnum\nb>0 +\loop\twa=\expandafter{\the\twa\the\ra}\advance\nb -1 +\ifnum\nb>0\repeat +\fi +\global\twa=\expandafter{\the\twa 0pt \the\linewidth}} +% +\def\computeilg{% compute the interline glue + \tcl=0\ilg=0pt\strutilg=0pt + \loop\setbox\wbox=\hbox{\char\tcl} + \ifdim\ht\wbox>\ilg\ilg=\ht\wbox\fi + \ifdim\dp\wbox>\strutilg\strutilg=\dp\wbox\fi + \advance\tcl by 1 + \ifnum\tcl<128\repeat + \ht\wbox=\ilg + \dp\wbox=\strutilg + \strutilg=\ht\wbox %\advance\strutilg by\ilg + \ifdim\strutilg>\baselineskip + \typeout{character with height greater baselineskip found in font} + \typeout{baselineskip changed to 1.5 of that height!} + \baselineskip=1.5\strutilg + \fi + \global\ilg=\baselineskip + \global\advance\ilg-\ht\wbox \global\advance\ilg-\dp\wbox + \strutilg=\ht\wbox \advance\strutilg by\ilg + \setbox\wstrutbox=\hbox{\vrule height\strutilg depth\dp\wbox width0pt}} + + +% the following code from version.sty by Stephen Bellantoni 1990, loosely +% based on "annotation.sty" by Tom Hofmann. Used to exclude "biography" from +% anonymous mode. +\begingroup +\catcode`@=11\relax% +\catcode`{=12\relax\catcode`}=12\relax% +\catcode`(=1\relax \catcode`)=2\relax% +\gdef\glpinclude#1(% + \expandafter\gdef\csname #1\endcsname% + ()% + \expandafter\gdef\csname end#1\endcsname% + ()% +)% +\gdef\glpexclude#1(% + \expandafter\gdef\csname #1\endcsname% + (\@bsphack\catcode`{=12\relax\catcode`}=12\relax\csname #1@NOTE\endcsname)% + \long\expandafter\gdef\csname #1@NOTE\endcsname ##1\end{#1}% + (\csname #1END@NOTE\endcsname)% + \expandafter\gdef\csname #1END@NOTE\endcsname% + (\@esphack\end(#1))% +)% +\endgroup + +%------- +\def\@confplacedate{\typeout{ieee: Warning! No \noexpand\confplacedate set!} +\bfseries `confplacedate' needs to be set. For example, to: Stanford, CA, USA, +September 29--30, 1991} +\def\confplacedate#1{\def\@confplacedate{#1}} + +%%%%%%%%%%%%%%%%%%%%%%%%% End of ieee.cls %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% diff --git a/cryptominisat/cppsrc/docs/satcomp14-pdf/sigproc.bib b/cryptominisat/cppsrc/docs/satcomp14-pdf/sigproc.bib new file mode 100644 index 00000000..6ccae92a --- /dev/null +++ b/cryptominisat/cppsrc/docs/satcomp14-pdf/sigproc.bib @@ -0,0 +1,2549 @@ +@BOOK{salas:calculus, + AUTHOR = "S.L. Salas and Einar Hille", + TITLE = "Calculus: One and Several Variable", + PUBLISHER = "John Wiley and Sons", + ADDRESS = "New York", + YEAR = "1978" } + +@inproceedings{804350, + author = {Thomas J. Schaefer}, + title = {The complexity of satisfiability problems}, + booktitle = {{STOC}'78}, + year = {1978}, + pages = {216--226}, + location = {San Diego, California, United States}, + doi = {http://doi.acm.org/10.1145/800133.804350}, +} + +Proceedings of the tenth annual ACM symposium on Theory of computing -- +publisher = {ACM Press}, +address = {New York, NY, USA}, + +@inproceedings{smith94phase, + author = "Barbara Smith", + title = "The Phase Transition in Constraint Satisfaction Problems: {A} {CL}oser Look at the Mushy Region", + booktitle = {{ECAI}'94}, + year = "1994" +} + +@inproceedings{cheeseman91where, + author = "Peter Cheeseman and Bob Kanefsky and William M. Taylor", + title = "Where the Really Hard Problems Are", + booktitle = "IJCAI-91", + pages = "331--337", + year = "1991", +} +Proceedings of the Twelfth International Joint Conference on Artificial Intelligence, Sidney, Australia + +@INPROCEEDINGS{Juels-2004-scn, + author = {Juels, Ari}, + title = {Minimalist Cryptography for Low-Cost {RFID} Tags}, + booktitle = {International Conference on Security in Communication Networks --- SCN 2004}, + year = {2004}, + editor = {Blundo, Carlo and Cimato, Stelvio}, + volume = {3352}, + series = {LNCS}, + pages = {149--164}, + month = {September}, + publisher = {Springer-Verlag}, + address = {Amalfi, Italia}, +} + + +@inproceedings{achlioptas-threshold, + author = {Dimitris Achlioptas and Yuval Peres}, + title = {The Threshold for Random k-{SAT} is 2\^\ k(ln 2 - O(k))}, + booktitle = {{STOC}'03}, + year = {2003}, + isbn = {1-58113-674-9}, + pages = {223--231}, + location = {San Diego, CA, USA}, + doi = {http://doi.acm.org/10.1145/780542.780577}, +} +Proceedings of the thirty-fifth annual ACM symposium on Theory of computing -- +publisher = {ACM Press} +address = {New York, NY, USA} + +@article{DPLL, + author = {Martin Davis and Hilary Putnam}, + title = {A Computing Procedure for Quantification Theory}, + journal = {J. ACM}, + volume = {7}, + number = {3}, + year = {1960}, + issn = {0004-5411}, + pages = {201--215}, + doi = {http://doi.acm.org/10.1145/321033.321034}, +} +publisher = {ACM Press}, +address = {New York, NY, USA}, + +@inproceedings {Minisat+, + author = {E\'en, Niklas and S\"orensson, Niklas}, + title = {Translating {P}seudo-{B}oolean constraints into {SAT}}, + booktitle= {Journal on Satisfiability, Boolean Modeling and Computation}, + year = {2006}, + pages = {1-26}, + volume = {2}, +} + +@inproceedings {EenS03MiniSat, + title = {An Extensible {SAT}-solver}, + author = {Niklas E\'en and Niklas S\"{o}rensson}, + booktitle = {SAT}, + editor = {Enrico Giunchiglia and Armando Tacchella}, + pages = {502--518}, + publisher = {Springer}, + series = {LNCS}, + url = {http://dblp.uni-trier.de/db/conf/sat/sat2003.html#EenS03}, + volume = {2919}, + year = {2003}, + ee = {http://www.cs.chalmers.se/Cs/Research/FormalMethods/MiniSat/cgi/MiniSat.ps.gz.cgi}, + keywords = {2003 2004 SAT-solver ais-07w efficiency implementation }, +} + +@misc { toolbar, + author="S. Bouveret and F. Heras and S. de Givry and J. Larrosa and M. Sanchez and T. Schiex", + title="Toolbar: a state-of-the-art platform for wcsp", + url="http://www.inra.fr/mia/T/degivry/ToolBar.pdf", + year="2004" +} + +@inproceedings{1267340, + author = {Kirschenbaum, Ilan and Wool, Avishai}, + title = {How to build a low-cost, extended-range {RFID} skimmer}, + booktitle = {USENIX-SS'06: Proceedings of the 15th conference on {USENIX} Security Symposium}, + year = {2006}, + location = {Vancouver, B.C., Canada}, + publisher = {{USENIX} Association}, + address = {Berkeley, CA, USA}, +} + +@misc{Benetton-boycott, + author = {{CASPIAN - Consumers Against Supermarket Privacy Invasion and Numbering}}, + howpublished={Press release}, + note= {\url{http://www.boycottbenetton.com}}, + title = {Boycott {B}enetton}, + year = {2003}, + month = {March}, +} + +@article{ improved-deterministic, + author="Michael H. Schulz and Elisabeth Auth", + title="Improved Deterministic Test Pattern Generation with Applications to Redundancy Identification", + year="1989", + month="July", + journal="IEEE Transactions on computer-aided design", + volume="8", + number="7", + pages={811--816}, + issn="0278-0070" +} +publisher = " IEEE Circuits and Systems Society", +address="Piscataway, NJ 08854, USA", + +@inproceedings{244560, + author = {Jo\&\#227;o P. Marques Silva and Karem A. Sakallah}, + title = {{GRASP}-a new search algorithm for satisfiability}, + booktitle = {ICCAD'96}, + year = {1996}, + isbn = {0-8186-7597-7}, + pages = {220--227}, + location = {San Jose, California, United States}, + publisher = {IEEE Computer Society}, +} +Proceedings of the 1996 IEEE/ACM international conference on Computer-aided design --- +address = {Washington, DC, USA}, + + @inproceedings{ chai03fast, + author = "D. Chai and A. Kuehlmann", + title = "A fast pseudo-boolean constraint solver", + pages = {305--317}, + booktitle = "IEEE Transactions on Computer-Aided Design of Integrated Circuits and Systems 2003", + year = {2003}, + month =" mar", + volume = "24", + issue = "3", + issn = "0278-0070" +} +publisher = "IEEE Circuits and Systems Society", + +@TechReport{EPC-standard, + author = "EPCglobal", + url="http://www.epcglobalinc.org/standards/specs/13.56_MHz_ISM_Band_Class_1_RFID_Tag_Interface_Specification.pdf", + title="13.56 {MHz} {ISM} Band Class 1 Radio Frequency Identification Tag Interface Specification (2003)", + institution = "Auto-ID cetner, MIT", + year ="2003", + month = "February", + version = "1.0.0" +} +address = "77 massachusetts avenue, bldg 3-449, cambridge, ma 02139-4307, USA", + +@INPROCEEDINGS{LuLHHN-2007-percom, + author = {Lu, Li and Liu, Yunhao and Hu, Lei and Han, Jinsong and Ni, Lionel}, + title = {A Dynamic Key-Updating Private Authentication Protocol for {RFID} Systems}, + booktitle = {PerCom 2007}, + year = {2007}, + pages = {13--22}, + month = {March}, + organization = {IEEE} +} +International Conference on Pervasive Computing and Communications +publisher = {IEEE Computer Society Press} +address = {New York, USA}, + +@INPROCEEDINGS{Ohkubo04Efficient, + author = {Ohkubo, Miyako and Suzuki, Koutarou and Kinoshita, Shingo}, + title = {Efficient Hash-Chain Based {RFID} Privacy Protection Scheme}, + booktitle = {International Conference on Ubiquitous Computing --- Ubicomp 2004, Workshop Privacy: Current Status and Future Directions}, + month = {September}, + year = {2004}, + address = {Nottingham, England}, +} + +@INPROCEEDINGS{MolnarSW-2005-sac, + author = {Molnar, David and Soppera, Andrea and Wagner, David}, + title = {A Scalable, Delegatable Pseudonym Protocol Enabling Ownership Transfer of {RFID} Tags}, + booktitle = {Selected Areas in Cryptography --- SAC 2005}, + editor = {Preneel, Bart and Tavares, Stafford}, + volume = {3897}, + series = {LNCS}, + pages = {276--290}, + month = {August}, + series = {LNCS}, + publisher = {Springer-Verlag}, + year = {2005}, + address = {Kingston, Canada}, +} + +@inproceedings{DBLP:conf/otm/FeldhoferR06, + author = {Martin Feldhofer and Christian Rechberger}, + title = {A Case Against Currently Used Hash Functions in {RFID} Protocols}, + booktitle = {OTM Workshops (1)}, + year = {2006}, + pages = {372-381}, + ee = {http://dx.doi.org/10.1007/11915034_61}, + crossref = {DBLP:conf/otm/2006-w1}, + bibsource = {DBLP, http://dblp.uni-trier.de} +} + +@proceedings{DBLP:conf/otm/2006-w1, + editor = {Robert Meersman and Zahir Tari and Pilar Herrero}, + title = {On the Move to Meaningful Internet Systems 2006: OTM 2006 Workshops, OTM Confederated International Workshops and Posters, AWeSOMe, CAMS, COMINF, IS, KSinBIT, MIOS-CIAO, MONET, OnToContent, ORM, PerSys, OTM Academy Doctoral Consortium, RDDS, SWWS, and SeBGIS 2006, Montpellier, France, October 29 - November 3, 2006. Proceedings, Part I}, + booktitle = {OTM Workshops (1)}, + publisher = {Springer}, + series = {LNCS}, + volume = {4277}, + year = {2006}, + isbn = {3-540-48269-5}, + bibsource = {DBLP, http://dblp.uni-trier.de} +} + + +@INPROCEEDINGS{VajdaB-2003-ubicom, + author = {Vajda, Istv\'an and Butty\'an, Levente}, + title = {Lightweight Authentication Protocols for Low-Cost {RFID} Tags}, + booktitle = {Ubicomp 2003 Second Workshop on Security in Ubiquitous Computing}, + month = {October}, + year = {2003} +} +address = {Seattle, WA, USA}, + +@INPROCEEDINGS{LiW-2007-sec, + author = {Li, Tieyan and Wang, Guilin}, + title = {Security Analysis of Two Ultra-Lightweight {RFID} Authentication Protocols}, + booktitle = {IFIP SEC 2007}, + month = {May}, + organization = {IFIP}, +} +year = {2007}, +address = {Sandton, Gauteng, South Africa}, + +@MISC{BatinaGKMTV-2006-eprint, + author = {Batina, Lejla and Guajardo, Jorge and Kerins, Tim and Mentens, Nele and Tuyls, Pim and Verbauwhede, Ingrid}, + title = {An Elliptic Curve Processor Suitable For {RFID}-Tags}, + howpublished = {Cryptology ePrint Archive, Report 2006/227}, + year = {2006}, + organization = {IACR}, +} + +@inproceedings {AES-grain-sand, + title = {{AES} implementation on a grain of sand}, + issue = "1", + ISSN="1747-0722", + pages = {13--20}, + author="Feldhofer, M. and Wolkerstorfer, J. and Rijmen, V.", + year = "2005", + voulme="152", + booktitle = "Information Security", + organization = {IEEE}, +} +publisher = {IEEE Computer Society Press}, + +@MISC{Juels-2005-manuscript-2, + author = {Juels, Ari}, + title = {{RFID} Security and Privacy: A research Survey}, + howpublished = {Manuscript}, + year = {2005}, + month = {September}, + organization = {RSA Laboratories}, +} + +@INPROCEEDINGS{JuelsW-2007-percom, + author = {Juels, Ari and Weis, Stephen}, + title = {{Defining Strong Privacy for RFID}}, + booktitle = {International Conference on Pervasive Computing and Communications --- PerCom 2007}, + year = {2007}, + editor = {}, + volume = {}, + series = {}, + pages = {342--347}, + address = {New York City, New York, USA}, + month = {March}, + organization = {IEEE}, + publisher = {IEEE Computer Society Press}, + bibsource = {Information Security Group (GSI), UCL, Louvain-la-Neuve, Belgium}, +} + +@INPROCEEDINGS{Vaudenay-2007-asiacrypt, + author = {Vaudenay, Serge}, + title = {On Privacy Models for {RFID}}, + booktitle = {Advances in Cryptology --- Asiacrypt 2007}, + year = {2007}, + editor = {}, + volume = {4833}, + series = {LNCS}, + pages = {68--87}, + address = {Kuching, Malaysia}, + month = {December}, + organization = {}, + publisher = {Springer-Verlag}, + bibsource = {Information Security Group (GSI), UCL, Louvain-la-Neuve, Belgium}, +} + +@INPROCEEDINGS{BolotnyyR-2007-percom, + author = {Bolotnyy, Leonid and Robins, Gabriel}, + title = {Physically Unclonable Function-Based Security and Privacy in {RFID} Systems}, + booktitle = {PerCom 2007}, + year = {2007}, + pages = {211--220}, + month = {March}, + organization = {IEEE}, +} +publisher = {IEEE Computer Society Press} +International Conference on Pervasive Computing and Communications -- +address = {New York, USA}, + +@INPROCEEDINGS{JuelsRS-2003-ccs, + author = {Juels, Ari and Rivest, Ronald and Szydlo, Michael}, + title = {The Blocker Tag: Selective Blocking of {RFID} Tags for Consumer Privacy}, + booktitle = {ACM CCS 2003}, + year = {2003}, + editor = {Atluri, Vijay}, + pages = {103--111}, + month = {October}, + publisher = "ACM Press" +} +address = {Washington, DC, USA}, +Conference on Computer and Communications Security +organization = "ACM", + +@INPROCEEDINGS{JuelsW-2005-crypto, + author = {Juels, Ari and Weis, Stephen}, + title = {Authenticating Pervasive Devices with Human Protocols}, + booktitle = {Advances in Cryptology --- CRYPTO'05}, + year = {2005}, + editor = {Shoup, Victor}, + volume = {3126}, + series = {LNCS}, + pages = {293--308}, + month = {August}, + organization = {IACR}, + address = {Santa Barbara, California, USA}, + publisher = {Springer-Verlag}, + series = {LNCS}, +} + +@inproceedings{ zhang01efficient, + author = "Lintao Zhang and Conor F. Madigan and Matthew W. Moskewicz and Sharad Malik", + title = "Efficient Conflict Driven Learning in Boolean Satisfiability Solver", + booktitle = "{ICCAD}", + pages = "279-285", + year = "2001", + url = "citeseer.ist.psu.edu/article/zhang01efficient.html" } + + +@INPROCEEDINGS{ButtyanHV-2006-pet, + author = {Butty\'an, Levente and Holczer, Tam\'as and Vajda, Istv\'an}, + title = {Optimal Key-Trees for Tree-Based Private Authentication}, + booktitle = {Workshop on Privacy Enhancing Technologies --- PET 2006}, + pages = {332-350}, + month = {June}, + year = {2007}, + address = {Cambridge, United Kingdom}, +} + + +@INPROCEEDINGS{Castelluccia07Secret, + author = {Castelluccia, Claude and Soos, Mate}, + title = {Secret Shuffling: A Novel Approach to {RFID} Private Identification}, + booktitle = {{RFIDSec}'07}, + pages = {169-180}, + year = {2007}, + month = {July} +} +Proceedings of the International Conference on RFID Security 2007 + +@INPROCEEDINGS{breaking-lmap, + author = {Mihaly B\'arasz and Bal\'azs Boros and P\'eter Ligeti and Krisztina L\'oja and D\'aniel Nagy}, + title = {Breaking {LMAP}}, + pages = {69-78}, + month = {July}, + year = {2007}, + booktitle = {Conference on RFID Security --- {RFIDSec}'07}, + address = {Malaga, Spain}, +} + +@INPROCEEDINGS{Initial-SRAM, + author = {Daniel Holcom and Wayne Burleson and Kevin Fu.}, + title = {Initial {SRAM} state as a Fingerprint and Source of True Random Numbers for {RFID} Tags}, + booktitle = {{RFIDSec}'07}, + pages = {29-40}, + month = {July}, + year = {2007} +} +Proceedings of the International Conference on RFID Security 2007 + +@inproceedings{HBattack, + author = {Gilbert, Henri and Robshaw, Matt and Sibert, Herve}, + title = {An Active Attack Against {HB}$^+$ - A Provably Secure Lightweight Authentication Protocol}, + booktitle = {IEE Electronic Letters 41, 21}, + year = {2005}, + pages = {1169--1170} +} + +@INPROCEEDINGS{KatzS-2006-eurocrypt, + author = {Katz, Jonathan and Sun Shin, Ji}, + title = {Parallel and Concurrent Security of the {HB} and {HB}$^{+}$ Protocols}, + booktitle = {Advances in Cryptology --- EUROCRYPT '06}, + organization = {IACR}, + year = {2006} +} +Advances in Cryptology +publisher = {Springer-Verlag}, + +@MISC{KatzS-2006-eprint, + author = {Katz, Jonathan and Smith, Adam}, + title = {Analyzing the {HB} and {HB}+ Protocols in the ``Large Error'' Case}, + howpublished = {Cryptology ePrint Archive, Report 2006/326}, + organization = {IACR}, +} + +@inproceedings{1229319, + author = {Tri Van Le and Mike Burmester and Breno de Medeiros}, + title = {Universally composable and forward-secure {RFID} authentication and authenticated key exchange}, + booktitle = {Proceedings of the 2nd ACM symposium on Information, Computer and Communications Security --- {ASIACCS}'07}, + year = {2007}, + isbn = {1-59593-574-6}, + pages = {242--252}, + location = {Singapore}, + publisher = {ACM}, + address = {New York, NY, USA}, + doi = {http://doi.acm.org/10.1145/1229285.1229319}, +} + + + +@INPROCEEDINGS{PUF-based-RNG, + author = {Charles W. O'Donnell and G. Edward Suh and Srinivas Devadas}, + title = {{PUF}-Based Random Number Generation}, + booktitle = {MIT CSAIL CSG Technical Memo 481}, + url = {http://csg.csail.mit.edu/pubs/memos/Memo-481/Memo-481.pdf}, + year = {2004}, + month = {November} +} + +@book{Ipatov05Spread, + author = {Valeri P. Ipatov}, + year = {2005}, + month = {May}, + title = {Spread Spectrum and {CDMA}: {P}rinciples and Applications}, + publisher = {John Wiley \& Sons, Ltd.}, + ISBN = {978-0470091784}, +} + +@article{DBLP:journals/ijwmc/HellJM07, + author = {Martin Hell and + Thomas Johansson and + Willi Meier}, + title = {Grain: a stream cipher for constrained environments}, + journal = {IJWMC}, + volume = {2}, + number = {1}, + year = {2007}, + pages = {86-93}, + ee = {http://dx.doi.org/10.1504/IJWMC.2007.013798}, + bibsource = {DBLP, http://dblp.uni-trier.de} +} + +@book{applied-crypto, + year= {1996}, + ISBN ={0-8493-8523-7}, + author={Alfred J. Menezes and Paul C. van Oorschot and Scott A. Vanstone}, + title ={Handbook of applied cryptography}, + publisher={CRC Press}, + address={Boca Raton, Florida}, +} +url={http://cacr.math.uwaterloo.ca/hac} + +@inproceedings{DiPietro07Information, + author={Roberto Di Pietro and Refik Molva}, + title={Information confinement, privacy, and security in {RFID} systems}, + month={September}, + booktitle={Proceedings of the 12th European Symposium On Research In Computer Security}, + year={2007}, + pages={187-202}, +} + +@inproceedings{PerisHER-2006-rfidsec, + author = {Peris-Lopez, Pedro and Hernandez-Castro, Julio Cesar and Estevez-Tapiador, Juan and Ribagorda, Arturo}, + title = {{LMAP}: A Real Lightweight Mutual Authentication Protocol for Low-cost {RFID} tags}, + booktitle = {Proceedings of {RFIDSec}'06}, + year = {2006}, + month = {July}, + address = {Graz, Austria}, + organization = {Ecrypt}, +} + +@INPROCEEDINGS{BringerCD-2006-secperu, + author = {Bringer, Julien and Chabanne, Herv\'e and Dottax Emmanuelle}, + title = {{HB}$^{++}$: a Lightweight Authentication Protocol Secure against Some Attacks}, + booktitle = {{IEEE} SecPerU 2006}, + year = {2006}, + month = {June}, + organization = {IEEE}, +} +International Conference on Pervasive Services, Workshop on Security, Privacy and Trust in Pervasive and Ubiquitous Computing +address = {Lyon, France}, +publisher = {IEEE Computer Society Press}, + +@INPROCEEDINGS{PerisHER-2006-uic, + author = {Peris-Lopez, Pedro and Hernandez-Castro, Julio Cesar and Estevez-Tapiador, Juan and Ribagorda, Arturo}, + title = {{M2AP}: A Minimalist Mutual-Authentication Protocol for Low-cost {RFID} Tags}, + booktitle = {International Conference on Ubiquitous Intelligence and Computing --- {UIC}’06}, + year = {2006}, + editor = {}, + volume = {4159}, + pages = {912--923}, + month = {September}, + series = {LNCS}, + publisher = {Springer-Verlag}, +} + + +@INPROCEEDINGS{M2AP-break, + author={Mih\'aly B\'ar\'asz and Bal\'azs Boros and P\'eter Ligeti and Krisztina L\'oja and D\'aniel A. Nagy}, + title={Passive Attack Against the {M2AP} Mutual Authentication Protocol for {RFID} Tags}, + year = {2007}, + month= {September}, + date = {24-25}, + booktitle={{RFID} 2007 --- The First International {EURASIP} Workshop on {RFID} Technology}, + country = {Austria}, + city={Vienna} +} + +@INPROCEEDINGS{HBppbreak, + author= {Henri Gilbert and Matthew J.B. Robshaw and Yannick Seurin}, + title={Good Variants of {HB}+ are Hard to Find}, + year={2008}, + month={January}, + booktitle={Financial Cryptography}, + publisher={Springer}, + country={Mexico} +} + +@inproceedings{MAGMA, + author = {Wieb Bosma and John Cannon and Graham Matthews}, + title = {Programming with algebraic structures: design of the {MAGMA} language}, + booktitle = {Proceedings of the international symposium on Symbolic and algebraic computation --- ISSAC '94}, + year = {1994}, + isbn = {0-89791-638-7}, + pages = {52--57}, + location = {Oxford, United Kingdom}, + doi = {http://doi.acm.org/10.1145/190347.190362}, + publisher = {ACM}, + address = {New York, NY, USA}, +} + +@inproceedings{Singular, + author = {Gert-Martin Greuel and Gerhard Pfister and Hans Sch\"{o}nemann}, + title = {{SINGULAR} --- A computer algebra system for polynomial computations}, + booktitle = {Symbolic computation and automated reasoning}, + year = {2001}, + isbn = {1-56881-145-4}, + pages = {227--233}, + publisher = {A. K. Peters, Ltd.}, + address = {Natick, MA, USA}, +} + +@misc{SAGE, + author = {{The SAGE Group}}, + year = {2008}, + title = {{SAGE} Mathematics Software}, + note = {\url{http://www.sagemath.org}}, +} + +@misc{new-sparse-technique, + author={H{\aa}vard Raddum and Igor Semae}, + title={New Technique for Solving Sparse Equation Systems}, + month={January}, + year={2006}, + note={\url{eprint.iacr.org/2006/475/}}, +} + +@TechReport{algebraic-DES, + author={Nicolas T. Courtois and Gregory V. Bard}, + title={Algebraic Cryptanalysis of the {D}ata {E}ncryption {S}tandard}, + year={2006}, + institution = {IACR E-print}, + number = {2006/402}, + month={November}, + booktitle={IACR E-print, \url{http://eprint.iacr.org/2006/402}}, +} + + + +@inproceedings{early-DES-algebraic, + author={Chaum, David and Evertse, Jan-Hendrik}, + title={Cryptanalysis of {DES} with a Reduced Number of Rounds}, + booktitle = {Advances in Cryptology --- {CRYPTO}'85}, + year = {1986}, + pages = {192--211}, + publisher = {Springer-Verlag} +} + +@InProceedings{Bofilletal2008CAV, + author = {M. Bofill and R. Nieuwenhuis and A. Oliveras and E. Rodr\'\i guez-Carbonell and A. Rubio}, + title = {The {B}arcelogic {SMT} Solver}, + pages = {294-298}, + booktitle = {{CAV}'08}, + year = {2008}, + series = {LNCS}, + volume = {5123}, + publisher = {Springer}, + editor = {A. Gupta and S. Malik}, +} + +@techreport{RSAT, + author = {Knot Pipatsrisawat and Adnan Darwiche}, + institution = {Automated Reasoning Group, Computer Science}, + title = {{RS}at 2.0: {SAT} Solver Description}, + year = {2007}, +} + +@inproceedings{DBLP:conf/fse/CourtoisBW08, + author = {Nicolas Courtois and Gregory V. Bard and David Wagner}, + title = {Algebraic and Slide Attacks on {K}ee{L}oq}, + booktitle = {FSE}, + year = {2008}, + pages = {97-115}, + ee = {http://dx.doi.org/10.1007/978-3-540-71039-4_6}, + crossref = {DBLP:conf/fse/2008}, + bibsource = {DBLP, http://dblp.uni-trier.de} +} + +@TechReport{cryptoeprint:2008:166, + author = {Nicolas T. Courtois and Karsten Nohl and Sean O'Neil}, + title = {Algebraic Attacks on the {C}rypto-1 Stream Cipher in {Mifare} {C}lassic and {O}yster Cards}, + number = {2008/166}, + institution = {Cryptology ePrint Archive}, + year = {2008}, +} +howpublished = {Cryptology ePrint Archive, Report 2008/166}, +note = {\url{http://eprint.iacr.org/}}, + +@INPROCEEDINGS{Biere99symbolicmodel, + author = {Armin Biere and A. Cimatti and E. M. Clarke and M. Fujita and Y. Zhu}, + title = {Symbolic Model Checking Using {SAT} Procedures instead of {BDDs}}, + booktitle = {Proc. of Design Automation Conference ({DAC}'99)}, + year = {1999}, + pages = {317--320} +} + +@INPROCEEDINGS{temporalinduction, + author = {E\'en, Niklas and S\"orensson, Niklas}, + title = {Temporal Induction by Incremental {SAT} Solving}, + booktitle={Proc. of First Intrenational Workshop on Bounded Model Checking}, + year={2003}, + volume={89}, + issue={4}, + series={ENTCS}, + publisher={Elsevier} +} + +@inproceedings{ARMS02, + author = {Fadi A. Aloul and Arathi Ramani and Igor Markov and Karem Sakallah}, + title = {Generic {ILP} versus Specialized 0-1 {ILP}: an Update}, + booktitle = {Proc. ACM/IEEE Intl. Conf. Comp.-Aided Design}, + pages = {450 - 457}, + month = {November}, + year = {2002}, + URL = {http://www.gigascale.org/pubs/190.html} +} + +@inproceedings{knowledge-compiling, + author={Adnan Dawiche}, + title={New advances in compiling {CNF} to decomposable negation normal form}, + booktitle={Proc. of European Conference on Artificial Intelligence}, + year={2004}, + pages={328 - 332}, +} + +@InProceedings{S-Match, + author = {Fausto Giunchiglia and Pavel Shvaiko and Mikalai Yatskevich}, + title = {S-{M}atch: an algorithm and an implementation of semantic matching}, + booktitle = {Semantic Interoperability and Integration}, + year = {2005}, + number = {04391}, + series = {Dagstuhl Seminar Proceedings}, + ISSN = {1862-4405}, + publisher = {IBFI}, + note = {\url{http://drops.dagstuhl.de/opus/volltexte/2005/37}}, + editor = {Y. Kalfoglou and M. Schorlemmer and A. Sheth and S. Staab and M. Uschold}, +} +publisher = {Internationales Begegnungs- und Forschungszentrum fuer Informatik (IBFI)}, + + + +@techreport{bard-thesis, + author = {Gregory V. Bard}, + title = {Algorithms for the Solution of Polynomial and Linear Systems of Equations over Finite Fields, with an Application to the Cryptanalysis of {K}ee{L}oq}, + institution={University of Maryland Dissertation}, + month={April}, + year={2008}, + note = {Ph.D. Thesis}, +} + +@inproceedings{Toyocrypt-nicolas-attack, + author={Nicolas T. Courtois}, + title={Higher Order Correlation Attacks, {XL} algorithm and Cryptanalysis of {T}oyocrypt ({A}n updated version)}, + booktitle={ICISC 2002}, + series={LNCS}, + volume={2587}, + publisher={Springer}, + year={2002}, +} + +@inproceedings{General-LFSR-attacks, + author={Nicolas T. Courtois and Willi Meier}, + title={Algebraic Attacks on Stream Ciphers with Linear Feedback}, + booktitle={Advances in Cryptology --- EUROCRYPT '03}, + series={LNCS}, + volume={2656}, + pages={345–359}, + publisher={Springer}, + address = {Warsaw, Poland} +} + +@inproceedings{Canniere06Trivium, + author = {Christophe De Canni{\`e}re}, + title = {Trivium: A Stream Cipher Construction Inspired by Block Cipher Design Principles}, + booktitle = {ISC}, + year = {2006}, + pages = {171-186}, + ee = {http://dx.doi.org/10.1007/11836810_13}, + crossref = {DBLP:conf/isw/2006}, + bibsource = {DBLP, http://dblp.uni-trier.de} +} + +@proceedings{DBLP:conf/isw/2006, + editor = {Sokratis K. Katsikas and et al}, + title = {Information Security, 9th International Conference, ISC 2006, Samos Island, Greece, August 30 - September 2, 2006, Proceedings}, + booktitle = {ISC}, + publisher = {Springer}, + series = {LNCS}, + volume = {4176}, + year = {2006}, + isbn = {3-540-38341-7}, + bibsource = {DBLP, http://dblp.uni-trier.de} +} +and +Javier Lopez and +Michael Backes and +Stefanos Gritzalis and +Bart Preneel + +@inproceedings{BiviumWithSATsolvers, + author = {Tobias Eibach and Enrico Pilz and Gunnar V{\"o}lkel}, + title = {Attacking {B}ivium Using {SAT} Solvers}, + booktitle = {SAT}, + year = {2008}, + pages = {63-76}, + ee = {http://dx.doi.org/10.1007/978-3-540-79719-7_7}, + crossref = {DBLP:conf/sat/2008}, + bibsource = {DBLP, http://dblp.uni-trier.de} +} + +@proceedings{DBLP:conf/sat/2008, + editor = {Hans Kleine B{\"u}ning and Xishun Zhao}, + title = {Theory and Applications of Satisfiability Testing - SAT 2008, 11th International Conference, SAT 2008, Guangzhou, China, May 12-15, 2008. Proceedings}, + booktitle = {SAT}, + publisher = {Springer}, + series = {LNCS}, + volume = {4996}, + year = {2008}, + isbn = {978-3-540-79718-0}, + bibsource = {DBLP, http://dblp.uni-trier.de} +} + +@TechReport{Bivium, + author={Havard Raddum}, + title={Cryptanalytic results on {T}rivium}, + institution = {ECRYPT Stream Cipher Project}, + year={2006}, + number={2006/039}, + note = {\url{www.ecrypt.eu.org/stream/papersdir/2006/039.ps}}, +} + +@misc{using-equation-solvers, + author = {Havard Raddum and Igor Semaev}, + title = {New Technique for Solving Sparse Equation Systems}, + howpublished = {Cryptology ePrint Archive, Report 2006/475}, + year = {2006}, + note = {\url{http://eprint.iacr.org/}}, +} + + +@TechReport{BiviumWithMiniSat, + author={Cameron McDonald and Chris Charnes and Josef Pieprzyk}, + title={Attacking {B}ivium with {M}ini{S}at}, + institution = {ECRYPT Stream Cipher Project}, + year={2007}, + number={2007/040} +} + +@inproceedings{FaugereF5, + author = {Jean-Charles Faug\`{e}re}, + title = {A new efficient algorithm for computing {G}r\"{o}bner bases without reduction to zero ({F}5)}, + booktitle = {ISSAC '02}, + year = {2002}, + isbn = {1-58113-484-3}, + pages = {75--83}, + location = {Lille, France}, + doi = {http://doi.acm.org/10.1145/780506.780516}, + publisher = {ACM}, + } +ISSAC '02: Proceedings of the 2002 international symposium on Symbolic and algebraic computation +address = {New York, NY, USA}, + + +@article{FaugereF4, + author = {Jean-Charles Faug\`{e}re}, + title = {A new efficient algorithm for computing {G}r\"{o}bner bases ({F}4)}, + journal = {Journal of Pure and Applied Algebra}, + year = {1999}, + month = {June}, + pages = {61--88}, + volume = {1}, + number = {139}, +} + +@inproceedings{DismantlingMifare, + author = {Flavio D. Garcia and et al.}, + title = {Dismantling {MIFARE} {C}lassic}, + booktitle = {ESORICS}, + year = {2008}, + pages = {97-114}, + ee = {http://dx.doi.org/10.1007/978-3-540-88313-5_7}, + crossref = {DBLP:conf/esorics/2008}, + bibsource = {DBLP, http://dblp.uni-trier.de} +} +and +Gerhard de Koning Gans and +Ruben Muijrers and +Peter van Rossum and +Roel Verdult and +Ronny Wichers Schreur and +Bart Jacobs + +@proceedings{DBLP:conf/esorics/2008, + editor = {Sushil Jajodia and Javier L{\'o}pez}, + title = {Computer Security - ESORICS 2008, 13th European Symposium on Research in Computer Security, M{\'a}laga, Spain, October 6-8, 2008. Proceedings}, + booktitle = {ESORICS}, + publisher = {Springer}, + series = {LNCS}, + volume = {5283}, + year = {2008}, + isbn = {978-3-540-88312-8}, + bibsource = {DBLP, http://dblp.uni-trier.de} +} + +@misc{Karsten-webpage-HiTag2, + author={Karsten Nohl}, + title={Description of {H}i{T}ag2}, + howpublished={Press release}, + note= {\url{http://cryptolib.com/ciphers/hitag2/}}, + month={March}, + day = {12}, + year={2008}, +} + +@InProceedings{Ouafi08Privacy, + address = {Berlin}, + affiliation = {EPFL}, + author = {Ouafi, Khaled and Phan, Raphael C.-W.}, + booktitle = {Information {S}ecurity {P}ractice and {E}xperience, 4th {I}nternational {C}onference, {ISPEC} 2008}, + location = {Sydney, Australia}, + oai-id = {oai:infoscience.epfl.ch:126418}, + oai-set = {conf; fulltext; fulltext-public}, + pages = {263--277}, + publisher = {Springer}, + review = {REVIEWED}, + series = {LNCS}, + status = {PUBLISHED}, + title = {Privacy of {R}ecent {RFID} {A}uthentication {P}rotocols}, + unit = {LASEC}, + year = {2008}, + keywords = {RFID; authentication protocols, ; privacy; untraceability; provably secure}, + details = {http://infoscience.epfl.ch/record/126418}, + documenturl = {http://infoscience.epfl.ch/getfile.py?recid=126418&mode=best}, +} + +@INPROCEEDINGS{Ohkubo04Cryptographic, + author = {Miyako Ohkubo Koutarou and Koutarou Suzuki and Shingo Kinoshita}, + title = {Cryptographic Approach to "Privacy-Friendly" Tags}, + booktitle = {RFID Privacy Workshop}, + year = {2003}, + address = {MIT, Massachusetts, USA}, + month = {November}, +} + +@article{Lamport81Password, + author = {Lamport,, Leslie}, + title = {Password authentication with insecure communication}, + journal = {Commun. ACM}, + volume = {24}, + number = {11}, + year = {1981}, + issn = {0001-0782}, + pages = {770--772}, + doi = {http://doi.acm.org/10.1145/358790.358797}, + publisher = {ACM}, + address = {New York, NY, USA}, + } + +@InProceedings{OSK_Avoine, + affiliation = {EPFL}, + author = {Avoine, Gildas and Oechslin, Philippe}, + booktitle = {The 2nd {IEEE} {I}nternational {W}orkshop on {P}ervasive {C}omputing and {C}ommunication {S}ecurity - {P}er{S}ec 2005}, + details = {http://infoscience.epfl.ch/record/99461}, + documenturl = {http://infoscience.epfl.ch/getfile.py?recid=99461&mode=best}, + keywords = {NCCR-MICS; NCCR-MICS/CL3}, + location = {Kauai island, Hawaii, USA}, + oai-id = {oai:infoscience.epfl.ch:99461}, + oai-set = {conf; fulltext; fulltext-public}, + pages = {110--114}, + review = {REVIEWED}, + status = {PUBLISHED}, + title = {A {S}calable and {P}rovably {S}ecure {H}ash-{B}ased {RFID} {P}rotocol}, + unit = {LASEC}, + year = 2005 +} + +@inproceedings{Trade-off-Hellman, + author = {Hellman, Martin E.}, + title = {A cryptanalytic time-memory trade off}, + booktitle = {{IEEE} Transactions on Information Theory}, + volume = {IT-26/4}, + pages = {401--406}, + year = {1980}, +} + +@inproceedings{Faster-crypto-time-memory, + author = {Oechslin, Philippe }, + booktitle = {Advances in Cryptology --- CRYPTO 2003}, + series = {LNCS}, + volume = {2729}, + publisher = {Springer}, + pages = {617--630}, + posted-at = {2008-07-07 15:11:06}, + priority = {2}, + title = {Making a Faster Cryptanalytic Time-Memory Trade-Off}, + url = {http://www.springerlink.com/content/u9gxwd29p2tnx3wl}, + year = {2003} +} + +@inproceedings{Molnar04Keytrees, + address = {New York, NY, USA}, + author = {Molnar, David and Wagner, David }, + booktitle = {CCS '04: Proceedings of the 11th ACM conference on Computer and communications security}, + citeulike-article-id = {202290}, + doi = {10.1145/1030083.1030112}, + isbn = {1581139616}, + keywords = {libraries, privacy}, + pages = {210--219}, + posted-at = {2007-12-25 21:42:23}, + priority = {5}, + publisher = {ACM Press}, + title = {Privacy and security in library {RFID}: issues, practices, and architectures}, + url = {http://dx.doi.org/10.1145/1030083.1030112}, + year = {2004} +} + +@INPROCEEDINGS{NohlE-2008-sec, + author = {Nohl, Karsten and Evans, David}, + title = {{Hiding in Groups: On the Expressiveness of Privacy Distributions}}, + booktitle = {Proceedings of The Ifip Tc 11 23rd International Information Security Conference --- SEC 2008}, + year = {2008}, + editor = {}, + volume = {278}, + series = {LNCS}, + pages = {1--15}, + address = {Milan, Italia}, + month = {September}, + organization = {}, + publisher = {Springer}, + bibsource = {Information Security Group (GIS), UCL, Louvain-la-Neuve, Belgium}, +} + +@inproceedings{DBLP:conf/fse/Shamir08, + author = {Adi Shamir}, + title = {{SQUASH} --- A New {MAC} with Provable Security Properties for Highly Constrained Devices Such as {RFID} Tags}, + booktitle = {FSE}, + year = {2008}, + pages = {144-157}, + ee = {http://dx.doi.org/10.1007/978-3-540-71039-4_9}, + crossref = {DBLP:conf/fse/2008}, + bibsource = {DBLP, http://dblp.uni-trier.de} +} + +@proceedings{DBLP:conf/fse/2008, + editor = {Kaisa Nyberg}, + title = {Fast Software Encryption, 15th International Workshop, {FSE} 2008, Lausanne, Switzerland, February 10-13, 2008, Revised Selected Papers}, + booktitle = {FSE}, + publisher = {Springer}, + series = {LNCS}, + volume = {5086}, + year = {2008}, + isbn = {978-3-540-71038-7}, + bibsource = {DBLP, http://dblp.uni-trier.de} +} + +@inproceedings{Oren2008WIPRPublic, +author = {Yossef Oren and Martin Feldhofer}, +title = {{WIPR} --- a Public Key Implementation on Two Grains of Sand}, +booktitle = {Workshop on RFID Security 2008}, +year = {2008}, +editor = {Sandra Dominikus}, +pages = {15 - 27}, +} + +@inproceedings{DBLP:conf/ctrsa/McLooneR07, + author = {M{\'a}ire McLoone and Matthew J. B. Robshaw}, + title = {Public Key Cryptography and {RFID} Tags}, + booktitle = {CT-RSA}, + year = {2007}, + pages = {372-384}, + ee = {http://dx.doi.org/10.1007/11967668_24}, + crossref = {DBLP:conf/ctrsa/2007}, + bibsource = {DBLP, http://dblp.uni-trier.de} +} + +@proceedings{DBLP:conf/ctrsa/2007, + editor = {Masayuki Abe}, + title = {Topics in Cryptology - CT-RSA 2007, The Cryptographers' Track at the RSA Conference 2007, San Francisco, CA, USA, February 5-9, 2007, Proceedings}, + booktitle = {CT-RSA}, + publisher = {Springer}, + series = {LNCS}, + volume = {4377}, + year = {2006}, + isbn = {3-540-69327-0}, + bibsource = {DBLP, http://dblp.uni-trier.de} +} + + + +@proceedings{DBLP:conf/eurocrypt/91, + editor = {Donald W. Davies}, + title = {Advances in Cryptology --- EUROCRYPT '91, Workshop on the Theory and Application of of Cryptographic Techniques, Brighton, UK, April 8-11, 1991, Proceedings}, + booktitle = {Advances in Cryptology --- EUROCRYPT '91}, + publisher = {Springer}, + series = {LNCS}, + volume = {547}, + year = {1991}, + isbn = {3-540-54620-0}, +} + +@inproceedings{DBLP:conf/eurocrypt/Girault91, + author = {Marc Girault}, + title = {Self-Certified Public Keys}, + booktitle = {Advances in Cryptology --- EUROCRYPT '91}, + year = {1991}, + pages = {490-497}, + ee = {http://link.springer.de/link/service/series/0558/bibs/0547/05470490.htm}, + bibsource = {DBLP, http://dblp.uni-trier.de} +} + +@inproceedings{DBLP:conf/cardis/Girault00, + author = {Marc Girault}, + title = {Low-Size Coupons for Low-Cost {IC} Cards}, + booktitle = {CARDIS}, + year = {2000}, + pages = {39-50}, + crossref = {DBLP:conf/cardis/2000}, + bibsource = {DBLP, http://dblp.uni-trier.de} +} + +@proceedings{DBLP:conf/cardis/2000, + editor = {Josep Domingo-Ferrer and David Chan and Anthony Watson}, + title = {Smart Card Research and Advanced Applications, Proceedings of the Fourth Working Conference on Smart Card Research and Advanced Applications, CARDIS 2000, September 20-22, 2000, Bristol, UK}, + booktitle = {CARDIS}, + publisher = {Kluwer}, + series = {IFIP Conference Proceedings}, + volume = {180}, + year = {2000}, + isbn = {0-7923-7953-5}, + bibsource = {DBLP, http://dblp.uni-trier.de} +} + +@inproceedings{Secure-human-ID, + author = {Hopper,, Nicholas J. and Blum,, Manuel}, + title = {Secure Human Identification Protocols}, + booktitle = {ASIACRYPT '01: Proceedings of the 7th International Conference on the Theory and Application of Cryptology and Information Security}, + year = {2001}, + isbn = {3-540-42987-5}, + pages = {52--66}, + publisher = {Springer-Verlag}, + address = {London, UK}, +} + +@ARTICLE{Inherent-intracability, +title={On the inherent intractability of certain coding problems (Corresp.)}, +author={ Berlekamp, E. and McEliece, R. and van Tilborg, H.}, +journal={Information Theory, IEEE Transactions on}, +year={1978}, +month={May}, +volume={24}, +number={3}, +pages={ 384-386}, +keywords={null Decoding, Linear codes}, +doi={}, +ISSN={0018-9448}, +} + +@article{Noise-tolerant-learning, + author = {Blum,, Avrim and Kalai,, Adam and Wasserman,, Hal}, + title = {Noise-tolerant learning, the parity problem, and the statistical query model}, + journal = {J. ACM}, + volume = {50}, + number = {4}, + year = {2003}, + issn = {0004-5411}, + pages = {506--519}, + doi = {http://doi.acm.org/10.1145/792538.792543}, + publisher = {ACM}, + address = {New York, NY, USA}, +} + + +@INPROCEEDINGS{To06anovel, + author = {Marc P. C. Fossorier and Miodrag J. Mihaljević and Hideki Imai and Yang Cui and Kanta Matsuura}, + title = {A Novel Algorithm for Solving the {LPN} Problem and Its Applicatio to Security Evaluation of the {HB} Protocol for {RFID} Authentication}, + booktitle = {INDOCRYPT}, + editor = {Rana Barua and Tanja Lange}, + volume = {4329}, + series = {LNCS}, + year = {2006}, + pages = {48--62}, + publisher = {Springer} +} + +@INPROCEEDINGS{Levieil_animproved, + author = {Éric Levieil and Pierre-Alain Fouque}, + title = {An improved {LPN} algorithm}, + editor = {Roberto De Prisco and Moti Yung}, + booktitle = {Security and Cryptography for Networks --- SCN}, + volume = {4116}, + series = {LNCS}, + year = {2006}, + pages = {348--359}, + Publisher = {Springer Berlin / Heidelberg}, + ISSN = {0302-9743}, +} + +@INPROCEEDINGS{HBpp, +title={{HB}$^{++}$: a Lightweight Authentication Protocol Secure against Some Attacks}, +author={Bringer, J. and Chabanne, H. and Dottax, E.}, +booktitle={Security, Privacy and Trust in Pervasive and Ubiquitous Computing, 2006 --- SecPerU 2006}, +year={2006}, +month={June}, +volume={}, +number={}, +pages={28--33}, +doi={10.1109/SECPERU.2006.10}, +} + +@inproceedings{DBLP:conf/eurocrypt/GilbertRS08, + author = {Henri Gilbert and Matthew J. B. Robshaw and Yannick Seurin}, + title = {{HB}$^{\mbox{\#}}$: Increasing the Security and Efficiency of {HB}$^{\mbox{+}}$}, + booktitle = {Advances in Cryptology --- EUROCRYPT '08}, + year = {2008}, + pages = {361-378}, + ee = {http://dx.doi.org/10.1007/978-3-540-78967-3_21}, + crossref = {DBLP:conf/eurocrypt/2008}, + bibsource = {DBLP, http://dblp.uni-trier.de} +} + +@proceedings{DBLP:conf/eurocrypt/2008, + editor = {Nigel P. Smart}, + title = {Advances in Cryptology --- EUROCRYPT 2008, 27th Annual International Conference on the Theory and Applications of Cryptographic Techniques, Istanbul, Turkey, April 13-17, 2008. Proceedings}, + booktitle = {Advances in Cryptology --- EUROCRYPT '08}, + publisher = {Springer}, + series = {LNCS}, + volume = {4965}, + year = {2008}, + isbn = {978-3-540-78966-6}, + bibsource = {DBLP, http://dblp.uni-trier.de} +} + +@proceedings{DBLP:conf/fse/2001, + editor = {Mitsuru Matsui}, + title = {Fast Software Encryption, 8th International Workshop, FSE 2001 Yokohama, Japan, April 2-4, 2001, Revised Papers}, + booktitle = {FSE}, + publisher = {Springer}, + series = {LNCS}, + volume = {2355}, + year = {2002}, + isbn = {3-540-43869-6}, + bibsource = {DBLP, http://dblp.uni-trier.de} +} + +@techreport{Rabin79Digitalized, + author = {Rabin, M. O.}, + title = {Digitalized Signatures and Public-Key Functions as Intractable as Factorization}, + year = {1979}, + institution = {Massachusetts Institute of Technology}, + address = {Cambridge, MA, USA}, + } + +@article{HBmp, + author = {Munilla,, J. and Peinado,, A.}, + title = {{HB}-{MP}: A further step in the HB-family of lightweight authentication protocols}, + journal = {Comput. Netw.}, + volume = {51}, + number = {9}, + year = {2007}, + issn = {1389-1286}, + pages = {2262--2267}, + doi = {http://dx.doi.org/10.1016/j.comnet.2007.01.011}, + publisher = {Elsevier North-Holland, Inc.}, + address = {New York, NY, USA}, + } + +@article{HBstar, + author={D.N. Duc and K. Kim}, + title={Securing {HB}$^+$ Against {GRS} Man-in-the-Middle Attack}, + journal={Institute of Electronics, Information and Communication Engineers, Symposium on Cryptography and Information, Security}, + date = {January 23--26}, + year = {2007}, +} + +@INPROCEEDINGS{OuafiOV-2008-asiacrypt, + author = {Ouafi, Khaled and Overbeck, Raphael and Vaudenay, Serge}, + title = {On the Security of {HB\#} against a Man-in-the-Middle Attack}, + booktitle = {Advances in Cryptology --- Asiacrypt 2008}, + year = {2008}, + editor = {}, + volume = {5350}, + series = {LNCS}, + pages = {108--124}, + address = {Melbourne, Australia}, + month = {December}, + organization = {}, + publisher = {Springer}, + bibsource = {Information Security Group (GSI), UCL, Louvain-la-Neuve, Belgium}, +} + +@INPROCEEDINGS{PRESENT, + author = {Bogdanov, Andrey and Knudsen, Lars Ramkilde and Leander, Gregor and Paar, Christof and Poschmann, Axel and Robshaw, Matthew J.B. and Seurin, Yannick and Vikkelsoe, C.}, + title = {{PRESENT}: An Ultra-Lightweight Block Cipher}, + booktitle = {Workshop on Cryptographic Hardware and Embedded Systems --- CHES 2007}, + year = {2007}, + editor = {Paillier, Pascal and Verbauwhede, Ingrid}, + volume = {4727}, + series = {LNCS}, + pages = {450--466}, + address = {Vienna, Austria}, + month = {September}, + organization = {}, + publisher = {Springer-Verlag}, + bibsource = {Information Security Group (GSI), UCL, Louvain-la-Neuve, Belgium}, +} + +@INPROCEEDINGS{ChoiKKK-2006-isce, + author = {Choi, Yongje and Kim, Mooseop and Kim, Taesung and Kim, Howon}, + title = {Low power implementation of {SHA}-1 algorithm for {RFID} system}, + booktitle = {IEEE Tenth International Symposium on Consumer Electronics --- ISCE '06}, + year = {2006}, + editor = {}, + volume = {}, + series = {}, + pages = {1--5}, + address = {St.Petersburg, Russia}, + month = {September}, + organization = {}, + publisher = {}, + bibsource = {Information Security Group (GSI), UCL, Louvain-la-Neuve, Belgium}, +} + +@INPROCEEDINGS{DES-RFID-implement, + author = {Axel Poschmann and Gregor Le and Kai Schramm and Christof Paar}, + title = {A Family of Light-Weight Block Ciphers Based on {DES} Suited for {RFID} Applications}, + booktitle = {Proceedings of FSE 2007, LNCS}, + year = {2006}, + publisher = {Springer-Verlag} +} + +@article{4253019, +title={Strong Crypto for {RFID} Tags - A Comparison of Low-Power Hardware Implementations}, +author={Feldhofer, M. and Wolkerstorfer, J.}, +journal={Circuits and Systems, 2007. ISCAS 2007. IEEE International Symposium on}, +year={2007}, +month={May}, +volume={}, +number={}, +pages={1839-1842}, +keywords={cryptographic protocols, radiofrequency identificationAES-128, ECC-192, MD5, SHA-1, SHA-256, implementation efficiency, passive RFID tags, security protocols, standardized cryptographic algorithms, strong cryptography}, +doi={10.1109/ISCAS.2007.378272}, +ISSN={}, +} + +@techreport{PUF-optical, + author= {P. Ravinkanth}, + title= {Physical One-Way Functions}, + note = {Ph.D. Thesis}, + institution = {MIT}, + year={2001} +} + +@inproceedings{PUF-silicon, + author={B. Gassend and D. Clarke and M. van Dijk and S. Devadas}, + title = {Controlled Physical Random Functions}, + booktitle = {Proceedings of the 18th Annual Computer Security Applications Conference --- ACSAC '02}, + year = {2002}, + ISBN = {0-7695-1828-1}, + page = {149}, + publisher = {IEEE}, +} + +@article{PUF-circ-secret-key, + author = {D. Lim and J. W. Lee and B. Gassend and G. E. Suh and M. van Dijk and S. Devadas}, + title = {Extracting Secret Keys From Integrated Circuits}, + journal = {IEEE Transactions on Very Large Scale Integration (VLSI) Systems}, + pages = {1200--1205}, + year = {2005}, + issue = {13 (10)}, +} + + +@INPROCEEDINGS{Li99equivalencyreasoning, + author = {Chu Min Li}, + title = {Equivalency reasoning to solve a class of hard {SAT} problems}, + booktitle = {Information Processing Letters}, + year = {1999}, + pages = {76--1} +} + +@INPROCEEDINGS{Silva96conflictanalysis, + author = {Joo P. Marques and Silva Karem and A. Sakallah}, + title = {Conflict analysis in search algorithms for propositional satisfiability}, + booktitle = {Proc. of the IEEE Intl. Conf. on Tools with Artificial Intelligence}, + year = {1996} +} + +@article{Chaff01, + author = {Sharad Malik and Ying Zhao and Conor F. Madigan and Lintao Zhang and Matthew W. Moskewicz}, + title = {Chaff: Engineering an Efficient {SAT} Solver}, + journal ={Design Automation Conference}, + year = {2001}, + pages = {530-535}, + doi = {http://doi.ieeecomputersociety.org/10.1109/DAC.2001.935565}, + publisher = {IEEE Computer Society}, + address = {Los Alamitos, CA, USA}, +} +volume = {0}, +isbn = {}, + +@article{visualizingDPLL, + author = {Sinz, Carsten}, + title = {Visualizing {SAT} Instances and Runs of the {DPLL} Algorithm}, + journal = {J. Autom. Reason.}, + volume = {39}, + number = {2}, + year = {2007}, + issn = {0168-7433}, + pages = {219--243}, + doi = {http://dx.doi.org/10.1007/s10817-007-9074-1}, + publisher = {Kluwer Academic Publishers}, + address = {Hingham, MA, USA}, + } + +@inproceedings{nicolas.linear_feedback, + author={Nicolas T. Courtois}, + title={Fast Algebraic Attacks on Stream Ciphers with Linear Feedback}, + booktitle={Advances in Cryptology --- {CRYPTO} 2003}, + year={2003}, + pages={176-194}, + volume={2729/2003}, + series={LNCS}, + publisher={Springer}, +} + +@misc{Karsten-webpage-Cyrpto-1, + author={Karsten Nohl}, + title={Cryptanalysis of {C}rypto-1}, + howpublished={Press release}, + month={March}, + day = {12}, + year={2008}, + note= {\url{http://www.cs.virginia.edu/~kn5f/Mifare.Cryptanalysis.htm}} +} + +@Misc{Radboud-Mifare-press, + author = {{Digital {S}ecurity group, {R}adboud {U}niversity {N}ijmegen}}, + title = {Security Flaw in {M}ifare {C}lassic}, + howpublished = {Press release}, + month = {March}, + day = {12}, + year = {2008}, + note = {\url{http://www.ru.nl/english/general/radboud_university/vm/security_flaw_in/}}, +} + +@ARTICLE{Massacci00logicalcryptanalysis, + author = {Fabio Massacci and Laura Marraro}, + title = {Logical cryptanalysis as a {SAT}-problem: Encoding and analysis}, + journal = {Journal of Automated Reasoning}, + year = {2000}, + volume = {24}, + pages = {165--203} +} + +@article{Monte-Carlo-method, + abstract = {We shall present here the motivation and a general description of a method dealing with a class of problems in mathematical physics. The method is, essentially, a statistical approach to the study of differential equations, or more generally, of integro-differential equations that occur in various branches of the natural sciences.}, + author = {Metropolis, Nicholas and Ulam, S. }, + citeulike-article-id = {1886002}, + doi = {10.2307/2280232}, + journal = {Journal of the American Statistical Association}, + keywords = {random, sampling}, + number = {247}, + pages = {335--341}, + posted-at = {2009-04-12 22:32:37}, + priority = {2}, + title = {The {M}onte {C}arlo Method}, + url = {http://dx.doi.org/10.2307/2280232}, + volume = {44}, + year = {1949} +} + +@article{Rabin-primality-test, + author = {Rabin, Michael O. }, + citeulike-article-id = {1505894}, + doi = {10.1016/0022-314X(80)90084-0}, + journal = {J. Number Theory}, + mrnumber = {MR566880}, + number = {1}, + pages = {128--138}, + posted-at = {2007-07-27 00:11:40}, + priority = {2}, + title = {Probabilistic algorithm for testing primality}, + url = {http://dx.doi.org/10.1016/0022-314X(80)90084-0}, + volume = {12}, + year = {1980} +} + +@article{Mersenne-Twister, + address = {New York, NY, USA}, + author = {Matsumoto, Makoto and Nishimura, Takuji }, + citeulike-article-id = {611171}, + doi = {10.1145/272991.272995}, + issn = {1049-3301}, + journal = {ACM Trans. Model. Comput. Simul.}, + keywords = {algorithm}, + month = {January}, + number = {1}, + pages = {3--30}, + posted-at = {2008-10-26 00:03:42}, + priority = {0}, + publisher = {ACM Press}, + title = {Mersenne twister: a 623-dimensionally equidistributed uniform pseudo-random number generator}, + url = {http://dx.doi.org/10.1145/272991.272995}, + volume = {8}, + year = {1998} +} + +@inproceedings{L'Ecuyer98randomnumber, + author = {Pierre L'Ecuyer and Peter Hellekalek}, + title = {Random Number Generators: Selection Criteria and Testing}, + booktitle = {Random and Quasi-Random Point Sets}, + series = {Lecture Notes in Statistics}, + volume = {138}, + publisher = {Springer-Verlag}, + address = {New York}, + pages = {223--266}, + year = {1998}, +} + +@inproceedings{DBLP:conf/sat/SinzD05, + author = {Carsten Sinz and Edda-Maria Dieringer}, + title = {{DP}vis --- {A} Tool to Visualize the Structure of {SAT} Instances}, + booktitle = {SAT}, + year = {2005}, + pages = {257-268}, + ee = {http://dx.doi.org/10.1007/11499107_19}, + crossref = {DBLP:conf/sat/2005}, + bibsource = {DBLP, http://dblp.uni-trier.de} +} + + +@article{gomes00heavytailed, + author = {Carla P. Gomes and Bart Selman and Nuno Crato and Henry A. Kautz}, + title = {Heavy-Tailed Phenomena in Satisfiability and Constraint Satisfaction Problems}, + journal = {Journal of Automated Reasoning}, + volume = {24}, + number = {1/2}, + pages = {67--100}, + year = {2000}, + url = {citeseer.ist.psu.edu/article/gomes99heavytailed.html} +} + +@article{Mandelbrot60Pareto, + author = {Benoît B. Mandelbrot}, + title = {The Pareto-Lévy law and the distribution of income}, + journal = {Internat. Econom. Rev.}, + volume = {1}, + year = {1960}, + pages = {79--106} +} + +@inproceedings{Moura07tutorial, + author = {Leonardo de Moura, Bruno Dutertre and Natarajan Shankar}, + title = {A Tutorial on Satisfiability Modulo Theories}, + series = {LNCS}, + publisher = {Springer Berlin / Heidelberg}, + issn = {0302-9743}, + volume = {4590/2007}, + year = {2007}, + isbn = {978-3-540-73367-6}, + pages = {20--36}, + booktitle = {Computer Aided Verification}, +} + doi = {10.1007/978-3-540-73368-3}, + +@article{Karnaugh53Logic, + author = {Karnaugh, Maurice}, + year = {1953}, + month = {November}, + title = {The Map Method for Synthesis of Combinational Logic Circuits}, + journal = {Transactions of American Institute of Electrical Engineers part I}, + volume = {72}, + number = {9}, + pages = {593--599}, +} + +@inproceedings{Li00Integrating, + author = {Li, Chu Min}, + title = {Integrating Equivalency Reasoning into Davis-Putnam Procedure}, + booktitle = {Proceedings of the Seventeenth National Conference on Artificial Intelligence and Twelfth Conference on Innovative Applications of Artificial Intelligence}, + year = {2000}, + isbn = {0-262-51112-6}, + pages = {291--296}, + publisher = {AAAI Press / The MIT Press}, +} + +@article{Warners99TwoPhase, + author = {Joost P. Warners and Hans Van Maaren}, + title = {A Two Phase Algorithm for Solving a Class of Hard Satisfiability Problems}, + journal = {Operations Research Letters}, + year = {1999}, + volume = {23}, + number = {3--5}, + pages = {81--88} +} + +@inproceedings{Massacci00Taming, + author = {Peter Baumgartner and Fabio Massacci}, + title = {The Taming of the {(X)OR}}, + series = {LNCS}, + publisher = {Springer Berlin / Heidelberg}, + ISSN = {0302-9743}, + volume = {1861/2000}, + booktitle = {Computational Logic — CL 2000}, + doi = {10.1007/3-540-44957-4}, + year = {2000}, + isbn = {978-3-540-67797-0}, + pages = {508--522}, +} + +@inproceedings{Massacci99Using, + author = {Fabio Massacci}, + title = {Using {W}alk-{SAT} and {R}el-sat for cryptographic key search}, + booktitle = {Proc. of IJCAI-99}, + year = {1999}, + editor = {Morgan Kaufmann}, + pages = {290--295}, +} + +@inproceedings{Girault04Public, +author = {Marc Girault and David Lefranc}, +title = {Public Key Authentication with One (Online) Single Addition}, +series = {LNCS}, +bublisher = {Springer Berlin / Heidelberg}, +ISSN = {0302-9743}, +volume = {3156/2004}, +booktitle = {Cryptographic Hardware and Embedded Systems - CHES 2004}, +doi ={10.1007/b99451}, +year = {2004}, +isbn = {978-3-540-22666-6}, +pages = {967--984} +} + +@article{Hsieh72OnOptimal, + author = {Hsieh, H. Y. and Ghausi, M. S.}, + title = {On optimal-pivoting algorithms in sparse matrices}, + journal = {IEEE Trans. Circuit Theory}, + volume = {CT-19}, + pages = {93--96}, + month = {January}, + year = {1972} +} + +@article{HerasetalJAIR2008, + author = {Federico Heras and Javier Larrosa and Albert Oliveras}, + title = {{MiniMaxSAT: An efficient Weighted Max-SAT Solver}}, + journal = {Journal of Artificial Intelligence Research}, + volume = {31}, + year = {2008}, + pages = {1--32} + } + +@techreport{Wieringa07MiniMarch, + title = {{M}ini{M}arch --- {E}mbedding lookahead direction heuristics in a conflict driven solver}, + author = {Siert Wieringa}, + institution = {Technische Universiteit Delft}, + note = {Research Report}, + year = {2007}, + url = {http://www.st.ewi.tudelft.nl/sat/theses/minimarch.pdf}, +} + +techreport{OSI-MIT-Licence, +url = {http://www.opensource.org/licenses/mit-license.php} + + +@techreport{eStream, + title = {The e{STREAM} Portfolio}, + author = {Steve Babbage and Christophe De Canniere and Anne Canteaut and Carlos Cid and Henri Gilbert and Thomas Johansson and Christof Paar and Matthew Parker and Bart Preneel and Vincent Rijmen and Matt Robshaw and Hongjun Wu}, + url = {http://www.ecrypt.eu.org/stream/portfolio.pdf}, + institution = {eStream Project}, + year = {2008}, + month = {September}, + day = {8}, +} + +@techreport{Kibria08MiniSat, + author = {Raihan Kibria}, + title = {Midi{S}AT - {A}n extension of {M}ini{SAT}}, + institution = {Department of Electrical and Computer Engineering, Darmstadt University of Technology}, + year = {2005}, + month = {April}, + day = {26}, + url = {www.lri.fr/~simon/contest/results/descriptions/solvers/midisat_static.pdf}, +} + +@incollection{DaemenR05Rijndael, + author = {Joan Daemen and Vincent Rijmen}, + title = {Rijndael/AES}, + booktitle = {Encyclopedia of Cryptography and Security}, + year = {2005}, + ee = {http://dx.doi.org/10.1007/0-387-23483-7_358}, + crossref = {DBLP:reference/crypt/2005}, + bibsource = {DBLP, http://dblp.uni-trier.de} +} + +@book{DBLP:reference/crypt/2005, + editor = {Henk C. A. van Tilborg}, + title = {Encyclopedia of Cryptography and Security}, + publisher = {Springer}, + year = {2005}, + isbn = {978-0-387-23473-1}, + bibsource = {DBLP, http://dblp.uni-trier.de} +} + +@article{Strassen69Gaussian, + author = {Volker Strassen}, + title = {Gaussian Elimination is Not Optimal}, + journal = {Numerische Mathematik}, + volume = {13}, + pages = {354--356}, + year = {1969} +} + +@techreport{Crawford94TheMinimal, + author = {Crawford, J. M. and Kearns, M. J. and Shapire, R. E.}, + title = {The Minimal Disagreement Parity Problem as a Hard Satisfiability Problem}, + institution = {Computational Intelligence Research Laboratory and {AT\&T} {B}ell {L}abs}, + month = {February}, + year = {1994}, +} + +@inproceedings{OuafiV09Smashing, + author = {Khaled Ouafi and Serge Vaudenay}, + title = {Smashing {SQUASH}-0}, + volume = {5479}, + crossref = {DBLP:conf/eurocrypt/2009}, +} + +@inproceedings{ShamirRFIDSecLecture, +author = {Adi Shamir}, +title = {{SQUASH}: {A} new one-way hash function with provable security properties for higley contrained devices such as {RFID} tags}, +booktitle = {Invited lecture to the RFID Securty 2007 Workshop}, +year = {2007}, +} + +@misc{DES77, + author = {{National Bureau of Standards}}, + year = {1977}, + title = {Data {E}ncryption {S}tandard}, + institution = {U. S. Department of Commerce, National Bureau of Standards, Standards Publication (FIPS PUB) 46}, + address = {Washington, DC}, +}s + +@INPROCEEDINGS{Tsudik06Yet, + author = {Tsudik, Gene}, + title = {{YA-TRAP}: Yet Another Trivial {RFID} Authentication Protocol}, + booktitle = {International Conference on Pervasive Computing and Communications --- PerCom 2006}, + year = {2006}, + editor = {}, + volume = {}, + series = {}, + pages = {640--643}, + address = {Pisa, Italy}, + month = {March}, + organization = {IEEE}, + publisher = {IEEE Computer Society Press}, + bibsource = {Information Security Group (GSI), UCL, Louvain-la-Neuve, Belgium}, +} + + +@INPROCEEDINGS{Conti07RIPP, + author = {Conti, Mauro and Pietro, Roberto~Di and Mancini, Luigi~Vincenzo and Spognardi, Angelo}, + title = {{RIPP-FS}: an {RFID} Identification, Privacy Preserving Protocol with Forward Secrecy}, + booktitle = {International Workshop on Pervasive Computing and Communication Security --- PerSec '07}, + year = {2007}, + editor = {}, + volume = {}, + series = {}, + pages = {229--234}, + address = {New York City, New York, USA}, + month = {March}, + organization = {IEEE}, + publisher = {IEEE Computer Society Press}, + bibsource = {Information Security Group (GSI), UCL, Louvain-la-Neuve, Belgium}, +} + +@INPROCEEDINGS{Burmester06Provably, + author = {Burmester, Mike and Le, Tri van and Medeiros, Breno de}, + title = {Provably Secure Ubiquitous Systems: Universally Composable {RFID} Authentication Protocols}, + booktitle = {Conference on Security and Privacy for Emerging Areas in Communication Networks --- SecureComm '06}, + year = {2006}, + editor = {}, + volume = {}, + series = {}, + pages = {}, + address = {Baltimore, Maryland, USA}, + month = {August-September}, + organization = {IEEE}, + publisher = {}, + bibsource = {Information Security Group (GSI), UCL, Louvain-la-Neuve, Belgium}, +} + +@misc{ISO14443-standard, + author = {ISO/IEC}, + title = {14443-3 --- {I}dentification cards -- {C}ontactless integrated circuit(s) cards -- {P}roximity cards -- {P}art 3: {I}nitialization and anticollision}, + year = {2001, Stage: 90.92 --- 2007-12-11}, + institution = {International Organization for Standardization}, + address = {Geneva, Switzerland}, + url = {http://www.isotopicmaps.org/sam/sam-model/YYYY-MM-DD/}, +} + +@INPROCEEDINGS{Bailey05Shoehorning, + author = {Bailey, Daniel and Juels, Ari}, + title = {{Shoehorning Security into the EPC Standard}}, + booktitle = {International Conference on Security in Communication Networks --- SCN 2006}, + year = {2006}, + editor = {De~Prisco, Roberto and Yung, Moti}, + volume = {4116}, + series = {LNCS}, + pages = {303--320}, + address = {Maiori, Italy}, + month = {September}, + organization = {}, + publisher = {Springer-Verlag}, + bibsource = {Information Security Group (GSI), UCL, Louvain-la-Neuve, Belgium}, +} + +@INPROCEEDINGS{Soos08Analysing, + author = {Soos, Mate}, + title = {{Analysing the {M}olva and {D}i {P}ietro Private {RFID} Authentication Scheme}}, + booktitle = {Workshop on RFID Security --- RFIDSec'08}, + year = {2008}, + editor = {}, + volume = {}, + series = {}, + pages = {}, + address = {Budapest, Hungary}, + month = {July}, + organization = {}, + publisher = {}, +} + +@inproceedings{DBLP:conf/ccs/BurmesterMM08, + author = {Mike Burmester and Breno de Medeiros and Rossana Motta}, + title = {Robust, anonymous {RFID} authentication with constant key-lookup}, + booktitle = {ASIACCS}, + year = {2008}, + pages = {283-291}, + ee = {http://doi.acm.org/10.1145/1368310.1368351}, + crossref = {DBLP:conf/ccs/2008asia}, + bibsource = {DBLP, http://dblp.uni-trier.de} +} + +@proceedings{DBLP:conf/ccs/2008asia, + editor = {Masayuki Abe and Virgil D. Gligor}, + title = {Proceedings of the 2008 ACM Symposium on Information, Computer and Communications Security, ASIACCS 2008, Tokyo, Japan, March 18-20, 2008}, + booktitle = {ASIACCS}, + publisher = {ACM}, + year = {2008}, + isbn = {978-1-59593-979-1}, + bibsource = {DBLP, http://dblp.uni-trier.de} +} + +@INPROCEEDINGS{Blass09Ff, + author = {Blass, Erik-Oliver and Kurmus, Anil and Molva, Refik and Noubir, Guevara and Shikfa, Abdullatif}, + title = {{The {F}f-Family of Protocols for {RFID}-Privacy and Authentication}}, + booktitle = {Workshop on RFID Security --- RFIDSec'09}, + year = {2009}, + editor = {}, + volume = {}, + series = {}, + pages = {}, + address = {Leuven, Belgium}, + month = {July}, + organization = {}, + publisher = {}, + bibsource = {Information Security Group (GSI), UCL, Louvain-la-Neuve, Belgium}, +} + +@inproceedings{DBLP:conf/cardis/CastellucciaA06, + author = {Claude Castelluccia and Gildas Avoine}, + title = {Noisy Tags: {A} Pretty Good Key Exchange Protocol for {RFID} Tags}, + booktitle = {CARDIS}, + year = {2006}, + pages = {289-299}, + ee = {http://dx.doi.org/10.1007/11733447_21}, + crossref = {DBLP:conf/cardis/2006}, + bibsource = {DBLP, http://dblp.uni-trier.de} +} + +@proceedings{DBLP:conf/cardis/2006, + editor = {Josep Domingo-Ferrer and + Joachim Posegga and + Daniel Schreckling}, + title = {Smart Card Research and Advanced Applications, 7th IFIP + WG 8.8/11.2 International Conference, CARDIS 2006, Tarragona, + Spain, April 19-21, 2006, Proceedings}, + booktitle = {CARDIS}, + publisher = {Springer}, + series = {LNCS}, + volume = {3928}, + year = {2006}, + isbn = {3-540-33311-8}, + bibsource = {DBLP, http://dblp.uni-trier.de} +} + + +@inproceedings{DBLP:conf/ches/SavryPDRR07, + author = {O. Savry and F. Pebay-Peyroula and F. Dehmas and G. Robert and J. Reverdy}, + title = {{RFID} Noisy Reader --- {H}ow to Prevent from Eavesdropping on the Communication?}, + booktitle = {CHES}, + year = {2007}, + pages = {334-345}, + ee = {http://dx.doi.org/10.1007/978-3-540-74735-2_23}, + crossref = {DBLP:conf/ches/2007}, + bibsource = {DBLP, http://dblp.uni-trier.de} +} + +@proceedings{DBLP:conf/ches/2007, + editor = {Pascal Paillier and Ingrid Verbauwhede}, + title = {Cryptographic Hardware and Embedded Systems --- {CHES} 2007, + 9th International Workshop, Vienna, Austria, September 10-13, + 2007, Proceedings}, + booktitle = {CHES}, + publisher = {Springer}, + series = {LNCS}, + volume = {4727}, + year = {2007}, + isbn = {978-3-540-74734-5}, + bibsource = {DBLP, http://dblp.uni-trier.de} +} + +@article{Hancke07Modulating, + author = {G. Hancke}, + title = {Modulating a noisy carrier signal for eavesdropping-resistant {HF RFID}}, + journal = {e\&i --- Elektrotechnik und Informationstechnik}, + year = {2007}, + volume = {124}, + number = {11}, + month = {November}, + pages = {404--408}, + publisher = {Springer Wien}, + ISSN = {0932-383X}, + DOI = {10.1007/s00502-007-0479-7} +} + +@inproceedings{1423361, + author = {Babbage, Steve and Dodd, Matthew}, + title = {The {MICKEY} Stream Ciphers}, + booktitle = {New Stream Cipher Designs: The e{STREAM} Finalists}, + year = {2008}, + isbn = {978-3-540-68350-6}, + pages = {191--209}, + doi = {http://dx.doi.org/10.1007/978-3-540-68351-3_15}, + publisher = {Springer-Verlag}, + address = {Berlin, Heidelberg}, + } + +@inproceedings{DBLP:conf/wistp/DeursenMR08, + author = {Ton van Deursen and Sjouke Mauw and Sasa Radomirovic}, + title = {Untraceability of {RFID} Protocols}, + booktitle = {WISTP}, + year = {2008}, + pages = {1-15}, + ee = {http://dx.doi.org/10.1007/978-3-540-79966-5_1}, + crossref = {DBLP:conf/wistp/2008}, + bibsource = {DBLP, http://dblp.uni-trier.de} +} + +@proceedings{DBLP:conf/wistp/2008, + editor = {Jose Antonio Onieva and Damien Sauveron and Serge Chaumette and Dieter Gollmann and Constantinos Markantonakis}, + title = {Information Security Theory and Practices. Smart Devices, Convergence and Next Generation Networks, Second {IFIP WG} 11.2 International Workshop, {WISTP} 2008, Seville, Spain, May 13-16, 2008. Proceedings}, + booktitle = {WISTP}, + publisher = {Springer}, + series = {LNCS}, + volume = {5019}, + year = {2008}, + isbn = {978-3-540-79965-8}, + bibsource = {DBLP, http://dblp.uni-trier.de} +} + +@misc{A51, + author = {Ross Anderson}, + title = {A5 (was: Hacking digital phones)}, + howpublished = {Newsgroup Communication}, + year = {1994}, +} + +@inproceedings{DBLP:conf/cardis/GansHG08, + author = {Gerhard de Koning Gans and Jaap-Henk Hoepman and Flavio D. Garcia}, + title = {A Practical Attack on the {MIFARE} {C}lassic}, + booktitle = {CARDIS}, + year = {2008}, + pages = {267-282}, + ee = {http://dx.doi.org/10.1007/978-3-540-85893-5_20}, + crossref = {DBLP:conf/cardis/2008}, + bibsource = {DBLP, http://dblp.uni-trier.de} +} + +@proceedings{DBLP:conf/cardis/2008, + editor = {Gilles Grimaud and Fran\c{c}ois-Xavier Standaert}, + title = {Smart Card Research and Advanced Applications, 8th IFIP WG 8.8/11.2 International Conference, CARDIS 2008, London, UK, September 8-11, 2008. Proceedings}, + booktitle = {CARDIS}, + publisher = {Springer}, + series = {LNCS}, + volume = {5189}, + year = {2008}, + isbn = {978-3-540-85892-8}, + bibsource = {DBLP, http://dblp.uni-trier.de} +} + +@inproceedings{DBLP:conf/ima/CourtoisB07, + author = {Nicolas T. Courtois and Gregory V. Bard}, + title = {Algebraic Cryptanalysis of the {D}ata {E}ncryption {S}tandard}, + booktitle = {{IMA} Int. Conf.}, + year = {2007}, + pages = {152-169}, + ee = {http://dx.doi.org/10.1007/978-3-540-77272-9_10}, + crossref = {DBLP:conf/ima/2007}, + bibsource = {DBLP, http://dblp.uni-trier.de} +} + +@proceedings{DBLP:conf/ima/2007, + editor = {Steven D. Galbraith}, + title = {Cryptography and Coding, 11th IMA International Conference, Cirencester, UK, December 18-20, 2007, Proceedings}, + booktitle = {IMA Int. Conf.}, + publisher = {Springer}, + series = {LNCS}, + volume = {4887}, + year = {2007}, + isbn = {978-3-540-77271-2}, + bibsource = {DBLP, http://dblp.uni-trier.de} +} + +@book{Bard-algebraic, + title = {Algebraic Cryptanalysis}, + author = {Gregory V. Bard}, + year = {2009}, + pages = {392}, + volume = {XXXIV}, + series = {Security and Cryptology}, + ISBN = {978-0-387-88756-2}, + publisher = {Springer}, +} + +@inproceedings{Graphviz, + author = {John Ellson and Emden R. Gansner and Eleftherios Koutsofios and Stephen C. North and Gordon Woodhull}, + year = {2001}, + title = {Graphviz --- open source graph drawing tools}, + pages = {483--484}, + crossref = {DBLP:conf/gd/2001}, +} + +@proceedings{DBLP:conf/gd/2001, + editor = {Petra Mutzel and Michael J{\"u}nger and Sebastian Leipert}, + title = {Graph Drawing, 9th International Symposium, GD 2001 Vienna, Austria, September 23--26, 2001, Revised Papers}, + booktitle = {Graph Drawing}, + publisher = {Springer}, + series = {LNCS}, + volume = {2265}, + year = {2002}, + isbn = {3-540-43309-0}, + bibsource = {DBLP, http://dblp.uni-trier.de} +} + +@inproceedings{Borghoff09Mixed, + booktitle = {WEWoRC --- Western European Workshop on Research in Cryptology}, + title = {Bivium as a Mixed-0-1 Linear Programming Problem}, + author = {Julia Borghoff and Lars R. Knudsen and Mathias Stolpe}, + month = {July}, + year = {2009}, + address = {Graz, Austria}, +} + +@inproceedings{DBLP:conf/eurocrypt/DinurS09, + author = {Itai Dinur and Adi Shamir}, + title = {Cube Attacks on Tweakable Black Box Polynomials}, + booktitle = {EUROCRYPT}, + year = {2009}, + pages = {278--299}, + ee = {http://dx.doi.org/10.1007/978-3-642-01001-9_16}, + crossref = {DBLP:conf/eurocrypt/2009}, + bibsource = {DBLP, http://dblp.uni-trier.de} +} + +@proceedings{DBLP:conf/eurocrypt/2009, + editor = {Antoine Joux}, + title = {Advances in Cryptology --- EUROCRYPT 2009, 28th Annual International Conference on the Theory and Applications of Cryptographic Techniques, Cologne, Germany, April 26--30, 2009. Proceedings}, + booktitle = {EUROCRYPT}, + publisher = {Springer}, + series = {LNCS}, + volume = {5479}, + year = {2009}, + isbn = {978-3-642-01000-2}, + ee = {http://dx.doi.org/10.1007/978-3-642-01001-9}, + bibsource = {DBLP, http://dblp.uni-trier.de} +} + +@book{eStreamFinalists, + title = {The e{STREAM} Finalists}, + editor = {Matthew Robshaw and Olivier Billet}, + series = {LNCS}, + subseries = {Security and Cryptology}, + volume = {4986}, + year = {2008}, + pages = {295}, + isbn = {978-3-540-68350-6}, + publisher = {Springer}, +} + +@article{diffie76new, + author = "Whitfield Diffie and Martin E. Hellman", + title = "New Directions in Cryptography", + journal = "IEEE Transactions on Information Theory", + volume = "IT-22", + number = "6", + pages = "644--654", + date = "November 1976", + year = "1976", + url = "citeseer.ist.psu.edu/diffie76new.html" +} + +@ARTICLE{Rivest78amethod, + author = {Ron L. Rivest and Adi Shamir and Leonard Max Adleman}, + title = {A Method for Obtaining Digital Signatures and Public-Key Cryptosystems}, + journal = {Communications of the ACM}, + year = {1978}, + volume = {21}, + pages = {120--126} +} + +@inproceedings{Pfizmann01Anonimity, + author = {Andreas Pfitzmann and Marit Köhntopp}, + title = {Anonymity, Unobservability, and Pseudonymity --- {A} Proposal for Terminology}, + series = {LNCS}, + publisher = {Springer Berlin / Heidelberg}, + issn = {0302-9743}, + volume = {2009}, + year = {2001}, + booktitle = {Designing Privacy Enhancing Technologies}, + doi = {10.1007/3-540-44702-4}, + isbn = {978-3-540-41724-8}, + pages = {1--9}, +} + +@misc{Bard07efficientmethods, + author = {Gregory V. Bard and Nicolas T. Courtois and Chris Jefferson}, + title = {Efficient Methods for Conversion and Solution of Sparse Systems of Low-Degree Multivariate Polynomials over {GF}(2) via {SAT}-Solvers}, + howpublished = {Cryptology ePrint Archive, Report 2007/024, \url{http://eprint.iacr.org/2007/024}}, + year = {2007}, + organization = {IACR}, +} + +@inproceedings{DBLP:conf/sat/SoosNC09, + author = {Mate Soos and + Karsten Nohl and + Claude Castelluccia}, + title = {Extending {SAT} Solvers to Cryptographic Problems}, + booktitle = {SAT}, + year = {2009}, + pages = {244--257}, + ee = {http://dx.doi.org/10.1007/978-3-642-02777-2_24}, + crossref = {DBLP:conf/sat/2009}, + bibsource = {DBLP, http://dblp.uni-trier.de} +} + +@inproceedings{DBLP:conf/cav/GaneshD07, + author = {Vijay Ganesh and + David L. Dill}, + title = {A Decision Procedure for Bit-Vectors and Arrays}, + booktitle = {CAV}, + year = {2007}, + pages = {519-531}, + ee = {http://dx.doi.org/10.1007/978-3-540-73368-3_52}, + crossref = {DBLP:conf/cav/2007}, + bibsource = {DBLP, http://dblp.uni-trier.de} +} + +@proceedings{DBLP:conf/cav/2007, + editor = {Werner Damm and + Holger Hermanns}, + title = {Computer Aided Verification, 19th International Conference, + CAV 2007, Berlin, Germany, July 3-7, 2007, Proceedings}, + booktitle = {CAV}, + publisher = {Springer}, + series = {LNCS}, + volume = {4590}, + year = {2007}, + isbn = {978-3-540-73367-6}, + bibsource = {DBLP, http://dblp.uni-trier.de} +} + +@misc{Logic2CNF, + author = {Edd Barrett}, + title = {Logic2{CNF} Logic Solver and Converter}, + note = {\url{http://projects.cs.kent.ac.uk/projects/logic2cnf/trac/wiki/WikiStart}}, + year = {2010}, + month = {March}, +} + +@misc{CryptoMiniSat, + author = {Mate Soos}, + title = {Crypto{M}ini{S}at --- a {SAT} solver for cryptographic problems}, + note = {\url{http://planete.inrialpes.fr/~soos/CryptoMiniSat/index.html}}, + year = {2009}, +} + +@inproceedings{DBLP:conf/sat/EenB05, + author = {Niklas E{\'e}n and + Armin Biere}, + title = {Effective Preprocessing in {SAT} Through Variable and Clause + Elimination}, + booktitle = {SAT}, + year = {2005}, + pages = {61-75}, + ee = {http://dx.doi.org/10.1007/11499107_5}, + crossref = {DBLP:conf/sat/2005}, + bibsource = {DBLP, http://dblp.uni-trier.de} +} + +@inproceedings{glucose, + author = {Gilles Audemard and Laurent Simon}, + title = {{GLUCOSE}: a solver that predicts learnt clauses quality}, + booktitle = {SAT 2009 competitive events booklet}, + year = {2009}, + pages = {7--8}, +} + +@inproceedings{precosat, + author = {Armin Biere}, + title = {P\{re,i\}coSAT@SC’09}, + booktitle = {SAT 2009 competitive events booklet}, + year = {2009}, + pages = {41--42}, +} + +@inproceedings{DBLP:conf/sat/HeuleM04a, + author = {Marijn Heule and + Hans van Maaren}, + title = {Aligning {CNF}- and Equivalence-Reasoning}, + booktitle = {SAT (Selected Papers}, + year = {2004}, + pages = {145--156}, + ee = {http://dx.doi.org/10.1007/11527695_12}, + crossref = {DBLP:conf/sat/2004lncs}, + bibsource = {DBLP, http://dblp.uni-trier.de} +} + +@proceedings{DBLP:conf/sat/2004lncs, + editor = {Holger H. Hoos and + David G. Mitchell}, + title = {Theory and Applications of Satisfiability Testing, 7th International + Conference, SAT 2004, Vancouver, BC, Canada, May 10-13, + 2004, Revised Selected Papers}, + booktitle = {SAT (Selected Papers)}, + publisher = {Springer}, + series = {LNCS}, + volume = {3542}, + year = {2005}, + isbn = {3-540-27829-X}, + bibsource = {DBLP, http://dblp.uni-trier.de} +} + +@techreport{Heule-thesis, + author = {Marijn Heule}, + title = {{m}arch: Towards a lookahead Sat solver for general purposes}, + institution={Technische Universiteit Delft}, + month={February}, + year={2004}, +} + +@techreport{Heule-phd, + author = {Marijn J.H. Heule}, + title = {Smart solving: Tool and techniques for satisfiability solvers}, + institution={Technische Universiteit Delft}, + year={2008}, +} + +@article{DBLP:journals/amai/JeroslowW90, + author = {Robert G. Jeroslow and + Jinchang Wang}, + title = {Solving Propositional Satisfiability Problems}, + journal = {Ann. Math. Artif. Intell.}, + volume = {1}, + year = {1990}, + pages = {167-187}, + bibsource = {DBLP, http://dblp.uni-trier.de} +} + +@inproceedings{DBLP:conf/sat/PipatsrisawatD07, + author = {Knot Pipatsrisawat and + Adnan Darwiche}, + title = {A Lightweight Component Caching Scheme for Satisfiability + Solvers}, + booktitle = {SAT}, + year = {2007}, + pages = {294-299}, + ee = {http://dx.doi.org/10.1007/978-3-540-72788-0_28}, + crossref = {DBLP:conf/sat/2007}, + bibsource = {DBLP, http://dblp.uni-trier.de} +} + +@proceedings{DBLP:conf/sat/2007, + editor = {Jo{\~a}o Marques-Silva and + Karem A. Sakallah}, + title = {Theory and Applications of Satisfiability Testing --- SAT + 2007, 10th International Conference, Lisbon, Portugal, May + 28-31, 2007, Proceedings}, + booktitle = {SAT}, + publisher = {Springer}, + series = {LNCS}, + volume = {4501}, + year = {2007}, + isbn = {978-3-540-72787-3}, + bibsource = {DBLP, http://dblp.uni-trier.de} +} + +@inproceedings{DBLP:conf/ijcai/AudemardS09, + author = {Gilles Audemard and + Laurent Simon}, + title = {Predicting Learnt Clauses Quality in Modern {SAT} Solvers}, + booktitle = {IJCAI}, + year = {2009}, + pages = {399-404}, + ee = {http://ijcai.org/papers09/Papers/IJCAI09-074.pdf}, + crossref = {DBLP:conf/ijcai/2009}, + bibsource = {DBLP, http://dblp.uni-trier.de} +} + +@proceedings{DBLP:conf/ijcai/2009, + editor = {Craig Boutilier}, + title = {IJCAI 2009, Proceedings of the 21st International Joint + Conference on Artificial Intelligence, Pasadena, California, + USA, July 11-17, 2009}, + booktitle = {IJCAI}, + year = {2009}, + bibsource = {DBLP, http://dblp.uni-trier.de} +} + + +@inproceedings{DBLP:conf/tacas/JarvisaloBH10, + author = {Matti J{\"a}rvisalo and + Armin Biere and + Marijn Heule}, + title = {Blocked Clause Elimination}, + booktitle = {TACAS}, + year = {2010}, + pages = {129-144}, + ee = {http://dx.doi.org/10.1007/978-3-642-12002-2_10}, + crossref = {DBLP:conf/tacas/2010}, + bibsource = {DBLP, http://dblp.uni-trier.de} +} + +@proceedings{DBLP:conf/tacas/2010, + editor = {Javier Esparza and + Rupak Majumdar}, + title = {Tools and Algorithms for the Construction and Analysis of + Systems, 16th International Conference, TACAS 2010, Held + as Part of the Joint European Conferences on Theory and + Practice of Software, ETAPS 2010, Paphos, Cyprus, March + 20-28, 2010. Proceedings}, + booktitle = {TACAS}, + publisher = {Springer}, + series = {LNCS}, + volume = {6015}, + year = {2010}, + isbn = {978-3-642-12001-5}, + ee = {http://dx.doi.org/10.1007/978-3-642-12002-2}, + bibsource = {DBLP, http://dblp.uni-trier.de} +} + +@article{DBLP:journals/dam/Li03, + author = {Chu Min Li}, + title = {Equivalent literal propagation in the {DLL} procedure}, + journal = {Discrete Applied Mathematics}, + volume = {130}, + number = {2}, + year = {2003}, + pages = {251-276}, + ee = {http://dx.doi.org/10.1016/S0166-218X(02)00407-9}, + bibsource = {DBLP, http://dblp.uni-trier.de} +} + +@misc{Grid5000, + author = {{The Grid'5000 team}}, + title = {The {G}rid'5000 project}, + note = {\url{https://www.grid5000.fr}}, +} + year = {2008}, + +@article{DBLP:journals/endm/Berre01, + author = {Daniel Le Berre}, + title = {Exploiting the real power of unit propagation lookahead}, + journal = {Electronic Notes in Discrete Mathematics}, + volume = {9}, + year = {2001}, + pages = {59-80}, + ee = {http://dx.doi.org/10.1016/S1571-0653(04)00314-2}, + bibsource = {DBLP, http://dblp.uni-trier.de} +} + +@inproceedings{DBLP:conf/sat/GershmanS05, + author = {Roman Gershman and Ofer Strichman}, + title = {Cost-Effective Hyper-Resolution for Preprocessing {CNF} Formulas}, + booktitle = {SAT}, + year = {2005}, + pages = {423-429}, + ee = {http://dx.doi.org/10.1007/11499107_34}, + crossref = {DBLP:conf/sat/2005}, + bibsource = {DBLP, http://dblp.uni-trier.de} +} + + +@inproceedings{DBLP:conf/sat/HeuleJB11, + author = {Marijn Heule and + Matti J{\"a}rvisalo and + Armin Biere}, + title = {Efficient {CNF} Simplification Based on Binary Implication + Graphs}, + booktitle = {SAT}, + year = {2011}, + pages = {201-215}, + ee = {http://dx.doi.org/10.1007/978-3-642-21581-0_17}, + crossref = {DBLP:conf/sat/2011}, + bibsource = {DBLP, http://dblp.uni-trier.de} +} +@proceedings{DBLP:conf/sat/2011, + editor = {Karem A. Sakallah and + Laurent Simon}, + title = {Theory and Applications of Satisfiability Testing - SAT + 2011 - 14th International Conference, SAT 2011, Ann Arbor, + MI, USA, June 19-22, 2011. Proceedings}, + booktitle = {SAT}, + publisher = {Springer}, + series = {LNCS}, + volume = {6695}, + year = {2011}, + isbn = {978-3-642-21580-3}, + ee = {http://dx.doi.org/10.1007/978-3-642-21581-0}, + bibsource = {DBLP, http://dblp.uni-trier.de} +} + + +@inproceedings{DBLP:conf/ecai/PietteHS08, + author = {C{\'e}dric Piette and + Youssef Hamadi and + Lakhdar Sais}, + title = {Vivifying Propositional Clausal Formulae}, + booktitle = {ECAI}, + year = {2008}, + pages = {525-529}, + ee = {http://dx.doi.org/10.3233/978-1-58603-891-5-525}, + crossref = {DBLP:conf/ecai/2008}, + bibsource = {DBLP, http://dblp.uni-trier.de} +} +@proceedings{DBLP:conf/ecai/2008, + editor = {Malik Ghallab and + Constantine D. Spyropoulos and + Nikos Fakotakis and + Nikolaos M. Avouris}, + title = {ECAI 2008 - 18th European Conference on Artificial Intelligence, + Patras, Greece, July 21-25, 2008, Proceedings}, + booktitle = {ECAI}, + publisher = {IOS Press}, + series = {Frontiers in Artificial Intelligence and Applications}, + volume = {178}, + year = {2008}, + isbn = {978-1-58603-891-5}, + ee = {http://www.booksonline.iospress.nl/Content/View.aspx?piid=9905}, + bibsource = {DBLP, http://dblp.uni-trier.de} +} + +@inproceedings{DBLP:conf/sat/HanS09, + author = {HyoJung Han and + Fabio Somenzi}, + title = {On-the-Fly Clause Improvement}, + booktitle = {SAT}, + year = {2009}, + pages = {209-222}, + ee = {http://dx.doi.org/10.1007/978-3-642-02777-2_21}, + crossref = {DBLP:conf/sat/2009}, + bibsource = {DBLP, http://dblp.uni-trier.de} +} + + +@inproceedings{DBLP:conf/sat/SorenssonB09, + author = {Niklas S{\"o}rensson and + Armin Biere}, + title = {Minimizing Learned Clauses}, + booktitle = {SAT}, + year = {2009}, + pages = {237-243}, + ee = {http://dx.doi.org/10.1007/978-3-642-02777-2_23}, + crossref = {DBLP:conf/sat/2009}, + bibsource = {DBLP, http://dblp.uni-trier.de} +} + +@inproceedings{DBLP:conf/sat/BacchusW03, + author = {Fahiem Bacchus and + Jonathan Winter}, + title = {Effective Preprocessing with Hyper-Resolution and Equality + Reduction}, + booktitle = {SAT}, + year = {2003}, + pages = {341-355}, + ee = {http://dx.doi.org/10.1007/978-3-540-24605-3_26}, + crossref = {DBLP:conf/sat/2003}, + bibsource = {DBLP, http://dblp.uni-trier.de} +} +@proceedings{DBLP:conf/sat/2003, + editor = {Enrico Giunchiglia and + Armando Tacchella}, + title = {Theory and Applications of Satisfiability Testing, 6th International + Conference, SAT 2003. Santa Margherita Ligure, Italy, May + 5-8, 2003 Selected Revised Papers}, + booktitle = {SAT}, + publisher = {Springer}, + series = {LNCS}, + volume = {2919}, + year = {2004}, + isbn = {3-540-20851-8}, + bibsource = {DBLP, http://dblp.uni-trier.de} +} + +@proceedings{DBLP:conf/sat/2005, + editor = {Fahiem Bacchus and + Toby Walsh}, + title = {Theory and Applications of Satisfiability Testing, 8th International + Conference, SAT 2005, St. Andrews, UK, June 19-23, 2005, + Proceedings}, + booktitle = {SAT}, + publisher = {Springer}, + series = {LNCS}, + volume = {3569}, + year = {2005}, + isbn = {3-540-26276-8}, + bibsource = {DBLP, http://dblp.uni-trier.de} +} + +@proceedings{DBLP:conf/sat/2009, + editor = {Oliver Kullmann}, + title = {Theory and Applications of Satisfiability Testing - SAT + 2009, 12th International Conference, SAT 2009, Swansea, + UK, June 30 - July 3, 2009. Proceedings}, + booktitle = {SAT}, + publisher = {Springer}, + series = {Lecture Notes in Computer Science}, + volume = {5584}, + year = {2009}, + isbn = {978-3-642-02776-5}, + ee = {http://dx.doi.org/10.1007/978-3-642-02777-2}, + bibsource = {DBLP, http://dblp.uni-trier.de} +} + +@inproceedings{DBLP:conf/hvc/MantheyHB12, + author = {Norbert Manthey and + Marijn Heule and + Armin Biere}, + title = {Automated Reencoding of Boolean Formulas}, + booktitle = {Haifa Verification Conference}, + year = {2012}, + pages = {102-117}, + ee = {http://dx.doi.org/10.1007/978-3-642-39611-3_14}, + crossref = {DBLP:conf/hvc/2012}, + bibsource = {DBLP, http://dblp.uni-trier.de} +} + +@proceedings{DBLP:conf/hvc/2012, + editor = {Armin Biere and + Amir Nahir and + Tanja E. J. Vos}, + title = {Hardware and Software: Verification and Testing - 8th International + Haifa Verification Conference, HVC 2012, Haifa, Israel, + November 6-8, 2012. Revised Selected Papers}, + booktitle = {Haifa Verification Conference}, + publisher = {Springer}, + series = {Lecture Notes in Computer Science}, + volume = {7857}, + year = {2013}, + isbn = {978-3-642-39610-6}, + ee = {http://dx.doi.org/10.1007/978-3-642-39611-3}, + bibsource = {DBLP, http://dblp.uni-trier.de} +} \ No newline at end of file diff --git a/cryptominisat/cppsrc/docs/satcomp14-pdf/splncs03.bst b/cryptominisat/cppsrc/docs/satcomp14-pdf/splncs03.bst new file mode 100644 index 00000000..32791691 --- /dev/null +++ b/cryptominisat/cppsrc/docs/satcomp14-pdf/splncs03.bst @@ -0,0 +1,1519 @@ +%% BibTeX bibliography style `splncs03' +%% +%% BibTeX bibliography style for use with numbered references in +%% Springer Verlag's "Lecture Notes in Computer Science" series. +%% (See Springer's documentation for llncs.cls for +%% more details of the suggested reference format.) Note that this +%% file will not work for author-year style citations. +%% +%% Use \documentclass{llncs} and \bibliographystyle{splncs03}, and cite +%% a reference with (e.g.) \cite{smith77} to get a "[1]" in the text. +%% +%% This file comes to you courtesy of Maurizio "Titto" Patrignani of +%% Dipartimento di Informatica e Automazione Universita' Roma Tre +%% +%% ================================================================================================ +%% This was file `titto-lncs-02.bst' produced on Wed Apr 1, 2009 +%% Edited by hand by titto based on `titto-lncs-01.bst' (see below) +%% +%% CHANGES (with respect to titto-lncs-01.bst): +%% - Removed the call to \urlprefix (thus no "URL" string is added to the output) +%% ================================================================================================ +%% This was file `titto-lncs-01.bst' produced on Fri Aug 22, 2008 +%% Edited by hand by titto based on `titto.bst' (see below) +%% +%% CHANGES (with respect to titto.bst): +%% - Removed the "capitalize" command for editors string "(eds.)" and "(ed.)" +%% - Introduced the functions titto.bbl.pages and titto.bbl.page for journal pages (without "pp.") +%% - Added a new.sentence command to separate with a dot booktitle and series in the inproceedings +%% - Commented all new.block commands before urls and notes (to separate them with a comma) +%% - Introduced the functions titto.bbl.volume for handling journal volumes (without "vol." label) +%% - Used for editors the same name conventions used for authors (see function format.in.ed.booktitle) +%% - Removed a \newblock to avoid long spaces between title and "In: ..." +%% - Added function titto.space.prefix to add a space instead of "~" after the (removed) "vol." label +%% ================================================================================================ +%% This was file `titto.bst', +%% generated with the docstrip utility. +%% +%% The original source files were: +%% +%% merlin.mbs (with options: `vonx,nm-rvvc,yr-par,jttl-rm,volp-com,jwdpg,jwdvol,numser,ser-vol,jnm-x,btit-rm,bt-rm,edparxc,bkedcap,au-col,in-col,fin-bare,pp,ed,abr,mth-bare,xedn,jabr,and-com,and-com-ed,xand,url,url-blk,em-x,nfss,') +%% ---------------------------------------- +%% *** Tentative .bst file for Springer LNCS *** +%% +%% Copyright 1994-2007 Patrick W Daly + % =============================================================== + % IMPORTANT NOTICE: + % This bibliographic style (bst) file has been generated from one or + % more master bibliographic style (mbs) files, listed above. + % + % This generated file can be redistributed and/or modified under the terms + % of the LaTeX Project Public License Distributed from CTAN + % archives in directory macros/latex/base/lppl.txt; either + % version 1 of the License, or any later version. + % =============================================================== + % Name and version information of the main mbs file: + % \ProvidesFile{merlin.mbs}[2007/04/24 4.20 (PWD, AO, DPC)] + % For use with BibTeX version 0.99a or later + %------------------------------------------------------------------- + % This bibliography style file is intended for texts in ENGLISH + % This is a numerical citation style, and as such is standard LaTeX. + % It requires no extra package to interface to the main text. + % The form of the \bibitem entries is + % \bibitem{key}... + % Usage of \cite is as follows: + % \cite{key} ==>> [#] + % \cite[chap. 2]{key} ==>> [#, chap. 2] + % where # is a number determined by the ordering in the reference list. + % The order in the reference list is alphabetical by authors. + %--------------------------------------------------------------------- + +ENTRY + { address + author + booktitle + chapter + edition + editor + eid + howpublished + institution + journal + key + month + note + number + organization + pages + publisher + school + series + title + type + url + volume + year + } + {} + { label } +INTEGERS { output.state before.all mid.sentence after.sentence after.block } +FUNCTION {init.state.consts} +{ #0 'before.all := + #1 'mid.sentence := + #2 'after.sentence := + #3 'after.block := +} +STRINGS { s t} +FUNCTION {output.nonnull} +{ 's := + output.state mid.sentence = + { ", " * write$ } + { output.state after.block = + { add.period$ write$ +% newline$ +% "\newblock " write$ % removed for titto-lncs-01 + " " write$ % to avoid long spaces between title and "In: ..." + } + { output.state before.all = + 'write$ + { add.period$ " " * write$ } + if$ + } + if$ + mid.sentence 'output.state := + } + if$ + s +} +FUNCTION {output} +{ duplicate$ empty$ + 'pop$ + 'output.nonnull + if$ +} +FUNCTION {output.check} +{ 't := + duplicate$ empty$ + { pop$ "empty " t * " in " * cite$ * warning$ } + 'output.nonnull + if$ +} +FUNCTION {fin.entry} +{ duplicate$ empty$ + 'pop$ + 'write$ + if$ + newline$ +} + +FUNCTION {new.block} +{ output.state before.all = + 'skip$ + { after.block 'output.state := } + if$ +} +FUNCTION {new.sentence} +{ output.state after.block = + 'skip$ + { output.state before.all = + 'skip$ + { after.sentence 'output.state := } + if$ + } + if$ +} +FUNCTION {add.blank} +{ " " * before.all 'output.state := +} + + +FUNCTION {add.colon} +{ duplicate$ empty$ + 'skip$ + { ":" * add.blank } + if$ +} + +FUNCTION {date.block} +{ + new.block +} + +FUNCTION {not} +{ { #0 } + { #1 } + if$ +} +FUNCTION {and} +{ 'skip$ + { pop$ #0 } + if$ +} +FUNCTION {or} +{ { pop$ #1 } + 'skip$ + if$ +} +STRINGS {z} +FUNCTION {remove.dots} +{ 'z := + "" + { z empty$ not } + { z #1 #1 substring$ + z #2 global.max$ substring$ 'z := + duplicate$ "." = 'pop$ + { * } + if$ + } + while$ +} +FUNCTION {new.block.checka} +{ empty$ + 'skip$ + 'new.block + if$ +} +FUNCTION {new.block.checkb} +{ empty$ + swap$ empty$ + and + 'skip$ + 'new.block + if$ +} +FUNCTION {new.sentence.checka} +{ empty$ + 'skip$ + 'new.sentence + if$ +} +FUNCTION {new.sentence.checkb} +{ empty$ + swap$ empty$ + and + 'skip$ + 'new.sentence + if$ +} +FUNCTION {field.or.null} +{ duplicate$ empty$ + { pop$ "" } + 'skip$ + if$ +} +FUNCTION {emphasize} +{ skip$ } +FUNCTION {tie.or.space.prefix} +{ duplicate$ text.length$ #3 < + { "~" } + { " " } + if$ + swap$ +} +FUNCTION {titto.space.prefix} % always introduce a space +{ duplicate$ text.length$ #3 < + { " " } + { " " } + if$ + swap$ +} + + +FUNCTION {capitalize} +{ "u" change.case$ "t" change.case$ } + +FUNCTION {space.word} +{ " " swap$ * " " * } + % Here are the language-specific definitions for explicit words. + % Each function has a name bbl.xxx where xxx is the English word. + % The language selected here is ENGLISH +FUNCTION {bbl.and} +{ "and"} + +FUNCTION {bbl.etal} +{ "et~al." } + +FUNCTION {bbl.editors} +{ "eds." } + +FUNCTION {bbl.editor} +{ "ed." } + +FUNCTION {bbl.edby} +{ "edited by" } + +FUNCTION {bbl.edition} +{ "edn." } + +FUNCTION {bbl.volume} +{ "vol." } + +FUNCTION {titto.bbl.volume} % for handling journals +{ "" } + +FUNCTION {bbl.of} +{ "of" } + +FUNCTION {bbl.number} +{ "no." } + +FUNCTION {bbl.nr} +{ "no." } + +FUNCTION {bbl.in} +{ "in" } + +FUNCTION {bbl.pages} +{ "pp." } + +FUNCTION {bbl.page} +{ "p." } + +FUNCTION {titto.bbl.pages} % for journals +{ "" } + +FUNCTION {titto.bbl.page} % for journals +{ "" } + +FUNCTION {bbl.chapter} +{ "chap." } + +FUNCTION {bbl.techrep} +{ "Tech. Rep." } + +FUNCTION {bbl.mthesis} +{ "Master's thesis" } + +FUNCTION {bbl.phdthesis} +{ "Ph.D. thesis" } + +MACRO {jan} {"Jan."} + +MACRO {feb} {"Feb."} + +MACRO {mar} {"Mar."} + +MACRO {apr} {"Apr."} + +MACRO {may} {"May"} + +MACRO {jun} {"Jun."} + +MACRO {jul} {"Jul."} + +MACRO {aug} {"Aug."} + +MACRO {sep} {"Sep."} + +MACRO {oct} {"Oct."} + +MACRO {nov} {"Nov."} + +MACRO {dec} {"Dec."} + +MACRO {acmcs} {"ACM Comput. Surv."} + +MACRO {acta} {"Acta Inf."} + +MACRO {cacm} {"Commun. ACM"} + +MACRO {ibmjrd} {"IBM J. Res. Dev."} + +MACRO {ibmsj} {"IBM Syst.~J."} + +MACRO {ieeese} {"IEEE Trans. Software Eng."} + +MACRO {ieeetc} {"IEEE Trans. Comput."} + +MACRO {ieeetcad} + {"IEEE Trans. Comput. Aid. Des."} + +MACRO {ipl} {"Inf. Process. Lett."} + +MACRO {jacm} {"J.~ACM"} + +MACRO {jcss} {"J.~Comput. Syst. Sci."} + +MACRO {scp} {"Sci. Comput. Program."} + +MACRO {sicomp} {"SIAM J. Comput."} + +MACRO {tocs} {"ACM Trans. Comput. Syst."} + +MACRO {tods} {"ACM Trans. Database Syst."} + +MACRO {tog} {"ACM Trans. Graphic."} + +MACRO {toms} {"ACM Trans. Math. Software"} + +MACRO {toois} {"ACM Trans. Office Inf. Syst."} + +MACRO {toplas} {"ACM Trans. Progr. Lang. Syst."} + +MACRO {tcs} {"Theor. Comput. Sci."} + +FUNCTION {bibinfo.check} +{ swap$ + duplicate$ missing$ + { + pop$ pop$ + "" + } + { duplicate$ empty$ + { + swap$ pop$ + } + { swap$ + pop$ + } + if$ + } + if$ +} +FUNCTION {bibinfo.warn} +{ swap$ + duplicate$ missing$ + { + swap$ "missing " swap$ * " in " * cite$ * warning$ pop$ + "" + } + { duplicate$ empty$ + { + swap$ "empty " swap$ * " in " * cite$ * warning$ + } + { swap$ + pop$ + } + if$ + } + if$ +} +FUNCTION {format.url} +{ url empty$ + { "" } +% { "\urlprefix\url{" url * "}" * } + { "\url{" url * "}" * } % changed in titto-lncs-02.bst + if$ +} + +INTEGERS { nameptr namesleft numnames } + + +STRINGS { bibinfo} + +FUNCTION {format.names} +{ 'bibinfo := + duplicate$ empty$ 'skip$ { + 's := + "" 't := + #1 'nameptr := + s num.names$ 'numnames := + numnames 'namesleft := + { namesleft #0 > } + { s nameptr + "{vv~}{ll}{, jj}{, f{.}.}" + format.name$ + bibinfo bibinfo.check + 't := + nameptr #1 > + { + namesleft #1 > + { ", " * t * } + { + s nameptr "{ll}" format.name$ duplicate$ "others" = + { 't := } + { pop$ } + if$ + "," * + t "others" = + { + " " * bbl.etal * + } + { " " * t * } + if$ + } + if$ + } + 't + if$ + nameptr #1 + 'nameptr := + namesleft #1 - 'namesleft := + } + while$ + } if$ +} +FUNCTION {format.names.ed} +{ + 'bibinfo := + duplicate$ empty$ 'skip$ { + 's := + "" 't := + #1 'nameptr := + s num.names$ 'numnames := + numnames 'namesleft := + { namesleft #0 > } + { s nameptr + "{f{.}.~}{vv~}{ll}{ jj}" + format.name$ + bibinfo bibinfo.check + 't := + nameptr #1 > + { + namesleft #1 > + { ", " * t * } + { + s nameptr "{ll}" format.name$ duplicate$ "others" = + { 't := } + { pop$ } + if$ + "," * + t "others" = + { + + " " * bbl.etal * + } + { " " * t * } + if$ + } + if$ + } + 't + if$ + nameptr #1 + 'nameptr := + namesleft #1 - 'namesleft := + } + while$ + } if$ +} +FUNCTION {format.authors} +{ author "author" format.names +} +FUNCTION {get.bbl.editor} +{ editor num.names$ #1 > 'bbl.editors 'bbl.editor if$ } + +FUNCTION {format.editors} +{ editor "editor" format.names duplicate$ empty$ 'skip$ + { + " " * + get.bbl.editor +% capitalize + "(" swap$ * ")" * + * + } + if$ +} +FUNCTION {format.note} +{ + note empty$ + { "" } + { note #1 #1 substring$ + duplicate$ "{" = + 'skip$ + { output.state mid.sentence = + { "l" } + { "u" } + if$ + change.case$ + } + if$ + note #2 global.max$ substring$ * "note" bibinfo.check + } + if$ +} + +FUNCTION {format.title} +{ title + duplicate$ empty$ 'skip$ + { "t" change.case$ } + if$ + "title" bibinfo.check +} +FUNCTION {output.bibitem} +{ newline$ + "\bibitem{" write$ + cite$ write$ + "}" write$ + newline$ + "" + before.all 'output.state := +} + +FUNCTION {n.dashify} +{ + 't := + "" + { t empty$ not } + { t #1 #1 substring$ "-" = + { t #1 #2 substring$ "--" = not + { "--" * + t #2 global.max$ substring$ 't := + } + { { t #1 #1 substring$ "-" = } + { "-" * + t #2 global.max$ substring$ 't := + } + while$ + } + if$ + } + { t #1 #1 substring$ * + t #2 global.max$ substring$ 't := + } + if$ + } + while$ +} + +FUNCTION {word.in} +{ bbl.in capitalize + ":" * + " " * } + +FUNCTION {format.date} +{ + month "month" bibinfo.check + duplicate$ empty$ + year "year" bibinfo.check duplicate$ empty$ + { swap$ 'skip$ + { "there's a month but no year in " cite$ * warning$ } + if$ + * + } + { swap$ 'skip$ + { + swap$ + " " * swap$ + } + if$ + * + remove.dots + } + if$ + duplicate$ empty$ + 'skip$ + { + before.all 'output.state := + " (" swap$ * ")" * + } + if$ +} +FUNCTION {format.btitle} +{ title "title" bibinfo.check + duplicate$ empty$ 'skip$ + { + } + if$ +} +FUNCTION {either.or.check} +{ empty$ + 'pop$ + { "can't use both " swap$ * " fields in " * cite$ * warning$ } + if$ +} +FUNCTION {format.bvolume} +{ volume empty$ + { "" } + { bbl.volume volume tie.or.space.prefix + "volume" bibinfo.check * * + series "series" bibinfo.check + duplicate$ empty$ 'pop$ + { emphasize ", " * swap$ * } + if$ + "volume and number" number either.or.check + } + if$ +} +FUNCTION {format.number.series} +{ volume empty$ + { number empty$ + { series field.or.null } + { output.state mid.sentence = + { bbl.number } + { bbl.number capitalize } + if$ + number tie.or.space.prefix "number" bibinfo.check * * + series empty$ + { "there's a number but no series in " cite$ * warning$ } + { bbl.in space.word * + series "series" bibinfo.check * + } + if$ + } + if$ + } + { "" } + if$ +} + +FUNCTION {format.edition} +{ edition duplicate$ empty$ 'skip$ + { + output.state mid.sentence = + { "l" } + { "t" } + if$ change.case$ + "edition" bibinfo.check + " " * bbl.edition * + } + if$ +} +INTEGERS { multiresult } +FUNCTION {multi.page.check} +{ 't := + #0 'multiresult := + { multiresult not + t empty$ not + and + } + { t #1 #1 substring$ + duplicate$ "-" = + swap$ duplicate$ "," = + swap$ "+" = + or or + { #1 'multiresult := } + { t #2 global.max$ substring$ 't := } + if$ + } + while$ + multiresult +} +FUNCTION {format.pages} +{ pages duplicate$ empty$ 'skip$ + { duplicate$ multi.page.check + { + bbl.pages swap$ + n.dashify + } + { + bbl.page swap$ + } + if$ + tie.or.space.prefix + "pages" bibinfo.check + * * + } + if$ +} +FUNCTION {format.journal.pages} +{ pages duplicate$ empty$ 'pop$ + { swap$ duplicate$ empty$ + { pop$ pop$ format.pages } + { + ", " * + swap$ + n.dashify + pages multi.page.check + 'titto.bbl.pages + 'titto.bbl.page + if$ + swap$ tie.or.space.prefix + "pages" bibinfo.check + * * + * + } + if$ + } + if$ +} +FUNCTION {format.journal.eid} +{ eid "eid" bibinfo.check + duplicate$ empty$ 'pop$ + { swap$ duplicate$ empty$ 'skip$ + { + ", " * + } + if$ + swap$ * + } + if$ +} +FUNCTION {format.vol.num.pages} % this function is used only for journal entries +{ volume field.or.null + duplicate$ empty$ 'skip$ + { +% bbl.volume swap$ tie.or.space.prefix + titto.bbl.volume swap$ titto.space.prefix +% rationale for the change above: for journals you don't want "vol." label +% hence it does not make sense to attach the journal number to the label when +% it is short + "volume" bibinfo.check + * * + } + if$ + number "number" bibinfo.check duplicate$ empty$ 'skip$ + { + swap$ duplicate$ empty$ + { "there's a number but no volume in " cite$ * warning$ } + 'skip$ + if$ + swap$ + "(" swap$ * ")" * + } + if$ * + eid empty$ + { format.journal.pages } + { format.journal.eid } + if$ +} + +FUNCTION {format.chapter.pages} +{ chapter empty$ + 'format.pages + { type empty$ + { bbl.chapter } + { type "l" change.case$ + "type" bibinfo.check + } + if$ + chapter tie.or.space.prefix + "chapter" bibinfo.check + * * + pages empty$ + 'skip$ + { ", " * format.pages * } + if$ + } + if$ +} + +FUNCTION {format.booktitle} +{ + booktitle "booktitle" bibinfo.check +} +FUNCTION {format.in.ed.booktitle} +{ format.booktitle duplicate$ empty$ 'skip$ + { +% editor "editor" format.names.ed duplicate$ empty$ 'pop$ % changed by titto + editor "editor" format.names duplicate$ empty$ 'pop$ + { + " " * + get.bbl.editor +% capitalize + "(" swap$ * ") " * + * swap$ + * } + if$ + word.in swap$ * + } + if$ +} +FUNCTION {empty.misc.check} +{ author empty$ title empty$ howpublished empty$ + month empty$ year empty$ note empty$ + and and and and and + key empty$ not and + { "all relevant fields are empty in " cite$ * warning$ } + 'skip$ + if$ +} +FUNCTION {format.thesis.type} +{ type duplicate$ empty$ + 'pop$ + { swap$ pop$ + "t" change.case$ "type" bibinfo.check + } + if$ +} +FUNCTION {format.tr.number} +{ number "number" bibinfo.check + type duplicate$ empty$ + { pop$ bbl.techrep } + 'skip$ + if$ + "type" bibinfo.check + swap$ duplicate$ empty$ + { pop$ "t" change.case$ } + { tie.or.space.prefix * * } + if$ +} +FUNCTION {format.article.crossref} +{ + key duplicate$ empty$ + { pop$ + journal duplicate$ empty$ + { "need key or journal for " cite$ * " to crossref " * crossref * warning$ } + { "journal" bibinfo.check emphasize word.in swap$ * } + if$ + } + { word.in swap$ * " " *} + if$ + " \cite{" * crossref * "}" * +} +FUNCTION {format.crossref.editor} +{ editor #1 "{vv~}{ll}" format.name$ + "editor" bibinfo.check + editor num.names$ duplicate$ + #2 > + { pop$ + "editor" bibinfo.check + " " * bbl.etal + * + } + { #2 < + 'skip$ + { editor #2 "{ff }{vv }{ll}{ jj}" format.name$ "others" = + { + "editor" bibinfo.check + " " * bbl.etal + * + } + { + bbl.and space.word + * editor #2 "{vv~}{ll}" format.name$ + "editor" bibinfo.check + * + } + if$ + } + if$ + } + if$ +} +FUNCTION {format.book.crossref} +{ volume duplicate$ empty$ + { "empty volume in " cite$ * "'s crossref of " * crossref * warning$ + pop$ word.in + } + { bbl.volume + capitalize + swap$ tie.or.space.prefix "volume" bibinfo.check * * bbl.of space.word * + } + if$ + editor empty$ + editor field.or.null author field.or.null = + or + { key empty$ + { series empty$ + { "need editor, key, or series for " cite$ * " to crossref " * + crossref * warning$ + "" * + } + { series emphasize * } + if$ + } + { key * } + if$ + } + { format.crossref.editor * } + if$ + " \cite{" * crossref * "}" * +} +FUNCTION {format.incoll.inproc.crossref} +{ + editor empty$ + editor field.or.null author field.or.null = + or + { key empty$ + { format.booktitle duplicate$ empty$ + { "need editor, key, or booktitle for " cite$ * " to crossref " * + crossref * warning$ + } + { word.in swap$ * } + if$ + } + { word.in key * " " *} + if$ + } + { word.in format.crossref.editor * " " *} + if$ + " \cite{" * crossref * "}" * +} +FUNCTION {format.org.or.pub} +{ 't := + "" + address empty$ t empty$ and + 'skip$ + { + t empty$ + { address "address" bibinfo.check * + } + { t * + address empty$ + 'skip$ + { ", " * address "address" bibinfo.check * } + if$ + } + if$ + } + if$ +} +FUNCTION {format.publisher.address} +{ publisher "publisher" bibinfo.warn format.org.or.pub +} + +FUNCTION {format.organization.address} +{ organization "organization" bibinfo.check format.org.or.pub +} + +FUNCTION {article} +{ output.bibitem + format.authors "author" output.check + add.colon + new.block + format.title "title" output.check + new.block + crossref missing$ + { + journal + "journal" bibinfo.check + "journal" output.check + add.blank + format.vol.num.pages output + format.date "year" output.check + } + { format.article.crossref output.nonnull + format.pages output + } + if$ +% new.block + format.url output +% new.block + format.note output + fin.entry +} +FUNCTION {book} +{ output.bibitem + author empty$ + { format.editors "author and editor" output.check + add.colon + } + { format.authors output.nonnull + add.colon + crossref missing$ + { "author and editor" editor either.or.check } + 'skip$ + if$ + } + if$ + new.block + format.btitle "title" output.check + crossref missing$ + { format.bvolume output + new.block + new.sentence + format.number.series output + format.publisher.address output + } + { + new.block + format.book.crossref output.nonnull + } + if$ + format.edition output + format.date "year" output.check +% new.block + format.url output +% new.block + format.note output + fin.entry +} +FUNCTION {booklet} +{ output.bibitem + format.authors output + add.colon + new.block + format.title "title" output.check + new.block + howpublished "howpublished" bibinfo.check output + address "address" bibinfo.check output + format.date output +% new.block + format.url output +% new.block + format.note output + fin.entry +} + +FUNCTION {inbook} +{ output.bibitem + author empty$ + { format.editors "author and editor" output.check + add.colon + } + { format.authors output.nonnull + add.colon + crossref missing$ + { "author and editor" editor either.or.check } + 'skip$ + if$ + } + if$ + new.block + format.btitle "title" output.check + crossref missing$ + { + format.bvolume output + format.chapter.pages "chapter and pages" output.check + new.block + new.sentence + format.number.series output + format.publisher.address output + } + { + format.chapter.pages "chapter and pages" output.check + new.block + format.book.crossref output.nonnull + } + if$ + format.edition output + format.date "year" output.check +% new.block + format.url output +% new.block + format.note output + fin.entry +} + +FUNCTION {incollection} +{ output.bibitem + format.authors "author" output.check + add.colon + new.block + format.title "title" output.check + new.block + crossref missing$ + { format.in.ed.booktitle "booktitle" output.check + format.bvolume output + format.chapter.pages output + new.sentence + format.number.series output + format.publisher.address output + format.edition output + format.date "year" output.check + } + { format.incoll.inproc.crossref output.nonnull + format.chapter.pages output + } + if$ +% new.block + format.url output +% new.block + format.note output + fin.entry +} +FUNCTION {inproceedings} +{ output.bibitem + format.authors "author" output.check + add.colon + new.block + format.title "title" output.check + new.block + crossref missing$ + { format.in.ed.booktitle "booktitle" output.check + new.sentence % added by titto + format.bvolume output + format.pages output + new.sentence + format.number.series output + publisher empty$ + { format.organization.address output } + { organization "organization" bibinfo.check output + format.publisher.address output + } + if$ + format.date "year" output.check + } + { format.incoll.inproc.crossref output.nonnull + format.pages output + } + if$ +% new.block + format.url output +% new.block + format.note output + fin.entry +} +FUNCTION {conference} { inproceedings } +FUNCTION {manual} +{ output.bibitem + author empty$ + { organization "organization" bibinfo.check + duplicate$ empty$ 'pop$ + { output + address "address" bibinfo.check output + } + if$ + } + { format.authors output.nonnull } + if$ + add.colon + new.block + format.btitle "title" output.check + author empty$ + { organization empty$ + { + address new.block.checka + address "address" bibinfo.check output + } + 'skip$ + if$ + } + { + organization address new.block.checkb + organization "organization" bibinfo.check output + address "address" bibinfo.check output + } + if$ + format.edition output + format.date output +% new.block + format.url output +% new.block + format.note output + fin.entry +} + +FUNCTION {mastersthesis} +{ output.bibitem + format.authors "author" output.check + add.colon + new.block + format.btitle + "title" output.check + new.block + bbl.mthesis format.thesis.type output.nonnull + school "school" bibinfo.warn output + address "address" bibinfo.check output + format.date "year" output.check +% new.block + format.url output +% new.block + format.note output + fin.entry +} + +FUNCTION {misc} +{ output.bibitem + format.authors output + add.colon + title howpublished new.block.checkb + format.title output + howpublished new.block.checka + howpublished "howpublished" bibinfo.check output + format.date output +% new.block + format.url output +% new.block + format.note output + fin.entry + empty.misc.check +} +FUNCTION {phdthesis} +{ output.bibitem + format.authors "author" output.check + add.colon + new.block + format.btitle + "title" output.check + new.block + bbl.phdthesis format.thesis.type output.nonnull + school "school" bibinfo.warn output + address "address" bibinfo.check output + format.date "year" output.check +% new.block + format.url output +% new.block + format.note output + fin.entry +} + +FUNCTION {proceedings} +{ output.bibitem + editor empty$ + { organization "organization" bibinfo.check output + } + { format.editors output.nonnull } + if$ + add.colon + new.block + format.btitle "title" output.check + format.bvolume output + editor empty$ + { publisher empty$ + { format.number.series output } + { + new.sentence + format.number.series output + format.publisher.address output + } + if$ + } + { publisher empty$ + { + new.sentence + format.number.series output + format.organization.address output } + { + new.sentence + format.number.series output + organization "organization" bibinfo.check output + format.publisher.address output + } + if$ + } + if$ + format.date "year" output.check +% new.block + format.url output +% new.block + format.note output + fin.entry +} + +FUNCTION {techreport} +{ output.bibitem + format.authors "author" output.check + add.colon + new.block + format.title + "title" output.check + new.block + format.tr.number output.nonnull + institution "institution" bibinfo.warn output + address "address" bibinfo.check output + format.date "year" output.check +% new.block + format.url output +% new.block + format.note output + fin.entry +} + +FUNCTION {unpublished} +{ output.bibitem + format.authors "author" output.check + add.colon + new.block + format.title "title" output.check + format.date output +% new.block + format.url output +% new.block + format.note "note" output.check + fin.entry +} + +FUNCTION {default.type} { misc } +READ +FUNCTION {sortify} +{ purify$ + "l" change.case$ +} +INTEGERS { len } +FUNCTION {chop.word} +{ 's := + 'len := + s #1 len substring$ = + { s len #1 + global.max$ substring$ } + 's + if$ +} +FUNCTION {sort.format.names} +{ 's := + #1 'nameptr := + "" + s num.names$ 'numnames := + numnames 'namesleft := + { namesleft #0 > } + { s nameptr + "{ll{ }}{ ff{ }}{ jj{ }}" + format.name$ 't := + nameptr #1 > + { + " " * + namesleft #1 = t "others" = and + { "zzzzz" * } + { t sortify * } + if$ + } + { t sortify * } + if$ + nameptr #1 + 'nameptr := + namesleft #1 - 'namesleft := + } + while$ +} + +FUNCTION {sort.format.title} +{ 't := + "A " #2 + "An " #3 + "The " #4 t chop.word + chop.word + chop.word + sortify + #1 global.max$ substring$ +} +FUNCTION {author.sort} +{ author empty$ + { key empty$ + { "to sort, need author or key in " cite$ * warning$ + "" + } + { key sortify } + if$ + } + { author sort.format.names } + if$ +} +FUNCTION {author.editor.sort} +{ author empty$ + { editor empty$ + { key empty$ + { "to sort, need author, editor, or key in " cite$ * warning$ + "" + } + { key sortify } + if$ + } + { editor sort.format.names } + if$ + } + { author sort.format.names } + if$ +} +FUNCTION {author.organization.sort} +{ author empty$ + { organization empty$ + { key empty$ + { "to sort, need author, organization, or key in " cite$ * warning$ + "" + } + { key sortify } + if$ + } + { "The " #4 organization chop.word sortify } + if$ + } + { author sort.format.names } + if$ +} +FUNCTION {editor.organization.sort} +{ editor empty$ + { organization empty$ + { key empty$ + { "to sort, need editor, organization, or key in " cite$ * warning$ + "" + } + { key sortify } + if$ + } + { "The " #4 organization chop.word sortify } + if$ + } + { editor sort.format.names } + if$ +} +FUNCTION {presort} +{ type$ "book" = + type$ "inbook" = + or + 'author.editor.sort + { type$ "proceedings" = + 'editor.organization.sort + { type$ "manual" = + 'author.organization.sort + 'author.sort + if$ + } + if$ + } + if$ + " " + * + year field.or.null sortify + * + " " + * + title field.or.null + sort.format.title + * + #1 entry.max$ substring$ + 'sort.key$ := +} +ITERATE {presort} +SORT +STRINGS { longest.label } +INTEGERS { number.label longest.label.width } +FUNCTION {initialize.longest.label} +{ "" 'longest.label := + #1 'number.label := + #0 'longest.label.width := +} +FUNCTION {longest.label.pass} +{ number.label int.to.str$ 'label := + number.label #1 + 'number.label := + label width$ longest.label.width > + { label 'longest.label := + label width$ 'longest.label.width := + } + 'skip$ + if$ +} +EXECUTE {initialize.longest.label} +ITERATE {longest.label.pass} +FUNCTION {begin.bib} +{ preamble$ empty$ + 'skip$ + { preamble$ write$ newline$ } + if$ + "\begin{thebibliography}{" longest.label * "}" * + write$ newline$ + "\providecommand{\url}[1]{\texttt{#1}}" + write$ newline$ + "\providecommand{\urlprefix}{URL }" + write$ newline$ +} +EXECUTE {begin.bib} +EXECUTE {init.state.consts} +ITERATE {call.type$} +FUNCTION {end.bib} +{ newline$ + "\end{thebibliography}" write$ newline$ +} +EXECUTE {end.bib} +%% End of customized bst file +%% +%% End of file `titto.bst'. + + diff --git a/cryptominisat/cppsrc/docs/satcomp15-pdf/Makefile b/cryptominisat/cppsrc/docs/satcomp15-pdf/Makefile new file mode 100644 index 00000000..9b86a32c --- /dev/null +++ b/cryptominisat/cppsrc/docs/satcomp15-pdf/Makefile @@ -0,0 +1,25 @@ +TEX = pdflatex -shell-escape -interaction=nonstopmode -file-line-error +PRE = $(TEX) -ini -job-name="preamble" "&pdflatex preamble.tex\dump" +BIB = bibtex + +all: cmsv4.pdf + +view : + okular cmsv44.pdf + +cmsv4.pdf : clean cmsv4.tex cmsv4.bbl cmsv4.blg + $(TEX) cmsv4.tex + $(TEX) cmsv4.tex + mv cmsv4.pdf cmsv44.pdf + +cmsv4.bbl cmsv4.blg : cmsv4.bib cmsv4.aux + $(BIB) cmsv4 + +cmsv4.aux : cmsv4.tex + $(TEX) cmsv4.tex + +cmsv4.bib : cmsv4.tex + $(TEX) cmsv4.tex + +clean: + rm -f *.log *.pdf *.blg *.bbl *.aux *.out diff --git a/cryptominisat/cppsrc/docs/satcomp15-pdf/cmsv4.kilepr b/cryptominisat/cppsrc/docs/satcomp15-pdf/cmsv4.kilepr new file mode 100644 index 00000000..1c48f5ab --- /dev/null +++ b/cryptominisat/cppsrc/docs/satcomp15-pdf/cmsv4.kilepr @@ -0,0 +1,53 @@ +[General] +def_graphic_ext= +img_extIsRegExp=false +img_extensions=.eps .jpg .jpeg .png .pdf .ps .fig .gif .dvi +kileprversion=2 +kileversion=2.1.0 +lastDocument=cmsv4.tex +masterDocument= +name=auth_eloadas +pkg_extIsRegExp=false +pkg_extensions=.cls .sty .bbx .cbx .lbx +src_extIsRegExp=false +src_extensions=.tex .ltx .latex .dtx .ins .bib .mp + +[Tools] +MakeIndex= +QuickBuild= + +[document-settings,item:cmsv4.tex] +Bookmarks= +Encoding=UTF-8 +FoldedColumns= +FoldedLines= +Highlighting=LaTeX +Indentation Mode=normal +Mode=LaTeX +ReadWrite=true + +[item:cmsv4.kilepr] +archive=true +column=0 +encoding= +highlight= +line=0 +mode= +open=false +order=-1 + +[item:cmsv4.tex] +archive=true +column=1 +encoding=UTF-8 +highlight=LaTeX +line=245 +mode=LaTeX +open=true +order=0 + +[view-settings,view=0,item:cmsv4.tex] +CursorColumn=1 +CursorLine=245 +JumpList= +ViMarks= diff --git a/cryptominisat/cppsrc/docs/satcomp15-pdf/cmsv4.tex b/cryptominisat/cppsrc/docs/satcomp15-pdf/cmsv4.tex new file mode 100644 index 00000000..128ca6c2 --- /dev/null +++ b/cryptominisat/cppsrc/docs/satcomp15-pdf/cmsv4.tex @@ -0,0 +1,66 @@ +%\documentclass[runningheads]{llncs} +\documentclass[final]{ieee} + +\usepackage{microtype} %This gives MUCH better PDF results! +%\usepackage[active]{srcltx} %DVI search +\usepackage[cmex10]{amsmath} +\usepackage{amssymb} +\usepackage{fnbreak} %warn for split footnotes +\usepackage{url} +%\usepackage{qtree} %for drawing trees +%\usepackage{fancybox} % if we need rounded corners +%\usepackage{pict2e} % large circles can be drawn +%\usepackage{courier} %for using courier in texttt{} +%\usepackage{nth} %allows to \nth{4} to make 1st 2nd, etc. +%\usepackage{subfigure} %allows to have side-by-side figures +%\usepackage{booktabs} %nice tables +%\usepackage{multirow} %allow multiple cells with rows in tabular +\usepackage[utf8]{inputenc} % allows to write Faugere correctly +\usepackage[bookmarks=true, citecolor=black, linkcolor=black, colorlinks=true]{hyperref} +\hypersetup{ +pdfauthor = {Mate Soos}, +pdftitle = {CryptoMiniSat v4.4}, +pdfsubject = {SAT Race 2015}, +pdfkeywords = {SAT Solver, DPLL}, +pdfcreator = {PdfLaTeX with hyperref package}, +pdfproducer = {PdfLaTex}} +%\usepackage{butterma} + +%\usepackage{pstricks} +\usepackage{graphicx,epsfig,xcolor} + +\begin{document} +\title{The CryptoMiniSat-4.4 set of solvers at the SAT Race 2015} +\author{Mate Soos, Marius Lindauer} + +\maketitle +\thispagestyle{empty} +\pagestyle{empty} + +\section{Introduction} +This paper presents the conflict-driven clause-learning SAT solver CryptoMiniSat v4.4 (\emph{CMS4.4}) as submitted to SAT Race 15. CMS4.4 aims to be a modern, open-source SAT solver that allows for multi-threaded in-processing techniques while still retaining a strong CDCL component. In this description only the features relative to CMS4.4, the previous year's submission, are explained. Please refer to the previous years' description for details. In general, CMS4.4 is a in-processing SAT solver that usues optimized datastructures and finely-tuned timeouts to have good control over both memory and time usage of simplification steps. + +\subsection{Using watchlists as occurrence lists} +As per lingeling \cite{lingeling}, CMS4.4 now uses the watchlist to store occurrence lists (when they are needed) and related occurrence information such as data related to looking for XOR clauses or gates. This significantly reduces the memory overhead and, due to cache locality, increases speed. + +\subsection{Removal of uneeded code} +Over the years, many lines of code has been added to CMS that in the end didn't help and often was detrimental to both maintinability and efficiency of the solver. Many such additions have now been removed. This simplifies understanding and developing the system. Further, it allows the system to be more lean especially in the tight loops such as propagation and conflict analysis where most of the time is spent. + +\subsection{Integration of ideas from SWDiA5BY A26} +Some of the ideas from SWDiA5BY A26\cite{swdia} have been included into CMS. In particular, the clause cleaning system employed and the switching restart have both made their way into CMS. Further, SWDiA5BY A26 was used as a test-bed against CMS to clean up the codebase from unwated and unneeded elements. + +\subsection{Incremental solving} +Incremental solving for a in-processing solver is not trivial and many bugs have been found in fuzzing the incremental solving interface. The fuzzer developed for this purpose contains more than 1000 lines of python and allows for testing both the incremental and the DRAT~\cite{drat} interface of the solver. + +\subsection{Auto-tuning} +The version 'autotune' reconfigures itself after about 160K conflicts. The configuration picked is one of 13 different setups that vary many different parameters of the solving such as learnt clause removal strategy, restart strategy, and in-processing strategies. CMS4.4 was run on all SAT Comp'09 + 11 + 13 problems with all configurations, extracting relevant information from the all problems after they have been solved and simplified for 160K conflicts. The information extracted and the top 5 best configurations were then given to a machine learning algorithm (C5.0\cite{Quinlan:1993:CPM:152181}) which built a decision tree from this data. This decision tree was then translated into C++ and compiled into the CMS4.4 source code. + +This work was carried out by the first author through a script for Amazon Web Services for reliably running any setup ($>1500$ lines of python), a script for extracting and sanitizing the parameters ($>500$ lines of python), and a script for translating the rule-based output of C5 into C++. + +\bibliographystyle{splncs03} +\bibliography{sigproc} + +\vfill +\pagebreak + +\end{document} diff --git a/cryptominisat/cppsrc/docs/satcomp15-pdf/ieee.cls b/cryptominisat/cppsrc/docs/satcomp15-pdf/ieee.cls new file mode 100644 index 00000000..3c57bba5 --- /dev/null +++ b/cryptominisat/cppsrc/docs/satcomp15-pdf/ieee.cls @@ -0,0 +1,1497 @@ +% Copyright 2014 IEEEE +% for terms of use see https://www.ieee.org/publications_standards/publications/rights/copyrightpolicy.html + +% ========================================================================= +% ------------------------------------------------------------------------- +% XX X +% X +% XX XXX XXX XXX XXX X XXXX +% X X X X X X X X X X X +% X XXXXX XXXXX XXXXX X X XXX +% X X X X XX X X X X +% XXX XXX XXX XXX XX XXX X XXXX +% ------------------------------------------------------------------------- +% ========================================================================= +% ieee.cls --- For formatting IEEE conference & journal papers +% --- Compiled by Gregory Plett, Sept 1997 +% +% This class was inspired by one first compiled by Gerry Murray and +% Silvano Balemi for LaTeX209. It was later updated for use with +% LaTeX2e, and some bugs were fixed, all by Istvan Kollar. Lastly, +% I have tried to make the class easier to use by paper authors. +% Significant new functionality has been added. Many routines are +% "borrowed" from other people's packages and modified extensively. +% When I rembered where I got the routines from, I gave the author +% credit. +% +% After I made many changes on my own, I found a version by Peter +% N"uchter, and tried to retain some amount of compatibility with his +% version. To be completely compatible with him, you may need to +% manually: +% \usepackage{rawfonts}\usepackage{oldlfont} +% \AtBeginDocument{\parindent1.0em} (?) +% +%=========================================================================== +% +% Usage: +% \documentclass[main-mode,sub-mode,misc-options]{ieee} +% \usepackage{your own packages} +% \begin{document} +% \bibliographystyle{IEEEbib} +% \title[short]{regular} +% \author[short]{full} +% \maketitle +% \begin{abstract}...\end{abstract} +% \begin{keywords}...\end{keywords} +% \section{...} +% \PARstart ... or \PARstartCal ... +% ... +% \begin{biography}[picname.ps]{Author's name}...\end{biography} +% \end{document} +% +% The document class options are: +% +% main-mode: One of the following is required. (draft is the default) +% draft: Double-spaced, single column with date/time stamp. +% submission: Double-spaced, suitable for submission for review. +% compressed: Same as "submission", only single spaced. +% final: Double-column, for assessing page-length and +% format of final version. +% +% sub-mode: +% techreport: This can modify "final" to produce a two-col +% technical report. +% internal: This can modify "submission", "compressed" or "final". +% It changes the header to notify the reader that +% this is a version of the manuscript to be used for +% internal review processes only, and not to be +% distributed. +% submitted: This can modify "compressed" or "final". It changes +% the header to notify the reader that this +% is a preprint and not to be distributed. +% inpress: This can modify "compressed" or "final". It changes the +% header to notify the reader that this paper has +% been accepted for publishing, but it is not yet to be +% distributed. +% reprint: This can modify "final". It changes the header +% to notify the reader where the paper is reprinted from. +% +% misc-options: +% narroweqnarray: Changes the spacing around the "=" sign in +% equation arrays to make it the same as in displayed math. +% inline: Compresses the horizontal spacing of inline math equations. +% notitlepage: No separate title page. (default) +% titlepage: Separate title page. +% anonymous: Omit all author information from main part of paper. +% Author info only prints on titlepage. +% 9pt,10pt,11pt,12pt: Choose the appropriate type size. You should +% not need to do this as the "correct" size is automatically +% chosen. However, if you want, you may use these to change +% the type size of the main text. "9pt" is a bit of a hack +% to retain backward-compatibility. +% invited: If the paper is an "invited" paper, then this option +% prints "(Invited Paper)" under the authors' names. +% +% For regular IEEE submissions, define the journal name as: +% \journal{IEEE Trans. Inst. Meas.} +% +% To specify the conference place and date: +% \confplacedate{Ottawa, Canada, May 19--21, 1997} +% +% Before \maketitle, define: +% \title{Title of paper} +% \author{Author1\member{Fellow}\authorinfo{Department of +% Electrical Engineering\\ Some University, Somewhere, CA 94305 +% USA} \and Author2\member{Senior Member}\authorinfo{Deptartment of +% Measurement and Instrument Eng., Another University, ...}} +% +% Note, the contents of \authorinfo tends to vary depending on if it is +% a conference or journal paper. The amount of manual changes are +% small, and must be done by a human anyway. The example given is for an +% IMTC conference. +% +% See also IEEEbib.bst and ieeefig.sty +% Also very useful for document preparation is the style file "endfloat", +% available on all CTAN TeX archives. +% +%=========================================================================== +% modified 14 October 2002: +% - fixed bibliography listing of [#] when # < 10 and number of +% references is greater than 9. Thanks for Janos Markus for finding +% this bug and suggesting a solution. +% modified 15 January 2000: +% - "fixed" narroweqnarray. Never implemented! Now it is... +% modified 12 January 2000: +% - modified so only first \title and \author commands are recognized. +% This allows LyX to have \title and \author with full syntax in +% header, but dummy \title and \author show up in GUI. +% - added "\date" so the \date command can change "submitted" and +% "draft" date headers. +% modified 11 January 2000: +% - added PARstartLyX and PARstartCalLyX for LyX compatibility +% - added biographyLyX +% modified 1 Dec 1997: +% - fixed first page in reprint mode to be same length as other pages +% - added "invited" misc-option +% modified 5 Sept 1997: +% - added the inpress, reprint and internal sub-modes +% - removed IMTC-conf and CDC-conf to separate files +% modified 1 Sept 1997: +% - included Babel package compatibility +% - removed paper title from header on first page of draft +% manuscript +% - removed the fixed option "letterpaper" to allow a4paper (etc) +% modified 1 Aug 1997: +% - included the CDC-conf option +%=========================================================================== +% ************************************************************************** +% ****** ****************************************** +% ***** LaTeX2e INITIALIZATION ***************************************** +% ****** ****************************************** +% ************************************************************************** +\typeout{Document Class `ieee' .} +\NeedsTeXFormat{LaTeX2e}[1993/11/11] % Oldest acceptable version of LaTeX2e +\ProvidesClass{ieee}[2000/01/11] % Name of package provided, date +\def\i@@@cls{exists} + +% Initial Code & Declaration of Options +% ------------------------------------- +\newif\ifev@l \ev@lfalse % true if "final" mode. +\newif\ifsubm@t \subm@tfalse % true if "submission" mode. +\newif\ifdr@ft \dr@fttrue % true if "draft" mode. +\newif\ifc@mpress \c@mpressfalse % true if "compressed" mode. + +\newif\if@technote \@technotefalse % true if "technote" sub-mode. +\newif\ifintern@l \intern@lfalse % true if "internal" sub-mode. +\newif\ifprepr@nt \prepr@ntfalse % true if "preprint" sub-mode. +\newif\ifinpr@ss \inpr@ssfalse % true if "inpress" sub-mode. +\newif\ifrepr@nt \repr@ntfalse % true if "reprint" sub-mode. + +\newif\iftitlep@ge \titlep@gefalse % true if has own titlepage +\newif\if@non \@nonfalse % true if anonymous +\newif\ifixpt \ixptfalse % true if trying to do 9 pt +\newif\if@nvited \@nvitedfalse % true if an invited paper + +% Main options +% ------------ +\DeclareOption{draft}{\ev@lfalse\subm@tfalse\dr@fttrue% + \typeout{ieee: `Draft' mode selected.}} +\DeclareOption{submission}{\ev@lfalse\dr@ftfalse\subm@ttrue% + \typeout{ieee: `Submission' mode selected.}} +\DeclareOption{compressed}{\ev@lfalse\dr@ftfalse\subm@tfalse\c@mpresstrue% + \typeout{ieee: `Compressed' mode selected.}} +\DeclareOption{final}{\ev@ltrue\dr@ftfalse\subm@tfalse% + \typeout{ieee: `Final' mode selected.}} +\DeclareOption{evaluation}{\ev@ltrue\dr@ftfalse\subm@tfalse% + \typeout{ieee: `Final' mode selected.}} % synonym for final + +% Sub options +% ----------- +\DeclareOption{technote}{\@technotetrue% + \typeout{ieee: `Technote' sub-mode selected.}} +\DeclareOption{internal}{\intern@ltrue\prepr@ntfalse\inpr@ssfalse\repr@ntfalse% + \typeout{ieee: `Internal-Review' sub-mode selected.}} +\DeclareOption{submitted}{\intern@lfalse\prepr@nttrue\inpr@ssfalse\repr@ntfalse% + \typeout{ieee: `Submitted' sub-mode selected.}} +\DeclareOption{preprint}{\intern@lfalse\prepr@nttrue\inpr@ssfalse\repr@ntfalse% + \typeout{ieee: `Submitted' sub-mode selected.}} % synonym for submitted +\DeclareOption{inpress}{\intern@lfalse\prepr@ntfalse\inpr@sstrue\repr@ntfalse% + \typeout{ieee: `Inpress' sub-mode selected.}} +\DeclareOption{reprint}{\intern@lfalse\prepr@ntfalse\inpr@ssfalse\repr@nttrue% + \typeout{ieee: `Reprint' sub-mode selected.}} + +% Misc options +% ------------ + % regular or compressed "=" spacing in +\def\eqnarr@ysep{\arraycolsep} % eqnarray (this is the default) + % NOTE: we must use "def" and not "=" + % as arraycolsep not yet defined. +\DeclareOption{narroweqnarray}{\gdef\eqnarr@ysep{0.28em\relax}% + \typeout{ieee: Narrow equation arrays selected.}} +\DeclareOption{inline}{\everymath{\thinmuskip=2mu plus 1mu + \medmuskip=3mu plus 1mu minus 2mu + \thickmuskip=4mu plus 2mu\relax}% + \typeout{ieee: Narrower inline equations selected.}} +\DeclareOption{notitlepage}{\titlep@gefalse% + \typeout{ieee: No separate title page.}} +\DeclareOption{titlepage}{\titlep@getrue% + \typeout{ieee: Use separate title page.}} +\DeclareOption{anonymous}{\@nontrue\AtBeginDocument{\glpexclude{biography}} + \typeout{ieee: Omit author information from paper.}} +\DeclareOption{invited}{\@nvitedtrue% + \typeout{ieee: (Invited Paper).}} + +\DeclareOption{9pt}{\ixpttrue% + \typeout{ieee: Trying to emulate old `9pt' document class.}} + +\DeclareOption*{\PassOptionsToClass{\CurrentOption}{article}} + +% Execution of Options/Package Loading +% ------------------------------------ +\newlength\narrowcol +\newlength\parindentsave % recover parindent in blsone text + +\ProcessOptions +\ifev@l % if "final" mode... + \if@technote\ixpttrue\typeout{ieee: Trying to emulate old `9pt' + document class.}\fi% + \LoadClass[twoside,final,twocolumn,10pt]{article} +\else % if "draft"/"submission"/(compressed) mode... + \ifixpt + \LoadClass[oneside,final,onecolumn,10pt]{article} + \else + \LoadClass[oneside,final,onecolumn,12pt]{article} + \fi +\fi +\RequirePackage[final]{graphicx} +\RequirePackage{ifthen} + +% Re-Definitions of English words which must be done before +% the Babel package (optional) is loaded. +% --------------------------------------------------------- +\def\keywordsname{Index Terms} +\def\indexterms#1{\def\keywordsname{#1}} +\def\appendicesname{Appendices} +\def\figurename{Fig.} + +% ************************************************************************** +% ***** Check Sub-Options for Compatibility w/ Main-Options ************ +% ************************************************************************** +\if@technote\ifev@l\else\ClassError{ieee}{`technote' sub-mode may be + used only with the `final' ^^Jmain-mode. It may not be used + with either the `draft,' `submission,' or ^^J`compressed' + main-modes}{}\endinput\fi\fi +\ifintern@l\ifdr@ft\ClassError{ieee}{`internal' sub-mode may be + used only with the ^^J`submission,' `compressed,' or `final' main-modes. + It may not be used ^^Jwith the `draft' main-mode}{}\endinput\fi\fi +\ifprepr@nt\ifc@mpress\else\ifev@l\else\ClassError{ieee}{`submitted' + sub-mode may be used only with the ^^J`compressed' or `final' + main-modes. It may not be used with either the ^^J`draft' or + `submission' main-modes}{}\endinput\fi\fi\fi +\ifinpr@ss\ifc@mpress\else\ifev@l\else\ClassError{ieee}{`inpress' + sub-mode may be used only with the `compressed' ^^Jor `final' + main-modes. It may not be used with either the `draft' or + ^^J`submission' main-modes}{}\endinput\fi\fi\fi +\ifrepr@nt\ifev@l\else\ClassError{ieee}{`reprint' + sub-mode may be used only with the `final' ^^Jmain-mode. It may not be + used with either the `draft,' `submission,' or ^^J`compressed' + main-modes}{}\endinput\fi\fi + +% ************************************************************************** +% ***** Page Layout Definition ***************************************** +% ************************************************************************** +%% Layout definitions (mostly) common to all options. + +\hoffset 0in \voffset 0in +\headheight 12pt \headsep 7mm +\marginparsep 10pt \marginparwidth 20pt +\marginparpush 25pt +\columnsep 4mm +\parindent 1.0em +\lineskip 1pt +\normallineskip 1pt +\def\baselinestretch{1} + +\partopsep \z@ +\topsep 1.3ex +\parsep \z@ +\itemsep \z@ + +\setlength{\parindentsave}{\parindent} + +\ifev@l % if "evaluation" mode + % if camera-ready or A4paper ... + \ifdim\paperwidth<211mm + \oddsidemargin -11.4mm \evensidemargin -11.4mm + % for regular US Letter, not camera-ready + \else + \oddsidemargin -8.45mm \evensidemargin -8.45mm + \fi + \ifrepr@nt + \textheight 237.5mm % leave 6mm for cpyright on first page + \else + \textheight 243.5mm + \fi + \voffset -0.5in + \textwidth 182.0mm + \topmargin -12pt + \setlength{\narrowcol}{89mm} +\else % if "draft"/"submission" mode... + \ifc@mpress % and "compressed" + \oddsidemargin -0.25in \evensidemargin -0.25in + \textheight 9in \textwidth 7in + \topmargin -0.25in + \setlength{\narrowcol}{7in} + \else % and NOT "compressed" + \renewcommand\baselinestretch{1.8}\renewcommand{\arraystretch}{0.8} + \parindent=1.8\parindent + \oddsidemargin 0pt \evensidemargin 0pt + \headheight 12pt \headsep 0.375in + \topmargin 0pt + \textheight 8.5in \textwidth 6.5in + \marginparsep 0in \marginparwidth 0pt + \marginparpush 5pt + \setlength{\narrowcol}{6.5in} + \fi +\fi + +\def\normalstyle{\rmfamily} + +% ************************************************************************** +% ***** Font Definition ************************************************ +% ************************************************************************** +%% The 9-point option is being faked since it is not supported by the +%% article base class. + +%% Check if we have selected 9 points +\ifixpt +\typeout{-- This is a 9 point document} +\gdef\@ptsize{9} +\def\@normalsize{\@setsize\normalsize{10.7pt}\ixpt\@ixpt +\abovedisplayskip 1em plus2pt minus5pt\belowdisplayskip \abovedisplayskip +\abovedisplayshortskip \z@ plus3pt\belowdisplayshortskip .6em plus3pt minus3pt +\topsep \belowdisplayshortskip%!PN +} +\def\small{\@setsize\small{9.12pt}\viiipt\@viipt} +\def\footnotesize{\@setsize\footnotesize{8.15pt}\viipt\@vipt} +\def\scriptsize{\@setsize\scriptsize{8pt}\vipt\@vpt} +\def\tiny{\@setsize\tiny{5pt}\vpt\@vpt} +\def\large{\@setsize\large{12pt}\xpt\@xpt} +\def\Large{\@setsize\Large{14pt}\xiipt\@xiipt} +\def\LARGE{\@setsize\LARGE{18pt}\xivpt\@xivpt} +\def\huge{\@setsize\huge{22pt}\xviipt\@xviipt} +\def\Huge{\@setsize\Huge{25pt}\xxpt\@xxpt} +\fi +%% +%% Check if we have selected 10 points +\def\@tempa{0}\if\@ptsize\@tempa +\typeout{-- This is a 10 point document} +\def\@normalsize{\@setsize\normalsize{11.9pt}\xpt\@xpt +\abovedisplayskip 1em plus2pt minus5pt\belowdisplayskip \abovedisplayskip +\abovedisplayshortskip \z@ plus3pt\belowdisplayshortskip .6em plus3pt minus3pt +\topsep \belowdisplayshortskip%!PN +} +\def\small{\@setsize\small{9.2pt}\viiipt\@viiipt} +\def\footnotesize{\@setsize\footnotesize{8.8pt}\viiipt\@viiipt} +\def\scriptsize{\@setsize\scriptsize{8pt}\viipt\@viipt} +\def\tiny{\@setsize\tiny{6pt}\vpt\@vpt} +\def\normalsize{\@setsize\normalsize{11.9pt}\xpt\@xpt} +\def\large{\@setsize\large{14pt}\xiipt\@xiipt} +\def\Large{\@setsize\Large{18pt}\xivpt\@xivpt} +\def\LARGE{\@setsize\LARGE{22pt}\xviipt\@xviipt} +\def\huge{\@setsize\huge{22pt}\xxpt\@xxpt} +\def\Huge{\@setsize\Huge{28pt}\xxvpt\@xxvpt} +\fi +%% +%% Check if we have selected 11 points +\def\@tempa{1}\if\@ptsize\@tempa +\typeout{-- This is an 11 point document} +\def\@normalsize{\@setsize\normalsize{13.6pt}\xipt\@xipt +\abovedisplayskip 1em plus2pt minus5pt\belowdisplayskip \abovedisplayskip +\abovedisplayshortskip \z@ plus3pt\belowdisplayshortskip .6em plus3pt minus3pt +\topsep \belowdisplayshortskip%!PN +} +\def\small{\@setsize\small{12pt}\xpt\@xpt} +\def\footnotesize{\@setsize\footnotesize{11pt}\ixpt\@ixpt} +\def\scriptsize{\@setsize\scriptsize{9.5pt}\viiipt\@viiipt} +\def\tiny{\@setsize\tiny{7pt}\vipt\@vipt} +\def\normalsize{\@setsize\normalsize{13.6pt}\xipt\@xipt} +\def\large{\@setsize\large{14pt}\xiipt\@xiipt} +\def\Large{\@setsize\Large{18pt}\xivpt\@xivpt} +\def\LARGE{\@setsize\LARGE{22pt}\xviipt\@xviipt} +\def\huge{\@setsize\huge{25pt}\xxpt\@xxpt} +\def\Huge{\@setsize\Huge{30pt}\xxvpt\@xxvpt} +\fi +%% +%% Check if we have selected 12 points +\def\@tempa{2}\if\@ptsize\@tempa +\typeout{-- This is a 12 point document} +\def\@normalsize{\@setsize\normalsize{14pt}\xiipt\@xiipt +\abovedisplayskip 1em plus3pt minus6pt\belowdisplayskip \abovedisplayskip +\abovedisplayshortskip \z@ plus3pt\belowdisplayshortskip .6em plus4pt minus4pt +\topsep \belowdisplayshortskip%!PN +} +\def\small{\@setsize\small{11.4pt}\xpt\@xpt} +\def\footnotesize{\@setsize\footnotesize{10pt}\ixpt\@ixpt} +\def\scriptsize{\@setsize\scriptsize{9pt}\viiipt\@viiipt} +\def\tiny{\@setsize\tiny{8pt}\vipt\@vipt} +\def\normalsize{\@setsize\normalsize{14pt}\xiipt\@xiipt} +\def\large{\@setsize\large{18pt}\xivpt\@xivpt} +\def\Large{\@setsize\Large{22pt}\xviipt\@xviipt} +\def\LARGE{\@setsize\LARGE{25pt}\xxpt\@xxpt} +\def\huge{\@setsize\huge{30pt}\xxvpt\@xxvpt} +\let\Huge=\huge +\fi + +\AtBeginDocument{\normalsize\normalstyle\ps@headings\pagenumbering{arabic}} + +% ************************************************************************** +% ***** List Definition ************************************************ +% ************************************************************************** +%% Change aspect of lists with +%% 1) \itemindent, label indentation wrt to left list margin +%% 2) \leftmargini, the indentation of the whole list (on left, first level) +\ifev@l + \itemindent -1em + \leftmargini 2em + \leftmarginii 1em + \leftmarginiii 1.5em + \leftmarginiv 1.5em + \leftmarginv 1.0em + \leftmarginvi 1.0em +\else + \itemindent -1em + \leftmargini 3em + \leftmarginii 3em + \leftmarginiii 3em + \leftmarginiv 3em + \leftmarginv 3em + \leftmarginvi 3em +\fi +%\itemindent 2em % Alternative values: sometimes used.. +%\leftmargini 0em +\labelsep 5pt +\leftmargin\leftmargini +\labelwidth \z@ + +\def\@listI{\leftmargin\leftmargini} \@listI +\def\@listi{\leftmargin\leftmargini \topsep \z@ plus 1pt minus 1pt} +\def\@listii{\leftmargin\leftmarginii\labelwidth\leftmarginii + \advance\labelwidth-\labelsep \topsep \z@} +\def\@listiii{\leftmargin\leftmarginiii\labelwidth\leftmarginiii + \advance\labelwidth-\labelsep \topsep \z@} +\def\@listiv{\leftmargin\leftmarginiv\labelwidth\leftmarginiv + \advance\labelwidth-\labelsep \topsep \z@} +\def\@listv{\leftmargin\leftmarginv\labelwidth\leftmarginv + \advance\labelwidth-\labelsep \topsep \z@} +\def\@listvi{\leftmargin\leftmarginvi\labelwidth\leftmarginvi + \advance\labelwidth-\labelsep \topsep \z@} + +\def\labelenumi{\theenumi.} \def\theenumi{\arabic{enumi}} +\def\labelenumii{(\theenumii)} \def\theenumii{\alph{enumii}} +\def\labelenumiii{\theenumiii.} \def\theenumiii{\roman{enumiii}} +\def\labelenumiv{\theenumiv.} \def\theenumiv{\Alph{enumiv}} +\def\p@enumii{\theenumi} +\def\p@enumiii{\theenumi(\theenumii)} +\def\p@enumiv{\p@enumiii\theenumiii} + +\def\labelitemi{$\scriptstyle\bullet$} +\def\labelitemii{\bf --} +\def\labelitemiii{$\ast$} +\def\labelitemiv{$\cdot$} + +%% \itemindent is set to \z@ by list, so define new temporary variable +\newdimen\tmpitemindent +\def\verse{\let\\=\@centercr + \list{}{\itemsep\z@ \itemindent -1.5em \listparindent \itemindent + \rightmargin\leftmargin\advance\leftmargin 1.5em}\item[]} +\let\endverse\endlist +\def\quotation{\list{}{\listparindent 1.5em \itemindent\listparindent + \rightmargin\leftmargin \parsep 0pt plus 1pt}\item[]} +\let\endquotation=\endlist +\def\quote{\list{}{\rightmargin\leftmargin}\item[]} +\let\endquote=\endlist +\def\@mklab#1{#1} +\def\description{\tmpitemindent\itemindent\list{}{\itemindent\tmpitemindent + \labelwidth\z@\def\makelabel##1{\hspace\labelsep\emph{##1}}}} +\def\enddescription{\endlist\par} +\def\enumerate{\tmpitemindent\itemindent\ifnum \@enumdepth >3 \@toodeep\else + \advance\@enumdepth \@ne \edef\@enumctr{enum\romannumeral\the\@enumdepth}% + \list{\csname label\@enumctr\endcsname}{\itemindent\tmpitemindent + \usecounter{\@enumctr}\def\makelabel##1{\hspace\labelsep\hfil{##1}}}\fi} +\def\endenumerate{\endlist\par} +\def\itemize{\tmpitemindent\itemindent\ifnum \@itemdepth >3 \@toodeep\else + \advance\@itemdepth\@ne + \edef\@itemitem{labelitem\romannumeral\the\@itemdepth}% + \list{\csname\@itemitem\endcsname}{\itemindent\tmpitemindent + \def\makelabel##1{\hspace\labelsep\hfil\emph{##1}}}\fi} +\def\enditemize{\endlist\par} + +\newif\if@restonecol +\def\titlepage{\@restonecolfalse\if@twocolumn\@restonecoltrue\onecolumn + \else \newpage \fi \thispagestyle{coverpagestyle}\c@page\z@} +\def\endtitlepage{\if@restonecol\twocolumn \else \newpage \fi% +\if@twoside\mbox{}\thispagestyle{coverpagestyle}\c@page\z@\cleardoublepage\fi} + +\arraycolsep 5pt +\tabcolsep 6pt +\arrayrulewidth .4pt +\doublerulesep 2pt +\tabbingsep\labelsep + +% ************************************************************************** +% ***** Footnote Definition ******************************************** +% ************************************************************************** +\skip\footins 10pt plus 5pt minus 2pt +\footnotesep 7pt +\footskip 6mm +\skip\@mpfootins = \skip\footins +\fboxsep = 3pt \fboxrule = .4pt +\long\def\@makefntext#1{\parindent .8em\indent$^{\@thefnmark}$#1} +\def\footnoterule{} + +% Reset baselinestretch within footnotes. +% Originally stolen from Stanford University thesis style. +% -------------------------------------------------------- +\long\def\@footnotetext#1{\insert\footins{\blsone% + \footnotesize\interlinepenalty\interfootnotelinepenalty + \splittopskip\footnotesep + \splitmaxdepth \dp\strutbox \floatingpenalty \@MM + \hsize\columnwidth \@parboxrestore + \edef\@currentlabel{\csname p@footnote\endcsname\@thefnmark}\@makefntext + \let\par\\ + {\rule{\z@}{\footnotesep}\ignorespaces + #1\strut}}} + +% ************************************************************************** +% ***** Keep track of Sections ***************************************** +% ************************************************************************** +\if@technote + \setcounter{secnumdepth}{3} +\else + \setcounter{secnumdepth}{4} +\fi + +\def\thesection{\@Roman\c@section} +\def\thesubsection{\Alph{subsection}} +\def\thesubsubsection{\thesubsection.\arabic{subsubsection}} +\def\thesubsubsectiondis{\Alph{subsection}.\arabic{subsubsection}} +\def\theparagraph{\thesubsubsection.\alph{paragraph}} +\def\theparagraphdis{\thesubsubsectiondis.\alph{paragraph}} + +\def\theequation{\arabic{equation}} + +% ************************************************************************** +% ***** Table of Contents, List of Figures/Tables Definitions ********** +% ************************************************************************** +\def\@pnumwidth{1.55em} +\def\@tocrmarg {2.55em} +\def\@dotsep{4.5} +\setcounter{tocdepth}{3} + +\def\tableofcontents{\section*{\contentsname}\@starttoc{toc}} +\def\l@section#1#2{\addpenalty{\@secpenalty} \addvspace{1.0em plus 1pt} + \@tempdima 1.8em \begingroup \parindent \z@ \rightskip \@pnumwidth + \parfillskip-\@pnumwidth \bf\leavevmode #1\hfil\hbox to\@pnumwidth{\hss #2} + \par \endgroup} +\def\l@subsection{\@dottedtocline{2}{1.5em}{2.3em}} +\def\l@subsubsection{\@dottedtocline{3}{3.8em}{3.2em}} +\def\listoffigures{\section*{\listfigurename}\@starttoc{lof}} +\def\l@figure{\@dottedtocline{1}{1em}{1.8em}} +\def\listoftables{\section*{\listtablename}\@starttoc{lot}} +\let\l@table\l@figure + +% ************************************************************************** +% ***** Float Definitions ********************************************** +% ************************************************************************** +%% Normal Floats %% Double Column Floats +\floatsep 12pt plus 2pt minus 2pt \dblfloatsep 12pt plus 2pt minus 2pt +\textfloatsep 20pt plus 2pt minus 4pt \dbltextfloatsep 20pt plus 2pt minus 4pt +%\@maxsep 20pt \@dblmaxsep 20pt %!PN +\@fptop 0pt plus 1fil \@dblfptop 0pt plus 1fil +\@fpsep 8pt plus 2fil \@dblfpsep 8pt plus 2fil +\@fpbot 0pt plus 1fil \@dblfpbot 0pt plus 1fil +\def\topfraction{1.0} \def\dbltopfraction{1.0} +\def\floatpagefraction{0.8} \def\dblfloatpagefraction{0.8} +\setcounter{topnumber}{2} \setcounter{dbltopnumber}{4} +% +\intextsep 12pt plus 2pt minus 2pt +\setcounter{bottomnumber}{2} +\def\bottomfraction{.4} +\setcounter{totalnumber}{4} +\def\textfraction{.2} + +% Reset baselinestretch within floats. +% Originally stolen from Stanford University thesis style. +% -------------------------------------------------------- +\def\@xfloat#1[#2]{\ifhmode \@bsphack\@floatpenalty -\@Mii\else + \@floatpenalty-\@Miii\fi\def\@captype{#1}\ifinner + \@parmoderr\@floatpenalty\z@ + \else\@next\@currbox\@freelist{\@tempcnta\csname ftype@#1\endcsname + \multiply\@tempcnta\@xxxii\advance\@tempcnta\sixt@@n + \@tfor \@tempa :=#2\do + {\if\@tempa h\advance\@tempcnta \@ne\fi + \if\@tempa t\advance\@tempcnta \tw@\fi + \if\@tempa b\advance\@tempcnta 4\relax\fi + \if\@tempa p\advance\@tempcnta 8\relax\fi + }\global\count\@currbox\@tempcnta}\@fltovf\fi + \global\setbox\@currbox\vbox\bgroup + \def\baselinestretch{1}\small\normalsize + \hsize\columnwidth \@parboxrestore} + +% ************************************************************************** +% ***** Caption Definition ********************************************* +% ************************************************************************** +% some journals do not have centered captions for figures. +\newif\ifc@ptionleft \c@ptionlefttrue +\def\leftfigcaptions{\c@ptionlefttrue} +\def\centerfigcaptions{\c@ptionleftfalse} + +\long\def\caption{\refstepcounter\@captype \@dblarg{\@caption\@captype}} + +\long\def\@caption#1[#2]#3{\par\addcontentsline{\csname ext@#1\endcsname}{#1}{% + \protect\numberline{\csname the#1\endcsname}{\ignorespaces #2}} + \begingroup \@parboxrestore \normalsize + \@makecaption{\csname fnum@#1\endcsname}{\ignorespaces #3}{#1}\par + \endgroup} + +\def\tablestring{table} +\def\figurestring{figure} + +% changed by GLP to allow table captions to be set to a specific maximum +% width "\captionwidth", if defined. +\newlength{\captionindent} +\long\def\@makecaption#1#2#3{ +\ifx\figurestring#3 + \vskip 5pt + \setbox\@tempboxa\hbox{\small #1.~ #2} + \ifdim \wd\@tempboxa >\hsize + \setbox\@tempboxa\hbox{\small #1.~ } + %\setlength\captionindent{\wd\@tempboxa} \divide\captionindent by 2 + %\parbox[t]{\hsize}{\small \hangindent \captionindent \hangafter=1% + \parbox[t]{\hsize}{\small + \unhbox\@tempboxa#2} + \else \hbox + to\hsize{\small\ifc@ptionleft\else\hfil\fi\box\@tempboxa\hfil} + \fi +\else + \begin{center} + \ifx\captionwidth\undefined {\small #1}\\{\small\scshape #2} + \else + \begin{minipage}{\captionwidth} + \begin{center}{\small #1}\\{\small\scshape #2}\end{center} + \end{minipage} + \fi + \end{center}\vskip 4pt +\fi} + +\def\thefigure{\@arabic\c@figure} +\def\fps@figure{tbp} +\def\ftype@figure{1} +\def\ext@figure{lof} +\def\fnum@figure{\figurename\ \thefigure} +%\def\figure{\@float{figure}} % GLP +%\let\endfigure\end@float +\@namedef{figure*}{\@dblfloat{figure}} +\@namedef{endfigure*}{\end@dblfloat} + +\def\thetable{\@Roman\c@table} +\def\fps@table{tbp} +\def\ftype@table{2} +\def\ext@table{lot} +\def\fnum@table{TABLE~\thetable} +\def\table{\@float{table}} +\let\endtable\end@float +\@namedef{table*}{\@dblfloat{table}} +\@namedef{endtable*}{\end@dblfloat} + +% ************************************************************************** +% ***** Header/Footer Definition *************************************** +% ************************************************************************** +% compute the time in hours and minutes; make new vars \timehh and \timemm +\newcount\timehh\newcount\timemm\timehh=\time\divide\timehh by 60 +\timemm=\time\count255=\timehh\multiply\count255 by-60 +\advance\timemm by \count255 +\ifnum\timehh=12\def\apm{pm}\else +\ifnum\timehh>12\def\apm{pm}\advance\timehh by-12\else +\def\apm{am}\fi\fi +\def\t@me{\number\timehh\,:\,\ifnum\timemm<10 0\fi\number\timemm\,\apm} + +% default definitions +% ------------------- +\def\theevenhe@d{\footnotesize\thepage \hfil \leftmark\hbox{}} +\def\theoddhe@d{\hbox{}\footnotesize\rightmark \hfil \thepage} +\def\theevenf@@t{} +\def\theoddf@@t{} + +\def\theeventphe@d{\footnotesize\thepage \hfil \hbox{}} +\def\theoddtphe@d{\hbox{}\footnotesize \hfil \thepage} +\def\theeventpf@@t{} +\def\theoddtpf@@t{} + +\def\theevencphe@d{} +\def\theoddcphe@d{} +\def\theevencpf@@t{} +\def\theoddcpf@@t{} + +\def\internalmsg{Preliminary version for evaluation: Please do not + circulate without the permission of the author(s)} +\def\submittedmsg{SUBMITTED FOR PUBLICATION TO:} +\def\acceptedmsg{ACCEPTED FOR PUBLICATION:} +\def\inpressmsg{(IN PRESS)} +\def\reprintmsg{REPRINTED FROM:} + +% default cover page style (optional cover page) +% ---------------------------------------------- +\def\ps@coverpagestyle{ + \def\@oddhead{\theoddcphe@d} \def\@evenhead{\theevencphe@d} + \def\@oddfoot{\theoddcpf@@t} \def\@evenfoot{\theevencpf@@t} +} + +% default title page style (first page of paper) +% ---------------------------------------------- +\def\ps@titlepagestyle{ + \def\@oddhead{\theoddtphe@d} \def\@evenhead{\theeventphe@d} + \def\@oddfoot{\theoddtpf@@t} \def\@evenfoot{\theeventpf@@t} +} + +% default regular page style +% -------------------------- +\if@twoside + \def\ps@headings{ + \def\@oddhead{\theoddhe@d} + \def\@evenhead{\theevenhe@d} + \def\@oddfoot{\theoddf@@t} \def\@evenfoot{\theevenf@@t} + } +\else + \def\ps@headings{ + \def\@oddhead{\theoddhe@d} + \def\@oddfoot{\theoddf@@t} + \def\@evenhead{} \def\@evenfoot{} + } +\fi + +% For draft mode (no sub-modes allowed) +% ------------------------------------- +\ifdr@ft + \def\leftmark{\sh@rttitle}\let\rightmark\leftmark + \def\theoddf@@t{\footnotesize\today---\t@me\hfil DRAFT} + \def\theevenf@@t{\footnotesize DRAFT\hfil\today---\t@me} + \def\theoddtpf@@t{\footnotesize\today---\t@me\hfil DRAFT} + \def\theeventpf@@t{\footnotesize DRAFT\hfil\today---\t@me} +\fi + +% For submission mode (default plus internal sub-modes allowed) +% ------------------------------------------------------------- +\ifsubm@t + \def\leftmark{\sh@rttitle}\def\rightmark{\titl@line} + \ifintern@l + \def\theeventphe@d{\footnotesize\thepage \hfil \rightmark\hbox{}} + \def\theoddtphe@d{\hbox{}\footnotesize\rightmark \hfil \thepage} + \def\rightmark{\vbox to 0pt{\vss\hbox{\internalmsg} \hbox{\sh@rttitle}}} + \def\leftmark{\vbox to 0pt{\vss\hbox{\internalmsg} + \hbox{\phantom{\internalmsg}\llap{\sh@rttitle}}}} + \else % put date on first page. + \edef\TODAY{\uppercase{\today}} + \def\theeventphe@d{\footnotesize\thepage \hfil \submittedmsg\ + \@journal\@titletext, \TODAY} + \def\theoddtphe@d{\footnotesize\submittedmsg\ + \@journal\@titletext, \TODAY\hfil \thepage} + \def\theevencphe@d{\footnotesize\hbox{} \hfil \submittedmsg\ + \@journal\@titletext, \TODAY} + \def\theoddcphe@d{\footnotesize\submittedmsg\ + \@journal\@titletext, \TODAY\hfil \hbox{}} + \fi +\fi + +% For compressed mode (default, internal, submitted and +% inpress sub-modes allowed) +% ----------------------------------------------------- +\ifc@mpress + \def\leftmark{\sh@rttitle}\def\rightmark{\titl@line} + \ifintern@l + \def\theeventphe@d{\footnotesize\thepage \hfil \rightmark\hbox{}} + \def\theoddtphe@d{\hbox{}\footnotesize\rightmark \hfil \thepage} + \def\rightmark{\vbox to 0pt{\vss\hbox{\internalmsg} \hbox{\sh@rttitle}}} + \def\leftmark{\vbox to 0pt{\vss\hbox{\internalmsg} + \hbox{\phantom{\internalmsg}\llap{\sh@rttitle}}}} + \fi + \ifprepr@nt + \edef\TODAY{\uppercase{\today}} + \def\theeventphe@d{\footnotesize\thepage \hfil \submittedmsg\ + \@journal\@titletext, \TODAY} + \def\theoddtphe@d{\footnotesize\submittedmsg\ + \@journal\@titletext, \TODAY\hfil \thepage} + \def\theevencphe@d{\footnotesize\hbox{} \hfil \submittedmsg\ + \@journal\@titletext, \TODAY} + \def\theoddcphe@d{\footnotesize\submittedmsg\ + \@journal\@titletext, \TODAY\hfil \hbox{}} + \fi + \ifinpr@ss + \def\leftmark{\acceptedmsg\ \@journal\@titletext, \inpressmsg} + \def\theeventphe@d{\footnotesize\thepage \hfil \leftmark\hbox{}} + \def\theoddtphe@d{\hbox{}\footnotesize\leftmark \hfil \thepage} + \fi +\fi + +% For final (evaluate) mode (default, techreport, internal, +% submitted, inpress and reprint sub-modes allowed) +% --------------------------------------------------------- +\ifev@l + \edef\TODAY{\uppercase{\today}} + \def\leftmark{\@journal\@titletext}\def\rightmark{\titl@line} + \def\theeventphe@d{\footnotesize\thepage \hfil \leftmark\hbox{}} + \def\theoddtphe@d{\hbox{}\footnotesize\leftmark \hfil \thepage} + \if@technote % make header a little bigger + \def\theevenhe@d{\small\thepage \hfil \leftmark\hbox{}} + \def\theoddhe@d{\hbox{}\small\rightmark \hfil \thepage} + \def\theeventphe@d{\small\thepage \hfil \leftmark\hbox{}} + \def\theoddtphe@d{\hbox{}\small\leftmark \hfil \thepage} + \fi + \ifintern@l + \def\theeventphe@d{\footnotesize\thepage \hfil \rightmark\hbox{}} + \def\theoddtphe@d{\hbox{}\footnotesize\rightmark \hfil \thepage} + \def\rightmark{\vbox to 0pt{\vss\hbox{\internalmsg} \hbox{\sh@rttitle}}} + \def\leftmark{\vbox to 0pt{\vss\hbox{\internalmsg} + \hbox{\phantom{\internalmsg}\llap{\sh@rttitle}}}} + \fi + \ifprepr@nt + \def\leftmark{\submittedmsg\ \@journal\@titletext, \TODAY} + \fi + \ifinpr@ss + \def\leftmark{\acceptedmsg\ \@journal\@titletext, \inpressmsg} + \fi + \ifrepr@nt + % reset page size on second and following pages b/c no copyright info + \let\oldshipout\shipout + \gdef\shipout{\global\textheight 243.5mm\oldshipout} + \def\theeventpf@@t{\footnotesize\hfil\@ieeecopyright\hfil} + \def\theoddtpf@@t{\footnotesize\hfil\@ieeecopyright\hfil} + \def\leftmark{\reprintmsg\ \@journal\@titletext} + \fi +\fi + +%% Defines the command for putting the header. footernote{TEXT} is the same +%% as markboth{TEXT}{TEXT}. Here for compatibility with other style files. +\def\markboth#1#2{\def\leftmark{#1}\def\rightmark{#2}} +\def\footernote#1{\markboth{#1}{#1}} + +% ************************************************************************** +% ***** Citation/Bibliography Definitions ****************************** +% ************************************************************************** +%% separate citations with "], [" +\def\@citex[#1]#2{\if@filesw\immediate\write\@auxout{\string\citation{#2}}\fi +\def\@citea{}\@cite{\@for\@citeb:=#2\do {\@citea\def\@citea{], +[}\@ifundefined {b@\@citeb}{{\bf ?}\@warning {Citation `\@citeb' on +page \thepage \space undefined}}% +{\csname b@\@citeb\endcsname}}}{#1}} + +\def\@cite#1#2{[{#1\if@tempswa, #2\fi}]} + +%% Allow short (name-less) citations, when used in conjunction with a +%% bibliography style that creates labels like \citename{, } +\let\@internalcite\cite +\def\cite{\def\citename##1{##1}\@internalcite} +\def\shortcite{\def\citename##1{}\@internalcite} +\def\@biblabel#1{\def\citename##1{##1}[#1]\hfill} + +\def\thebibliography#1{\section*{\refname}\footnotesize\list + {\hss[\arabic{enumi}]}{\settowidth\labelwidth{[#1]}\leftmargin\labelwidth + \advance\leftmargin\labelsep \itemsep 0pt plus .5pt + \usecounter{enumi}} + \def\newblock{\hskip .11em plus .33em minus .07em} + \sloppy\clubpenalty4000\widowpenalty4000 + \sfcode`\.=1000\relax + \ifev@l\else\normalsize\fi %added by GLP +} +\let\endthebibliography=\endlist + +% ************************************************************************** +% ***** Appendix/Appendices Definitions ******************************** +% ************************************************************************** +\newcounter{numappendices}\setcounter{numappendices}{0} +\newif\ifappendix \appendixfalse +%% appendix command for one single appendix +\def\appendix{\par + \appendixtrue + \typeout{appendices: \arabic{numappendices}} + \setcounter{section}{0}\setcounter{subsection}{0} + \gdef\thesection{\Alph{section}} + \ifnum \value{numappendices}>1 + \section*{\appendicesname} + \else + \section*{\appendixname} + \fi + \setcounter{numappendices}{0} +} +%% appendices command for multiple appendicies +\def\appendices{\par + \appendixtrue + \typeout{appendices: \arabic{numappendices}} + \setcounter{section}{0}\setcounter{subsection}{0} + \gdef\thesection{\Alph{section}} \section*{\appendicesname} + \setcounter{numappendices}{0} +} +\AtEndDocument{\if@filesw\immediate\write\@auxout{\string\setcounter{numappendices}{\arabic{numappendices}}}\fi} + +% ************************************************************************** +% ***** Title Definitions ********************************************** +% ************************************************************************** +\def\titl@line{\sh@rttitle} %for the header at the top of the page. + +\def\@title{\typeout{ieee: Warning! No \noexpand\title given!}} +\def\title{\@ifnextchar [{\titlea}{\titleb}}%] + +\def\set@title#1{\gdef\@title{#1}\global\def\set@title##1{}} +\def\setsh@rttitle#1{\gdef\sh@rttitle{#1}\global\def\setsh@rttitle##1{}} +\def\titlea[#1]#2{\set@title{#2}\setsh@rttitle{\uppercase{#1}}} +\def\titleb#1{\set@title{#1}\setsh@rttitle{\uppercase{#1}}} + +\def\authorinfo#1{\let\\\relax\thanks{#1}} + +\ifev@l + \if@technote + \def\member#1{} + \else + \def\member#1{, \emph{#1, IEEE}} + \fi +\else + \def\member#1{} +\fi + +\def\and{\unskip% % \begin{tabular} +\end{tabular}% +\hskip 0pt plus 0.1pt% +\begin{tabular}[t]{@{}c@{}}\ }% + +\def\@author{\typeout{ieee: Warning! No \noexpand\author given!}} +\def\author{\@ifnextchar [{\authora}{\authorb}}%] +\def\set@author#1{\gdef\@author{#1}\global\def\set@author##1{}} +\def\settitl@line#1{\gdef\titl@line{#1}\global\def\settitl@line##1{}} +\def\authora[#1]#2{\set@author{#2}\if@non\else\settitl@line{#1: \sh@rttitle}\fi} +\def\authorb#1{\set@author{#1}} + +\def\date#1{\def\today{#1}\edef\TODAY{\uppercase{\today}}} + +\long\def\maketitle{% + \begingroup + \let\@thanks\@empty + \renewcommand\thefootnote{} % the \thanks{} mark type is empty + \iftitlep@ge\begin{titlepage}\@maketitlepage\@thanks\end{titlepage}% + \let\@thanks\@empty\fi + \thispagestyle{titlepagestyle} + \if@twocolumn + \if@technote + %\if@twoside\newpage\cleardoublepage\else\newpage\fi% + \newpage\global\@topnum\z@ + \ifrepr@nt + \ifx\@loginfo\undefined\typeout{ieee: Warning! No \noexpand\loginfo + given!}\else\let\\\relax\thanks{\@loginfo}\fi% + \fi + \@maketitle + \else + \ifnum \col@number=\@ne + \ifrepr@nt + \ifx\@loginfo\undefined\typeout{ieee: Warning! No \noexpand\loginfo + given!}\else\let\\\relax\thanks{\@loginfo}\fi% + \fi + \@maketitle + \else \twocolumn[% + \ifrepr@nt% + \ifx\@loginfo\undefined\typeout{ieee: Warning! No \noexpand\loginfo% + given!}\else\let\\\relax\thanks{\@loginfo}\fi% + \fi% + \@maketitle]% + \fi + \fi + \else + \newpage + \global\@topnum\z@ % Prevents figures from going at top of page. + \ifrepr@nt + \ifx\@loginfo\undefined\typeout{ieee: Warning! No \noexpand\loginfo + given!}\else\let\\\relax\thanks{\@loginfo}\fi + \fi + \@maketitle + \fi + \thispagestyle{titlepagestyle}% + \@thanks + \endgroup + \setcounter{footnote}{0}% + \global\let\thanks\relax \global\let\maketitle\relax + \global\let\@maketitle\relax \global\let\@thanks\@empty + \global\let\@author\@empty \global\let\@date\@empty + \global\let\@title\@empty \global\let\title\relax + \global\let\author\relax \global\let\date\relax + \global\let\and\relax +} + +\long\def\@maketitle{\unskip\newpage% + \begin{center}\blsone + \let \footnote \thanks + \if@technote + {\bfseries\@title\par}\if@non\else\vskip 1.3em{\lineskip .5em + \noindent\begin{tabular}[t]{@{}c@{}}\@author\end{tabular}}\fi\par + \else\unskip + \noindent{\Huge\@title\par}% + \if@non\else\vskip1.0em% + \noindent{\large\lineskip .5em% + \begin{tabular}[t]{@{}c@{}}\@author\end{tabular}}% + \fi\par% + \if@nvited\vskip1.0em\noindent\emph{\large(Invited Paper)}\par\fi + \fi + \ifrepr@nt + \ifx\@lognumber\undefined\typeout{ieee: Warning! No + \noexpand\pubitemident or \noexpand\lognumber + given!}\else\thanks{\@lognumber}\fi% + \fi + \end{center}\par\vskip 0.5em}% + +\long\def\@maketitlepage{\newpage% + \mbox{}\vfil + \begin{center}\blsone + \let \footnote \thanks + \if@technote + {\bfseries\@title\par}\vskip 1.3em{\lineskip .5em + \noindent\begin{tabular}[t]{@{}c@{}}\@author\end{tabular}\par} + \else + \vskip0.2em{\Huge\@title\par}\vskip1.0em% + \iftitlep@ge\vfil\fi + \noindent{\large\lineskip .5em% + \begin{tabular}[t]{@{}c@{}}\@author\end{tabular}\par}% + \fi + \end{center}\par\vfil\mbox{}} + +\def\@journal{\typeout{ieee: Warning! No \noexpand\journal given!}} +\def\journal#1{\def\@journal{\uppercase{#1}}} + +\def\@ieeecopyright{\typeout{ieee: Warning! No \noexpand\ieeecopyright given!}} +\def\ieeecopyright#1{\def\@ieeecopyright{#1}} + +\def\lognumber#1{\def\@lognumber{IEEE Log Number #1.}} +\def\pubitemident#1{\def\@lognumber{Publisher Item Identifier #1.}} +\long\def\loginfo#1{\long\def\@loginfo{\hbox{\vrule height 3ex width \z@}#1}} + +\def\sh@rttitle{} +\def\@titletext{} +\def\titletext#1{\def\@titletext{#1}} + +\def\firstpage#1{\setcounter{page}{#1}} + +% ************************************************************************** +% ***** Abstract Definition ******************************************** +% ************************************************************************** +\def\abstract{% + \if@twocolumn + \small\bfseries{\itshape\abstractname\/---}% + \else + \begin{center}\vspace{-0.8em}\small\bf\abstractname\end{center} + \quotation\small + \fi\ignorespaces} +\def\endabstract{\vspace{0.6em}\par\if@twocolumn\else\endquotation\fi + \normalsize\normalstyle} + +% ************************************************************************** +% ***** Keywords Definition ******************************************** +% ************************************************************************** +\def\keywords{\vspace{-.3em} + \if@twocolumn + \small\bfseries{\itshape\keywordsname\/---}% + \else + \begin{center}\small\bf\keywordsname\end{center}\quotation\small + \fi\ignorespaces} +\def\endkeywords{\vspace{0.6em}\par\if@twocolumn\else\endquotation\fi + \normalsize\normalstyle} + +% ************************************************************************** +% ***** Fix Section Numbering ****************************************** +% ************************************************************************** +\gdef\@punct{.\ \ } % Punctuation after run-in section heading +\def\@sect#1#2#3#4#5#6[#7]#8{% + \ifnum #2>\c@secnumdepth + \def\@svsec\@empty + \else + \refstepcounter{#1}% + \protected@edef\@svsec{% + %\ifnum #2=1\Roman{#1}.\fi\ifnum #2=2\Alph{#1}.\fi + \ifnum #2=1\thesection.\fi + \ifnum #2=2\thesubsection.\fi + \ifnum #2>2{\csname the#1dis\endcsname}\if@technote.\fi\fi \hskip .5em} + \ifnum #2=1\ifappendix\stepcounter{numappendices}\fi\fi + \fi + \@tempskipa #5\relax + \ifdim \@tempskipa>\z@ + \begingroup #6\relax + \@hangfrom{\hskip #3\relax\@svsec}{\interlinepenalty \@M #8\par} + \endgroup + \csname #1mark\endcsname{#7} + \addcontentsline{toc}{#1}{\ifnum #2>\c@secnumdepth\else + \protect\numberline{\csname the#1\endcsname}\fi#7} + \else + \def\@svsechd{#6\hskip #3\@svsec #8\@punct\csname #1mark\endcsname{#7} + \addcontentsline{toc}{#1}{\ifnum #2>\c@secnumdepth \else + \protect\numberline{\csname the#1\endcsname}\fi#7}} + \fi + \@xsect{#5}} + +\def\@ssect#1#2#3#4#5{\@tempskipa #3\relax + \ifdim \@tempskipa>\z@ + \begingroup #4\@hangfrom{\hskip #1}{\interlinepenalty \@M #5\par}\endgroup + \else \def\@svsechd{#4\hskip #1\relax #5\@punct}\fi + \@xsect{#3}} + +% ************************************************************************** +% ***** Section Definitions ******************************************** +% ************************************************************************** +\def\section{\@startsection{section}{1}{\z@}{2.0ex plus .5ex + minus .2ex}{1.0ex plus .2ex}{\centering\scshape}} +\def\subsection{\@startsection{subsection}{2}{\z@}{2.0ex plus .5ex + minus .2ex}{1.0ex plus .2ex}{\itshape}} +\if@technote + \def\subsubsection{\@startsection{subsubsection}{3}{\z@}{2.0ex plus .5ex + minus .1ex}{0pt}{\itshape}} +\else + \def\subsubsection{\@startsection{subsubsection}{3}{\z@}{2.0ex plus .5ex + minus .2ex}{1.0ex plus .2ex}{\normalstyle}} + \def\paragraph{\@startsection{paragraph}{4}{\z@}{1.0ex plus .5ex + minus .2ex}{0ex}{\normalstyle}} +\fi + +% ************************************************************************** +% ***** Special Environment Definitions ******************************** +% ************************************************************************** +\def\QED{\mbox{\rule[0pt]{1.5ex}{1.5ex}}} +\def\proof{\noindent\hspace{1em}{\it Proof: }} +\def\endproof{\hspace*{\fill}~\QED\par\endtrivlist\unskip} +\def\@begintheorem#1#2{\tmpitemindent\itemindent\topsep 0pt\normalstyle\trivlist + \item[\hskip \labelsep{\indent\it #1\ #2:}]\itemindent\tmpitemindent} +\def\@opargbegintheorem#1#2#3{\tmpitemindent\itemindent\topsep 0pt\normalstyle \trivlist + \item[\hskip\labelsep{\indent\it #1\ #2\ \normalstyle(#3)}]\itemindent\tmpitemindent} +\def\@endtheorem{\endtrivlist\unskip} + +% ************************************************************************** +% ***** Special Environment Definitions ******************************** +% ************************************************************************** +\if@twoside\else\raggedbottom\fi + +%% Definition for Big letter at the beginning of a paragraph +%% +\def\PARstart#1#2 {\begingroup\def\par{\endgraf\endgroup\lineskiplimit=0pt} + \setbox2=\hbox{\uppercase{#2} }\newdimen\tmpht \tmpht \ht2 + \advance\tmpht by \baselineskip\font\hhuge=cmr10 at \tmpht + \setbox1=\hbox{{\hhuge #1}} + \count7=\tmpht \count8=\ht1\divide\count8 by 1000 \divide\count7 by\count8 + \tmpht=.001\tmpht\multiply\tmpht by \count7\font\hhuge=cmr10 at \tmpht + \setbox1=\hbox{{\hhuge #1}} \noindent \hangindent1.05\wd1 + \hangafter=-2 {\hskip-\hangindent \lower1\ht1\hbox{\raise1.0\ht2\copy1}% + \kern-0\wd1}\copy2\lineskiplimit=-1000pt} + +\def\PARstartCal#1#2 {\begingroup\def\par{\endgraf\endgroup\lineskiplimit=0pt} + \setbox2=\hbox{\uppercase{#2} }\newdimen\tmpht \tmpht \ht2 + \advance\tmpht by \baselineskip\font\hhuge=cmsy10 at \tmpht + \setbox1=\hbox{{\hhuge #1\/}} + \count7=\tmpht \count8=\ht1\divide\count8 by 1000 \divide\count7 by\count8 + \tmpht=.001\tmpht\multiply\tmpht by \count7\font\hhuge=cmsy10 at \tmpht + \setbox1=\hbox{{\hhuge #1\/}} \noindent \hangindent1.05\wd1 + \hangafter=-2 {\hskip-\hangindent \lower1\ht1\hbox{\raise1.0\ht2\copy1}% + \kern-0\wd1}\copy2\lineskiplimit=-1000pt} + +\def\PARstartLyX#1{\PARstart #1} +\def\PARstartCalLyX#1{\PARstartCal #1} + +\if@technote\def\PARstart#1#2{#1#2}\fi % if technical note, disable it +\if@technote\def\PARstartCal#1#2{#1#2}\fi % if technical note, disable it +\if@technote\def\PARstartLyX#1{#1}\fi % if technical note, disable it +\if@technote\def\PARstartCalLyx#1{#1}\fi % if technical note, disable it + +% ************************************************************************** +% ***** Misc. Definitions ********************************************** +% ************************************************************************** +%Restore single spacing +\newcommand{\blsone}{\renewcommand\baselinestretch{1}% + \renewcommand\arraystretch{1.2}\setlength{\parindent}{\parindentsave}% + \normalsize} +\newcommand{\capitem}[1]{{\hspace{0.2ex}(#1)}~} +\newcommand{\insdate}{} + +% ************************************************************************** +% ***** MATH Definitions *********************************************** +% ************************************************************************** +\def\eqnarray{% + \stepcounter{equation}% + \def\@currentlabel{\p@equation\theequation}% + \global\@eqnswtrue + \m@th + \global\@eqcnt\z@ + \tabskip\@centering + \let\\\@eqncr + $$\everycr{}\halign to\displaywidth\bgroup + \hskip\@centering$\displaystyle\tabskip\z@skip{##}$\@eqnsel + &\global\@eqcnt\@ne\hskip \eqnarr@ysep\hfil${##}$\hfil + &\global\@eqcnt\tw@ \hskip \eqnarr@ysep + $\displaystyle{##}$\hfil\tabskip\@centering + &\global\@eqcnt\thr@@ \hb@xt@\z@\bgroup\hss##\egroup + \tabskip\z@skip + \cr +} +\def\endeqnarray{% + \@@eqncr + \egroup + \global\advance\c@equation\m@ne + $$\@ignoretrue +} + +% ************************************************************************** +% ***** Biography Definitions ****************************************** +% ************************************************************************** +% This is the main code for the biography environment of the IEEE +% transactions class. The previous biography code had some known +% problems which were difficult to fix. The crux of the issue was that +% the photo frame was overlaid by text when \baselinestretch>1 or when +% the biography consisted of multiple short paragraphs. +% +% The fix was done by extracting code from the excellent package: +% 'picinpar.sty' version 1.2a as of july 13, 1993 +% by Friedhelm Sowa +% +% (At least most of) The bugs you find in this code were introduced +% unwittingly by myself. +% +%---------------- +% Known problems: +% +% - Don't use multiple blank lines to separate paragraphs. A single +% blank line works well, but multiple blank lines will confuse +% the code. This has something to do with the \def\par{\\\indent} +% line, but I can't think of an appropriate fix. Similarly, make +% sure the environment doesn't end with an extra blank line. +% - Don't use \samepage +% - Use \footnotemark within and \footnotetext outside the +% window-environment instead of \footnote +% - When using the epic-package load picinpar before epic +% like \documentstyle[...,picinpar,epic]{...} +% +% Counts +\newcount\br \newcount\nb \newcount\tcdsav \newcount\tcl \newcount\tcd +\newcount\tcn \newcount\cumtcl +% Dimens +\newdimen\rtside \newdimen\hpic \newdimen\vpic \newdimen\strutilg +\newdimen\picwd \newdimen\topheight \newdimen\ilg \newdimen\lpic +\newdimen\lwindowsep \newdimen\rwindowsep % VK 10 Feb 93 +\lwindowsep0.5\baselineskip % " +\rwindowsep0.5\baselineskip % " +\newdimen\cumpar +% Tokens +\newtoks\twa \newtoks\la \newtoks\ra \newtoks\ha \newtoks\pictoc +% Boxes +\newbox\rawtext \newbox\holder \newbox\windowbox \newbox\wartext +\newbox\finaltext \newbox\aslice \newbox\bslice \newbox\wbox +\newbox\wstrutbox \newbox\picbox \newbox\waslice \newbox\wbslice +\newbox\fslice + % Another strut +\def\wstrut{\relax\ifmmode\copy\wstrutbox\else\unhcopy\wstrutbox\fi} +% + +\def\getpic#1{\sbox{\@tempboxa}{\includegraphics{#1}}% +\newcount\tmpcta \tmpcta=\ht\@tempboxa% +\newcount\tmpctb \tmpctb=\wd\@tempboxa% +\divide\tmpctb by 100% +\divide\tmpcta by\tmpctb% +\ifnum\tmpcta>133% +\typeout{ieee: Biography picture `#1' too tall.}% +\frame{\hbox to 25mm{\hfil\resizebox{!}{32mm}{\usebox{\@tempboxa}}\hfil}}% +\else \ifnum\tmpcta<123% +\typeout{ieee: Biography picture `#1' too wide.}% +\frame{\vbox to 32mm{\vss\hbox{\resizebox{25mm}{!}{\usebox{\@tempboxa}}}\vss}}% +\else% +\resizebox{25mm}{32mm}{\usebox{\@tempboxa}} +\fi\fi} + +\long\def\biographyLyX#1{\if@non\else\begin{biography} #1\end{biography}\fi} + +\if@non + \long\def\biography{} +\else + \long\def\biography{\@ifnextchar [{\@biographyb}{\@biographya[{\unitlength + 1mm\hbox{\framebox(25,32){}}}]}} +\fi + +\long\def\@biographyb[#1]{\@biographya[\getpic{#1}]} + +\long\def\@biographya[#1]#2{\bgroup +\footnotesize\bigskip\bigskip\bigskip\parskip=0pt\par% +\rule{0pt}{35mm}\vspace*{-35mm}\par% garantees correct page breaking +\begin{main@bio}[{#1}]% +\noindent{\bf #2}% +} +\def\endbiography{\if@non\else\end{main@bio}\egroup\fi} + +\long\def\main@bio[#1]{% #1 is the material for setting a graphic box +\vskip\parskip\everypar{} +\global\cumpar=0pt +\global\cumtcl=0 + \tcd=0 + \rtside=0pt +% \hpic=\linewidth + \twa={} \la={} \ra={} \ha={} +\setbox\wbox=\hbox{(} +\computeilg +\pictoc={#1} +\setbox\windowbox=\vbox{\hbox{#1}} +\picwd=\wd\windowbox +\hpic=\picwd +\vpic=\ht\windowbox\advance\vpic\dp\windowbox +\rtside=\linewidth\advance\rtside-\picwd +\setbox\picbox=\vbox{\hsize=\hpic\vbox to\vpic{\box\windowbox}}% \vfill}}% + +\vpic=\ht\picbox\advance\vpic\dp\picbox +\ifdim\rtside>0pt\advance\rtside-\rwindowsep\fi % " +\global\br=\rtside +\ifnum\picwd=0 +\ifdim\vpic>0pt\picwd=\hpic +\else\vpic=\ht\picbox\advance\vpic\dp\picbox +\fi +\fi + \global\tcl=0 \lpic=0pt + \loop\global\advance\tcl by 1 \lpic=\tcl\baselineskip + \ifdim\lpic<\vpic\repeat + \vpic=\lpic + \global\cumtcl=\tcl +% +% Here we know exactly the number of indented lines and +% are able to generate the tokens for the \parshape list +% + \ifnum\br>0\ra={ 0pt \rtside}\fi + \ifnum\tcd>0\ha={ 0pt \linewidth}\fi + \ifnum\tcl<1\global\tcl=1\fi + \createparshapespec + \tcd=0 % restore the lintel + \global\tcdsav=0 +% +% This is a very tricky part of the package. Some day there +% will exist a detailed documentation. +% +\def\par{\\\indent} +% +% This is where we start to pick up the paragraph(s) +% + \setbox\rawtext=\vbox\bgroup\unvbox\rawtext\unskip + \clubpenalty=0\widowpenalty=0 + \ifnum\brokenpenalty<\maxdimen\else\brokenpenalty=9999\fi + \tolerance=1000 + \parshape=\tcn \the\twa } +% +\def\endmain@bio{% + %\par + \global\tcd=\tcdsav + \egroup\vskip\parskip\parshape=0 % reset parshape; end \box\rawtext + \vbadness=10000 + \splittopskip=0pt +% +% Now we build the boxes beside the window +% +\global\topheight=\tcl\baselineskip +\ifnum\br>0\setbox\holder=\vsplit\rawtext to\topheight\fi +\tcn=\tcl \nb=0 +\ifnum\br>0\nb=\tcn\fi +% +% text on the right side +% +\ifnum\nb>0 + \loop\advance\nb -1 + \setbox\bslice=\vsplit\holder to\baselineskip + \prune\bslice\rtside + \setbox\wbslice=\vbox{\unvbox\wbslice\hbox + to\rtside{\box\bslice\hfil}} + \ifdim\ht\holder>0pt\repeat +\fi +%GLP add fix to make sure bio starts at top of picture +\setbox\wbslice=\vbox to\topheight{\unvbox\wbslice\vfill\vss} +% +% fixing the dimensions of the window part +% +\topheight=\ht\wbslice +% +% ship out the window material to the main vertical list +% +\setbox\windowbox=\vbox{\hbox to\linewidth{% +\vbox to\topheight{\hrule width\picwd height0pt depth0pt\vskip0pt% +\vfill\unvbox\picbox% +\ifnum\picwd>0\vfill\fi% +\vss}\ifnum\br>0\hfill\vbox{\box\wbslice}\fi}}% +% +\unvbox\windowbox% +\loop% lines below picture.... + \setbox\bslice=\vsplit\rawtext to\baselineskip + \prune\bslice\linewidth + \setbox\wbslice=\vbox{\hbox to\linewidth{\box\bslice\hfil}} + \unvbox\wbslice + \ifdim\ht\rawtext>0pt +\repeat +%GLP +%\ifnum\nb>0\topheight=\nb\baselineskip %\advance\topheight by\ilg +%\vspace*{\topheight} +%\fi +}% FINITO +% +% What else do we need? +% +\def\prune#1#2{ +% take a \vbox containing a single \hbox, +% \unvbox it, and cancel the \lastskip +% put in a \hbox of width #2 + \unvbox#1 \setbox#1=\lastbox % \box#1 now is an \hbox + \ifdim\ht#1=\parskip + \setbox#1=\hbox to#2{\vrule height\parskip depth0pt width0pt\hfill} + \else\ifdim\ht#1=0pt\relax + \else\setbox#1=\hbox to#2{\wstrut\unhbox#1\unskip}\fi\fi} +% +% Here the token \twa is generated. +% It's not so difficult as it looks like. +% +\def\createparshapespec{% +\global\tcn=0 +\ifnum\br>0\global\tcn=\tcl\fi +\nb=0 +\ifnum\br>0\nb=\tcn\fi +\global\advance\tcn by\tcd \global\advance\tcn by1 +\ifnum\tcd>0 +\loop\twa=\expandafter{\the\twa\the\ha}\advance\tcd -1 +\ifnum\tcd>0\repeat +\fi +\ifnum\nb>0 +\loop\twa=\expandafter{\the\twa\the\ra}\advance\nb -1 +\ifnum\nb>0\repeat +\fi +\global\twa=\expandafter{\the\twa 0pt \the\linewidth}} +% +\def\computeilg{% compute the interline glue + \tcl=0\ilg=0pt\strutilg=0pt + \loop\setbox\wbox=\hbox{\char\tcl} + \ifdim\ht\wbox>\ilg\ilg=\ht\wbox\fi + \ifdim\dp\wbox>\strutilg\strutilg=\dp\wbox\fi + \advance\tcl by 1 + \ifnum\tcl<128\repeat + \ht\wbox=\ilg + \dp\wbox=\strutilg + \strutilg=\ht\wbox %\advance\strutilg by\ilg + \ifdim\strutilg>\baselineskip + \typeout{character with height greater baselineskip found in font} + \typeout{baselineskip changed to 1.5 of that height!} + \baselineskip=1.5\strutilg + \fi + \global\ilg=\baselineskip + \global\advance\ilg-\ht\wbox \global\advance\ilg-\dp\wbox + \strutilg=\ht\wbox \advance\strutilg by\ilg + \setbox\wstrutbox=\hbox{\vrule height\strutilg depth\dp\wbox width0pt}} + + +% the following code from version.sty by Stephen Bellantoni 1990, loosely +% based on "annotation.sty" by Tom Hofmann. Used to exclude "biography" from +% anonymous mode. +\begingroup +\catcode`@=11\relax% +\catcode`{=12\relax\catcode`}=12\relax% +\catcode`(=1\relax \catcode`)=2\relax% +\gdef\glpinclude#1(% + \expandafter\gdef\csname #1\endcsname% + ()% + \expandafter\gdef\csname end#1\endcsname% + ()% +)% +\gdef\glpexclude#1(% + \expandafter\gdef\csname #1\endcsname% + (\@bsphack\catcode`{=12\relax\catcode`}=12\relax\csname #1@NOTE\endcsname)% + \long\expandafter\gdef\csname #1@NOTE\endcsname ##1\end{#1}% + (\csname #1END@NOTE\endcsname)% + \expandafter\gdef\csname #1END@NOTE\endcsname% + (\@esphack\end(#1))% +)% +\endgroup + +%------- +\def\@confplacedate{\typeout{ieee: Warning! No \noexpand\confplacedate set!} +\bfseries `confplacedate' needs to be set. For example, to: Stanford, CA, USA, +September 29--30, 1991} +\def\confplacedate#1{\def\@confplacedate{#1}} + +%%%%%%%%%%%%%%%%%%%%%%%%% End of ieee.cls %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% diff --git a/cryptominisat/cppsrc/docs/satcomp15-pdf/sigproc.bib b/cryptominisat/cppsrc/docs/satcomp15-pdf/sigproc.bib new file mode 100644 index 00000000..b8fc175a --- /dev/null +++ b/cryptominisat/cppsrc/docs/satcomp15-pdf/sigproc.bib @@ -0,0 +1,2589 @@ +@BOOK{salas:calculus, + AUTHOR = "S.L. Salas and Einar Hille", + TITLE = "Calculus: One and Several Variable", + PUBLISHER = "John Wiley and Sons", + ADDRESS = "New York", + YEAR = "1978" } + +@inproceedings{804350, + author = {Thomas J. Schaefer}, + title = {The complexity of satisfiability problems}, + booktitle = {{STOC}'78}, + year = {1978}, + pages = {216--226}, + location = {San Diego, California, United States}, + doi = {http://doi.acm.org/10.1145/800133.804350}, +} + +Proceedings of the tenth annual ACM symposium on Theory of computing -- +publisher = {ACM Press}, +address = {New York, NY, USA}, + +@inproceedings{smith94phase, + author = "Barbara Smith", + title = "The Phase Transition in Constraint Satisfaction Problems: {A} {CL}oser Look at the Mushy Region", + booktitle = {{ECAI}'94}, + year = "1994" +} + +@inproceedings{swdia, + author = "Chanseok Oh", + title = "{MiniSat HACK 999ED, MiniSat HACK 1430ED and SWDiA5BY}", + booktitle = "SAT Competition 2014 Booklet", + year = "201", +} + +@inproceedings{lingeling, + author = "Armin Biere", + title = "Yet another Local Search Solver and Lingeling and Friends Entering the SAT Competition 2014", + booktitle = "SAT Competition 2014 Booklet", + year = "2014", +} + +@inproceedings{cheeseman91where, + author = "Peter Cheeseman and Bob Kanefsky and William M. Taylor", + title = "Where the Really Hard Problems Are", + booktitle = "IJCAI-91", + pages = "331--337", + year = "1991", +} +Proceedings of the Twelfth International Joint Conference on Artificial Intelligence, Sidney, Australia + +@INPROCEEDINGS{Juels-2004-scn, + author = {Juels, Ari}, + title = {Minimalist Cryptography for Low-Cost {RFID} Tags}, + booktitle = {International Conference on Security in Communication Networks --- SCN 2004}, + year = {2004}, + editor = {Blundo, Carlo and Cimato, Stelvio}, + volume = {3352}, + series = {LNCS}, + pages = {149--164}, + month = {September}, + publisher = {Springer-Verlag}, + address = {Amalfi, Italia}, +} + + +@inproceedings{achlioptas-threshold, + author = {Dimitris Achlioptas and Yuval Peres}, + title = {The Threshold for Random k-{SAT} is 2\^\ k(ln 2 - O(k))}, + booktitle = {{STOC}'03}, + year = {2003}, + isbn = {1-58113-674-9}, + pages = {223--231}, + location = {San Diego, CA, USA}, + doi = {http://doi.acm.org/10.1145/780542.780577}, +} +Proceedings of the thirty-fifth annual ACM symposium on Theory of computing -- +publisher = {ACM Press} +address = {New York, NY, USA} + +@article{DPLL, + author = {Martin Davis and Hilary Putnam}, + title = {A Computing Procedure for Quantification Theory}, + journal = {J. ACM}, + volume = {7}, + number = {3}, + year = {1960}, + issn = {0004-5411}, + pages = {201--215}, + doi = {http://doi.acm.org/10.1145/321033.321034}, +} +publisher = {ACM Press}, +address = {New York, NY, USA}, + +@inproceedings {Minisat+, + author = {E\'en, Niklas and S\"orensson, Niklas}, + title = {Translating {P}seudo-{B}oolean constraints into {SAT}}, + booktitle= {Journal on Satisfiability, Boolean Modeling and Computation}, + year = {2006}, + pages = {1-26}, + volume = {2}, +} + +@inproceedings {EenS03MiniSat, + title = {An Extensible {SAT}-solver}, + author = {Niklas E\'en and Niklas S\"{o}rensson}, + booktitle = {SAT}, + editor = {Enrico Giunchiglia and Armando Tacchella}, + pages = {502--518}, + publisher = {Springer}, + series = {LNCS}, + url = {http://dblp.uni-trier.de/db/conf/sat/sat2003.html#EenS03}, + volume = {2919}, + year = {2003}, + ee = {http://www.cs.chalmers.se/Cs/Research/FormalMethods/MiniSat/cgi/MiniSat.ps.gz.cgi}, + keywords = {2003 2004 SAT-solver ais-07w efficiency implementation }, +} + +@misc { toolbar, + author="S. Bouveret and F. Heras and S. de Givry and J. Larrosa and M. Sanchez and T. Schiex", + title="Toolbar: a state-of-the-art platform for wcsp", + url="http://www.inra.fr/mia/T/degivry/ToolBar.pdf", + year="2004" +} + +@inproceedings{1267340, + author = {Kirschenbaum, Ilan and Wool, Avishai}, + title = {How to build a low-cost, extended-range {RFID} skimmer}, + booktitle = {USENIX-SS'06: Proceedings of the 15th conference on {USENIX} Security Symposium}, + year = {2006}, + location = {Vancouver, B.C., Canada}, + publisher = {{USENIX} Association}, + address = {Berkeley, CA, USA}, +} + +@misc{Benetton-boycott, + author = {{CASPIAN - Consumers Against Supermarket Privacy Invasion and Numbering}}, + howpublished={Press release}, + note= {\url{http://www.boycottbenetton.com}}, + title = {Boycott {B}enetton}, + year = {2003}, + month = {March}, +} + +@article{ improved-deterministic, + author="Michael H. Schulz and Elisabeth Auth", + title="Improved Deterministic Test Pattern Generation with Applications to Redundancy Identification", + year="1989", + month="July", + journal="IEEE Transactions on computer-aided design", + volume="8", + number="7", + pages={811--816}, + issn="0278-0070" +} +publisher = " IEEE Circuits and Systems Society", +address="Piscataway, NJ 08854, USA", + +@inproceedings{244560, + author = {Jo\&\#227;o P. Marques Silva and Karem A. Sakallah}, + title = {{GRASP}-a new search algorithm for satisfiability}, + booktitle = {ICCAD'96}, + year = {1996}, + isbn = {0-8186-7597-7}, + pages = {220--227}, + location = {San Jose, California, United States}, + publisher = {IEEE Computer Society}, +} +Proceedings of the 1996 IEEE/ACM international conference on Computer-aided design --- +address = {Washington, DC, USA}, + + @inproceedings{ chai03fast, + author = "D. Chai and A. Kuehlmann", + title = "A fast pseudo-boolean constraint solver", + pages = {305--317}, + booktitle = "IEEE Transactions on Computer-Aided Design of Integrated Circuits and Systems 2003", + year = {2003}, + month =" mar", + volume = "24", + issue = "3", + issn = "0278-0070" +} +publisher = "IEEE Circuits and Systems Society", + +@TechReport{EPC-standard, + author = "EPCglobal", + url="http://www.epcglobalinc.org/standards/specs/13.56_MHz_ISM_Band_Class_1_RFID_Tag_Interface_Specification.pdf", + title="13.56 {MHz} {ISM} Band Class 1 Radio Frequency Identification Tag Interface Specification (2003)", + institution = "Auto-ID cetner, MIT", + year ="2003", + month = "February", + version = "1.0.0" +} +address = "77 massachusetts avenue, bldg 3-449, cambridge, ma 02139-4307, USA", + +@INPROCEEDINGS{LuLHHN-2007-percom, + author = {Lu, Li and Liu, Yunhao and Hu, Lei and Han, Jinsong and Ni, Lionel}, + title = {A Dynamic Key-Updating Private Authentication Protocol for {RFID} Systems}, + booktitle = {PerCom 2007}, + year = {2007}, + pages = {13--22}, + month = {March}, + organization = {IEEE} +} +International Conference on Pervasive Computing and Communications +publisher = {IEEE Computer Society Press} +address = {New York, USA}, + +@INPROCEEDINGS{Ohkubo04Efficient, + author = {Ohkubo, Miyako and Suzuki, Koutarou and Kinoshita, Shingo}, + title = {Efficient Hash-Chain Based {RFID} Privacy Protection Scheme}, + booktitle = {International Conference on Ubiquitous Computing --- Ubicomp 2004, Workshop Privacy: Current Status and Future Directions}, + month = {September}, + year = {2004}, + address = {Nottingham, England}, +} + +@INPROCEEDINGS{MolnarSW-2005-sac, + author = {Molnar, David and Soppera, Andrea and Wagner, David}, + title = {A Scalable, Delegatable Pseudonym Protocol Enabling Ownership Transfer of {RFID} Tags}, + booktitle = {Selected Areas in Cryptography --- SAC 2005}, + editor = {Preneel, Bart and Tavares, Stafford}, + volume = {3897}, + series = {LNCS}, + pages = {276--290}, + month = {August}, + series = {LNCS}, + publisher = {Springer-Verlag}, + year = {2005}, + address = {Kingston, Canada}, +} + +@inproceedings{DBLP:conf/otm/FeldhoferR06, + author = {Martin Feldhofer and Christian Rechberger}, + title = {A Case Against Currently Used Hash Functions in {RFID} Protocols}, + booktitle = {OTM Workshops (1)}, + year = {2006}, + pages = {372-381}, + ee = {http://dx.doi.org/10.1007/11915034_61}, + crossref = {DBLP:conf/otm/2006-w1}, + bibsource = {DBLP, http://dblp.uni-trier.de} +} + +@proceedings{DBLP:conf/otm/2006-w1, + editor = {Robert Meersman and Zahir Tari and Pilar Herrero}, + title = {On the Move to Meaningful Internet Systems 2006: OTM 2006 Workshops, OTM Confederated International Workshops and Posters, AWeSOMe, CAMS, COMINF, IS, KSinBIT, MIOS-CIAO, MONET, OnToContent, ORM, PerSys, OTM Academy Doctoral Consortium, RDDS, SWWS, and SeBGIS 2006, Montpellier, France, October 29 - November 3, 2006. Proceedings, Part I}, + booktitle = {OTM Workshops (1)}, + publisher = {Springer}, + series = {LNCS}, + volume = {4277}, + year = {2006}, + isbn = {3-540-48269-5}, + bibsource = {DBLP, http://dblp.uni-trier.de} +} + + +@INPROCEEDINGS{VajdaB-2003-ubicom, + author = {Vajda, Istv\'an and Butty\'an, Levente}, + title = {Lightweight Authentication Protocols for Low-Cost {RFID} Tags}, + booktitle = {Ubicomp 2003 Second Workshop on Security in Ubiquitous Computing}, + month = {October}, + year = {2003} +} +address = {Seattle, WA, USA}, + +@INPROCEEDINGS{LiW-2007-sec, + author = {Li, Tieyan and Wang, Guilin}, + title = {Security Analysis of Two Ultra-Lightweight {RFID} Authentication Protocols}, + booktitle = {IFIP SEC 2007}, + month = {May}, + organization = {IFIP}, +} +year = {2007}, +address = {Sandton, Gauteng, South Africa}, + +@MISC{BatinaGKMTV-2006-eprint, + author = {Batina, Lejla and Guajardo, Jorge and Kerins, Tim and Mentens, Nele and Tuyls, Pim and Verbauwhede, Ingrid}, + title = {An Elliptic Curve Processor Suitable For {RFID}-Tags}, + howpublished = {Cryptology ePrint Archive, Report 2006/227}, + year = {2006}, + organization = {IACR}, +} + +@inproceedings {AES-grain-sand, + title = {{AES} implementation on a grain of sand}, + issue = "1", + ISSN="1747-0722", + pages = {13--20}, + author="Feldhofer, M. and Wolkerstorfer, J. and Rijmen, V.", + year = "2005", + voulme="152", + booktitle = "Information Security", + organization = {IEEE}, +} +publisher = {IEEE Computer Society Press}, + +@MISC{Juels-2005-manuscript-2, + author = {Juels, Ari}, + title = {{RFID} Security and Privacy: A research Survey}, + howpublished = {Manuscript}, + year = {2005}, + month = {September}, + organization = {RSA Laboratories}, +} + +@INPROCEEDINGS{JuelsW-2007-percom, + author = {Juels, Ari and Weis, Stephen}, + title = {{Defining Strong Privacy for RFID}}, + booktitle = {International Conference on Pervasive Computing and Communications --- PerCom 2007}, + year = {2007}, + editor = {}, + volume = {}, + series = {}, + pages = {342--347}, + address = {New York City, New York, USA}, + month = {March}, + organization = {IEEE}, + publisher = {IEEE Computer Society Press}, + bibsource = {Information Security Group (GSI), UCL, Louvain-la-Neuve, Belgium}, +} + +@INPROCEEDINGS{Vaudenay-2007-asiacrypt, + author = {Vaudenay, Serge}, + title = {On Privacy Models for {RFID}}, + booktitle = {Advances in Cryptology --- Asiacrypt 2007}, + year = {2007}, + editor = {}, + volume = {4833}, + series = {LNCS}, + pages = {68--87}, + address = {Kuching, Malaysia}, + month = {December}, + organization = {}, + publisher = {Springer-Verlag}, + bibsource = {Information Security Group (GSI), UCL, Louvain-la-Neuve, Belgium}, +} + +@INPROCEEDINGS{BolotnyyR-2007-percom, + author = {Bolotnyy, Leonid and Robins, Gabriel}, + title = {Physically Unclonable Function-Based Security and Privacy in {RFID} Systems}, + booktitle = {PerCom 2007}, + year = {2007}, + pages = {211--220}, + month = {March}, + organization = {IEEE}, +} +publisher = {IEEE Computer Society Press} +International Conference on Pervasive Computing and Communications -- +address = {New York, USA}, + +@INPROCEEDINGS{JuelsRS-2003-ccs, + author = {Juels, Ari and Rivest, Ronald and Szydlo, Michael}, + title = {The Blocker Tag: Selective Blocking of {RFID} Tags for Consumer Privacy}, + booktitle = {ACM CCS 2003}, + year = {2003}, + editor = {Atluri, Vijay}, + pages = {103--111}, + month = {October}, + publisher = "ACM Press" +} +address = {Washington, DC, USA}, +Conference on Computer and Communications Security +organization = "ACM", + +@INPROCEEDINGS{JuelsW-2005-crypto, + author = {Juels, Ari and Weis, Stephen}, + title = {Authenticating Pervasive Devices with Human Protocols}, + booktitle = {Advances in Cryptology --- CRYPTO'05}, + year = {2005}, + editor = {Shoup, Victor}, + volume = {3126}, + series = {LNCS}, + pages = {293--308}, + month = {August}, + organization = {IACR}, + address = {Santa Barbara, California, USA}, + publisher = {Springer-Verlag}, + series = {LNCS}, +} + +@inproceedings{ zhang01efficient, + author = "Lintao Zhang and Conor F. Madigan and Matthew W. Moskewicz and Sharad Malik", + title = "Efficient Conflict Driven Learning in Boolean Satisfiability Solver", + booktitle = "{ICCAD}", + pages = "279-285", + year = "2001", + url = "citeseer.ist.psu.edu/article/zhang01efficient.html" } + + +@INPROCEEDINGS{ButtyanHV-2006-pet, + author = {Butty\'an, Levente and Holczer, Tam\'as and Vajda, Istv\'an}, + title = {Optimal Key-Trees for Tree-Based Private Authentication}, + booktitle = {Workshop on Privacy Enhancing Technologies --- PET 2006}, + pages = {332-350}, + month = {June}, + year = {2007}, + address = {Cambridge, United Kingdom}, +} + + +@INPROCEEDINGS{Castelluccia07Secret, + author = {Castelluccia, Claude and Soos, Mate}, + title = {Secret Shuffling: A Novel Approach to {RFID} Private Identification}, + booktitle = {{RFIDSec}'07}, + pages = {169-180}, + year = {2007}, + month = {July} +} +Proceedings of the International Conference on RFID Security 2007 + +@INPROCEEDINGS{breaking-lmap, + author = {Mihaly B\'arasz and Bal\'azs Boros and P\'eter Ligeti and Krisztina L\'oja and D\'aniel Nagy}, + title = {Breaking {LMAP}}, + pages = {69-78}, + month = {July}, + year = {2007}, + booktitle = {Conference on RFID Security --- {RFIDSec}'07}, + address = {Malaga, Spain}, +} + +@INPROCEEDINGS{Initial-SRAM, + author = {Daniel Holcom and Wayne Burleson and Kevin Fu.}, + title = {Initial {SRAM} state as a Fingerprint and Source of True Random Numbers for {RFID} Tags}, + booktitle = {{RFIDSec}'07}, + pages = {29-40}, + month = {July}, + year = {2007} +} +Proceedings of the International Conference on RFID Security 2007 + +@inproceedings{HBattack, + author = {Gilbert, Henri and Robshaw, Matt and Sibert, Herve}, + title = {An Active Attack Against {HB}$^+$ - A Provably Secure Lightweight Authentication Protocol}, + booktitle = {IEE Electronic Letters 41, 21}, + year = {2005}, + pages = {1169--1170} +} + +@INPROCEEDINGS{KatzS-2006-eurocrypt, + author = {Katz, Jonathan and Sun Shin, Ji}, + title = {Parallel and Concurrent Security of the {HB} and {HB}$^{+}$ Protocols}, + booktitle = {Advances in Cryptology --- EUROCRYPT '06}, + organization = {IACR}, + year = {2006} +} +Advances in Cryptology +publisher = {Springer-Verlag}, + +@MISC{KatzS-2006-eprint, + author = {Katz, Jonathan and Smith, Adam}, + title = {Analyzing the {HB} and {HB}+ Protocols in the ``Large Error'' Case}, + howpublished = {Cryptology ePrint Archive, Report 2006/326}, + organization = {IACR}, +} + +@inproceedings{1229319, + author = {Tri Van Le and Mike Burmester and Breno de Medeiros}, + title = {Universally composable and forward-secure {RFID} authentication and authenticated key exchange}, + booktitle = {Proceedings of the 2nd ACM symposium on Information, Computer and Communications Security --- {ASIACCS}'07}, + year = {2007}, + isbn = {1-59593-574-6}, + pages = {242--252}, + location = {Singapore}, + publisher = {ACM}, + address = {New York, NY, USA}, + doi = {http://doi.acm.org/10.1145/1229285.1229319}, +} + + + +@INPROCEEDINGS{PUF-based-RNG, + author = {Charles W. O'Donnell and G. Edward Suh and Srinivas Devadas}, + title = {{PUF}-Based Random Number Generation}, + booktitle = {MIT CSAIL CSG Technical Memo 481}, + url = {http://csg.csail.mit.edu/pubs/memos/Memo-481/Memo-481.pdf}, + year = {2004}, + month = {November} +} + +@book{Ipatov05Spread, + author = {Valeri P. Ipatov}, + year = {2005}, + month = {May}, + title = {Spread Spectrum and {CDMA}: {P}rinciples and Applications}, + publisher = {John Wiley \& Sons, Ltd.}, + ISBN = {978-0470091784}, +} + +@article{DBLP:journals/ijwmc/HellJM07, + author = {Martin Hell and + Thomas Johansson and + Willi Meier}, + title = {Grain: a stream cipher for constrained environments}, + journal = {IJWMC}, + volume = {2}, + number = {1}, + year = {2007}, + pages = {86-93}, + ee = {http://dx.doi.org/10.1504/IJWMC.2007.013798}, + bibsource = {DBLP, http://dblp.uni-trier.de} +} + +@book{applied-crypto, + year= {1996}, + ISBN ={0-8493-8523-7}, + author={Alfred J. Menezes and Paul C. van Oorschot and Scott A. Vanstone}, + title ={Handbook of applied cryptography}, + publisher={CRC Press}, + address={Boca Raton, Florida}, +} +url={http://cacr.math.uwaterloo.ca/hac} + +@inproceedings{DiPietro07Information, + author={Roberto Di Pietro and Refik Molva}, + title={Information confinement, privacy, and security in {RFID} systems}, + month={September}, + booktitle={Proceedings of the 12th European Symposium On Research In Computer Security}, + year={2007}, + pages={187-202}, +} + +@inproceedings{PerisHER-2006-rfidsec, + author = {Peris-Lopez, Pedro and Hernandez-Castro, Julio Cesar and Estevez-Tapiador, Juan and Ribagorda, Arturo}, + title = {{LMAP}: A Real Lightweight Mutual Authentication Protocol for Low-cost {RFID} tags}, + booktitle = {Proceedings of {RFIDSec}'06}, + year = {2006}, + month = {July}, + address = {Graz, Austria}, + organization = {Ecrypt}, +} + +@INPROCEEDINGS{BringerCD-2006-secperu, + author = {Bringer, Julien and Chabanne, Herv\'e and Dottax Emmanuelle}, + title = {{HB}$^{++}$: a Lightweight Authentication Protocol Secure against Some Attacks}, + booktitle = {{IEEE} SecPerU 2006}, + year = {2006}, + month = {June}, + organization = {IEEE}, +} +International Conference on Pervasive Services, Workshop on Security, Privacy and Trust in Pervasive and Ubiquitous Computing +address = {Lyon, France}, +publisher = {IEEE Computer Society Press}, + +@INPROCEEDINGS{PerisHER-2006-uic, + author = {Peris-Lopez, Pedro and Hernandez-Castro, Julio Cesar and Estevez-Tapiador, Juan and Ribagorda, Arturo}, + title = {{M2AP}: A Minimalist Mutual-Authentication Protocol for Low-cost {RFID} Tags}, + booktitle = {International Conference on Ubiquitous Intelligence and Computing --- {UIC}’06}, + year = {2006}, + editor = {}, + volume = {4159}, + pages = {912--923}, + month = {September}, + series = {LNCS}, + publisher = {Springer-Verlag}, +} + + +@INPROCEEDINGS{M2AP-break, + author={Mih\'aly B\'ar\'asz and Bal\'azs Boros and P\'eter Ligeti and Krisztina L\'oja and D\'aniel A. Nagy}, + title={Passive Attack Against the {M2AP} Mutual Authentication Protocol for {RFID} Tags}, + year = {2007}, + month= {September}, + date = {24-25}, + booktitle={{RFID} 2007 --- The First International {EURASIP} Workshop on {RFID} Technology}, + country = {Austria}, + city={Vienna} +} + +@INPROCEEDINGS{HBppbreak, + author= {Henri Gilbert and Matthew J.B. Robshaw and Yannick Seurin}, + title={Good Variants of {HB}+ are Hard to Find}, + year={2008}, + month={January}, + booktitle={Financial Cryptography}, + publisher={Springer}, + country={Mexico} +} + +@inproceedings{MAGMA, + author = {Wieb Bosma and John Cannon and Graham Matthews}, + title = {Programming with algebraic structures: design of the {MAGMA} language}, + booktitle = {Proceedings of the international symposium on Symbolic and algebraic computation --- ISSAC '94}, + year = {1994}, + isbn = {0-89791-638-7}, + pages = {52--57}, + location = {Oxford, United Kingdom}, + doi = {http://doi.acm.org/10.1145/190347.190362}, + publisher = {ACM}, + address = {New York, NY, USA}, +} + +@inproceedings{Singular, + author = {Gert-Martin Greuel and Gerhard Pfister and Hans Sch\"{o}nemann}, + title = {{SINGULAR} --- A computer algebra system for polynomial computations}, + booktitle = {Symbolic computation and automated reasoning}, + year = {2001}, + isbn = {1-56881-145-4}, + pages = {227--233}, + publisher = {A. K. Peters, Ltd.}, + address = {Natick, MA, USA}, +} + +@misc{SAGE, + author = {{The SAGE Group}}, + year = {2008}, + title = {{SAGE} Mathematics Software}, + note = {\url{http://www.sagemath.org}}, +} + +@misc{new-sparse-technique, + author={H{\aa}vard Raddum and Igor Semae}, + title={New Technique for Solving Sparse Equation Systems}, + month={January}, + year={2006}, + note={\url{eprint.iacr.org/2006/475/}}, +} + +@TechReport{algebraic-DES, + author={Nicolas T. Courtois and Gregory V. Bard}, + title={Algebraic Cryptanalysis of the {D}ata {E}ncryption {S}tandard}, + year={2006}, + institution = {IACR E-print}, + number = {2006/402}, + month={November}, + booktitle={IACR E-print, \url{http://eprint.iacr.org/2006/402}}, +} + + + +@inproceedings{early-DES-algebraic, + author={Chaum, David and Evertse, Jan-Hendrik}, + title={Cryptanalysis of {DES} with a Reduced Number of Rounds}, + booktitle = {Advances in Cryptology --- {CRYPTO}'85}, + year = {1986}, + pages = {192--211}, + publisher = {Springer-Verlag} +} + +@InProceedings{Bofilletal2008CAV, + author = {M. Bofill and R. Nieuwenhuis and A. Oliveras and E. Rodr\'\i guez-Carbonell and A. Rubio}, + title = {The {B}arcelogic {SMT} Solver}, + pages = {294-298}, + booktitle = {{CAV}'08}, + year = {2008}, + series = {LNCS}, + volume = {5123}, + publisher = {Springer}, + editor = {A. Gupta and S. Malik}, +} + +@techreport{RSAT, + author = {Knot Pipatsrisawat and Adnan Darwiche}, + institution = {Automated Reasoning Group, Computer Science}, + title = {{RS}at 2.0: {SAT} Solver Description}, + year = {2007}, +} + +@inproceedings{DBLP:conf/fse/CourtoisBW08, + author = {Nicolas Courtois and Gregory V. Bard and David Wagner}, + title = {Algebraic and Slide Attacks on {K}ee{L}oq}, + booktitle = {FSE}, + year = {2008}, + pages = {97-115}, + ee = {http://dx.doi.org/10.1007/978-3-540-71039-4_6}, + crossref = {DBLP:conf/fse/2008}, + bibsource = {DBLP, http://dblp.uni-trier.de} +} + +@TechReport{cryptoeprint:2008:166, + author = {Nicolas T. Courtois and Karsten Nohl and Sean O'Neil}, + title = {Algebraic Attacks on the {C}rypto-1 Stream Cipher in {Mifare} {C}lassic and {O}yster Cards}, + number = {2008/166}, + institution = {Cryptology ePrint Archive}, + year = {2008}, +} +howpublished = {Cryptology ePrint Archive, Report 2008/166}, +note = {\url{http://eprint.iacr.org/}}, + +@INPROCEEDINGS{Biere99symbolicmodel, + author = {Armin Biere and A. Cimatti and E. M. Clarke and M. Fujita and Y. Zhu}, + title = {Symbolic Model Checking Using {SAT} Procedures instead of {BDDs}}, + booktitle = {Proc. of Design Automation Conference ({DAC}'99)}, + year = {1999}, + pages = {317--320} +} + +@INPROCEEDINGS{temporalinduction, + author = {E\'en, Niklas and S\"orensson, Niklas}, + title = {Temporal Induction by Incremental {SAT} Solving}, + booktitle={Proc. of First Intrenational Workshop on Bounded Model Checking}, + year={2003}, + volume={89}, + issue={4}, + series={ENTCS}, + publisher={Elsevier} +} + +@inproceedings{ARMS02, + author = {Fadi A. Aloul and Arathi Ramani and Igor Markov and Karem Sakallah}, + title = {Generic {ILP} versus Specialized 0-1 {ILP}: an Update}, + booktitle = {Proc. ACM/IEEE Intl. Conf. Comp.-Aided Design}, + pages = {450 - 457}, + month = {November}, + year = {2002}, + URL = {http://www.gigascale.org/pubs/190.html} +} + +@inproceedings{knowledge-compiling, + author={Adnan Dawiche}, + title={New advances in compiling {CNF} to decomposable negation normal form}, + booktitle={Proc. of European Conference on Artificial Intelligence}, + year={2004}, + pages={328 - 332}, +} + +@InProceedings{S-Match, + author = {Fausto Giunchiglia and Pavel Shvaiko and Mikalai Yatskevich}, + title = {S-{M}atch: an algorithm and an implementation of semantic matching}, + booktitle = {Semantic Interoperability and Integration}, + year = {2005}, + number = {04391}, + series = {Dagstuhl Seminar Proceedings}, + ISSN = {1862-4405}, + publisher = {IBFI}, + note = {\url{http://drops.dagstuhl.de/opus/volltexte/2005/37}}, + editor = {Y. Kalfoglou and M. Schorlemmer and A. Sheth and S. Staab and M. Uschold}, +} +publisher = {Internationales Begegnungs- und Forschungszentrum fuer Informatik (IBFI)}, + + + +@techreport{bard-thesis, + author = {Gregory V. Bard}, + title = {Algorithms for the Solution of Polynomial and Linear Systems of Equations over Finite Fields, with an Application to the Cryptanalysis of {K}ee{L}oq}, + institution={University of Maryland Dissertation}, + month={April}, + year={2008}, + note = {Ph.D. Thesis}, +} + +@inproceedings{Toyocrypt-nicolas-attack, + author={Nicolas T. Courtois}, + title={Higher Order Correlation Attacks, {XL} algorithm and Cryptanalysis of {T}oyocrypt ({A}n updated version)}, + booktitle={ICISC 2002}, + series={LNCS}, + volume={2587}, + publisher={Springer}, + year={2002}, +} + +@inproceedings{General-LFSR-attacks, + author={Nicolas T. Courtois and Willi Meier}, + title={Algebraic Attacks on Stream Ciphers with Linear Feedback}, + booktitle={Advances in Cryptology --- EUROCRYPT '03}, + series={LNCS}, + volume={2656}, + pages={345–359}, + publisher={Springer}, + address = {Warsaw, Poland} +} + +@inproceedings{Canniere06Trivium, + author = {Christophe De Canni{\`e}re}, + title = {Trivium: A Stream Cipher Construction Inspired by Block Cipher Design Principles}, + booktitle = {ISC}, + year = {2006}, + pages = {171-186}, + ee = {http://dx.doi.org/10.1007/11836810_13}, + crossref = {DBLP:conf/isw/2006}, + bibsource = {DBLP, http://dblp.uni-trier.de} +} + +@proceedings{DBLP:conf/isw/2006, + editor = {Sokratis K. Katsikas and et al}, + title = {Information Security, 9th International Conference, ISC 2006, Samos Island, Greece, August 30 - September 2, 2006, Proceedings}, + booktitle = {ISC}, + publisher = {Springer}, + series = {LNCS}, + volume = {4176}, + year = {2006}, + isbn = {3-540-38341-7}, + bibsource = {DBLP, http://dblp.uni-trier.de} +} +and +Javier Lopez and +Michael Backes and +Stefanos Gritzalis and +Bart Preneel + +@inproceedings{BiviumWithSATsolvers, + author = {Tobias Eibach and Enrico Pilz and Gunnar V{\"o}lkel}, + title = {Attacking {B}ivium Using {SAT} Solvers}, + booktitle = {SAT}, + year = {2008}, + pages = {63-76}, + ee = {http://dx.doi.org/10.1007/978-3-540-79719-7_7}, + crossref = {DBLP:conf/sat/2008}, + bibsource = {DBLP, http://dblp.uni-trier.de} +} + +@proceedings{DBLP:conf/sat/2008, + editor = {Hans Kleine B{\"u}ning and Xishun Zhao}, + title = {Theory and Applications of Satisfiability Testing - SAT 2008, 11th International Conference, SAT 2008, Guangzhou, China, May 12-15, 2008. Proceedings}, + booktitle = {SAT}, + publisher = {Springer}, + series = {LNCS}, + volume = {4996}, + year = {2008}, + isbn = {978-3-540-79718-0}, + bibsource = {DBLP, http://dblp.uni-trier.de} +} + +@TechReport{Bivium, + author={Havard Raddum}, + title={Cryptanalytic results on {T}rivium}, + institution = {ECRYPT Stream Cipher Project}, + year={2006}, + number={2006/039}, + note = {\url{www.ecrypt.eu.org/stream/papersdir/2006/039.ps}}, +} + +@misc{using-equation-solvers, + author = {Havard Raddum and Igor Semaev}, + title = {New Technique for Solving Sparse Equation Systems}, + howpublished = {Cryptology ePrint Archive, Report 2006/475}, + year = {2006}, + note = {\url{http://eprint.iacr.org/}}, +} + + +@TechReport{BiviumWithMiniSat, + author={Cameron McDonald and Chris Charnes and Josef Pieprzyk}, + title={Attacking {B}ivium with {M}ini{S}at}, + institution = {ECRYPT Stream Cipher Project}, + year={2007}, + number={2007/040} +} + +@inproceedings{FaugereF5, + author = {Jean-Charles Faug\`{e}re}, + title = {A new efficient algorithm for computing {G}r\"{o}bner bases without reduction to zero ({F}5)}, + booktitle = {ISSAC '02}, + year = {2002}, + isbn = {1-58113-484-3}, + pages = {75--83}, + location = {Lille, France}, + doi = {http://doi.acm.org/10.1145/780506.780516}, + publisher = {ACM}, + } +ISSAC '02: Proceedings of the 2002 international symposium on Symbolic and algebraic computation +address = {New York, NY, USA}, + + +@article{FaugereF4, + author = {Jean-Charles Faug\`{e}re}, + title = {A new efficient algorithm for computing {G}r\"{o}bner bases ({F}4)}, + journal = {Journal of Pure and Applied Algebra}, + year = {1999}, + month = {June}, + pages = {61--88}, + volume = {1}, + number = {139}, +} + +@inproceedings{DismantlingMifare, + author = {Flavio D. Garcia and et al.}, + title = {Dismantling {MIFARE} {C}lassic}, + booktitle = {ESORICS}, + year = {2008}, + pages = {97-114}, + ee = {http://dx.doi.org/10.1007/978-3-540-88313-5_7}, + crossref = {DBLP:conf/esorics/2008}, + bibsource = {DBLP, http://dblp.uni-trier.de} +} +and +Gerhard de Koning Gans and +Ruben Muijrers and +Peter van Rossum and +Roel Verdult and +Ronny Wichers Schreur and +Bart Jacobs + +@proceedings{DBLP:conf/esorics/2008, + editor = {Sushil Jajodia and Javier L{\'o}pez}, + title = {Computer Security - ESORICS 2008, 13th European Symposium on Research in Computer Security, M{\'a}laga, Spain, October 6-8, 2008. Proceedings}, + booktitle = {ESORICS}, + publisher = {Springer}, + series = {LNCS}, + volume = {5283}, + year = {2008}, + isbn = {978-3-540-88312-8}, + bibsource = {DBLP, http://dblp.uni-trier.de} +} + +@misc{Karsten-webpage-HiTag2, + author={Karsten Nohl}, + title={Description of {H}i{T}ag2}, + howpublished={Press release}, + note= {\url{http://cryptolib.com/ciphers/hitag2/}}, + month={March}, + day = {12}, + year={2008}, +} + +@InProceedings{Ouafi08Privacy, + address = {Berlin}, + affiliation = {EPFL}, + author = {Ouafi, Khaled and Phan, Raphael C.-W.}, + booktitle = {Information {S}ecurity {P}ractice and {E}xperience, 4th {I}nternational {C}onference, {ISPEC} 2008}, + location = {Sydney, Australia}, + oai-id = {oai:infoscience.epfl.ch:126418}, + oai-set = {conf; fulltext; fulltext-public}, + pages = {263--277}, + publisher = {Springer}, + review = {REVIEWED}, + series = {LNCS}, + status = {PUBLISHED}, + title = {Privacy of {R}ecent {RFID} {A}uthentication {P}rotocols}, + unit = {LASEC}, + year = {2008}, + keywords = {RFID; authentication protocols, ; privacy; untraceability; provably secure}, + details = {http://infoscience.epfl.ch/record/126418}, + documenturl = {http://infoscience.epfl.ch/getfile.py?recid=126418&mode=best}, +} + +@INPROCEEDINGS{Ohkubo04Cryptographic, + author = {Miyako Ohkubo Koutarou and Koutarou Suzuki and Shingo Kinoshita}, + title = {Cryptographic Approach to "Privacy-Friendly" Tags}, + booktitle = {RFID Privacy Workshop}, + year = {2003}, + address = {MIT, Massachusetts, USA}, + month = {November}, +} + +@article{Lamport81Password, + author = {Lamport,, Leslie}, + title = {Password authentication with insecure communication}, + journal = {Commun. ACM}, + volume = {24}, + number = {11}, + year = {1981}, + issn = {0001-0782}, + pages = {770--772}, + doi = {http://doi.acm.org/10.1145/358790.358797}, + publisher = {ACM}, + address = {New York, NY, USA}, + } + +@InProceedings{OSK_Avoine, + affiliation = {EPFL}, + author = {Avoine, Gildas and Oechslin, Philippe}, + booktitle = {The 2nd {IEEE} {I}nternational {W}orkshop on {P}ervasive {C}omputing and {C}ommunication {S}ecurity - {P}er{S}ec 2005}, + details = {http://infoscience.epfl.ch/record/99461}, + documenturl = {http://infoscience.epfl.ch/getfile.py?recid=99461&mode=best}, + keywords = {NCCR-MICS; NCCR-MICS/CL3}, + location = {Kauai island, Hawaii, USA}, + oai-id = {oai:infoscience.epfl.ch:99461}, + oai-set = {conf; fulltext; fulltext-public}, + pages = {110--114}, + review = {REVIEWED}, + status = {PUBLISHED}, + title = {A {S}calable and {P}rovably {S}ecure {H}ash-{B}ased {RFID} {P}rotocol}, + unit = {LASEC}, + year = 2005 +} + +@inproceedings{Trade-off-Hellman, + author = {Hellman, Martin E.}, + title = {A cryptanalytic time-memory trade off}, + booktitle = {{IEEE} Transactions on Information Theory}, + volume = {IT-26/4}, + pages = {401--406}, + year = {1980}, +} + +@inproceedings{Faster-crypto-time-memory, + author = {Oechslin, Philippe }, + booktitle = {Advances in Cryptology --- CRYPTO 2003}, + series = {LNCS}, + volume = {2729}, + publisher = {Springer}, + pages = {617--630}, + posted-at = {2008-07-07 15:11:06}, + priority = {2}, + title = {Making a Faster Cryptanalytic Time-Memory Trade-Off}, + url = {http://www.springerlink.com/content/u9gxwd29p2tnx3wl}, + year = {2003} +} + +@inproceedings{Molnar04Keytrees, + address = {New York, NY, USA}, + author = {Molnar, David and Wagner, David }, + booktitle = {CCS '04: Proceedings of the 11th ACM conference on Computer and communications security}, + citeulike-article-id = {202290}, + doi = {10.1145/1030083.1030112}, + isbn = {1581139616}, + keywords = {libraries, privacy}, + pages = {210--219}, + posted-at = {2007-12-25 21:42:23}, + priority = {5}, + publisher = {ACM Press}, + title = {Privacy and security in library {RFID}: issues, practices, and architectures}, + url = {http://dx.doi.org/10.1145/1030083.1030112}, + year = {2004} +} + +@INPROCEEDINGS{NohlE-2008-sec, + author = {Nohl, Karsten and Evans, David}, + title = {{Hiding in Groups: On the Expressiveness of Privacy Distributions}}, + booktitle = {Proceedings of The Ifip Tc 11 23rd International Information Security Conference --- SEC 2008}, + year = {2008}, + editor = {}, + volume = {278}, + series = {LNCS}, + pages = {1--15}, + address = {Milan, Italia}, + month = {September}, + organization = {}, + publisher = {Springer}, + bibsource = {Information Security Group (GIS), UCL, Louvain-la-Neuve, Belgium}, +} + +@inproceedings{DBLP:conf/fse/Shamir08, + author = {Adi Shamir}, + title = {{SQUASH} --- A New {MAC} with Provable Security Properties for Highly Constrained Devices Such as {RFID} Tags}, + booktitle = {FSE}, + year = {2008}, + pages = {144-157}, + ee = {http://dx.doi.org/10.1007/978-3-540-71039-4_9}, + crossref = {DBLP:conf/fse/2008}, + bibsource = {DBLP, http://dblp.uni-trier.de} +} + +@proceedings{DBLP:conf/fse/2008, + editor = {Kaisa Nyberg}, + title = {Fast Software Encryption, 15th International Workshop, {FSE} 2008, Lausanne, Switzerland, February 10-13, 2008, Revised Selected Papers}, + booktitle = {FSE}, + publisher = {Springer}, + series = {LNCS}, + volume = {5086}, + year = {2008}, + isbn = {978-3-540-71038-7}, + bibsource = {DBLP, http://dblp.uni-trier.de} +} + +@inproceedings{Oren2008WIPRPublic, +author = {Yossef Oren and Martin Feldhofer}, +title = {{WIPR} --- a Public Key Implementation on Two Grains of Sand}, +booktitle = {Workshop on RFID Security 2008}, +year = {2008}, +editor = {Sandra Dominikus}, +pages = {15 - 27}, +} + +@incollection{drat, +year={2014}, +isbn={978-3-319-09283-6}, +booktitle={Theory and Applications of Satisfiability Testing – SAT 2014}, +volume={8561}, +series={Lecture Notes in Computer Science}, +editor={Sinz, Carsten and Egly, Uwe}, +doi={10.1007/978-3-319-09284-3_31}, +title={DRAT-trim: Efficient Checking and Trimming Using Expressive Clausal Proofs}, +url={http://dx.doi.org/10.1007/978-3-319-09284-3_31}, +publisher={Springer International Publishing}, +author={Wetzler, Nathan and Heule, MarijnJ.H. and Hunt, WarrenA., Jr.}, +pages={422-429}, +language={English} +} + + +@inproceedings{DBLP:conf/ctrsa/McLooneR07, + author = {M{\'a}ire McLoone and Matthew J. B. Robshaw}, + title = {Public Key Cryptography and {RFID} Tags}, + booktitle = {CT-RSA}, + year = {2007}, + pages = {372-384}, + ee = {http://dx.doi.org/10.1007/11967668_24}, + crossref = {DBLP:conf/ctrsa/2007}, + bibsource = {DBLP, http://dblp.uni-trier.de} +} + +@proceedings{DBLP:conf/ctrsa/2007, + editor = {Masayuki Abe}, + title = {Topics in Cryptology - CT-RSA 2007, The Cryptographers' Track at the RSA Conference 2007, San Francisco, CA, USA, February 5-9, 2007, Proceedings}, + booktitle = {CT-RSA}, + publisher = {Springer}, + series = {LNCS}, + volume = {4377}, + year = {2006}, + isbn = {3-540-69327-0}, + bibsource = {DBLP, http://dblp.uni-trier.de} +} + + + +@proceedings{DBLP:conf/eurocrypt/91, + editor = {Donald W. Davies}, + title = {Advances in Cryptology --- EUROCRYPT '91, Workshop on the Theory and Application of of Cryptographic Techniques, Brighton, UK, April 8-11, 1991, Proceedings}, + booktitle = {Advances in Cryptology --- EUROCRYPT '91}, + publisher = {Springer}, + series = {LNCS}, + volume = {547}, + year = {1991}, + isbn = {3-540-54620-0}, +} + +@inproceedings{DBLP:conf/eurocrypt/Girault91, + author = {Marc Girault}, + title = {Self-Certified Public Keys}, + booktitle = {Advances in Cryptology --- EUROCRYPT '91}, + year = {1991}, + pages = {490-497}, + ee = {http://link.springer.de/link/service/series/0558/bibs/0547/05470490.htm}, + bibsource = {DBLP, http://dblp.uni-trier.de} +} + +@inproceedings{DBLP:conf/cardis/Girault00, + author = {Marc Girault}, + title = {Low-Size Coupons for Low-Cost {IC} Cards}, + booktitle = {CARDIS}, + year = {2000}, + pages = {39-50}, + crossref = {DBLP:conf/cardis/2000}, + bibsource = {DBLP, http://dblp.uni-trier.de} +} + +@proceedings{DBLP:conf/cardis/2000, + editor = {Josep Domingo-Ferrer and David Chan and Anthony Watson}, + title = {Smart Card Research and Advanced Applications, Proceedings of the Fourth Working Conference on Smart Card Research and Advanced Applications, CARDIS 2000, September 20-22, 2000, Bristol, UK}, + booktitle = {CARDIS}, + publisher = {Kluwer}, + series = {IFIP Conference Proceedings}, + volume = {180}, + year = {2000}, + isbn = {0-7923-7953-5}, + bibsource = {DBLP, http://dblp.uni-trier.de} +} + +@inproceedings{Secure-human-ID, + author = {Hopper,, Nicholas J. and Blum,, Manuel}, + title = {Secure Human Identification Protocols}, + booktitle = {ASIACRYPT '01: Proceedings of the 7th International Conference on the Theory and Application of Cryptology and Information Security}, + year = {2001}, + isbn = {3-540-42987-5}, + pages = {52--66}, + publisher = {Springer-Verlag}, + address = {London, UK}, +} + +@ARTICLE{Inherent-intracability, +title={On the inherent intractability of certain coding problems (Corresp.)}, +author={ Berlekamp, E. and McEliece, R. and van Tilborg, H.}, +journal={Information Theory, IEEE Transactions on}, +year={1978}, +month={May}, +volume={24}, +number={3}, +pages={ 384-386}, +keywords={null Decoding, Linear codes}, +doi={}, +ISSN={0018-9448}, +} + +@article{Noise-tolerant-learning, + author = {Blum,, Avrim and Kalai,, Adam and Wasserman,, Hal}, + title = {Noise-tolerant learning, the parity problem, and the statistical query model}, + journal = {J. ACM}, + volume = {50}, + number = {4}, + year = {2003}, + issn = {0004-5411}, + pages = {506--519}, + doi = {http://doi.acm.org/10.1145/792538.792543}, + publisher = {ACM}, + address = {New York, NY, USA}, +} + + +@INPROCEEDINGS{To06anovel, + author = {Marc P. C. Fossorier and Miodrag J. Mihaljević and Hideki Imai and Yang Cui and Kanta Matsuura}, + title = {A Novel Algorithm for Solving the {LPN} Problem and Its Applicatio to Security Evaluation of the {HB} Protocol for {RFID} Authentication}, + booktitle = {INDOCRYPT}, + editor = {Rana Barua and Tanja Lange}, + volume = {4329}, + series = {LNCS}, + year = {2006}, + pages = {48--62}, + publisher = {Springer} +} + +@INPROCEEDINGS{Levieil_animproved, + author = {Éric Levieil and Pierre-Alain Fouque}, + title = {An improved {LPN} algorithm}, + editor = {Roberto De Prisco and Moti Yung}, + booktitle = {Security and Cryptography for Networks --- SCN}, + volume = {4116}, + series = {LNCS}, + year = {2006}, + pages = {348--359}, + Publisher = {Springer Berlin / Heidelberg}, + ISSN = {0302-9743}, +} + +@INPROCEEDINGS{HBpp, +title={{HB}$^{++}$: a Lightweight Authentication Protocol Secure against Some Attacks}, +author={Bringer, J. and Chabanne, H. and Dottax, E.}, +booktitle={Security, Privacy and Trust in Pervasive and Ubiquitous Computing, 2006 --- SecPerU 2006}, +year={2006}, +month={June}, +volume={}, +number={}, +pages={28--33}, +doi={10.1109/SECPERU.2006.10}, +} + +@inproceedings{DBLP:conf/eurocrypt/GilbertRS08, + author = {Henri Gilbert and Matthew J. B. Robshaw and Yannick Seurin}, + title = {{HB}$^{\mbox{\#}}$: Increasing the Security and Efficiency of {HB}$^{\mbox{+}}$}, + booktitle = {Advances in Cryptology --- EUROCRYPT '08}, + year = {2008}, + pages = {361-378}, + ee = {http://dx.doi.org/10.1007/978-3-540-78967-3_21}, + crossref = {DBLP:conf/eurocrypt/2008}, + bibsource = {DBLP, http://dblp.uni-trier.de} +} + +@proceedings{DBLP:conf/eurocrypt/2008, + editor = {Nigel P. Smart}, + title = {Advances in Cryptology --- EUROCRYPT 2008, 27th Annual International Conference on the Theory and Applications of Cryptographic Techniques, Istanbul, Turkey, April 13-17, 2008. Proceedings}, + booktitle = {Advances in Cryptology --- EUROCRYPT '08}, + publisher = {Springer}, + series = {LNCS}, + volume = {4965}, + year = {2008}, + isbn = {978-3-540-78966-6}, + bibsource = {DBLP, http://dblp.uni-trier.de} +} + +@proceedings{DBLP:conf/fse/2001, + editor = {Mitsuru Matsui}, + title = {Fast Software Encryption, 8th International Workshop, FSE 2001 Yokohama, Japan, April 2-4, 2001, Revised Papers}, + booktitle = {FSE}, + publisher = {Springer}, + series = {LNCS}, + volume = {2355}, + year = {2002}, + isbn = {3-540-43869-6}, + bibsource = {DBLP, http://dblp.uni-trier.de} +} + +@techreport{Rabin79Digitalized, + author = {Rabin, M. O.}, + title = {Digitalized Signatures and Public-Key Functions as Intractable as Factorization}, + year = {1979}, + institution = {Massachusetts Institute of Technology}, + address = {Cambridge, MA, USA}, + } + +@article{HBmp, + author = {Munilla,, J. and Peinado,, A.}, + title = {{HB}-{MP}: A further step in the HB-family of lightweight authentication protocols}, + journal = {Comput. Netw.}, + volume = {51}, + number = {9}, + year = {2007}, + issn = {1389-1286}, + pages = {2262--2267}, + doi = {http://dx.doi.org/10.1016/j.comnet.2007.01.011}, + publisher = {Elsevier North-Holland, Inc.}, + address = {New York, NY, USA}, + } + +@article{HBstar, + author={D.N. Duc and K. Kim}, + title={Securing {HB}$^+$ Against {GRS} Man-in-the-Middle Attack}, + journal={Institute of Electronics, Information and Communication Engineers, Symposium on Cryptography and Information, Security}, + date = {January 23--26}, + year = {2007}, +} + +@INPROCEEDINGS{OuafiOV-2008-asiacrypt, + author = {Ouafi, Khaled and Overbeck, Raphael and Vaudenay, Serge}, + title = {On the Security of {HB\#} against a Man-in-the-Middle Attack}, + booktitle = {Advances in Cryptology --- Asiacrypt 2008}, + year = {2008}, + editor = {}, + volume = {5350}, + series = {LNCS}, + pages = {108--124}, + address = {Melbourne, Australia}, + month = {December}, + organization = {}, + publisher = {Springer}, + bibsource = {Information Security Group (GSI), UCL, Louvain-la-Neuve, Belgium}, +} + +@INPROCEEDINGS{PRESENT, + author = {Bogdanov, Andrey and Knudsen, Lars Ramkilde and Leander, Gregor and Paar, Christof and Poschmann, Axel and Robshaw, Matthew J.B. and Seurin, Yannick and Vikkelsoe, C.}, + title = {{PRESENT}: An Ultra-Lightweight Block Cipher}, + booktitle = {Workshop on Cryptographic Hardware and Embedded Systems --- CHES 2007}, + year = {2007}, + editor = {Paillier, Pascal and Verbauwhede, Ingrid}, + volume = {4727}, + series = {LNCS}, + pages = {450--466}, + address = {Vienna, Austria}, + month = {September}, + organization = {}, + publisher = {Springer-Verlag}, + bibsource = {Information Security Group (GSI), UCL, Louvain-la-Neuve, Belgium}, +} + +@INPROCEEDINGS{ChoiKKK-2006-isce, + author = {Choi, Yongje and Kim, Mooseop and Kim, Taesung and Kim, Howon}, + title = {Low power implementation of {SHA}-1 algorithm for {RFID} system}, + booktitle = {IEEE Tenth International Symposium on Consumer Electronics --- ISCE '06}, + year = {2006}, + editor = {}, + volume = {}, + series = {}, + pages = {1--5}, + address = {St.Petersburg, Russia}, + month = {September}, + organization = {}, + publisher = {}, + bibsource = {Information Security Group (GSI), UCL, Louvain-la-Neuve, Belgium}, +} + +@INPROCEEDINGS{DES-RFID-implement, + author = {Axel Poschmann and Gregor Le and Kai Schramm and Christof Paar}, + title = {A Family of Light-Weight Block Ciphers Based on {DES} Suited for {RFID} Applications}, + booktitle = {Proceedings of FSE 2007, LNCS}, + year = {2006}, + publisher = {Springer-Verlag} +} + +@article{4253019, +title={Strong Crypto for {RFID} Tags - A Comparison of Low-Power Hardware Implementations}, +author={Feldhofer, M. and Wolkerstorfer, J.}, +journal={Circuits and Systems, 2007. ISCAS 2007. IEEE International Symposium on}, +year={2007}, +month={May}, +volume={}, +number={}, +pages={1839-1842}, +keywords={cryptographic protocols, radiofrequency identificationAES-128, ECC-192, MD5, SHA-1, SHA-256, implementation efficiency, passive RFID tags, security protocols, standardized cryptographic algorithms, strong cryptography}, +doi={10.1109/ISCAS.2007.378272}, +ISSN={}, +} + +@techreport{PUF-optical, + author= {P. Ravinkanth}, + title= {Physical One-Way Functions}, + note = {Ph.D. Thesis}, + institution = {MIT}, + year={2001} +} + +@inproceedings{PUF-silicon, + author={B. Gassend and D. Clarke and M. van Dijk and S. Devadas}, + title = {Controlled Physical Random Functions}, + booktitle = {Proceedings of the 18th Annual Computer Security Applications Conference --- ACSAC '02}, + year = {2002}, + ISBN = {0-7695-1828-1}, + page = {149}, + publisher = {IEEE}, +} + +@article{PUF-circ-secret-key, + author = {D. Lim and J. W. Lee and B. Gassend and G. E. Suh and M. van Dijk and S. Devadas}, + title = {Extracting Secret Keys From Integrated Circuits}, + journal = {IEEE Transactions on Very Large Scale Integration (VLSI) Systems}, + pages = {1200--1205}, + year = {2005}, + issue = {13 (10)}, +} + + +@INPROCEEDINGS{Li99equivalencyreasoning, + author = {Chu Min Li}, + title = {Equivalency reasoning to solve a class of hard {SAT} problems}, + booktitle = {Information Processing Letters}, + year = {1999}, + pages = {76--1} +} + +@INPROCEEDINGS{Silva96conflictanalysis, + author = {Joo P. Marques and Silva Karem and A. Sakallah}, + title = {Conflict analysis in search algorithms for propositional satisfiability}, + booktitle = {Proc. of the IEEE Intl. Conf. on Tools with Artificial Intelligence}, + year = {1996} +} + +@article{Chaff01, + author = {Sharad Malik and Ying Zhao and Conor F. Madigan and Lintao Zhang and Matthew W. Moskewicz}, + title = {Chaff: Engineering an Efficient {SAT} Solver}, + journal ={Design Automation Conference}, + year = {2001}, + pages = {530-535}, + doi = {http://doi.ieeecomputersociety.org/10.1109/DAC.2001.935565}, + publisher = {IEEE Computer Society}, + address = {Los Alamitos, CA, USA}, +} +volume = {0}, +isbn = {}, + +@article{visualizingDPLL, + author = {Sinz, Carsten}, + title = {Visualizing {SAT} Instances and Runs of the {DPLL} Algorithm}, + journal = {J. Autom. Reason.}, + volume = {39}, + number = {2}, + year = {2007}, + issn = {0168-7433}, + pages = {219--243}, + doi = {http://dx.doi.org/10.1007/s10817-007-9074-1}, + publisher = {Kluwer Academic Publishers}, + address = {Hingham, MA, USA}, + } + +@inproceedings{nicolas.linear_feedback, + author={Nicolas T. Courtois}, + title={Fast Algebraic Attacks on Stream Ciphers with Linear Feedback}, + booktitle={Advances in Cryptology --- {CRYPTO} 2003}, + year={2003}, + pages={176-194}, + volume={2729/2003}, + series={LNCS}, + publisher={Springer}, +} + +@misc{Karsten-webpage-Cyrpto-1, + author={Karsten Nohl}, + title={Cryptanalysis of {C}rypto-1}, + howpublished={Press release}, + month={March}, + day = {12}, + year={2008}, + note= {\url{http://www.cs.virginia.edu/~kn5f/Mifare.Cryptanalysis.htm}} +} + +@Misc{Radboud-Mifare-press, + author = {{Digital {S}ecurity group, {R}adboud {U}niversity {N}ijmegen}}, + title = {Security Flaw in {M}ifare {C}lassic}, + howpublished = {Press release}, + month = {March}, + day = {12}, + year = {2008}, + note = {\url{http://www.ru.nl/english/general/radboud_university/vm/security_flaw_in/}}, +} + +@ARTICLE{Massacci00logicalcryptanalysis, + author = {Fabio Massacci and Laura Marraro}, + title = {Logical cryptanalysis as a {SAT}-problem: Encoding and analysis}, + journal = {Journal of Automated Reasoning}, + year = {2000}, + volume = {24}, + pages = {165--203} +} + +@article{Monte-Carlo-method, + abstract = {We shall present here the motivation and a general description of a method dealing with a class of problems in mathematical physics. The method is, essentially, a statistical approach to the study of differential equations, or more generally, of integro-differential equations that occur in various branches of the natural sciences.}, + author = {Metropolis, Nicholas and Ulam, S. }, + citeulike-article-id = {1886002}, + doi = {10.2307/2280232}, + journal = {Journal of the American Statistical Association}, + keywords = {random, sampling}, + number = {247}, + pages = {335--341}, + posted-at = {2009-04-12 22:32:37}, + priority = {2}, + title = {The {M}onte {C}arlo Method}, + url = {http://dx.doi.org/10.2307/2280232}, + volume = {44}, + year = {1949} +} + +@article{Rabin-primality-test, + author = {Rabin, Michael O. }, + citeulike-article-id = {1505894}, + doi = {10.1016/0022-314X(80)90084-0}, + journal = {J. Number Theory}, + mrnumber = {MR566880}, + number = {1}, + pages = {128--138}, + posted-at = {2007-07-27 00:11:40}, + priority = {2}, + title = {Probabilistic algorithm for testing primality}, + url = {http://dx.doi.org/10.1016/0022-314X(80)90084-0}, + volume = {12}, + year = {1980} +} + +@article{Mersenne-Twister, + address = {New York, NY, USA}, + author = {Matsumoto, Makoto and Nishimura, Takuji }, + citeulike-article-id = {611171}, + doi = {10.1145/272991.272995}, + issn = {1049-3301}, + journal = {ACM Trans. Model. Comput. Simul.}, + keywords = {algorithm}, + month = {January}, + number = {1}, + pages = {3--30}, + posted-at = {2008-10-26 00:03:42}, + priority = {0}, + publisher = {ACM Press}, + title = {Mersenne twister: a 623-dimensionally equidistributed uniform pseudo-random number generator}, + url = {http://dx.doi.org/10.1145/272991.272995}, + volume = {8}, + year = {1998} +} + +@inproceedings{L'Ecuyer98randomnumber, + author = {Pierre L'Ecuyer and Peter Hellekalek}, + title = {Random Number Generators: Selection Criteria and Testing}, + booktitle = {Random and Quasi-Random Point Sets}, + series = {Lecture Notes in Statistics}, + volume = {138}, + publisher = {Springer-Verlag}, + address = {New York}, + pages = {223--266}, + year = {1998}, +} + +@inproceedings{DBLP:conf/sat/SinzD05, + author = {Carsten Sinz and Edda-Maria Dieringer}, + title = {{DP}vis --- {A} Tool to Visualize the Structure of {SAT} Instances}, + booktitle = {SAT}, + year = {2005}, + pages = {257-268}, + ee = {http://dx.doi.org/10.1007/11499107_19}, + crossref = {DBLP:conf/sat/2005}, + bibsource = {DBLP, http://dblp.uni-trier.de} +} + + +@article{gomes00heavytailed, + author = {Carla P. Gomes and Bart Selman and Nuno Crato and Henry A. Kautz}, + title = {Heavy-Tailed Phenomena in Satisfiability and Constraint Satisfaction Problems}, + journal = {Journal of Automated Reasoning}, + volume = {24}, + number = {1/2}, + pages = {67--100}, + year = {2000}, + url = {citeseer.ist.psu.edu/article/gomes99heavytailed.html} +} + +@article{Mandelbrot60Pareto, + author = {Benoît B. Mandelbrot}, + title = {The Pareto-Lévy law and the distribution of income}, + journal = {Internat. Econom. Rev.}, + volume = {1}, + year = {1960}, + pages = {79--106} +} + +@inproceedings{Moura07tutorial, + author = {Leonardo de Moura, Bruno Dutertre and Natarajan Shankar}, + title = {A Tutorial on Satisfiability Modulo Theories}, + series = {LNCS}, + publisher = {Springer Berlin / Heidelberg}, + issn = {0302-9743}, + volume = {4590/2007}, + year = {2007}, + isbn = {978-3-540-73367-6}, + pages = {20--36}, + booktitle = {Computer Aided Verification}, +} + doi = {10.1007/978-3-540-73368-3}, + +@article{Karnaugh53Logic, + author = {Karnaugh, Maurice}, + year = {1953}, + month = {November}, + title = {The Map Method for Synthesis of Combinational Logic Circuits}, + journal = {Transactions of American Institute of Electrical Engineers part I}, + volume = {72}, + number = {9}, + pages = {593--599}, +} + +@inproceedings{Li00Integrating, + author = {Li, Chu Min}, + title = {Integrating Equivalency Reasoning into Davis-Putnam Procedure}, + booktitle = {Proceedings of the Seventeenth National Conference on Artificial Intelligence and Twelfth Conference on Innovative Applications of Artificial Intelligence}, + year = {2000}, + isbn = {0-262-51112-6}, + pages = {291--296}, + publisher = {AAAI Press / The MIT Press}, +} + +@article{Warners99TwoPhase, + author = {Joost P. Warners and Hans Van Maaren}, + title = {A Two Phase Algorithm for Solving a Class of Hard Satisfiability Problems}, + journal = {Operations Research Letters}, + year = {1999}, + volume = {23}, + number = {3--5}, + pages = {81--88} +} + +@inproceedings{Massacci00Taming, + author = {Peter Baumgartner and Fabio Massacci}, + title = {The Taming of the {(X)OR}}, + series = {LNCS}, + publisher = {Springer Berlin / Heidelberg}, + ISSN = {0302-9743}, + volume = {1861/2000}, + booktitle = {Computational Logic — CL 2000}, + doi = {10.1007/3-540-44957-4}, + year = {2000}, + isbn = {978-3-540-67797-0}, + pages = {508--522}, +} + +@inproceedings{Massacci99Using, + author = {Fabio Massacci}, + title = {Using {W}alk-{SAT} and {R}el-sat for cryptographic key search}, + booktitle = {Proc. of IJCAI-99}, + year = {1999}, + editor = {Morgan Kaufmann}, + pages = {290--295}, +} + +@inproceedings{Girault04Public, +author = {Marc Girault and David Lefranc}, +title = {Public Key Authentication with One (Online) Single Addition}, +series = {LNCS}, +bublisher = {Springer Berlin / Heidelberg}, +ISSN = {0302-9743}, +volume = {3156/2004}, +booktitle = {Cryptographic Hardware and Embedded Systems - CHES 2004}, +doi ={10.1007/b99451}, +year = {2004}, +isbn = {978-3-540-22666-6}, +pages = {967--984} +} + +@article{Hsieh72OnOptimal, + author = {Hsieh, H. Y. and Ghausi, M. S.}, + title = {On optimal-pivoting algorithms in sparse matrices}, + journal = {IEEE Trans. Circuit Theory}, + volume = {CT-19}, + pages = {93--96}, + month = {January}, + year = {1972} +} + +@article{HerasetalJAIR2008, + author = {Federico Heras and Javier Larrosa and Albert Oliveras}, + title = {{MiniMaxSAT: An efficient Weighted Max-SAT Solver}}, + journal = {Journal of Artificial Intelligence Research}, + volume = {31}, + year = {2008}, + pages = {1--32} + } + +@techreport{Wieringa07MiniMarch, + title = {{M}ini{M}arch --- {E}mbedding lookahead direction heuristics in a conflict driven solver}, + author = {Siert Wieringa}, + institution = {Technische Universiteit Delft}, + note = {Research Report}, + year = {2007}, + url = {http://www.st.ewi.tudelft.nl/sat/theses/minimarch.pdf}, +} + +techreport{OSI-MIT-Licence, +url = {http://www.opensource.org/licenses/mit-license.php} + + +@techreport{eStream, + title = {The e{STREAM} Portfolio}, + author = {Steve Babbage and Christophe De Canniere and Anne Canteaut and Carlos Cid and Henri Gilbert and Thomas Johansson and Christof Paar and Matthew Parker and Bart Preneel and Vincent Rijmen and Matt Robshaw and Hongjun Wu}, + url = {http://www.ecrypt.eu.org/stream/portfolio.pdf}, + institution = {eStream Project}, + year = {2008}, + month = {September}, + day = {8}, +} + +@techreport{Kibria08MiniSat, + author = {Raihan Kibria}, + title = {Midi{S}AT - {A}n extension of {M}ini{SAT}}, + institution = {Department of Electrical and Computer Engineering, Darmstadt University of Technology}, + year = {2005}, + month = {April}, + day = {26}, + url = {www.lri.fr/~simon/contest/results/descriptions/solvers/midisat_static.pdf}, +} + +@incollection{DaemenR05Rijndael, + author = {Joan Daemen and Vincent Rijmen}, + title = {Rijndael/AES}, + booktitle = {Encyclopedia of Cryptography and Security}, + year = {2005}, + ee = {http://dx.doi.org/10.1007/0-387-23483-7_358}, + crossref = {DBLP:reference/crypt/2005}, + bibsource = {DBLP, http://dblp.uni-trier.de} +} + +@book{DBLP:reference/crypt/2005, + editor = {Henk C. A. van Tilborg}, + title = {Encyclopedia of Cryptography and Security}, + publisher = {Springer}, + year = {2005}, + isbn = {978-0-387-23473-1}, + bibsource = {DBLP, http://dblp.uni-trier.de} +} + +@article{Strassen69Gaussian, + author = {Volker Strassen}, + title = {Gaussian Elimination is Not Optimal}, + journal = {Numerische Mathematik}, + volume = {13}, + pages = {354--356}, + year = {1969} +} + +@techreport{Crawford94TheMinimal, + author = {Crawford, J. M. and Kearns, M. J. and Shapire, R. E.}, + title = {The Minimal Disagreement Parity Problem as a Hard Satisfiability Problem}, + institution = {Computational Intelligence Research Laboratory and {AT\&T} {B}ell {L}abs}, + month = {February}, + year = {1994}, +} + +@inproceedings{OuafiV09Smashing, + author = {Khaled Ouafi and Serge Vaudenay}, + title = {Smashing {SQUASH}-0}, + volume = {5479}, + crossref = {DBLP:conf/eurocrypt/2009}, +} + +@inproceedings{ShamirRFIDSecLecture, +author = {Adi Shamir}, +title = {{SQUASH}: {A} new one-way hash function with provable security properties for higley contrained devices such as {RFID} tags}, +booktitle = {Invited lecture to the RFID Securty 2007 Workshop}, +year = {2007}, +} + +@misc{DES77, + author = {{National Bureau of Standards}}, + year = {1977}, + title = {Data {E}ncryption {S}tandard}, + institution = {U. S. Department of Commerce, National Bureau of Standards, Standards Publication (FIPS PUB) 46}, + address = {Washington, DC}, +}s + +@INPROCEEDINGS{Tsudik06Yet, + author = {Tsudik, Gene}, + title = {{YA-TRAP}: Yet Another Trivial {RFID} Authentication Protocol}, + booktitle = {International Conference on Pervasive Computing and Communications --- PerCom 2006}, + year = {2006}, + editor = {}, + volume = {}, + series = {}, + pages = {640--643}, + address = {Pisa, Italy}, + month = {March}, + organization = {IEEE}, + publisher = {IEEE Computer Society Press}, + bibsource = {Information Security Group (GSI), UCL, Louvain-la-Neuve, Belgium}, +} + + +@INPROCEEDINGS{Conti07RIPP, + author = {Conti, Mauro and Pietro, Roberto~Di and Mancini, Luigi~Vincenzo and Spognardi, Angelo}, + title = {{RIPP-FS}: an {RFID} Identification, Privacy Preserving Protocol with Forward Secrecy}, + booktitle = {International Workshop on Pervasive Computing and Communication Security --- PerSec '07}, + year = {2007}, + editor = {}, + volume = {}, + series = {}, + pages = {229--234}, + address = {New York City, New York, USA}, + month = {March}, + organization = {IEEE}, + publisher = {IEEE Computer Society Press}, + bibsource = {Information Security Group (GSI), UCL, Louvain-la-Neuve, Belgium}, +} + +@INPROCEEDINGS{Burmester06Provably, + author = {Burmester, Mike and Le, Tri van and Medeiros, Breno de}, + title = {Provably Secure Ubiquitous Systems: Universally Composable {RFID} Authentication Protocols}, + booktitle = {Conference on Security and Privacy for Emerging Areas in Communication Networks --- SecureComm '06}, + year = {2006}, + editor = {}, + volume = {}, + series = {}, + pages = {}, + address = {Baltimore, Maryland, USA}, + month = {August-September}, + organization = {IEEE}, + publisher = {}, + bibsource = {Information Security Group (GSI), UCL, Louvain-la-Neuve, Belgium}, +} + +@misc{ISO14443-standard, + author = {ISO/IEC}, + title = {14443-3 --- {I}dentification cards -- {C}ontactless integrated circuit(s) cards -- {P}roximity cards -- {P}art 3: {I}nitialization and anticollision}, + year = {2001, Stage: 90.92 --- 2007-12-11}, + institution = {International Organization for Standardization}, + address = {Geneva, Switzerland}, + url = {http://www.isotopicmaps.org/sam/sam-model/YYYY-MM-DD/}, +} + +@INPROCEEDINGS{Bailey05Shoehorning, + author = {Bailey, Daniel and Juels, Ari}, + title = {{Shoehorning Security into the EPC Standard}}, + booktitle = {International Conference on Security in Communication Networks --- SCN 2006}, + year = {2006}, + editor = {De~Prisco, Roberto and Yung, Moti}, + volume = {4116}, + series = {LNCS}, + pages = {303--320}, + address = {Maiori, Italy}, + month = {September}, + organization = {}, + publisher = {Springer-Verlag}, + bibsource = {Information Security Group (GSI), UCL, Louvain-la-Neuve, Belgium}, +} + +@INPROCEEDINGS{Soos08Analysing, + author = {Soos, Mate}, + title = {{Analysing the {M}olva and {D}i {P}ietro Private {RFID} Authentication Scheme}}, + booktitle = {Workshop on RFID Security --- RFIDSec'08}, + year = {2008}, + editor = {}, + volume = {}, + series = {}, + pages = {}, + address = {Budapest, Hungary}, + month = {July}, + organization = {}, + publisher = {}, +} + +@inproceedings{DBLP:conf/ccs/BurmesterMM08, + author = {Mike Burmester and Breno de Medeiros and Rossana Motta}, + title = {Robust, anonymous {RFID} authentication with constant key-lookup}, + booktitle = {ASIACCS}, + year = {2008}, + pages = {283-291}, + ee = {http://doi.acm.org/10.1145/1368310.1368351}, + crossref = {DBLP:conf/ccs/2008asia}, + bibsource = {DBLP, http://dblp.uni-trier.de} +} + +@proceedings{DBLP:conf/ccs/2008asia, + editor = {Masayuki Abe and Virgil D. Gligor}, + title = {Proceedings of the 2008 ACM Symposium on Information, Computer and Communications Security, ASIACCS 2008, Tokyo, Japan, March 18-20, 2008}, + booktitle = {ASIACCS}, + publisher = {ACM}, + year = {2008}, + isbn = {978-1-59593-979-1}, + bibsource = {DBLP, http://dblp.uni-trier.de} +} + +@INPROCEEDINGS{Blass09Ff, + author = {Blass, Erik-Oliver and Kurmus, Anil and Molva, Refik and Noubir, Guevara and Shikfa, Abdullatif}, + title = {{The {F}f-Family of Protocols for {RFID}-Privacy and Authentication}}, + booktitle = {Workshop on RFID Security --- RFIDSec'09}, + year = {2009}, + editor = {}, + volume = {}, + series = {}, + pages = {}, + address = {Leuven, Belgium}, + month = {July}, + organization = {}, + publisher = {}, + bibsource = {Information Security Group (GSI), UCL, Louvain-la-Neuve, Belgium}, +} + +@inproceedings{DBLP:conf/cardis/CastellucciaA06, + author = {Claude Castelluccia and Gildas Avoine}, + title = {Noisy Tags: {A} Pretty Good Key Exchange Protocol for {RFID} Tags}, + booktitle = {CARDIS}, + year = {2006}, + pages = {289-299}, + ee = {http://dx.doi.org/10.1007/11733447_21}, + crossref = {DBLP:conf/cardis/2006}, + bibsource = {DBLP, http://dblp.uni-trier.de} +} + +@proceedings{DBLP:conf/cardis/2006, + editor = {Josep Domingo-Ferrer and + Joachim Posegga and + Daniel Schreckling}, + title = {Smart Card Research and Advanced Applications, 7th IFIP + WG 8.8/11.2 International Conference, CARDIS 2006, Tarragona, + Spain, April 19-21, 2006, Proceedings}, + booktitle = {CARDIS}, + publisher = {Springer}, + series = {LNCS}, + volume = {3928}, + year = {2006}, + isbn = {3-540-33311-8}, + bibsource = {DBLP, http://dblp.uni-trier.de} +} + + +@inproceedings{DBLP:conf/ches/SavryPDRR07, + author = {O. Savry and F. Pebay-Peyroula and F. Dehmas and G. Robert and J. Reverdy}, + title = {{RFID} Noisy Reader --- {H}ow to Prevent from Eavesdropping on the Communication?}, + booktitle = {CHES}, + year = {2007}, + pages = {334-345}, + ee = {http://dx.doi.org/10.1007/978-3-540-74735-2_23}, + crossref = {DBLP:conf/ches/2007}, + bibsource = {DBLP, http://dblp.uni-trier.de} +} + +@proceedings{DBLP:conf/ches/2007, + editor = {Pascal Paillier and Ingrid Verbauwhede}, + title = {Cryptographic Hardware and Embedded Systems --- {CHES} 2007, + 9th International Workshop, Vienna, Austria, September 10-13, + 2007, Proceedings}, + booktitle = {CHES}, + publisher = {Springer}, + series = {LNCS}, + volume = {4727}, + year = {2007}, + isbn = {978-3-540-74734-5}, + bibsource = {DBLP, http://dblp.uni-trier.de} +} + +@article{Hancke07Modulating, + author = {G. Hancke}, + title = {Modulating a noisy carrier signal for eavesdropping-resistant {HF RFID}}, + journal = {e\&i --- Elektrotechnik und Informationstechnik}, + year = {2007}, + volume = {124}, + number = {11}, + month = {November}, + pages = {404--408}, + publisher = {Springer Wien}, + ISSN = {0932-383X}, + DOI = {10.1007/s00502-007-0479-7} +} + +@inproceedings{1423361, + author = {Babbage, Steve and Dodd, Matthew}, + title = {The {MICKEY} Stream Ciphers}, + booktitle = {New Stream Cipher Designs: The e{STREAM} Finalists}, + year = {2008}, + isbn = {978-3-540-68350-6}, + pages = {191--209}, + doi = {http://dx.doi.org/10.1007/978-3-540-68351-3_15}, + publisher = {Springer-Verlag}, + address = {Berlin, Heidelberg}, + } + +@inproceedings{DBLP:conf/wistp/DeursenMR08, + author = {Ton van Deursen and Sjouke Mauw and Sasa Radomirovic}, + title = {Untraceability of {RFID} Protocols}, + booktitle = {WISTP}, + year = {2008}, + pages = {1-15}, + ee = {http://dx.doi.org/10.1007/978-3-540-79966-5_1}, + crossref = {DBLP:conf/wistp/2008}, + bibsource = {DBLP, http://dblp.uni-trier.de} +} + +@proceedings{DBLP:conf/wistp/2008, + editor = {Jose Antonio Onieva and Damien Sauveron and Serge Chaumette and Dieter Gollmann and Constantinos Markantonakis}, + title = {Information Security Theory and Practices. Smart Devices, Convergence and Next Generation Networks, Second {IFIP WG} 11.2 International Workshop, {WISTP} 2008, Seville, Spain, May 13-16, 2008. Proceedings}, + booktitle = {WISTP}, + publisher = {Springer}, + series = {LNCS}, + volume = {5019}, + year = {2008}, + isbn = {978-3-540-79965-8}, + bibsource = {DBLP, http://dblp.uni-trier.de} +} + +@misc{A51, + author = {Ross Anderson}, + title = {A5 (was: Hacking digital phones)}, + howpublished = {Newsgroup Communication}, + year = {1994}, +} + +@inproceedings{DBLP:conf/cardis/GansHG08, + author = {Gerhard de Koning Gans and Jaap-Henk Hoepman and Flavio D. Garcia}, + title = {A Practical Attack on the {MIFARE} {C}lassic}, + booktitle = {CARDIS}, + year = {2008}, + pages = {267-282}, + ee = {http://dx.doi.org/10.1007/978-3-540-85893-5_20}, + crossref = {DBLP:conf/cardis/2008}, + bibsource = {DBLP, http://dblp.uni-trier.de} +} + +@proceedings{DBLP:conf/cardis/2008, + editor = {Gilles Grimaud and Fran\c{c}ois-Xavier Standaert}, + title = {Smart Card Research and Advanced Applications, 8th IFIP WG 8.8/11.2 International Conference, CARDIS 2008, London, UK, September 8-11, 2008. Proceedings}, + booktitle = {CARDIS}, + publisher = {Springer}, + series = {LNCS}, + volume = {5189}, + year = {2008}, + isbn = {978-3-540-85892-8}, + bibsource = {DBLP, http://dblp.uni-trier.de} +} + +@inproceedings{DBLP:conf/ima/CourtoisB07, + author = {Nicolas T. Courtois and Gregory V. Bard}, + title = {Algebraic Cryptanalysis of the {D}ata {E}ncryption {S}tandard}, + booktitle = {{IMA} Int. Conf.}, + year = {2007}, + pages = {152-169}, + ee = {http://dx.doi.org/10.1007/978-3-540-77272-9_10}, + crossref = {DBLP:conf/ima/2007}, + bibsource = {DBLP, http://dblp.uni-trier.de} +} + +@proceedings{DBLP:conf/ima/2007, + editor = {Steven D. Galbraith}, + title = {Cryptography and Coding, 11th IMA International Conference, Cirencester, UK, December 18-20, 2007, Proceedings}, + booktitle = {IMA Int. Conf.}, + publisher = {Springer}, + series = {LNCS}, + volume = {4887}, + year = {2007}, + isbn = {978-3-540-77271-2}, + bibsource = {DBLP, http://dblp.uni-trier.de} +} + +@book{Bard-algebraic, + title = {Algebraic Cryptanalysis}, + author = {Gregory V. Bard}, + year = {2009}, + pages = {392}, + volume = {XXXIV}, + series = {Security and Cryptology}, + ISBN = {978-0-387-88756-2}, + publisher = {Springer}, +} + +@inproceedings{Graphviz, + author = {John Ellson and Emden R. Gansner and Eleftherios Koutsofios and Stephen C. North and Gordon Woodhull}, + year = {2001}, + title = {Graphviz --- open source graph drawing tools}, + pages = {483--484}, + crossref = {DBLP:conf/gd/2001}, +} + +@proceedings{DBLP:conf/gd/2001, + editor = {Petra Mutzel and Michael J{\"u}nger and Sebastian Leipert}, + title = {Graph Drawing, 9th International Symposium, GD 2001 Vienna, Austria, September 23--26, 2001, Revised Papers}, + booktitle = {Graph Drawing}, + publisher = {Springer}, + series = {LNCS}, + volume = {2265}, + year = {2002}, + isbn = {3-540-43309-0}, + bibsource = {DBLP, http://dblp.uni-trier.de} +} + +@inproceedings{Borghoff09Mixed, + booktitle = {WEWoRC --- Western European Workshop on Research in Cryptology}, + title = {Bivium as a Mixed-0-1 Linear Programming Problem}, + author = {Julia Borghoff and Lars R. Knudsen and Mathias Stolpe}, + month = {July}, + year = {2009}, + address = {Graz, Austria}, +} + +@inproceedings{DBLP:conf/eurocrypt/DinurS09, + author = {Itai Dinur and Adi Shamir}, + title = {Cube Attacks on Tweakable Black Box Polynomials}, + booktitle = {EUROCRYPT}, + year = {2009}, + pages = {278--299}, + ee = {http://dx.doi.org/10.1007/978-3-642-01001-9_16}, + crossref = {DBLP:conf/eurocrypt/2009}, + bibsource = {DBLP, http://dblp.uni-trier.de} +} + +@proceedings{DBLP:conf/eurocrypt/2009, + editor = {Antoine Joux}, + title = {Advances in Cryptology --- EUROCRYPT 2009, 28th Annual International Conference on the Theory and Applications of Cryptographic Techniques, Cologne, Germany, April 26--30, 2009. Proceedings}, + booktitle = {EUROCRYPT}, + publisher = {Springer}, + series = {LNCS}, + volume = {5479}, + year = {2009}, + isbn = {978-3-642-01000-2}, + ee = {http://dx.doi.org/10.1007/978-3-642-01001-9}, + bibsource = {DBLP, http://dblp.uni-trier.de} +} + +@book{eStreamFinalists, + title = {The e{STREAM} Finalists}, + editor = {Matthew Robshaw and Olivier Billet}, + series = {LNCS}, + subseries = {Security and Cryptology}, + volume = {4986}, + year = {2008}, + pages = {295}, + isbn = {978-3-540-68350-6}, + publisher = {Springer}, +} + +@article{diffie76new, + author = "Whitfield Diffie and Martin E. Hellman", + title = "New Directions in Cryptography", + journal = "IEEE Transactions on Information Theory", + volume = "IT-22", + number = "6", + pages = "644--654", + date = "November 1976", + year = "1976", + url = "citeseer.ist.psu.edu/diffie76new.html" +} + +@ARTICLE{Rivest78amethod, + author = {Ron L. Rivest and Adi Shamir and Leonard Max Adleman}, + title = {A Method for Obtaining Digital Signatures and Public-Key Cryptosystems}, + journal = {Communications of the ACM}, + year = {1978}, + volume = {21}, + pages = {120--126} +} + +@inproceedings{Pfizmann01Anonimity, + author = {Andreas Pfitzmann and Marit Köhntopp}, + title = {Anonymity, Unobservability, and Pseudonymity --- {A} Proposal for Terminology}, + series = {LNCS}, + publisher = {Springer Berlin / Heidelberg}, + issn = {0302-9743}, + volume = {2009}, + year = {2001}, + booktitle = {Designing Privacy Enhancing Technologies}, + doi = {10.1007/3-540-44702-4}, + isbn = {978-3-540-41724-8}, + pages = {1--9}, +} + +@misc{Bard07efficientmethods, + author = {Gregory V. Bard and Nicolas T. Courtois and Chris Jefferson}, + title = {Efficient Methods for Conversion and Solution of Sparse Systems of Low-Degree Multivariate Polynomials over {GF}(2) via {SAT}-Solvers}, + howpublished = {Cryptology ePrint Archive, Report 2007/024, \url{http://eprint.iacr.org/2007/024}}, + year = {2007}, + organization = {IACR}, +} + +@inproceedings{DBLP:conf/sat/SoosNC09, + author = {Mate Soos and + Karsten Nohl and + Claude Castelluccia}, + title = {Extending {SAT} Solvers to Cryptographic Problems}, + booktitle = {SAT}, + year = {2009}, + pages = {244--257}, + ee = {http://dx.doi.org/10.1007/978-3-642-02777-2_24}, + crossref = {DBLP:conf/sat/2009}, + bibsource = {DBLP, http://dblp.uni-trier.de} +} + +@inproceedings{DBLP:conf/cav/GaneshD07, + author = {Vijay Ganesh and + David L. Dill}, + title = {A Decision Procedure for Bit-Vectors and Arrays}, + booktitle = {CAV}, + year = {2007}, + pages = {519-531}, + ee = {http://dx.doi.org/10.1007/978-3-540-73368-3_52}, + crossref = {DBLP:conf/cav/2007}, + bibsource = {DBLP, http://dblp.uni-trier.de} +} + +@proceedings{DBLP:conf/cav/2007, + editor = {Werner Damm and + Holger Hermanns}, + title = {Computer Aided Verification, 19th International Conference, + CAV 2007, Berlin, Germany, July 3-7, 2007, Proceedings}, + booktitle = {CAV}, + publisher = {Springer}, + series = {LNCS}, + volume = {4590}, + year = {2007}, + isbn = {978-3-540-73367-6}, + bibsource = {DBLP, http://dblp.uni-trier.de} +} + +@misc{Logic2CNF, + author = {Edd Barrett}, + title = {Logic2{CNF} Logic Solver and Converter}, + note = {\url{http://projects.cs.kent.ac.uk/projects/logic2cnf/trac/wiki/WikiStart}}, + year = {2010}, + month = {March}, +} + +@misc{CryptoMiniSat, + author = {Mate Soos}, + title = {Crypto{M}ini{S}at --- a {SAT} solver for cryptographic problems}, + note = {\url{http://planete.inrialpes.fr/~soos/CryptoMiniSat/index.html}}, + year = {2009}, +} + +@inproceedings{DBLP:conf/sat/EenB05, + author = {Niklas E{\'e}n and + Armin Biere}, + title = {Effective Preprocessing in {SAT} Through Variable and Clause + Elimination}, + booktitle = {SAT}, + year = {2005}, + pages = {61-75}, + ee = {http://dx.doi.org/10.1007/11499107_5}, + crossref = {DBLP:conf/sat/2005}, + bibsource = {DBLP, http://dblp.uni-trier.de} +} + +@inproceedings{glucose, + author = {Gilles Audemard and Laurent Simon}, + title = {{GLUCOSE}: a solver that predicts learnt clauses quality}, + booktitle = {SAT 2009 competitive events booklet}, + year = {2009}, + pages = {7--8}, +} + +@inproceedings{precosat, + author = {Armin Biere}, + title = {P\{re,i\}coSAT@SC’09}, + booktitle = {SAT 2009 competitive events booklet}, + year = {2009}, + pages = {41--42}, +} + +@inproceedings{DBLP:conf/sat/HeuleM04a, + author = {Marijn Heule and + Hans van Maaren}, + title = {Aligning {CNF}- and Equivalence-Reasoning}, + booktitle = {SAT (Selected Papers}, + year = {2004}, + pages = {145--156}, + ee = {http://dx.doi.org/10.1007/11527695_12}, + crossref = {DBLP:conf/sat/2004lncs}, + bibsource = {DBLP, http://dblp.uni-trier.de} +} + +@proceedings{DBLP:conf/sat/2004lncs, + editor = {Holger H. Hoos and + David G. Mitchell}, + title = {Theory and Applications of Satisfiability Testing, 7th International + Conference, SAT 2004, Vancouver, BC, Canada, May 10-13, + 2004, Revised Selected Papers}, + booktitle = {SAT (Selected Papers)}, + publisher = {Springer}, + series = {LNCS}, + volume = {3542}, + year = {2005}, + isbn = {3-540-27829-X}, + bibsource = {DBLP, http://dblp.uni-trier.de} +} + +@techreport{Heule-thesis, + author = {Marijn Heule}, + title = {{m}arch: Towards a lookahead Sat solver for general purposes}, + institution={Technische Universiteit Delft}, + month={February}, + year={2004}, +} + +@techreport{Heule-phd, + author = {Marijn J.H. Heule}, + title = {Smart solving: Tool and techniques for satisfiability solvers}, + institution={Technische Universiteit Delft}, + year={2008}, +} + +@article{DBLP:journals/amai/JeroslowW90, + author = {Robert G. Jeroslow and + Jinchang Wang}, + title = {Solving Propositional Satisfiability Problems}, + journal = {Ann. Math. Artif. Intell.}, + volume = {1}, + year = {1990}, + pages = {167-187}, + bibsource = {DBLP, http://dblp.uni-trier.de} +} + +@inproceedings{DBLP:conf/sat/PipatsrisawatD07, + author = {Knot Pipatsrisawat and + Adnan Darwiche}, + title = {A Lightweight Component Caching Scheme for Satisfiability + Solvers}, + booktitle = {SAT}, + year = {2007}, + pages = {294-299}, + ee = {http://dx.doi.org/10.1007/978-3-540-72788-0_28}, + crossref = {DBLP:conf/sat/2007}, + bibsource = {DBLP, http://dblp.uni-trier.de} +} + +@proceedings{DBLP:conf/sat/2007, + editor = {Jo{\~a}o Marques-Silva and + Karem A. Sakallah}, + title = {Theory and Applications of Satisfiability Testing --- SAT + 2007, 10th International Conference, Lisbon, Portugal, May + 28-31, 2007, Proceedings}, + booktitle = {SAT}, + publisher = {Springer}, + series = {LNCS}, + volume = {4501}, + year = {2007}, + isbn = {978-3-540-72787-3}, + bibsource = {DBLP, http://dblp.uni-trier.de} +} + +@inproceedings{DBLP:conf/ijcai/AudemardS09, + author = {Gilles Audemard and + Laurent Simon}, + title = {Predicting Learnt Clauses Quality in Modern {SAT} Solvers}, + booktitle = {IJCAI}, + year = {2009}, + pages = {399-404}, + ee = {http://ijcai.org/papers09/Papers/IJCAI09-074.pdf}, + crossref = {DBLP:conf/ijcai/2009}, + bibsource = {DBLP, http://dblp.uni-trier.de} +} + +@proceedings{DBLP:conf/ijcai/2009, + editor = {Craig Boutilier}, + title = {IJCAI 2009, Proceedings of the 21st International Joint + Conference on Artificial Intelligence, Pasadena, California, + USA, July 11-17, 2009}, + booktitle = {IJCAI}, + year = {2009}, + bibsource = {DBLP, http://dblp.uni-trier.de} +} + + +@inproceedings{DBLP:conf/tacas/JarvisaloBH10, + author = {Matti J{\"a}rvisalo and + Armin Biere and + Marijn Heule}, + title = {Blocked Clause Elimination}, + booktitle = {TACAS}, + year = {2010}, + pages = {129-144}, + ee = {http://dx.doi.org/10.1007/978-3-642-12002-2_10}, + crossref = {DBLP:conf/tacas/2010}, + bibsource = {DBLP, http://dblp.uni-trier.de} +} + +@proceedings{DBLP:conf/tacas/2010, + editor = {Javier Esparza and + Rupak Majumdar}, + title = {Tools and Algorithms for the Construction and Analysis of + Systems, 16th International Conference, TACAS 2010, Held + as Part of the Joint European Conferences on Theory and + Practice of Software, ETAPS 2010, Paphos, Cyprus, March + 20-28, 2010. Proceedings}, + booktitle = {TACAS}, + publisher = {Springer}, + series = {LNCS}, + volume = {6015}, + year = {2010}, + isbn = {978-3-642-12001-5}, + ee = {http://dx.doi.org/10.1007/978-3-642-12002-2}, + bibsource = {DBLP, http://dblp.uni-trier.de} +} + +@article{DBLP:journals/dam/Li03, + author = {Chu Min Li}, + title = {Equivalent literal propagation in the {DLL} procedure}, + journal = {Discrete Applied Mathematics}, + volume = {130}, + number = {2}, + year = {2003}, + pages = {251-276}, + ee = {http://dx.doi.org/10.1016/S0166-218X(02)00407-9}, + bibsource = {DBLP, http://dblp.uni-trier.de} +} + +@misc{Grid5000, + author = {{The Grid'5000 team}}, + title = {The {G}rid'5000 project}, + note = {\url{https://www.grid5000.fr}}, +} + year = {2008}, + +@article{DBLP:journals/endm/Berre01, + author = {Daniel Le Berre}, + title = {Exploiting the real power of unit propagation lookahead}, + journal = {Electronic Notes in Discrete Mathematics}, + volume = {9}, + year = {2001}, + pages = {59-80}, + ee = {http://dx.doi.org/10.1016/S1571-0653(04)00314-2}, + bibsource = {DBLP, http://dblp.uni-trier.de} +} + +@inproceedings{DBLP:conf/sat/GershmanS05, + author = {Roman Gershman and Ofer Strichman}, + title = {Cost-Effective Hyper-Resolution for Preprocessing {CNF} Formulas}, + booktitle = {SAT}, + year = {2005}, + pages = {423-429}, + ee = {http://dx.doi.org/10.1007/11499107_34}, + crossref = {DBLP:conf/sat/2005}, + bibsource = {DBLP, http://dblp.uni-trier.de} +} + + +@inproceedings{DBLP:conf/sat/HeuleJB11, + author = {Marijn Heule and + Matti J{\"a}rvisalo and + Armin Biere}, + title = {Efficient {CNF} Simplification Based on Binary Implication + Graphs}, + booktitle = {SAT}, + year = {2011}, + pages = {201-215}, + ee = {http://dx.doi.org/10.1007/978-3-642-21581-0_17}, + crossref = {DBLP:conf/sat/2011}, + bibsource = {DBLP, http://dblp.uni-trier.de} +} +@proceedings{DBLP:conf/sat/2011, + editor = {Karem A. Sakallah and + Laurent Simon}, + title = {Theory and Applications of Satisfiability Testing - SAT + 2011 - 14th International Conference, SAT 2011, Ann Arbor, + MI, USA, June 19-22, 2011. Proceedings}, + booktitle = {SAT}, + publisher = {Springer}, + series = {LNCS}, + volume = {6695}, + year = {2011}, + isbn = {978-3-642-21580-3}, + ee = {http://dx.doi.org/10.1007/978-3-642-21581-0}, + bibsource = {DBLP, http://dblp.uni-trier.de} +} + + +@inproceedings{DBLP:conf/ecai/PietteHS08, + author = {C{\'e}dric Piette and + Youssef Hamadi and + Lakhdar Sais}, + title = {Vivifying Propositional Clausal Formulae}, + booktitle = {ECAI}, + year = {2008}, + pages = {525-529}, + ee = {http://dx.doi.org/10.3233/978-1-58603-891-5-525}, + crossref = {DBLP:conf/ecai/2008}, + bibsource = {DBLP, http://dblp.uni-trier.de} +} +@proceedings{DBLP:conf/ecai/2008, + editor = {Malik Ghallab and + Constantine D. Spyropoulos and + Nikos Fakotakis and + Nikolaos M. Avouris}, + title = {ECAI 2008 - 18th European Conference on Artificial Intelligence, + Patras, Greece, July 21-25, 2008, Proceedings}, + booktitle = {ECAI}, + publisher = {IOS Press}, + series = {Frontiers in Artificial Intelligence and Applications}, + volume = {178}, + year = {2008}, + isbn = {978-1-58603-891-5}, + ee = {http://www.booksonline.iospress.nl/Content/View.aspx?piid=9905}, + bibsource = {DBLP, http://dblp.uni-trier.de} +} + +@inproceedings{DBLP:conf/sat/HanS09, + author = {HyoJung Han and + Fabio Somenzi}, + title = {On-the-Fly Clause Improvement}, + booktitle = {SAT}, + year = {2009}, + pages = {209-222}, + ee = {http://dx.doi.org/10.1007/978-3-642-02777-2_21}, + crossref = {DBLP:conf/sat/2009}, + bibsource = {DBLP, http://dblp.uni-trier.de} +} + + +@inproceedings{DBLP:conf/sat/SorenssonB09, + author = {Niklas S{\"o}rensson and + Armin Biere}, + title = {Minimizing Learned Clauses}, + booktitle = {SAT}, + year = {2009}, + pages = {237-243}, + ee = {http://dx.doi.org/10.1007/978-3-642-02777-2_23}, + crossref = {DBLP:conf/sat/2009}, + bibsource = {DBLP, http://dblp.uni-trier.de} +} + +@inproceedings{DBLP:conf/sat/BacchusW03, + author = {Fahiem Bacchus and + Jonathan Winter}, + title = {Effective Preprocessing with Hyper-Resolution and Equality + Reduction}, + booktitle = {SAT}, + year = {2003}, + pages = {341-355}, + ee = {http://dx.doi.org/10.1007/978-3-540-24605-3_26}, + crossref = {DBLP:conf/sat/2003}, + bibsource = {DBLP, http://dblp.uni-trier.de} +} +@proceedings{DBLP:conf/sat/2003, + editor = {Enrico Giunchiglia and + Armando Tacchella}, + title = {Theory and Applications of Satisfiability Testing, 6th International + Conference, SAT 2003. Santa Margherita Ligure, Italy, May + 5-8, 2003 Selected Revised Papers}, + booktitle = {SAT}, + publisher = {Springer}, + series = {LNCS}, + volume = {2919}, + year = {2004}, + isbn = {3-540-20851-8}, + bibsource = {DBLP, http://dblp.uni-trier.de} +} + +@proceedings{DBLP:conf/sat/2005, + editor = {Fahiem Bacchus and + Toby Walsh}, + title = {Theory and Applications of Satisfiability Testing, 8th International + Conference, SAT 2005, St. Andrews, UK, June 19-23, 2005, + Proceedings}, + booktitle = {SAT}, + publisher = {Springer}, + series = {LNCS}, + volume = {3569}, + year = {2005}, + isbn = {3-540-26276-8}, + bibsource = {DBLP, http://dblp.uni-trier.de} +} + +@proceedings{DBLP:conf/sat/2009, + editor = {Oliver Kullmann}, + title = {Theory and Applications of Satisfiability Testing - SAT + 2009, 12th International Conference, SAT 2009, Swansea, + UK, June 30 - July 3, 2009. Proceedings}, + booktitle = {SAT}, + publisher = {Springer}, + series = {Lecture Notes in Computer Science}, + volume = {5584}, + year = {2009}, + isbn = {978-3-642-02776-5}, + ee = {http://dx.doi.org/10.1007/978-3-642-02777-2}, + bibsource = {DBLP, http://dblp.uni-trier.de} +} + +@inproceedings{DBLP:conf/hvc/MantheyHB12, + author = {Norbert Manthey and + Marijn Heule and + Armin Biere}, + title = {Automated Reencoding of Boolean Formulas}, + booktitle = {Haifa Verification Conference}, + year = {2012}, + pages = {102-117}, + ee = {http://dx.doi.org/10.1007/978-3-642-39611-3_14}, + crossref = {DBLP:conf/hvc/2012}, + bibsource = {DBLP, http://dblp.uni-trier.de} +} + +@proceedings{DBLP:conf/hvc/2012, + editor = {Armin Biere and + Amir Nahir and + Tanja E. J. Vos}, + title = {Hardware and Software: Verification and Testing - 8th International + Haifa Verification Conference, HVC 2012, Haifa, Israel, + November 6-8, 2012. Revised Selected Papers}, + booktitle = {Haifa Verification Conference}, + publisher = {Springer}, + series = {Lecture Notes in Computer Science}, + volume = {7857}, + year = {2013}, + isbn = {978-3-642-39610-6}, + ee = {http://dx.doi.org/10.1007/978-3-642-39611-3}, + bibsource = {DBLP, http://dblp.uni-trier.de} +} + +@book{Quinlan:1993:CPM:152181, + author = {Quinlan, J. Ross}, + title = {C4.5: Programs for Machine Learning}, + year = {1993}, + isbn = {1-55860-238-0}, + publisher = {Morgan Kaufmann Publishers Inc.}, + address = {San Francisco, CA, USA}, +} diff --git a/cryptominisat/cppsrc/docs/satcomp15-pdf/splncs03.bst b/cryptominisat/cppsrc/docs/satcomp15-pdf/splncs03.bst new file mode 100644 index 00000000..32791691 --- /dev/null +++ b/cryptominisat/cppsrc/docs/satcomp15-pdf/splncs03.bst @@ -0,0 +1,1519 @@ +%% BibTeX bibliography style `splncs03' +%% +%% BibTeX bibliography style for use with numbered references in +%% Springer Verlag's "Lecture Notes in Computer Science" series. +%% (See Springer's documentation for llncs.cls for +%% more details of the suggested reference format.) Note that this +%% file will not work for author-year style citations. +%% +%% Use \documentclass{llncs} and \bibliographystyle{splncs03}, and cite +%% a reference with (e.g.) \cite{smith77} to get a "[1]" in the text. +%% +%% This file comes to you courtesy of Maurizio "Titto" Patrignani of +%% Dipartimento di Informatica e Automazione Universita' Roma Tre +%% +%% ================================================================================================ +%% This was file `titto-lncs-02.bst' produced on Wed Apr 1, 2009 +%% Edited by hand by titto based on `titto-lncs-01.bst' (see below) +%% +%% CHANGES (with respect to titto-lncs-01.bst): +%% - Removed the call to \urlprefix (thus no "URL" string is added to the output) +%% ================================================================================================ +%% This was file `titto-lncs-01.bst' produced on Fri Aug 22, 2008 +%% Edited by hand by titto based on `titto.bst' (see below) +%% +%% CHANGES (with respect to titto.bst): +%% - Removed the "capitalize" command for editors string "(eds.)" and "(ed.)" +%% - Introduced the functions titto.bbl.pages and titto.bbl.page for journal pages (without "pp.") +%% - Added a new.sentence command to separate with a dot booktitle and series in the inproceedings +%% - Commented all new.block commands before urls and notes (to separate them with a comma) +%% - Introduced the functions titto.bbl.volume for handling journal volumes (without "vol." label) +%% - Used for editors the same name conventions used for authors (see function format.in.ed.booktitle) +%% - Removed a \newblock to avoid long spaces between title and "In: ..." +%% - Added function titto.space.prefix to add a space instead of "~" after the (removed) "vol." label +%% ================================================================================================ +%% This was file `titto.bst', +%% generated with the docstrip utility. +%% +%% The original source files were: +%% +%% merlin.mbs (with options: `vonx,nm-rvvc,yr-par,jttl-rm,volp-com,jwdpg,jwdvol,numser,ser-vol,jnm-x,btit-rm,bt-rm,edparxc,bkedcap,au-col,in-col,fin-bare,pp,ed,abr,mth-bare,xedn,jabr,and-com,and-com-ed,xand,url,url-blk,em-x,nfss,') +%% ---------------------------------------- +%% *** Tentative .bst file for Springer LNCS *** +%% +%% Copyright 1994-2007 Patrick W Daly + % =============================================================== + % IMPORTANT NOTICE: + % This bibliographic style (bst) file has been generated from one or + % more master bibliographic style (mbs) files, listed above. + % + % This generated file can be redistributed and/or modified under the terms + % of the LaTeX Project Public License Distributed from CTAN + % archives in directory macros/latex/base/lppl.txt; either + % version 1 of the License, or any later version. + % =============================================================== + % Name and version information of the main mbs file: + % \ProvidesFile{merlin.mbs}[2007/04/24 4.20 (PWD, AO, DPC)] + % For use with BibTeX version 0.99a or later + %------------------------------------------------------------------- + % This bibliography style file is intended for texts in ENGLISH + % This is a numerical citation style, and as such is standard LaTeX. + % It requires no extra package to interface to the main text. + % The form of the \bibitem entries is + % \bibitem{key}... + % Usage of \cite is as follows: + % \cite{key} ==>> [#] + % \cite[chap. 2]{key} ==>> [#, chap. 2] + % where # is a number determined by the ordering in the reference list. + % The order in the reference list is alphabetical by authors. + %--------------------------------------------------------------------- + +ENTRY + { address + author + booktitle + chapter + edition + editor + eid + howpublished + institution + journal + key + month + note + number + organization + pages + publisher + school + series + title + type + url + volume + year + } + {} + { label } +INTEGERS { output.state before.all mid.sentence after.sentence after.block } +FUNCTION {init.state.consts} +{ #0 'before.all := + #1 'mid.sentence := + #2 'after.sentence := + #3 'after.block := +} +STRINGS { s t} +FUNCTION {output.nonnull} +{ 's := + output.state mid.sentence = + { ", " * write$ } + { output.state after.block = + { add.period$ write$ +% newline$ +% "\newblock " write$ % removed for titto-lncs-01 + " " write$ % to avoid long spaces between title and "In: ..." + } + { output.state before.all = + 'write$ + { add.period$ " " * write$ } + if$ + } + if$ + mid.sentence 'output.state := + } + if$ + s +} +FUNCTION {output} +{ duplicate$ empty$ + 'pop$ + 'output.nonnull + if$ +} +FUNCTION {output.check} +{ 't := + duplicate$ empty$ + { pop$ "empty " t * " in " * cite$ * warning$ } + 'output.nonnull + if$ +} +FUNCTION {fin.entry} +{ duplicate$ empty$ + 'pop$ + 'write$ + if$ + newline$ +} + +FUNCTION {new.block} +{ output.state before.all = + 'skip$ + { after.block 'output.state := } + if$ +} +FUNCTION {new.sentence} +{ output.state after.block = + 'skip$ + { output.state before.all = + 'skip$ + { after.sentence 'output.state := } + if$ + } + if$ +} +FUNCTION {add.blank} +{ " " * before.all 'output.state := +} + + +FUNCTION {add.colon} +{ duplicate$ empty$ + 'skip$ + { ":" * add.blank } + if$ +} + +FUNCTION {date.block} +{ + new.block +} + +FUNCTION {not} +{ { #0 } + { #1 } + if$ +} +FUNCTION {and} +{ 'skip$ + { pop$ #0 } + if$ +} +FUNCTION {or} +{ { pop$ #1 } + 'skip$ + if$ +} +STRINGS {z} +FUNCTION {remove.dots} +{ 'z := + "" + { z empty$ not } + { z #1 #1 substring$ + z #2 global.max$ substring$ 'z := + duplicate$ "." = 'pop$ + { * } + if$ + } + while$ +} +FUNCTION {new.block.checka} +{ empty$ + 'skip$ + 'new.block + if$ +} +FUNCTION {new.block.checkb} +{ empty$ + swap$ empty$ + and + 'skip$ + 'new.block + if$ +} +FUNCTION {new.sentence.checka} +{ empty$ + 'skip$ + 'new.sentence + if$ +} +FUNCTION {new.sentence.checkb} +{ empty$ + swap$ empty$ + and + 'skip$ + 'new.sentence + if$ +} +FUNCTION {field.or.null} +{ duplicate$ empty$ + { pop$ "" } + 'skip$ + if$ +} +FUNCTION {emphasize} +{ skip$ } +FUNCTION {tie.or.space.prefix} +{ duplicate$ text.length$ #3 < + { "~" } + { " " } + if$ + swap$ +} +FUNCTION {titto.space.prefix} % always introduce a space +{ duplicate$ text.length$ #3 < + { " " } + { " " } + if$ + swap$ +} + + +FUNCTION {capitalize} +{ "u" change.case$ "t" change.case$ } + +FUNCTION {space.word} +{ " " swap$ * " " * } + % Here are the language-specific definitions for explicit words. + % Each function has a name bbl.xxx where xxx is the English word. + % The language selected here is ENGLISH +FUNCTION {bbl.and} +{ "and"} + +FUNCTION {bbl.etal} +{ "et~al." } + +FUNCTION {bbl.editors} +{ "eds." } + +FUNCTION {bbl.editor} +{ "ed." } + +FUNCTION {bbl.edby} +{ "edited by" } + +FUNCTION {bbl.edition} +{ "edn." } + +FUNCTION {bbl.volume} +{ "vol." } + +FUNCTION {titto.bbl.volume} % for handling journals +{ "" } + +FUNCTION {bbl.of} +{ "of" } + +FUNCTION {bbl.number} +{ "no." } + +FUNCTION {bbl.nr} +{ "no." } + +FUNCTION {bbl.in} +{ "in" } + +FUNCTION {bbl.pages} +{ "pp." } + +FUNCTION {bbl.page} +{ "p." } + +FUNCTION {titto.bbl.pages} % for journals +{ "" } + +FUNCTION {titto.bbl.page} % for journals +{ "" } + +FUNCTION {bbl.chapter} +{ "chap." } + +FUNCTION {bbl.techrep} +{ "Tech. Rep." } + +FUNCTION {bbl.mthesis} +{ "Master's thesis" } + +FUNCTION {bbl.phdthesis} +{ "Ph.D. thesis" } + +MACRO {jan} {"Jan."} + +MACRO {feb} {"Feb."} + +MACRO {mar} {"Mar."} + +MACRO {apr} {"Apr."} + +MACRO {may} {"May"} + +MACRO {jun} {"Jun."} + +MACRO {jul} {"Jul."} + +MACRO {aug} {"Aug."} + +MACRO {sep} {"Sep."} + +MACRO {oct} {"Oct."} + +MACRO {nov} {"Nov."} + +MACRO {dec} {"Dec."} + +MACRO {acmcs} {"ACM Comput. Surv."} + +MACRO {acta} {"Acta Inf."} + +MACRO {cacm} {"Commun. ACM"} + +MACRO {ibmjrd} {"IBM J. Res. Dev."} + +MACRO {ibmsj} {"IBM Syst.~J."} + +MACRO {ieeese} {"IEEE Trans. Software Eng."} + +MACRO {ieeetc} {"IEEE Trans. Comput."} + +MACRO {ieeetcad} + {"IEEE Trans. Comput. Aid. Des."} + +MACRO {ipl} {"Inf. Process. Lett."} + +MACRO {jacm} {"J.~ACM"} + +MACRO {jcss} {"J.~Comput. Syst. Sci."} + +MACRO {scp} {"Sci. Comput. Program."} + +MACRO {sicomp} {"SIAM J. Comput."} + +MACRO {tocs} {"ACM Trans. Comput. Syst."} + +MACRO {tods} {"ACM Trans. Database Syst."} + +MACRO {tog} {"ACM Trans. Graphic."} + +MACRO {toms} {"ACM Trans. Math. Software"} + +MACRO {toois} {"ACM Trans. Office Inf. Syst."} + +MACRO {toplas} {"ACM Trans. Progr. Lang. Syst."} + +MACRO {tcs} {"Theor. Comput. Sci."} + +FUNCTION {bibinfo.check} +{ swap$ + duplicate$ missing$ + { + pop$ pop$ + "" + } + { duplicate$ empty$ + { + swap$ pop$ + } + { swap$ + pop$ + } + if$ + } + if$ +} +FUNCTION {bibinfo.warn} +{ swap$ + duplicate$ missing$ + { + swap$ "missing " swap$ * " in " * cite$ * warning$ pop$ + "" + } + { duplicate$ empty$ + { + swap$ "empty " swap$ * " in " * cite$ * warning$ + } + { swap$ + pop$ + } + if$ + } + if$ +} +FUNCTION {format.url} +{ url empty$ + { "" } +% { "\urlprefix\url{" url * "}" * } + { "\url{" url * "}" * } % changed in titto-lncs-02.bst + if$ +} + +INTEGERS { nameptr namesleft numnames } + + +STRINGS { bibinfo} + +FUNCTION {format.names} +{ 'bibinfo := + duplicate$ empty$ 'skip$ { + 's := + "" 't := + #1 'nameptr := + s num.names$ 'numnames := + numnames 'namesleft := + { namesleft #0 > } + { s nameptr + "{vv~}{ll}{, jj}{, f{.}.}" + format.name$ + bibinfo bibinfo.check + 't := + nameptr #1 > + { + namesleft #1 > + { ", " * t * } + { + s nameptr "{ll}" format.name$ duplicate$ "others" = + { 't := } + { pop$ } + if$ + "," * + t "others" = + { + " " * bbl.etal * + } + { " " * t * } + if$ + } + if$ + } + 't + if$ + nameptr #1 + 'nameptr := + namesleft #1 - 'namesleft := + } + while$ + } if$ +} +FUNCTION {format.names.ed} +{ + 'bibinfo := + duplicate$ empty$ 'skip$ { + 's := + "" 't := + #1 'nameptr := + s num.names$ 'numnames := + numnames 'namesleft := + { namesleft #0 > } + { s nameptr + "{f{.}.~}{vv~}{ll}{ jj}" + format.name$ + bibinfo bibinfo.check + 't := + nameptr #1 > + { + namesleft #1 > + { ", " * t * } + { + s nameptr "{ll}" format.name$ duplicate$ "others" = + { 't := } + { pop$ } + if$ + "," * + t "others" = + { + + " " * bbl.etal * + } + { " " * t * } + if$ + } + if$ + } + 't + if$ + nameptr #1 + 'nameptr := + namesleft #1 - 'namesleft := + } + while$ + } if$ +} +FUNCTION {format.authors} +{ author "author" format.names +} +FUNCTION {get.bbl.editor} +{ editor num.names$ #1 > 'bbl.editors 'bbl.editor if$ } + +FUNCTION {format.editors} +{ editor "editor" format.names duplicate$ empty$ 'skip$ + { + " " * + get.bbl.editor +% capitalize + "(" swap$ * ")" * + * + } + if$ +} +FUNCTION {format.note} +{ + note empty$ + { "" } + { note #1 #1 substring$ + duplicate$ "{" = + 'skip$ + { output.state mid.sentence = + { "l" } + { "u" } + if$ + change.case$ + } + if$ + note #2 global.max$ substring$ * "note" bibinfo.check + } + if$ +} + +FUNCTION {format.title} +{ title + duplicate$ empty$ 'skip$ + { "t" change.case$ } + if$ + "title" bibinfo.check +} +FUNCTION {output.bibitem} +{ newline$ + "\bibitem{" write$ + cite$ write$ + "}" write$ + newline$ + "" + before.all 'output.state := +} + +FUNCTION {n.dashify} +{ + 't := + "" + { t empty$ not } + { t #1 #1 substring$ "-" = + { t #1 #2 substring$ "--" = not + { "--" * + t #2 global.max$ substring$ 't := + } + { { t #1 #1 substring$ "-" = } + { "-" * + t #2 global.max$ substring$ 't := + } + while$ + } + if$ + } + { t #1 #1 substring$ * + t #2 global.max$ substring$ 't := + } + if$ + } + while$ +} + +FUNCTION {word.in} +{ bbl.in capitalize + ":" * + " " * } + +FUNCTION {format.date} +{ + month "month" bibinfo.check + duplicate$ empty$ + year "year" bibinfo.check duplicate$ empty$ + { swap$ 'skip$ + { "there's a month but no year in " cite$ * warning$ } + if$ + * + } + { swap$ 'skip$ + { + swap$ + " " * swap$ + } + if$ + * + remove.dots + } + if$ + duplicate$ empty$ + 'skip$ + { + before.all 'output.state := + " (" swap$ * ")" * + } + if$ +} +FUNCTION {format.btitle} +{ title "title" bibinfo.check + duplicate$ empty$ 'skip$ + { + } + if$ +} +FUNCTION {either.or.check} +{ empty$ + 'pop$ + { "can't use both " swap$ * " fields in " * cite$ * warning$ } + if$ +} +FUNCTION {format.bvolume} +{ volume empty$ + { "" } + { bbl.volume volume tie.or.space.prefix + "volume" bibinfo.check * * + series "series" bibinfo.check + duplicate$ empty$ 'pop$ + { emphasize ", " * swap$ * } + if$ + "volume and number" number either.or.check + } + if$ +} +FUNCTION {format.number.series} +{ volume empty$ + { number empty$ + { series field.or.null } + { output.state mid.sentence = + { bbl.number } + { bbl.number capitalize } + if$ + number tie.or.space.prefix "number" bibinfo.check * * + series empty$ + { "there's a number but no series in " cite$ * warning$ } + { bbl.in space.word * + series "series" bibinfo.check * + } + if$ + } + if$ + } + { "" } + if$ +} + +FUNCTION {format.edition} +{ edition duplicate$ empty$ 'skip$ + { + output.state mid.sentence = + { "l" } + { "t" } + if$ change.case$ + "edition" bibinfo.check + " " * bbl.edition * + } + if$ +} +INTEGERS { multiresult } +FUNCTION {multi.page.check} +{ 't := + #0 'multiresult := + { multiresult not + t empty$ not + and + } + { t #1 #1 substring$ + duplicate$ "-" = + swap$ duplicate$ "," = + swap$ "+" = + or or + { #1 'multiresult := } + { t #2 global.max$ substring$ 't := } + if$ + } + while$ + multiresult +} +FUNCTION {format.pages} +{ pages duplicate$ empty$ 'skip$ + { duplicate$ multi.page.check + { + bbl.pages swap$ + n.dashify + } + { + bbl.page swap$ + } + if$ + tie.or.space.prefix + "pages" bibinfo.check + * * + } + if$ +} +FUNCTION {format.journal.pages} +{ pages duplicate$ empty$ 'pop$ + { swap$ duplicate$ empty$ + { pop$ pop$ format.pages } + { + ", " * + swap$ + n.dashify + pages multi.page.check + 'titto.bbl.pages + 'titto.bbl.page + if$ + swap$ tie.or.space.prefix + "pages" bibinfo.check + * * + * + } + if$ + } + if$ +} +FUNCTION {format.journal.eid} +{ eid "eid" bibinfo.check + duplicate$ empty$ 'pop$ + { swap$ duplicate$ empty$ 'skip$ + { + ", " * + } + if$ + swap$ * + } + if$ +} +FUNCTION {format.vol.num.pages} % this function is used only for journal entries +{ volume field.or.null + duplicate$ empty$ 'skip$ + { +% bbl.volume swap$ tie.or.space.prefix + titto.bbl.volume swap$ titto.space.prefix +% rationale for the change above: for journals you don't want "vol." label +% hence it does not make sense to attach the journal number to the label when +% it is short + "volume" bibinfo.check + * * + } + if$ + number "number" bibinfo.check duplicate$ empty$ 'skip$ + { + swap$ duplicate$ empty$ + { "there's a number but no volume in " cite$ * warning$ } + 'skip$ + if$ + swap$ + "(" swap$ * ")" * + } + if$ * + eid empty$ + { format.journal.pages } + { format.journal.eid } + if$ +} + +FUNCTION {format.chapter.pages} +{ chapter empty$ + 'format.pages + { type empty$ + { bbl.chapter } + { type "l" change.case$ + "type" bibinfo.check + } + if$ + chapter tie.or.space.prefix + "chapter" bibinfo.check + * * + pages empty$ + 'skip$ + { ", " * format.pages * } + if$ + } + if$ +} + +FUNCTION {format.booktitle} +{ + booktitle "booktitle" bibinfo.check +} +FUNCTION {format.in.ed.booktitle} +{ format.booktitle duplicate$ empty$ 'skip$ + { +% editor "editor" format.names.ed duplicate$ empty$ 'pop$ % changed by titto + editor "editor" format.names duplicate$ empty$ 'pop$ + { + " " * + get.bbl.editor +% capitalize + "(" swap$ * ") " * + * swap$ + * } + if$ + word.in swap$ * + } + if$ +} +FUNCTION {empty.misc.check} +{ author empty$ title empty$ howpublished empty$ + month empty$ year empty$ note empty$ + and and and and and + key empty$ not and + { "all relevant fields are empty in " cite$ * warning$ } + 'skip$ + if$ +} +FUNCTION {format.thesis.type} +{ type duplicate$ empty$ + 'pop$ + { swap$ pop$ + "t" change.case$ "type" bibinfo.check + } + if$ +} +FUNCTION {format.tr.number} +{ number "number" bibinfo.check + type duplicate$ empty$ + { pop$ bbl.techrep } + 'skip$ + if$ + "type" bibinfo.check + swap$ duplicate$ empty$ + { pop$ "t" change.case$ } + { tie.or.space.prefix * * } + if$ +} +FUNCTION {format.article.crossref} +{ + key duplicate$ empty$ + { pop$ + journal duplicate$ empty$ + { "need key or journal for " cite$ * " to crossref " * crossref * warning$ } + { "journal" bibinfo.check emphasize word.in swap$ * } + if$ + } + { word.in swap$ * " " *} + if$ + " \cite{" * crossref * "}" * +} +FUNCTION {format.crossref.editor} +{ editor #1 "{vv~}{ll}" format.name$ + "editor" bibinfo.check + editor num.names$ duplicate$ + #2 > + { pop$ + "editor" bibinfo.check + " " * bbl.etal + * + } + { #2 < + 'skip$ + { editor #2 "{ff }{vv }{ll}{ jj}" format.name$ "others" = + { + "editor" bibinfo.check + " " * bbl.etal + * + } + { + bbl.and space.word + * editor #2 "{vv~}{ll}" format.name$ + "editor" bibinfo.check + * + } + if$ + } + if$ + } + if$ +} +FUNCTION {format.book.crossref} +{ volume duplicate$ empty$ + { "empty volume in " cite$ * "'s crossref of " * crossref * warning$ + pop$ word.in + } + { bbl.volume + capitalize + swap$ tie.or.space.prefix "volume" bibinfo.check * * bbl.of space.word * + } + if$ + editor empty$ + editor field.or.null author field.or.null = + or + { key empty$ + { series empty$ + { "need editor, key, or series for " cite$ * " to crossref " * + crossref * warning$ + "" * + } + { series emphasize * } + if$ + } + { key * } + if$ + } + { format.crossref.editor * } + if$ + " \cite{" * crossref * "}" * +} +FUNCTION {format.incoll.inproc.crossref} +{ + editor empty$ + editor field.or.null author field.or.null = + or + { key empty$ + { format.booktitle duplicate$ empty$ + { "need editor, key, or booktitle for " cite$ * " to crossref " * + crossref * warning$ + } + { word.in swap$ * } + if$ + } + { word.in key * " " *} + if$ + } + { word.in format.crossref.editor * " " *} + if$ + " \cite{" * crossref * "}" * +} +FUNCTION {format.org.or.pub} +{ 't := + "" + address empty$ t empty$ and + 'skip$ + { + t empty$ + { address "address" bibinfo.check * + } + { t * + address empty$ + 'skip$ + { ", " * address "address" bibinfo.check * } + if$ + } + if$ + } + if$ +} +FUNCTION {format.publisher.address} +{ publisher "publisher" bibinfo.warn format.org.or.pub +} + +FUNCTION {format.organization.address} +{ organization "organization" bibinfo.check format.org.or.pub +} + +FUNCTION {article} +{ output.bibitem + format.authors "author" output.check + add.colon + new.block + format.title "title" output.check + new.block + crossref missing$ + { + journal + "journal" bibinfo.check + "journal" output.check + add.blank + format.vol.num.pages output + format.date "year" output.check + } + { format.article.crossref output.nonnull + format.pages output + } + if$ +% new.block + format.url output +% new.block + format.note output + fin.entry +} +FUNCTION {book} +{ output.bibitem + author empty$ + { format.editors "author and editor" output.check + add.colon + } + { format.authors output.nonnull + add.colon + crossref missing$ + { "author and editor" editor either.or.check } + 'skip$ + if$ + } + if$ + new.block + format.btitle "title" output.check + crossref missing$ + { format.bvolume output + new.block + new.sentence + format.number.series output + format.publisher.address output + } + { + new.block + format.book.crossref output.nonnull + } + if$ + format.edition output + format.date "year" output.check +% new.block + format.url output +% new.block + format.note output + fin.entry +} +FUNCTION {booklet} +{ output.bibitem + format.authors output + add.colon + new.block + format.title "title" output.check + new.block + howpublished "howpublished" bibinfo.check output + address "address" bibinfo.check output + format.date output +% new.block + format.url output +% new.block + format.note output + fin.entry +} + +FUNCTION {inbook} +{ output.bibitem + author empty$ + { format.editors "author and editor" output.check + add.colon + } + { format.authors output.nonnull + add.colon + crossref missing$ + { "author and editor" editor either.or.check } + 'skip$ + if$ + } + if$ + new.block + format.btitle "title" output.check + crossref missing$ + { + format.bvolume output + format.chapter.pages "chapter and pages" output.check + new.block + new.sentence + format.number.series output + format.publisher.address output + } + { + format.chapter.pages "chapter and pages" output.check + new.block + format.book.crossref output.nonnull + } + if$ + format.edition output + format.date "year" output.check +% new.block + format.url output +% new.block + format.note output + fin.entry +} + +FUNCTION {incollection} +{ output.bibitem + format.authors "author" output.check + add.colon + new.block + format.title "title" output.check + new.block + crossref missing$ + { format.in.ed.booktitle "booktitle" output.check + format.bvolume output + format.chapter.pages output + new.sentence + format.number.series output + format.publisher.address output + format.edition output + format.date "year" output.check + } + { format.incoll.inproc.crossref output.nonnull + format.chapter.pages output + } + if$ +% new.block + format.url output +% new.block + format.note output + fin.entry +} +FUNCTION {inproceedings} +{ output.bibitem + format.authors "author" output.check + add.colon + new.block + format.title "title" output.check + new.block + crossref missing$ + { format.in.ed.booktitle "booktitle" output.check + new.sentence % added by titto + format.bvolume output + format.pages output + new.sentence + format.number.series output + publisher empty$ + { format.organization.address output } + { organization "organization" bibinfo.check output + format.publisher.address output + } + if$ + format.date "year" output.check + } + { format.incoll.inproc.crossref output.nonnull + format.pages output + } + if$ +% new.block + format.url output +% new.block + format.note output + fin.entry +} +FUNCTION {conference} { inproceedings } +FUNCTION {manual} +{ output.bibitem + author empty$ + { organization "organization" bibinfo.check + duplicate$ empty$ 'pop$ + { output + address "address" bibinfo.check output + } + if$ + } + { format.authors output.nonnull } + if$ + add.colon + new.block + format.btitle "title" output.check + author empty$ + { organization empty$ + { + address new.block.checka + address "address" bibinfo.check output + } + 'skip$ + if$ + } + { + organization address new.block.checkb + organization "organization" bibinfo.check output + address "address" bibinfo.check output + } + if$ + format.edition output + format.date output +% new.block + format.url output +% new.block + format.note output + fin.entry +} + +FUNCTION {mastersthesis} +{ output.bibitem + format.authors "author" output.check + add.colon + new.block + format.btitle + "title" output.check + new.block + bbl.mthesis format.thesis.type output.nonnull + school "school" bibinfo.warn output + address "address" bibinfo.check output + format.date "year" output.check +% new.block + format.url output +% new.block + format.note output + fin.entry +} + +FUNCTION {misc} +{ output.bibitem + format.authors output + add.colon + title howpublished new.block.checkb + format.title output + howpublished new.block.checka + howpublished "howpublished" bibinfo.check output + format.date output +% new.block + format.url output +% new.block + format.note output + fin.entry + empty.misc.check +} +FUNCTION {phdthesis} +{ output.bibitem + format.authors "author" output.check + add.colon + new.block + format.btitle + "title" output.check + new.block + bbl.phdthesis format.thesis.type output.nonnull + school "school" bibinfo.warn output + address "address" bibinfo.check output + format.date "year" output.check +% new.block + format.url output +% new.block + format.note output + fin.entry +} + +FUNCTION {proceedings} +{ output.bibitem + editor empty$ + { organization "organization" bibinfo.check output + } + { format.editors output.nonnull } + if$ + add.colon + new.block + format.btitle "title" output.check + format.bvolume output + editor empty$ + { publisher empty$ + { format.number.series output } + { + new.sentence + format.number.series output + format.publisher.address output + } + if$ + } + { publisher empty$ + { + new.sentence + format.number.series output + format.organization.address output } + { + new.sentence + format.number.series output + organization "organization" bibinfo.check output + format.publisher.address output + } + if$ + } + if$ + format.date "year" output.check +% new.block + format.url output +% new.block + format.note output + fin.entry +} + +FUNCTION {techreport} +{ output.bibitem + format.authors "author" output.check + add.colon + new.block + format.title + "title" output.check + new.block + format.tr.number output.nonnull + institution "institution" bibinfo.warn output + address "address" bibinfo.check output + format.date "year" output.check +% new.block + format.url output +% new.block + format.note output + fin.entry +} + +FUNCTION {unpublished} +{ output.bibitem + format.authors "author" output.check + add.colon + new.block + format.title "title" output.check + format.date output +% new.block + format.url output +% new.block + format.note "note" output.check + fin.entry +} + +FUNCTION {default.type} { misc } +READ +FUNCTION {sortify} +{ purify$ + "l" change.case$ +} +INTEGERS { len } +FUNCTION {chop.word} +{ 's := + 'len := + s #1 len substring$ = + { s len #1 + global.max$ substring$ } + 's + if$ +} +FUNCTION {sort.format.names} +{ 's := + #1 'nameptr := + "" + s num.names$ 'numnames := + numnames 'namesleft := + { namesleft #0 > } + { s nameptr + "{ll{ }}{ ff{ }}{ jj{ }}" + format.name$ 't := + nameptr #1 > + { + " " * + namesleft #1 = t "others" = and + { "zzzzz" * } + { t sortify * } + if$ + } + { t sortify * } + if$ + nameptr #1 + 'nameptr := + namesleft #1 - 'namesleft := + } + while$ +} + +FUNCTION {sort.format.title} +{ 't := + "A " #2 + "An " #3 + "The " #4 t chop.word + chop.word + chop.word + sortify + #1 global.max$ substring$ +} +FUNCTION {author.sort} +{ author empty$ + { key empty$ + { "to sort, need author or key in " cite$ * warning$ + "" + } + { key sortify } + if$ + } + { author sort.format.names } + if$ +} +FUNCTION {author.editor.sort} +{ author empty$ + { editor empty$ + { key empty$ + { "to sort, need author, editor, or key in " cite$ * warning$ + "" + } + { key sortify } + if$ + } + { editor sort.format.names } + if$ + } + { author sort.format.names } + if$ +} +FUNCTION {author.organization.sort} +{ author empty$ + { organization empty$ + { key empty$ + { "to sort, need author, organization, or key in " cite$ * warning$ + "" + } + { key sortify } + if$ + } + { "The " #4 organization chop.word sortify } + if$ + } + { author sort.format.names } + if$ +} +FUNCTION {editor.organization.sort} +{ editor empty$ + { organization empty$ + { key empty$ + { "to sort, need editor, organization, or key in " cite$ * warning$ + "" + } + { key sortify } + if$ + } + { "The " #4 organization chop.word sortify } + if$ + } + { editor sort.format.names } + if$ +} +FUNCTION {presort} +{ type$ "book" = + type$ "inbook" = + or + 'author.editor.sort + { type$ "proceedings" = + 'editor.organization.sort + { type$ "manual" = + 'author.organization.sort + 'author.sort + if$ + } + if$ + } + if$ + " " + * + year field.or.null sortify + * + " " + * + title field.or.null + sort.format.title + * + #1 entry.max$ substring$ + 'sort.key$ := +} +ITERATE {presort} +SORT +STRINGS { longest.label } +INTEGERS { number.label longest.label.width } +FUNCTION {initialize.longest.label} +{ "" 'longest.label := + #1 'number.label := + #0 'longest.label.width := +} +FUNCTION {longest.label.pass} +{ number.label int.to.str$ 'label := + number.label #1 + 'number.label := + label width$ longest.label.width > + { label 'longest.label := + label width$ 'longest.label.width := + } + 'skip$ + if$ +} +EXECUTE {initialize.longest.label} +ITERATE {longest.label.pass} +FUNCTION {begin.bib} +{ preamble$ empty$ + 'skip$ + { preamble$ write$ newline$ } + if$ + "\begin{thebibliography}{" longest.label * "}" * + write$ newline$ + "\providecommand{\url}[1]{\texttt{#1}}" + write$ newline$ + "\providecommand{\urlprefix}{URL }" + write$ newline$ +} +EXECUTE {begin.bib} +EXECUTE {init.state.consts} +ITERATE {call.type$} +FUNCTION {end.bib} +{ newline$ + "\end{thebibliography}" write$ newline$ +} +EXECUTE {end.bib} +%% End of customized bst file +%% +%% End of file `titto.bst'. + + diff --git a/cryptominisat/cppsrc/docs/satcomp16-pdf/Makefile b/cryptominisat/cppsrc/docs/satcomp16-pdf/Makefile new file mode 100644 index 00000000..64b69b49 --- /dev/null +++ b/cryptominisat/cppsrc/docs/satcomp16-pdf/Makefile @@ -0,0 +1,25 @@ +TEX = pdflatex -shell-escape -interaction=nonstopmode -file-line-error +PRE = $(TEX) -ini -job-name="preamble" "&pdflatex preamble.tex\dump" +BIB = bibtex + +all: cmsv5.pdf + +view : + okular cmsv5.pdf + +cmsv5.pdf : clean cmsv5.tex cmsv5.bbl cmsv5.blg + $(TEX) cmsv5.tex + $(TEX) cmsv5.tex + mv cmsv5.pdf cmsv54.pdf + +cmsv5.bbl cmsv5.blg : cmsv5.bib cmsv5.aux + $(BIB) cmsv5 + +cmsv5.aux : cmsv5.tex + $(TEX) cmsv5.tex + +cmsv5.bib : cmsv5.tex + $(TEX) cmsv5.tex + +clean: + rm -f *.log *.pdf *.blg *.bbl *.aux *.out *.backup diff --git a/cryptominisat/cppsrc/docs/satcomp16-pdf/cmsv5.kilepr b/cryptominisat/cppsrc/docs/satcomp16-pdf/cmsv5.kilepr new file mode 100644 index 00000000..92617e20 --- /dev/null +++ b/cryptominisat/cppsrc/docs/satcomp16-pdf/cmsv5.kilepr @@ -0,0 +1,53 @@ +[General] +def_graphic_ext= +img_extIsRegExp=false +img_extensions=.eps .jpg .jpeg .png .pdf .ps .fig .gif .dvi +kileprversion=2 +kileversion=2.1.0 +lastDocument=cmsv5.tex +masterDocument= +name=auth_eloadas +pkg_extIsRegExp=false +pkg_extensions=.cls .sty .bbx .cbx .lbx +src_extIsRegExp=false +src_extensions=.tex .ltx .latex .dtx .ins .bib .mp + +[Tools] +MakeIndex= +QuickBuild= + +[document-settings,item:cmsv5.tex] +Bookmarks= +Encoding=UTF-8 +FoldedColumns= +FoldedLines= +Highlighting=LaTeX +Indentation Mode=normal +Mode=LaTeX +ReadWrite=true + +[item:cmsv5.kilepr] +archive=true +column=0 +encoding= +highlight= +line=0 +mode= +open=false +order=-1 + +[item:cmsv5.tex] +archive=true +column=1 +encoding=UTF-8 +highlight=LaTeX +line=245 +mode=LaTeX +open=true +order=0 + +[view-settings,view=0,item:cmsv5.tex] +CursorColumn=1 +CursorLine=245 +JumpList= +ViMarks= diff --git a/cryptominisat/cppsrc/docs/satcomp16-pdf/cmsv5.tex b/cryptominisat/cppsrc/docs/satcomp16-pdf/cmsv5.tex new file mode 100644 index 00000000..7cd4aaeb --- /dev/null +++ b/cryptominisat/cppsrc/docs/satcomp16-pdf/cmsv5.tex @@ -0,0 +1,64 @@ +%\documentclass[runningheads]{llncs} +\documentclass[final]{ieee} + +\usepackage{microtype} %This gives MUCH better PDF results! +%\usepackage[active]{srcltx} %DVI search +\usepackage[cmex10]{amsmath} +\usepackage{amssymb} +\usepackage{fnbreak} %warn for split footnotes +\usepackage{url} +%\usepackage{qtree} %for drawing trees +%\usepackage{fancybox} % if we need rounded corners +%\usepackage{pict2e} % large circles can be drawn +%\usepackage{courier} %for using courier in texttt{} +%\usepackage{nth} %allows to \nth{4} to make 1st 2nd, etc. +%\usepackage{subfigure} %allows to have side-by-side figures +%\usepackage{booktabs} %nice tables +%\usepackage{multirow} %allow multiple cells with rows in tabular +\usepackage[utf8]{inputenc} % allows to write Faugere correctly +\usepackage[bookmarks=true, citecolor=black, linkcolor=black, colorlinks=true]{hyperref} +\hypersetup{ +pdfauthor = {Mate Soos}, +pdftitle = {CryptoMiniSat v5}, +pdfsubject = {SAT Competition 2016}, +pdfkeywords = {SAT Solver, DPLL}, +pdfcreator = {PdfLaTeX with hyperref package}, +pdfproducer = {PdfLaTex}} +%\usepackage{butterma} + +%\usepackage{pstricks} +\usepackage{graphicx,epsfig,xcolor} + +\begin{document} +\title{The CryptoMiniSat 5 set of solvers at SAT Competition 2016} +\author{Mate Soos} + +\maketitle +\thispagestyle{empty} +\pagestyle{empty} + +\section{Introduction} +This paper presents the conflict-driven clause-learning SAT solver CryptoMiniSat v5 (\emph{CMS5}) as submitted to SAT Competition 2016. CMS5 aims to be a modern, open-source SAT solver that allows for multi-threaded in-processing techniques while still retaining a strong CDCL component. In this description only the features relative to CMS4.4, the previous year's submission, are explained. Please refer to the previous years' description for details. In general, CMS5 is a in-processing SAT solver that usues optimized datastructures and finely-tuned timeouts to have good control over both memory and time usage of simplification steps. + +\subsection{Removal of uneeded code} +Over the years, many lines of code has been added to CMS that in the end didn't help and often was detrimental to both maintinability and efficiency of the solver. Many such additions have now been removed. This simplifies understanding and developing the system. Further, it allows the system to be more lean especially in the tight loops such as propagation and conflict analysis where most of the time is spent. + +\subsection{Integration of ideas from COMiniSatPS} +Some of the ideas from COMiniSatPS\cite{swdia} have been included into CMS. In particular, the clause cleaning system employed and the switching restart have both made their way into CMS. + +\subsection{On-the-fly Gaussian Elimination} +On-the-fly Gaussian elimination is again part of CryptoMiniSat. This is explicitly disabled for the compeititon, but the code is available and well-tested. This allows for special uses of the solver that other solvers, without on-the-fly Gaussian elimination, are not capable of. + +\subsection{Clause usefulness guessing} +Besides glues and clause activites, CMS5 also tries to guess clause usefulness based on the trail size, the backjump level and the activity of the variables in the ancestor of the learnt clause. Although this is at a very early stage of development, it has been found to be helpful. + +\subsection{Auto-tuning} +The version 'autotune' reconfigures itself after about 160K conflicts. The configuration picked is one of 2 different setups that vary many different parameters of the solving such as learnt clause removal strategy, restart strategy, and in-processing strategies. CMS5 was run on all SAT Comp'09 + 11 + 13 + 14 + 15 problems with both configurations, extracting relevant information from the all problems after they have been solved and simplified for 160K conflicts. configurations were then given to a machine learning algorithm (C5.0\cite{Quinlan:1993:CPM:152181}) which built a decision tree from this data. This decision tree was then translated into C++ and compiled into the CMS5 source code. + +\bibliographystyle{splncs03} +\bibliography{sigproc} + +\vfill +\pagebreak + +\end{document} diff --git a/cryptominisat/cppsrc/docs/satcomp16-pdf/ieee.cls b/cryptominisat/cppsrc/docs/satcomp16-pdf/ieee.cls new file mode 100644 index 00000000..3c57bba5 --- /dev/null +++ b/cryptominisat/cppsrc/docs/satcomp16-pdf/ieee.cls @@ -0,0 +1,1497 @@ +% Copyright 2014 IEEEE +% for terms of use see https://www.ieee.org/publications_standards/publications/rights/copyrightpolicy.html + +% ========================================================================= +% ------------------------------------------------------------------------- +% XX X +% X +% XX XXX XXX XXX XXX X XXXX +% X X X X X X X X X X X +% X XXXXX XXXXX XXXXX X X XXX +% X X X X XX X X X X +% XXX XXX XXX XXX XX XXX X XXXX +% ------------------------------------------------------------------------- +% ========================================================================= +% ieee.cls --- For formatting IEEE conference & journal papers +% --- Compiled by Gregory Plett, Sept 1997 +% +% This class was inspired by one first compiled by Gerry Murray and +% Silvano Balemi for LaTeX209. It was later updated for use with +% LaTeX2e, and some bugs were fixed, all by Istvan Kollar. Lastly, +% I have tried to make the class easier to use by paper authors. +% Significant new functionality has been added. Many routines are +% "borrowed" from other people's packages and modified extensively. +% When I rembered where I got the routines from, I gave the author +% credit. +% +% After I made many changes on my own, I found a version by Peter +% N"uchter, and tried to retain some amount of compatibility with his +% version. To be completely compatible with him, you may need to +% manually: +% \usepackage{rawfonts}\usepackage{oldlfont} +% \AtBeginDocument{\parindent1.0em} (?) +% +%=========================================================================== +% +% Usage: +% \documentclass[main-mode,sub-mode,misc-options]{ieee} +% \usepackage{your own packages} +% \begin{document} +% \bibliographystyle{IEEEbib} +% \title[short]{regular} +% \author[short]{full} +% \maketitle +% \begin{abstract}...\end{abstract} +% \begin{keywords}...\end{keywords} +% \section{...} +% \PARstart ... or \PARstartCal ... +% ... +% \begin{biography}[picname.ps]{Author's name}...\end{biography} +% \end{document} +% +% The document class options are: +% +% main-mode: One of the following is required. (draft is the default) +% draft: Double-spaced, single column with date/time stamp. +% submission: Double-spaced, suitable for submission for review. +% compressed: Same as "submission", only single spaced. +% final: Double-column, for assessing page-length and +% format of final version. +% +% sub-mode: +% techreport: This can modify "final" to produce a two-col +% technical report. +% internal: This can modify "submission", "compressed" or "final". +% It changes the header to notify the reader that +% this is a version of the manuscript to be used for +% internal review processes only, and not to be +% distributed. +% submitted: This can modify "compressed" or "final". It changes +% the header to notify the reader that this +% is a preprint and not to be distributed. +% inpress: This can modify "compressed" or "final". It changes the +% header to notify the reader that this paper has +% been accepted for publishing, but it is not yet to be +% distributed. +% reprint: This can modify "final". It changes the header +% to notify the reader where the paper is reprinted from. +% +% misc-options: +% narroweqnarray: Changes the spacing around the "=" sign in +% equation arrays to make it the same as in displayed math. +% inline: Compresses the horizontal spacing of inline math equations. +% notitlepage: No separate title page. (default) +% titlepage: Separate title page. +% anonymous: Omit all author information from main part of paper. +% Author info only prints on titlepage. +% 9pt,10pt,11pt,12pt: Choose the appropriate type size. You should +% not need to do this as the "correct" size is automatically +% chosen. However, if you want, you may use these to change +% the type size of the main text. "9pt" is a bit of a hack +% to retain backward-compatibility. +% invited: If the paper is an "invited" paper, then this option +% prints "(Invited Paper)" under the authors' names. +% +% For regular IEEE submissions, define the journal name as: +% \journal{IEEE Trans. Inst. Meas.} +% +% To specify the conference place and date: +% \confplacedate{Ottawa, Canada, May 19--21, 1997} +% +% Before \maketitle, define: +% \title{Title of paper} +% \author{Author1\member{Fellow}\authorinfo{Department of +% Electrical Engineering\\ Some University, Somewhere, CA 94305 +% USA} \and Author2\member{Senior Member}\authorinfo{Deptartment of +% Measurement and Instrument Eng., Another University, ...}} +% +% Note, the contents of \authorinfo tends to vary depending on if it is +% a conference or journal paper. The amount of manual changes are +% small, and must be done by a human anyway. The example given is for an +% IMTC conference. +% +% See also IEEEbib.bst and ieeefig.sty +% Also very useful for document preparation is the style file "endfloat", +% available on all CTAN TeX archives. +% +%=========================================================================== +% modified 14 October 2002: +% - fixed bibliography listing of [#] when # < 10 and number of +% references is greater than 9. Thanks for Janos Markus for finding +% this bug and suggesting a solution. +% modified 15 January 2000: +% - "fixed" narroweqnarray. Never implemented! Now it is... +% modified 12 January 2000: +% - modified so only first \title and \author commands are recognized. +% This allows LyX to have \title and \author with full syntax in +% header, but dummy \title and \author show up in GUI. +% - added "\date" so the \date command can change "submitted" and +% "draft" date headers. +% modified 11 January 2000: +% - added PARstartLyX and PARstartCalLyX for LyX compatibility +% - added biographyLyX +% modified 1 Dec 1997: +% - fixed first page in reprint mode to be same length as other pages +% - added "invited" misc-option +% modified 5 Sept 1997: +% - added the inpress, reprint and internal sub-modes +% - removed IMTC-conf and CDC-conf to separate files +% modified 1 Sept 1997: +% - included Babel package compatibility +% - removed paper title from header on first page of draft +% manuscript +% - removed the fixed option "letterpaper" to allow a4paper (etc) +% modified 1 Aug 1997: +% - included the CDC-conf option +%=========================================================================== +% ************************************************************************** +% ****** ****************************************** +% ***** LaTeX2e INITIALIZATION ***************************************** +% ****** ****************************************** +% ************************************************************************** +\typeout{Document Class `ieee' .} +\NeedsTeXFormat{LaTeX2e}[1993/11/11] % Oldest acceptable version of LaTeX2e +\ProvidesClass{ieee}[2000/01/11] % Name of package provided, date +\def\i@@@cls{exists} + +% Initial Code & Declaration of Options +% ------------------------------------- +\newif\ifev@l \ev@lfalse % true if "final" mode. +\newif\ifsubm@t \subm@tfalse % true if "submission" mode. +\newif\ifdr@ft \dr@fttrue % true if "draft" mode. +\newif\ifc@mpress \c@mpressfalse % true if "compressed" mode. + +\newif\if@technote \@technotefalse % true if "technote" sub-mode. +\newif\ifintern@l \intern@lfalse % true if "internal" sub-mode. +\newif\ifprepr@nt \prepr@ntfalse % true if "preprint" sub-mode. +\newif\ifinpr@ss \inpr@ssfalse % true if "inpress" sub-mode. +\newif\ifrepr@nt \repr@ntfalse % true if "reprint" sub-mode. + +\newif\iftitlep@ge \titlep@gefalse % true if has own titlepage +\newif\if@non \@nonfalse % true if anonymous +\newif\ifixpt \ixptfalse % true if trying to do 9 pt +\newif\if@nvited \@nvitedfalse % true if an invited paper + +% Main options +% ------------ +\DeclareOption{draft}{\ev@lfalse\subm@tfalse\dr@fttrue% + \typeout{ieee: `Draft' mode selected.}} +\DeclareOption{submission}{\ev@lfalse\dr@ftfalse\subm@ttrue% + \typeout{ieee: `Submission' mode selected.}} +\DeclareOption{compressed}{\ev@lfalse\dr@ftfalse\subm@tfalse\c@mpresstrue% + \typeout{ieee: `Compressed' mode selected.}} +\DeclareOption{final}{\ev@ltrue\dr@ftfalse\subm@tfalse% + \typeout{ieee: `Final' mode selected.}} +\DeclareOption{evaluation}{\ev@ltrue\dr@ftfalse\subm@tfalse% + \typeout{ieee: `Final' mode selected.}} % synonym for final + +% Sub options +% ----------- +\DeclareOption{technote}{\@technotetrue% + \typeout{ieee: `Technote' sub-mode selected.}} +\DeclareOption{internal}{\intern@ltrue\prepr@ntfalse\inpr@ssfalse\repr@ntfalse% + \typeout{ieee: `Internal-Review' sub-mode selected.}} +\DeclareOption{submitted}{\intern@lfalse\prepr@nttrue\inpr@ssfalse\repr@ntfalse% + \typeout{ieee: `Submitted' sub-mode selected.}} +\DeclareOption{preprint}{\intern@lfalse\prepr@nttrue\inpr@ssfalse\repr@ntfalse% + \typeout{ieee: `Submitted' sub-mode selected.}} % synonym for submitted +\DeclareOption{inpress}{\intern@lfalse\prepr@ntfalse\inpr@sstrue\repr@ntfalse% + \typeout{ieee: `Inpress' sub-mode selected.}} +\DeclareOption{reprint}{\intern@lfalse\prepr@ntfalse\inpr@ssfalse\repr@nttrue% + \typeout{ieee: `Reprint' sub-mode selected.}} + +% Misc options +% ------------ + % regular or compressed "=" spacing in +\def\eqnarr@ysep{\arraycolsep} % eqnarray (this is the default) + % NOTE: we must use "def" and not "=" + % as arraycolsep not yet defined. +\DeclareOption{narroweqnarray}{\gdef\eqnarr@ysep{0.28em\relax}% + \typeout{ieee: Narrow equation arrays selected.}} +\DeclareOption{inline}{\everymath{\thinmuskip=2mu plus 1mu + \medmuskip=3mu plus 1mu minus 2mu + \thickmuskip=4mu plus 2mu\relax}% + \typeout{ieee: Narrower inline equations selected.}} +\DeclareOption{notitlepage}{\titlep@gefalse% + \typeout{ieee: No separate title page.}} +\DeclareOption{titlepage}{\titlep@getrue% + \typeout{ieee: Use separate title page.}} +\DeclareOption{anonymous}{\@nontrue\AtBeginDocument{\glpexclude{biography}} + \typeout{ieee: Omit author information from paper.}} +\DeclareOption{invited}{\@nvitedtrue% + \typeout{ieee: (Invited Paper).}} + +\DeclareOption{9pt}{\ixpttrue% + \typeout{ieee: Trying to emulate old `9pt' document class.}} + +\DeclareOption*{\PassOptionsToClass{\CurrentOption}{article}} + +% Execution of Options/Package Loading +% ------------------------------------ +\newlength\narrowcol +\newlength\parindentsave % recover parindent in blsone text + +\ProcessOptions +\ifev@l % if "final" mode... + \if@technote\ixpttrue\typeout{ieee: Trying to emulate old `9pt' + document class.}\fi% + \LoadClass[twoside,final,twocolumn,10pt]{article} +\else % if "draft"/"submission"/(compressed) mode... + \ifixpt + \LoadClass[oneside,final,onecolumn,10pt]{article} + \else + \LoadClass[oneside,final,onecolumn,12pt]{article} + \fi +\fi +\RequirePackage[final]{graphicx} +\RequirePackage{ifthen} + +% Re-Definitions of English words which must be done before +% the Babel package (optional) is loaded. +% --------------------------------------------------------- +\def\keywordsname{Index Terms} +\def\indexterms#1{\def\keywordsname{#1}} +\def\appendicesname{Appendices} +\def\figurename{Fig.} + +% ************************************************************************** +% ***** Check Sub-Options for Compatibility w/ Main-Options ************ +% ************************************************************************** +\if@technote\ifev@l\else\ClassError{ieee}{`technote' sub-mode may be + used only with the `final' ^^Jmain-mode. It may not be used + with either the `draft,' `submission,' or ^^J`compressed' + main-modes}{}\endinput\fi\fi +\ifintern@l\ifdr@ft\ClassError{ieee}{`internal' sub-mode may be + used only with the ^^J`submission,' `compressed,' or `final' main-modes. + It may not be used ^^Jwith the `draft' main-mode}{}\endinput\fi\fi +\ifprepr@nt\ifc@mpress\else\ifev@l\else\ClassError{ieee}{`submitted' + sub-mode may be used only with the ^^J`compressed' or `final' + main-modes. It may not be used with either the ^^J`draft' or + `submission' main-modes}{}\endinput\fi\fi\fi +\ifinpr@ss\ifc@mpress\else\ifev@l\else\ClassError{ieee}{`inpress' + sub-mode may be used only with the `compressed' ^^Jor `final' + main-modes. It may not be used with either the `draft' or + ^^J`submission' main-modes}{}\endinput\fi\fi\fi +\ifrepr@nt\ifev@l\else\ClassError{ieee}{`reprint' + sub-mode may be used only with the `final' ^^Jmain-mode. It may not be + used with either the `draft,' `submission,' or ^^J`compressed' + main-modes}{}\endinput\fi\fi + +% ************************************************************************** +% ***** Page Layout Definition ***************************************** +% ************************************************************************** +%% Layout definitions (mostly) common to all options. + +\hoffset 0in \voffset 0in +\headheight 12pt \headsep 7mm +\marginparsep 10pt \marginparwidth 20pt +\marginparpush 25pt +\columnsep 4mm +\parindent 1.0em +\lineskip 1pt +\normallineskip 1pt +\def\baselinestretch{1} + +\partopsep \z@ +\topsep 1.3ex +\parsep \z@ +\itemsep \z@ + +\setlength{\parindentsave}{\parindent} + +\ifev@l % if "evaluation" mode + % if camera-ready or A4paper ... + \ifdim\paperwidth<211mm + \oddsidemargin -11.4mm \evensidemargin -11.4mm + % for regular US Letter, not camera-ready + \else + \oddsidemargin -8.45mm \evensidemargin -8.45mm + \fi + \ifrepr@nt + \textheight 237.5mm % leave 6mm for cpyright on first page + \else + \textheight 243.5mm + \fi + \voffset -0.5in + \textwidth 182.0mm + \topmargin -12pt + \setlength{\narrowcol}{89mm} +\else % if "draft"/"submission" mode... + \ifc@mpress % and "compressed" + \oddsidemargin -0.25in \evensidemargin -0.25in + \textheight 9in \textwidth 7in + \topmargin -0.25in + \setlength{\narrowcol}{7in} + \else % and NOT "compressed" + \renewcommand\baselinestretch{1.8}\renewcommand{\arraystretch}{0.8} + \parindent=1.8\parindent + \oddsidemargin 0pt \evensidemargin 0pt + \headheight 12pt \headsep 0.375in + \topmargin 0pt + \textheight 8.5in \textwidth 6.5in + \marginparsep 0in \marginparwidth 0pt + \marginparpush 5pt + \setlength{\narrowcol}{6.5in} + \fi +\fi + +\def\normalstyle{\rmfamily} + +% ************************************************************************** +% ***** Font Definition ************************************************ +% ************************************************************************** +%% The 9-point option is being faked since it is not supported by the +%% article base class. + +%% Check if we have selected 9 points +\ifixpt +\typeout{-- This is a 9 point document} +\gdef\@ptsize{9} +\def\@normalsize{\@setsize\normalsize{10.7pt}\ixpt\@ixpt +\abovedisplayskip 1em plus2pt minus5pt\belowdisplayskip \abovedisplayskip +\abovedisplayshortskip \z@ plus3pt\belowdisplayshortskip .6em plus3pt minus3pt +\topsep \belowdisplayshortskip%!PN +} +\def\small{\@setsize\small{9.12pt}\viiipt\@viipt} +\def\footnotesize{\@setsize\footnotesize{8.15pt}\viipt\@vipt} +\def\scriptsize{\@setsize\scriptsize{8pt}\vipt\@vpt} +\def\tiny{\@setsize\tiny{5pt}\vpt\@vpt} +\def\large{\@setsize\large{12pt}\xpt\@xpt} +\def\Large{\@setsize\Large{14pt}\xiipt\@xiipt} +\def\LARGE{\@setsize\LARGE{18pt}\xivpt\@xivpt} +\def\huge{\@setsize\huge{22pt}\xviipt\@xviipt} +\def\Huge{\@setsize\Huge{25pt}\xxpt\@xxpt} +\fi +%% +%% Check if we have selected 10 points +\def\@tempa{0}\if\@ptsize\@tempa +\typeout{-- This is a 10 point document} +\def\@normalsize{\@setsize\normalsize{11.9pt}\xpt\@xpt +\abovedisplayskip 1em plus2pt minus5pt\belowdisplayskip \abovedisplayskip +\abovedisplayshortskip \z@ plus3pt\belowdisplayshortskip .6em plus3pt minus3pt +\topsep \belowdisplayshortskip%!PN +} +\def\small{\@setsize\small{9.2pt}\viiipt\@viiipt} +\def\footnotesize{\@setsize\footnotesize{8.8pt}\viiipt\@viiipt} +\def\scriptsize{\@setsize\scriptsize{8pt}\viipt\@viipt} +\def\tiny{\@setsize\tiny{6pt}\vpt\@vpt} +\def\normalsize{\@setsize\normalsize{11.9pt}\xpt\@xpt} +\def\large{\@setsize\large{14pt}\xiipt\@xiipt} +\def\Large{\@setsize\Large{18pt}\xivpt\@xivpt} +\def\LARGE{\@setsize\LARGE{22pt}\xviipt\@xviipt} +\def\huge{\@setsize\huge{22pt}\xxpt\@xxpt} +\def\Huge{\@setsize\Huge{28pt}\xxvpt\@xxvpt} +\fi +%% +%% Check if we have selected 11 points +\def\@tempa{1}\if\@ptsize\@tempa +\typeout{-- This is an 11 point document} +\def\@normalsize{\@setsize\normalsize{13.6pt}\xipt\@xipt +\abovedisplayskip 1em plus2pt minus5pt\belowdisplayskip \abovedisplayskip +\abovedisplayshortskip \z@ plus3pt\belowdisplayshortskip .6em plus3pt minus3pt +\topsep \belowdisplayshortskip%!PN +} +\def\small{\@setsize\small{12pt}\xpt\@xpt} +\def\footnotesize{\@setsize\footnotesize{11pt}\ixpt\@ixpt} +\def\scriptsize{\@setsize\scriptsize{9.5pt}\viiipt\@viiipt} +\def\tiny{\@setsize\tiny{7pt}\vipt\@vipt} +\def\normalsize{\@setsize\normalsize{13.6pt}\xipt\@xipt} +\def\large{\@setsize\large{14pt}\xiipt\@xiipt} +\def\Large{\@setsize\Large{18pt}\xivpt\@xivpt} +\def\LARGE{\@setsize\LARGE{22pt}\xviipt\@xviipt} +\def\huge{\@setsize\huge{25pt}\xxpt\@xxpt} +\def\Huge{\@setsize\Huge{30pt}\xxvpt\@xxvpt} +\fi +%% +%% Check if we have selected 12 points +\def\@tempa{2}\if\@ptsize\@tempa +\typeout{-- This is a 12 point document} +\def\@normalsize{\@setsize\normalsize{14pt}\xiipt\@xiipt +\abovedisplayskip 1em plus3pt minus6pt\belowdisplayskip \abovedisplayskip +\abovedisplayshortskip \z@ plus3pt\belowdisplayshortskip .6em plus4pt minus4pt +\topsep \belowdisplayshortskip%!PN +} +\def\small{\@setsize\small{11.4pt}\xpt\@xpt} +\def\footnotesize{\@setsize\footnotesize{10pt}\ixpt\@ixpt} +\def\scriptsize{\@setsize\scriptsize{9pt}\viiipt\@viiipt} +\def\tiny{\@setsize\tiny{8pt}\vipt\@vipt} +\def\normalsize{\@setsize\normalsize{14pt}\xiipt\@xiipt} +\def\large{\@setsize\large{18pt}\xivpt\@xivpt} +\def\Large{\@setsize\Large{22pt}\xviipt\@xviipt} +\def\LARGE{\@setsize\LARGE{25pt}\xxpt\@xxpt} +\def\huge{\@setsize\huge{30pt}\xxvpt\@xxvpt} +\let\Huge=\huge +\fi + +\AtBeginDocument{\normalsize\normalstyle\ps@headings\pagenumbering{arabic}} + +% ************************************************************************** +% ***** List Definition ************************************************ +% ************************************************************************** +%% Change aspect of lists with +%% 1) \itemindent, label indentation wrt to left list margin +%% 2) \leftmargini, the indentation of the whole list (on left, first level) +\ifev@l + \itemindent -1em + \leftmargini 2em + \leftmarginii 1em + \leftmarginiii 1.5em + \leftmarginiv 1.5em + \leftmarginv 1.0em + \leftmarginvi 1.0em +\else + \itemindent -1em + \leftmargini 3em + \leftmarginii 3em + \leftmarginiii 3em + \leftmarginiv 3em + \leftmarginv 3em + \leftmarginvi 3em +\fi +%\itemindent 2em % Alternative values: sometimes used.. +%\leftmargini 0em +\labelsep 5pt +\leftmargin\leftmargini +\labelwidth \z@ + +\def\@listI{\leftmargin\leftmargini} \@listI +\def\@listi{\leftmargin\leftmargini \topsep \z@ plus 1pt minus 1pt} +\def\@listii{\leftmargin\leftmarginii\labelwidth\leftmarginii + \advance\labelwidth-\labelsep \topsep \z@} +\def\@listiii{\leftmargin\leftmarginiii\labelwidth\leftmarginiii + \advance\labelwidth-\labelsep \topsep \z@} +\def\@listiv{\leftmargin\leftmarginiv\labelwidth\leftmarginiv + \advance\labelwidth-\labelsep \topsep \z@} +\def\@listv{\leftmargin\leftmarginv\labelwidth\leftmarginv + \advance\labelwidth-\labelsep \topsep \z@} +\def\@listvi{\leftmargin\leftmarginvi\labelwidth\leftmarginvi + \advance\labelwidth-\labelsep \topsep \z@} + +\def\labelenumi{\theenumi.} \def\theenumi{\arabic{enumi}} +\def\labelenumii{(\theenumii)} \def\theenumii{\alph{enumii}} +\def\labelenumiii{\theenumiii.} \def\theenumiii{\roman{enumiii}} +\def\labelenumiv{\theenumiv.} \def\theenumiv{\Alph{enumiv}} +\def\p@enumii{\theenumi} +\def\p@enumiii{\theenumi(\theenumii)} +\def\p@enumiv{\p@enumiii\theenumiii} + +\def\labelitemi{$\scriptstyle\bullet$} +\def\labelitemii{\bf --} +\def\labelitemiii{$\ast$} +\def\labelitemiv{$\cdot$} + +%% \itemindent is set to \z@ by list, so define new temporary variable +\newdimen\tmpitemindent +\def\verse{\let\\=\@centercr + \list{}{\itemsep\z@ \itemindent -1.5em \listparindent \itemindent + \rightmargin\leftmargin\advance\leftmargin 1.5em}\item[]} +\let\endverse\endlist +\def\quotation{\list{}{\listparindent 1.5em \itemindent\listparindent + \rightmargin\leftmargin \parsep 0pt plus 1pt}\item[]} +\let\endquotation=\endlist +\def\quote{\list{}{\rightmargin\leftmargin}\item[]} +\let\endquote=\endlist +\def\@mklab#1{#1} +\def\description{\tmpitemindent\itemindent\list{}{\itemindent\tmpitemindent + \labelwidth\z@\def\makelabel##1{\hspace\labelsep\emph{##1}}}} +\def\enddescription{\endlist\par} +\def\enumerate{\tmpitemindent\itemindent\ifnum \@enumdepth >3 \@toodeep\else + \advance\@enumdepth \@ne \edef\@enumctr{enum\romannumeral\the\@enumdepth}% + \list{\csname label\@enumctr\endcsname}{\itemindent\tmpitemindent + \usecounter{\@enumctr}\def\makelabel##1{\hspace\labelsep\hfil{##1}}}\fi} +\def\endenumerate{\endlist\par} +\def\itemize{\tmpitemindent\itemindent\ifnum \@itemdepth >3 \@toodeep\else + \advance\@itemdepth\@ne + \edef\@itemitem{labelitem\romannumeral\the\@itemdepth}% + \list{\csname\@itemitem\endcsname}{\itemindent\tmpitemindent + \def\makelabel##1{\hspace\labelsep\hfil\emph{##1}}}\fi} +\def\enditemize{\endlist\par} + +\newif\if@restonecol +\def\titlepage{\@restonecolfalse\if@twocolumn\@restonecoltrue\onecolumn + \else \newpage \fi \thispagestyle{coverpagestyle}\c@page\z@} +\def\endtitlepage{\if@restonecol\twocolumn \else \newpage \fi% +\if@twoside\mbox{}\thispagestyle{coverpagestyle}\c@page\z@\cleardoublepage\fi} + +\arraycolsep 5pt +\tabcolsep 6pt +\arrayrulewidth .4pt +\doublerulesep 2pt +\tabbingsep\labelsep + +% ************************************************************************** +% ***** Footnote Definition ******************************************** +% ************************************************************************** +\skip\footins 10pt plus 5pt minus 2pt +\footnotesep 7pt +\footskip 6mm +\skip\@mpfootins = \skip\footins +\fboxsep = 3pt \fboxrule = .4pt +\long\def\@makefntext#1{\parindent .8em\indent$^{\@thefnmark}$#1} +\def\footnoterule{} + +% Reset baselinestretch within footnotes. +% Originally stolen from Stanford University thesis style. +% -------------------------------------------------------- +\long\def\@footnotetext#1{\insert\footins{\blsone% + \footnotesize\interlinepenalty\interfootnotelinepenalty + \splittopskip\footnotesep + \splitmaxdepth \dp\strutbox \floatingpenalty \@MM + \hsize\columnwidth \@parboxrestore + \edef\@currentlabel{\csname p@footnote\endcsname\@thefnmark}\@makefntext + \let\par\\ + {\rule{\z@}{\footnotesep}\ignorespaces + #1\strut}}} + +% ************************************************************************** +% ***** Keep track of Sections ***************************************** +% ************************************************************************** +\if@technote + \setcounter{secnumdepth}{3} +\else + \setcounter{secnumdepth}{4} +\fi + +\def\thesection{\@Roman\c@section} +\def\thesubsection{\Alph{subsection}} +\def\thesubsubsection{\thesubsection.\arabic{subsubsection}} +\def\thesubsubsectiondis{\Alph{subsection}.\arabic{subsubsection}} +\def\theparagraph{\thesubsubsection.\alph{paragraph}} +\def\theparagraphdis{\thesubsubsectiondis.\alph{paragraph}} + +\def\theequation{\arabic{equation}} + +% ************************************************************************** +% ***** Table of Contents, List of Figures/Tables Definitions ********** +% ************************************************************************** +\def\@pnumwidth{1.55em} +\def\@tocrmarg {2.55em} +\def\@dotsep{4.5} +\setcounter{tocdepth}{3} + +\def\tableofcontents{\section*{\contentsname}\@starttoc{toc}} +\def\l@section#1#2{\addpenalty{\@secpenalty} \addvspace{1.0em plus 1pt} + \@tempdima 1.8em \begingroup \parindent \z@ \rightskip \@pnumwidth + \parfillskip-\@pnumwidth \bf\leavevmode #1\hfil\hbox to\@pnumwidth{\hss #2} + \par \endgroup} +\def\l@subsection{\@dottedtocline{2}{1.5em}{2.3em}} +\def\l@subsubsection{\@dottedtocline{3}{3.8em}{3.2em}} +\def\listoffigures{\section*{\listfigurename}\@starttoc{lof}} +\def\l@figure{\@dottedtocline{1}{1em}{1.8em}} +\def\listoftables{\section*{\listtablename}\@starttoc{lot}} +\let\l@table\l@figure + +% ************************************************************************** +% ***** Float Definitions ********************************************** +% ************************************************************************** +%% Normal Floats %% Double Column Floats +\floatsep 12pt plus 2pt minus 2pt \dblfloatsep 12pt plus 2pt minus 2pt +\textfloatsep 20pt plus 2pt minus 4pt \dbltextfloatsep 20pt plus 2pt minus 4pt +%\@maxsep 20pt \@dblmaxsep 20pt %!PN +\@fptop 0pt plus 1fil \@dblfptop 0pt plus 1fil +\@fpsep 8pt plus 2fil \@dblfpsep 8pt plus 2fil +\@fpbot 0pt plus 1fil \@dblfpbot 0pt plus 1fil +\def\topfraction{1.0} \def\dbltopfraction{1.0} +\def\floatpagefraction{0.8} \def\dblfloatpagefraction{0.8} +\setcounter{topnumber}{2} \setcounter{dbltopnumber}{4} +% +\intextsep 12pt plus 2pt minus 2pt +\setcounter{bottomnumber}{2} +\def\bottomfraction{.4} +\setcounter{totalnumber}{4} +\def\textfraction{.2} + +% Reset baselinestretch within floats. +% Originally stolen from Stanford University thesis style. +% -------------------------------------------------------- +\def\@xfloat#1[#2]{\ifhmode \@bsphack\@floatpenalty -\@Mii\else + \@floatpenalty-\@Miii\fi\def\@captype{#1}\ifinner + \@parmoderr\@floatpenalty\z@ + \else\@next\@currbox\@freelist{\@tempcnta\csname ftype@#1\endcsname + \multiply\@tempcnta\@xxxii\advance\@tempcnta\sixt@@n + \@tfor \@tempa :=#2\do + {\if\@tempa h\advance\@tempcnta \@ne\fi + \if\@tempa t\advance\@tempcnta \tw@\fi + \if\@tempa b\advance\@tempcnta 4\relax\fi + \if\@tempa p\advance\@tempcnta 8\relax\fi + }\global\count\@currbox\@tempcnta}\@fltovf\fi + \global\setbox\@currbox\vbox\bgroup + \def\baselinestretch{1}\small\normalsize + \hsize\columnwidth \@parboxrestore} + +% ************************************************************************** +% ***** Caption Definition ********************************************* +% ************************************************************************** +% some journals do not have centered captions for figures. +\newif\ifc@ptionleft \c@ptionlefttrue +\def\leftfigcaptions{\c@ptionlefttrue} +\def\centerfigcaptions{\c@ptionleftfalse} + +\long\def\caption{\refstepcounter\@captype \@dblarg{\@caption\@captype}} + +\long\def\@caption#1[#2]#3{\par\addcontentsline{\csname ext@#1\endcsname}{#1}{% + \protect\numberline{\csname the#1\endcsname}{\ignorespaces #2}} + \begingroup \@parboxrestore \normalsize + \@makecaption{\csname fnum@#1\endcsname}{\ignorespaces #3}{#1}\par + \endgroup} + +\def\tablestring{table} +\def\figurestring{figure} + +% changed by GLP to allow table captions to be set to a specific maximum +% width "\captionwidth", if defined. +\newlength{\captionindent} +\long\def\@makecaption#1#2#3{ +\ifx\figurestring#3 + \vskip 5pt + \setbox\@tempboxa\hbox{\small #1.~ #2} + \ifdim \wd\@tempboxa >\hsize + \setbox\@tempboxa\hbox{\small #1.~ } + %\setlength\captionindent{\wd\@tempboxa} \divide\captionindent by 2 + %\parbox[t]{\hsize}{\small \hangindent \captionindent \hangafter=1% + \parbox[t]{\hsize}{\small + \unhbox\@tempboxa#2} + \else \hbox + to\hsize{\small\ifc@ptionleft\else\hfil\fi\box\@tempboxa\hfil} + \fi +\else + \begin{center} + \ifx\captionwidth\undefined {\small #1}\\{\small\scshape #2} + \else + \begin{minipage}{\captionwidth} + \begin{center}{\small #1}\\{\small\scshape #2}\end{center} + \end{minipage} + \fi + \end{center}\vskip 4pt +\fi} + +\def\thefigure{\@arabic\c@figure} +\def\fps@figure{tbp} +\def\ftype@figure{1} +\def\ext@figure{lof} +\def\fnum@figure{\figurename\ \thefigure} +%\def\figure{\@float{figure}} % GLP +%\let\endfigure\end@float +\@namedef{figure*}{\@dblfloat{figure}} +\@namedef{endfigure*}{\end@dblfloat} + +\def\thetable{\@Roman\c@table} +\def\fps@table{tbp} +\def\ftype@table{2} +\def\ext@table{lot} +\def\fnum@table{TABLE~\thetable} +\def\table{\@float{table}} +\let\endtable\end@float +\@namedef{table*}{\@dblfloat{table}} +\@namedef{endtable*}{\end@dblfloat} + +% ************************************************************************** +% ***** Header/Footer Definition *************************************** +% ************************************************************************** +% compute the time in hours and minutes; make new vars \timehh and \timemm +\newcount\timehh\newcount\timemm\timehh=\time\divide\timehh by 60 +\timemm=\time\count255=\timehh\multiply\count255 by-60 +\advance\timemm by \count255 +\ifnum\timehh=12\def\apm{pm}\else +\ifnum\timehh>12\def\apm{pm}\advance\timehh by-12\else +\def\apm{am}\fi\fi +\def\t@me{\number\timehh\,:\,\ifnum\timemm<10 0\fi\number\timemm\,\apm} + +% default definitions +% ------------------- +\def\theevenhe@d{\footnotesize\thepage \hfil \leftmark\hbox{}} +\def\theoddhe@d{\hbox{}\footnotesize\rightmark \hfil \thepage} +\def\theevenf@@t{} +\def\theoddf@@t{} + +\def\theeventphe@d{\footnotesize\thepage \hfil \hbox{}} +\def\theoddtphe@d{\hbox{}\footnotesize \hfil \thepage} +\def\theeventpf@@t{} +\def\theoddtpf@@t{} + +\def\theevencphe@d{} +\def\theoddcphe@d{} +\def\theevencpf@@t{} +\def\theoddcpf@@t{} + +\def\internalmsg{Preliminary version for evaluation: Please do not + circulate without the permission of the author(s)} +\def\submittedmsg{SUBMITTED FOR PUBLICATION TO:} +\def\acceptedmsg{ACCEPTED FOR PUBLICATION:} +\def\inpressmsg{(IN PRESS)} +\def\reprintmsg{REPRINTED FROM:} + +% default cover page style (optional cover page) +% ---------------------------------------------- +\def\ps@coverpagestyle{ + \def\@oddhead{\theoddcphe@d} \def\@evenhead{\theevencphe@d} + \def\@oddfoot{\theoddcpf@@t} \def\@evenfoot{\theevencpf@@t} +} + +% default title page style (first page of paper) +% ---------------------------------------------- +\def\ps@titlepagestyle{ + \def\@oddhead{\theoddtphe@d} \def\@evenhead{\theeventphe@d} + \def\@oddfoot{\theoddtpf@@t} \def\@evenfoot{\theeventpf@@t} +} + +% default regular page style +% -------------------------- +\if@twoside + \def\ps@headings{ + \def\@oddhead{\theoddhe@d} + \def\@evenhead{\theevenhe@d} + \def\@oddfoot{\theoddf@@t} \def\@evenfoot{\theevenf@@t} + } +\else + \def\ps@headings{ + \def\@oddhead{\theoddhe@d} + \def\@oddfoot{\theoddf@@t} + \def\@evenhead{} \def\@evenfoot{} + } +\fi + +% For draft mode (no sub-modes allowed) +% ------------------------------------- +\ifdr@ft + \def\leftmark{\sh@rttitle}\let\rightmark\leftmark + \def\theoddf@@t{\footnotesize\today---\t@me\hfil DRAFT} + \def\theevenf@@t{\footnotesize DRAFT\hfil\today---\t@me} + \def\theoddtpf@@t{\footnotesize\today---\t@me\hfil DRAFT} + \def\theeventpf@@t{\footnotesize DRAFT\hfil\today---\t@me} +\fi + +% For submission mode (default plus internal sub-modes allowed) +% ------------------------------------------------------------- +\ifsubm@t + \def\leftmark{\sh@rttitle}\def\rightmark{\titl@line} + \ifintern@l + \def\theeventphe@d{\footnotesize\thepage \hfil \rightmark\hbox{}} + \def\theoddtphe@d{\hbox{}\footnotesize\rightmark \hfil \thepage} + \def\rightmark{\vbox to 0pt{\vss\hbox{\internalmsg} \hbox{\sh@rttitle}}} + \def\leftmark{\vbox to 0pt{\vss\hbox{\internalmsg} + \hbox{\phantom{\internalmsg}\llap{\sh@rttitle}}}} + \else % put date on first page. + \edef\TODAY{\uppercase{\today}} + \def\theeventphe@d{\footnotesize\thepage \hfil \submittedmsg\ + \@journal\@titletext, \TODAY} + \def\theoddtphe@d{\footnotesize\submittedmsg\ + \@journal\@titletext, \TODAY\hfil \thepage} + \def\theevencphe@d{\footnotesize\hbox{} \hfil \submittedmsg\ + \@journal\@titletext, \TODAY} + \def\theoddcphe@d{\footnotesize\submittedmsg\ + \@journal\@titletext, \TODAY\hfil \hbox{}} + \fi +\fi + +% For compressed mode (default, internal, submitted and +% inpress sub-modes allowed) +% ----------------------------------------------------- +\ifc@mpress + \def\leftmark{\sh@rttitle}\def\rightmark{\titl@line} + \ifintern@l + \def\theeventphe@d{\footnotesize\thepage \hfil \rightmark\hbox{}} + \def\theoddtphe@d{\hbox{}\footnotesize\rightmark \hfil \thepage} + \def\rightmark{\vbox to 0pt{\vss\hbox{\internalmsg} \hbox{\sh@rttitle}}} + \def\leftmark{\vbox to 0pt{\vss\hbox{\internalmsg} + \hbox{\phantom{\internalmsg}\llap{\sh@rttitle}}}} + \fi + \ifprepr@nt + \edef\TODAY{\uppercase{\today}} + \def\theeventphe@d{\footnotesize\thepage \hfil \submittedmsg\ + \@journal\@titletext, \TODAY} + \def\theoddtphe@d{\footnotesize\submittedmsg\ + \@journal\@titletext, \TODAY\hfil \thepage} + \def\theevencphe@d{\footnotesize\hbox{} \hfil \submittedmsg\ + \@journal\@titletext, \TODAY} + \def\theoddcphe@d{\footnotesize\submittedmsg\ + \@journal\@titletext, \TODAY\hfil \hbox{}} + \fi + \ifinpr@ss + \def\leftmark{\acceptedmsg\ \@journal\@titletext, \inpressmsg} + \def\theeventphe@d{\footnotesize\thepage \hfil \leftmark\hbox{}} + \def\theoddtphe@d{\hbox{}\footnotesize\leftmark \hfil \thepage} + \fi +\fi + +% For final (evaluate) mode (default, techreport, internal, +% submitted, inpress and reprint sub-modes allowed) +% --------------------------------------------------------- +\ifev@l + \edef\TODAY{\uppercase{\today}} + \def\leftmark{\@journal\@titletext}\def\rightmark{\titl@line} + \def\theeventphe@d{\footnotesize\thepage \hfil \leftmark\hbox{}} + \def\theoddtphe@d{\hbox{}\footnotesize\leftmark \hfil \thepage} + \if@technote % make header a little bigger + \def\theevenhe@d{\small\thepage \hfil \leftmark\hbox{}} + \def\theoddhe@d{\hbox{}\small\rightmark \hfil \thepage} + \def\theeventphe@d{\small\thepage \hfil \leftmark\hbox{}} + \def\theoddtphe@d{\hbox{}\small\leftmark \hfil \thepage} + \fi + \ifintern@l + \def\theeventphe@d{\footnotesize\thepage \hfil \rightmark\hbox{}} + \def\theoddtphe@d{\hbox{}\footnotesize\rightmark \hfil \thepage} + \def\rightmark{\vbox to 0pt{\vss\hbox{\internalmsg} \hbox{\sh@rttitle}}} + \def\leftmark{\vbox to 0pt{\vss\hbox{\internalmsg} + \hbox{\phantom{\internalmsg}\llap{\sh@rttitle}}}} + \fi + \ifprepr@nt + \def\leftmark{\submittedmsg\ \@journal\@titletext, \TODAY} + \fi + \ifinpr@ss + \def\leftmark{\acceptedmsg\ \@journal\@titletext, \inpressmsg} + \fi + \ifrepr@nt + % reset page size on second and following pages b/c no copyright info + \let\oldshipout\shipout + \gdef\shipout{\global\textheight 243.5mm\oldshipout} + \def\theeventpf@@t{\footnotesize\hfil\@ieeecopyright\hfil} + \def\theoddtpf@@t{\footnotesize\hfil\@ieeecopyright\hfil} + \def\leftmark{\reprintmsg\ \@journal\@titletext} + \fi +\fi + +%% Defines the command for putting the header. footernote{TEXT} is the same +%% as markboth{TEXT}{TEXT}. Here for compatibility with other style files. +\def\markboth#1#2{\def\leftmark{#1}\def\rightmark{#2}} +\def\footernote#1{\markboth{#1}{#1}} + +% ************************************************************************** +% ***** Citation/Bibliography Definitions ****************************** +% ************************************************************************** +%% separate citations with "], [" +\def\@citex[#1]#2{\if@filesw\immediate\write\@auxout{\string\citation{#2}}\fi +\def\@citea{}\@cite{\@for\@citeb:=#2\do {\@citea\def\@citea{], +[}\@ifundefined {b@\@citeb}{{\bf ?}\@warning {Citation `\@citeb' on +page \thepage \space undefined}}% +{\csname b@\@citeb\endcsname}}}{#1}} + +\def\@cite#1#2{[{#1\if@tempswa, #2\fi}]} + +%% Allow short (name-less) citations, when used in conjunction with a +%% bibliography style that creates labels like \citename{, } +\let\@internalcite\cite +\def\cite{\def\citename##1{##1}\@internalcite} +\def\shortcite{\def\citename##1{}\@internalcite} +\def\@biblabel#1{\def\citename##1{##1}[#1]\hfill} + +\def\thebibliography#1{\section*{\refname}\footnotesize\list + {\hss[\arabic{enumi}]}{\settowidth\labelwidth{[#1]}\leftmargin\labelwidth + \advance\leftmargin\labelsep \itemsep 0pt plus .5pt + \usecounter{enumi}} + \def\newblock{\hskip .11em plus .33em minus .07em} + \sloppy\clubpenalty4000\widowpenalty4000 + \sfcode`\.=1000\relax + \ifev@l\else\normalsize\fi %added by GLP +} +\let\endthebibliography=\endlist + +% ************************************************************************** +% ***** Appendix/Appendices Definitions ******************************** +% ************************************************************************** +\newcounter{numappendices}\setcounter{numappendices}{0} +\newif\ifappendix \appendixfalse +%% appendix command for one single appendix +\def\appendix{\par + \appendixtrue + \typeout{appendices: \arabic{numappendices}} + \setcounter{section}{0}\setcounter{subsection}{0} + \gdef\thesection{\Alph{section}} + \ifnum \value{numappendices}>1 + \section*{\appendicesname} + \else + \section*{\appendixname} + \fi + \setcounter{numappendices}{0} +} +%% appendices command for multiple appendicies +\def\appendices{\par + \appendixtrue + \typeout{appendices: \arabic{numappendices}} + \setcounter{section}{0}\setcounter{subsection}{0} + \gdef\thesection{\Alph{section}} \section*{\appendicesname} + \setcounter{numappendices}{0} +} +\AtEndDocument{\if@filesw\immediate\write\@auxout{\string\setcounter{numappendices}{\arabic{numappendices}}}\fi} + +% ************************************************************************** +% ***** Title Definitions ********************************************** +% ************************************************************************** +\def\titl@line{\sh@rttitle} %for the header at the top of the page. + +\def\@title{\typeout{ieee: Warning! No \noexpand\title given!}} +\def\title{\@ifnextchar [{\titlea}{\titleb}}%] + +\def\set@title#1{\gdef\@title{#1}\global\def\set@title##1{}} +\def\setsh@rttitle#1{\gdef\sh@rttitle{#1}\global\def\setsh@rttitle##1{}} +\def\titlea[#1]#2{\set@title{#2}\setsh@rttitle{\uppercase{#1}}} +\def\titleb#1{\set@title{#1}\setsh@rttitle{\uppercase{#1}}} + +\def\authorinfo#1{\let\\\relax\thanks{#1}} + +\ifev@l + \if@technote + \def\member#1{} + \else + \def\member#1{, \emph{#1, IEEE}} + \fi +\else + \def\member#1{} +\fi + +\def\and{\unskip% % \begin{tabular} +\end{tabular}% +\hskip 0pt plus 0.1pt% +\begin{tabular}[t]{@{}c@{}}\ }% + +\def\@author{\typeout{ieee: Warning! No \noexpand\author given!}} +\def\author{\@ifnextchar [{\authora}{\authorb}}%] +\def\set@author#1{\gdef\@author{#1}\global\def\set@author##1{}} +\def\settitl@line#1{\gdef\titl@line{#1}\global\def\settitl@line##1{}} +\def\authora[#1]#2{\set@author{#2}\if@non\else\settitl@line{#1: \sh@rttitle}\fi} +\def\authorb#1{\set@author{#1}} + +\def\date#1{\def\today{#1}\edef\TODAY{\uppercase{\today}}} + +\long\def\maketitle{% + \begingroup + \let\@thanks\@empty + \renewcommand\thefootnote{} % the \thanks{} mark type is empty + \iftitlep@ge\begin{titlepage}\@maketitlepage\@thanks\end{titlepage}% + \let\@thanks\@empty\fi + \thispagestyle{titlepagestyle} + \if@twocolumn + \if@technote + %\if@twoside\newpage\cleardoublepage\else\newpage\fi% + \newpage\global\@topnum\z@ + \ifrepr@nt + \ifx\@loginfo\undefined\typeout{ieee: Warning! No \noexpand\loginfo + given!}\else\let\\\relax\thanks{\@loginfo}\fi% + \fi + \@maketitle + \else + \ifnum \col@number=\@ne + \ifrepr@nt + \ifx\@loginfo\undefined\typeout{ieee: Warning! No \noexpand\loginfo + given!}\else\let\\\relax\thanks{\@loginfo}\fi% + \fi + \@maketitle + \else \twocolumn[% + \ifrepr@nt% + \ifx\@loginfo\undefined\typeout{ieee: Warning! No \noexpand\loginfo% + given!}\else\let\\\relax\thanks{\@loginfo}\fi% + \fi% + \@maketitle]% + \fi + \fi + \else + \newpage + \global\@topnum\z@ % Prevents figures from going at top of page. + \ifrepr@nt + \ifx\@loginfo\undefined\typeout{ieee: Warning! No \noexpand\loginfo + given!}\else\let\\\relax\thanks{\@loginfo}\fi + \fi + \@maketitle + \fi + \thispagestyle{titlepagestyle}% + \@thanks + \endgroup + \setcounter{footnote}{0}% + \global\let\thanks\relax \global\let\maketitle\relax + \global\let\@maketitle\relax \global\let\@thanks\@empty + \global\let\@author\@empty \global\let\@date\@empty + \global\let\@title\@empty \global\let\title\relax + \global\let\author\relax \global\let\date\relax + \global\let\and\relax +} + +\long\def\@maketitle{\unskip\newpage% + \begin{center}\blsone + \let \footnote \thanks + \if@technote + {\bfseries\@title\par}\if@non\else\vskip 1.3em{\lineskip .5em + \noindent\begin{tabular}[t]{@{}c@{}}\@author\end{tabular}}\fi\par + \else\unskip + \noindent{\Huge\@title\par}% + \if@non\else\vskip1.0em% + \noindent{\large\lineskip .5em% + \begin{tabular}[t]{@{}c@{}}\@author\end{tabular}}% + \fi\par% + \if@nvited\vskip1.0em\noindent\emph{\large(Invited Paper)}\par\fi + \fi + \ifrepr@nt + \ifx\@lognumber\undefined\typeout{ieee: Warning! No + \noexpand\pubitemident or \noexpand\lognumber + given!}\else\thanks{\@lognumber}\fi% + \fi + \end{center}\par\vskip 0.5em}% + +\long\def\@maketitlepage{\newpage% + \mbox{}\vfil + \begin{center}\blsone + \let \footnote \thanks + \if@technote + {\bfseries\@title\par}\vskip 1.3em{\lineskip .5em + \noindent\begin{tabular}[t]{@{}c@{}}\@author\end{tabular}\par} + \else + \vskip0.2em{\Huge\@title\par}\vskip1.0em% + \iftitlep@ge\vfil\fi + \noindent{\large\lineskip .5em% + \begin{tabular}[t]{@{}c@{}}\@author\end{tabular}\par}% + \fi + \end{center}\par\vfil\mbox{}} + +\def\@journal{\typeout{ieee: Warning! No \noexpand\journal given!}} +\def\journal#1{\def\@journal{\uppercase{#1}}} + +\def\@ieeecopyright{\typeout{ieee: Warning! No \noexpand\ieeecopyright given!}} +\def\ieeecopyright#1{\def\@ieeecopyright{#1}} + +\def\lognumber#1{\def\@lognumber{IEEE Log Number #1.}} +\def\pubitemident#1{\def\@lognumber{Publisher Item Identifier #1.}} +\long\def\loginfo#1{\long\def\@loginfo{\hbox{\vrule height 3ex width \z@}#1}} + +\def\sh@rttitle{} +\def\@titletext{} +\def\titletext#1{\def\@titletext{#1}} + +\def\firstpage#1{\setcounter{page}{#1}} + +% ************************************************************************** +% ***** Abstract Definition ******************************************** +% ************************************************************************** +\def\abstract{% + \if@twocolumn + \small\bfseries{\itshape\abstractname\/---}% + \else + \begin{center}\vspace{-0.8em}\small\bf\abstractname\end{center} + \quotation\small + \fi\ignorespaces} +\def\endabstract{\vspace{0.6em}\par\if@twocolumn\else\endquotation\fi + \normalsize\normalstyle} + +% ************************************************************************** +% ***** Keywords Definition ******************************************** +% ************************************************************************** +\def\keywords{\vspace{-.3em} + \if@twocolumn + \small\bfseries{\itshape\keywordsname\/---}% + \else + \begin{center}\small\bf\keywordsname\end{center}\quotation\small + \fi\ignorespaces} +\def\endkeywords{\vspace{0.6em}\par\if@twocolumn\else\endquotation\fi + \normalsize\normalstyle} + +% ************************************************************************** +% ***** Fix Section Numbering ****************************************** +% ************************************************************************** +\gdef\@punct{.\ \ } % Punctuation after run-in section heading +\def\@sect#1#2#3#4#5#6[#7]#8{% + \ifnum #2>\c@secnumdepth + \def\@svsec\@empty + \else + \refstepcounter{#1}% + \protected@edef\@svsec{% + %\ifnum #2=1\Roman{#1}.\fi\ifnum #2=2\Alph{#1}.\fi + \ifnum #2=1\thesection.\fi + \ifnum #2=2\thesubsection.\fi + \ifnum #2>2{\csname the#1dis\endcsname}\if@technote.\fi\fi \hskip .5em} + \ifnum #2=1\ifappendix\stepcounter{numappendices}\fi\fi + \fi + \@tempskipa #5\relax + \ifdim \@tempskipa>\z@ + \begingroup #6\relax + \@hangfrom{\hskip #3\relax\@svsec}{\interlinepenalty \@M #8\par} + \endgroup + \csname #1mark\endcsname{#7} + \addcontentsline{toc}{#1}{\ifnum #2>\c@secnumdepth\else + \protect\numberline{\csname the#1\endcsname}\fi#7} + \else + \def\@svsechd{#6\hskip #3\@svsec #8\@punct\csname #1mark\endcsname{#7} + \addcontentsline{toc}{#1}{\ifnum #2>\c@secnumdepth \else + \protect\numberline{\csname the#1\endcsname}\fi#7}} + \fi + \@xsect{#5}} + +\def\@ssect#1#2#3#4#5{\@tempskipa #3\relax + \ifdim \@tempskipa>\z@ + \begingroup #4\@hangfrom{\hskip #1}{\interlinepenalty \@M #5\par}\endgroup + \else \def\@svsechd{#4\hskip #1\relax #5\@punct}\fi + \@xsect{#3}} + +% ************************************************************************** +% ***** Section Definitions ******************************************** +% ************************************************************************** +\def\section{\@startsection{section}{1}{\z@}{2.0ex plus .5ex + minus .2ex}{1.0ex plus .2ex}{\centering\scshape}} +\def\subsection{\@startsection{subsection}{2}{\z@}{2.0ex plus .5ex + minus .2ex}{1.0ex plus .2ex}{\itshape}} +\if@technote + \def\subsubsection{\@startsection{subsubsection}{3}{\z@}{2.0ex plus .5ex + minus .1ex}{0pt}{\itshape}} +\else + \def\subsubsection{\@startsection{subsubsection}{3}{\z@}{2.0ex plus .5ex + minus .2ex}{1.0ex plus .2ex}{\normalstyle}} + \def\paragraph{\@startsection{paragraph}{4}{\z@}{1.0ex plus .5ex + minus .2ex}{0ex}{\normalstyle}} +\fi + +% ************************************************************************** +% ***** Special Environment Definitions ******************************** +% ************************************************************************** +\def\QED{\mbox{\rule[0pt]{1.5ex}{1.5ex}}} +\def\proof{\noindent\hspace{1em}{\it Proof: }} +\def\endproof{\hspace*{\fill}~\QED\par\endtrivlist\unskip} +\def\@begintheorem#1#2{\tmpitemindent\itemindent\topsep 0pt\normalstyle\trivlist + \item[\hskip \labelsep{\indent\it #1\ #2:}]\itemindent\tmpitemindent} +\def\@opargbegintheorem#1#2#3{\tmpitemindent\itemindent\topsep 0pt\normalstyle \trivlist + \item[\hskip\labelsep{\indent\it #1\ #2\ \normalstyle(#3)}]\itemindent\tmpitemindent} +\def\@endtheorem{\endtrivlist\unskip} + +% ************************************************************************** +% ***** Special Environment Definitions ******************************** +% ************************************************************************** +\if@twoside\else\raggedbottom\fi + +%% Definition for Big letter at the beginning of a paragraph +%% +\def\PARstart#1#2 {\begingroup\def\par{\endgraf\endgroup\lineskiplimit=0pt} + \setbox2=\hbox{\uppercase{#2} }\newdimen\tmpht \tmpht \ht2 + \advance\tmpht by \baselineskip\font\hhuge=cmr10 at \tmpht + \setbox1=\hbox{{\hhuge #1}} + \count7=\tmpht \count8=\ht1\divide\count8 by 1000 \divide\count7 by\count8 + \tmpht=.001\tmpht\multiply\tmpht by \count7\font\hhuge=cmr10 at \tmpht + \setbox1=\hbox{{\hhuge #1}} \noindent \hangindent1.05\wd1 + \hangafter=-2 {\hskip-\hangindent \lower1\ht1\hbox{\raise1.0\ht2\copy1}% + \kern-0\wd1}\copy2\lineskiplimit=-1000pt} + +\def\PARstartCal#1#2 {\begingroup\def\par{\endgraf\endgroup\lineskiplimit=0pt} + \setbox2=\hbox{\uppercase{#2} }\newdimen\tmpht \tmpht \ht2 + \advance\tmpht by \baselineskip\font\hhuge=cmsy10 at \tmpht + \setbox1=\hbox{{\hhuge #1\/}} + \count7=\tmpht \count8=\ht1\divide\count8 by 1000 \divide\count7 by\count8 + \tmpht=.001\tmpht\multiply\tmpht by \count7\font\hhuge=cmsy10 at \tmpht + \setbox1=\hbox{{\hhuge #1\/}} \noindent \hangindent1.05\wd1 + \hangafter=-2 {\hskip-\hangindent \lower1\ht1\hbox{\raise1.0\ht2\copy1}% + \kern-0\wd1}\copy2\lineskiplimit=-1000pt} + +\def\PARstartLyX#1{\PARstart #1} +\def\PARstartCalLyX#1{\PARstartCal #1} + +\if@technote\def\PARstart#1#2{#1#2}\fi % if technical note, disable it +\if@technote\def\PARstartCal#1#2{#1#2}\fi % if technical note, disable it +\if@technote\def\PARstartLyX#1{#1}\fi % if technical note, disable it +\if@technote\def\PARstartCalLyx#1{#1}\fi % if technical note, disable it + +% ************************************************************************** +% ***** Misc. Definitions ********************************************** +% ************************************************************************** +%Restore single spacing +\newcommand{\blsone}{\renewcommand\baselinestretch{1}% + \renewcommand\arraystretch{1.2}\setlength{\parindent}{\parindentsave}% + \normalsize} +\newcommand{\capitem}[1]{{\hspace{0.2ex}(#1)}~} +\newcommand{\insdate}{} + +% ************************************************************************** +% ***** MATH Definitions *********************************************** +% ************************************************************************** +\def\eqnarray{% + \stepcounter{equation}% + \def\@currentlabel{\p@equation\theequation}% + \global\@eqnswtrue + \m@th + \global\@eqcnt\z@ + \tabskip\@centering + \let\\\@eqncr + $$\everycr{}\halign to\displaywidth\bgroup + \hskip\@centering$\displaystyle\tabskip\z@skip{##}$\@eqnsel + &\global\@eqcnt\@ne\hskip \eqnarr@ysep\hfil${##}$\hfil + &\global\@eqcnt\tw@ \hskip \eqnarr@ysep + $\displaystyle{##}$\hfil\tabskip\@centering + &\global\@eqcnt\thr@@ \hb@xt@\z@\bgroup\hss##\egroup + \tabskip\z@skip + \cr +} +\def\endeqnarray{% + \@@eqncr + \egroup + \global\advance\c@equation\m@ne + $$\@ignoretrue +} + +% ************************************************************************** +% ***** Biography Definitions ****************************************** +% ************************************************************************** +% This is the main code for the biography environment of the IEEE +% transactions class. The previous biography code had some known +% problems which were difficult to fix. The crux of the issue was that +% the photo frame was overlaid by text when \baselinestretch>1 or when +% the biography consisted of multiple short paragraphs. +% +% The fix was done by extracting code from the excellent package: +% 'picinpar.sty' version 1.2a as of july 13, 1993 +% by Friedhelm Sowa +% +% (At least most of) The bugs you find in this code were introduced +% unwittingly by myself. +% +%---------------- +% Known problems: +% +% - Don't use multiple blank lines to separate paragraphs. A single +% blank line works well, but multiple blank lines will confuse +% the code. This has something to do with the \def\par{\\\indent} +% line, but I can't think of an appropriate fix. Similarly, make +% sure the environment doesn't end with an extra blank line. +% - Don't use \samepage +% - Use \footnotemark within and \footnotetext outside the +% window-environment instead of \footnote +% - When using the epic-package load picinpar before epic +% like \documentstyle[...,picinpar,epic]{...} +% +% Counts +\newcount\br \newcount\nb \newcount\tcdsav \newcount\tcl \newcount\tcd +\newcount\tcn \newcount\cumtcl +% Dimens +\newdimen\rtside \newdimen\hpic \newdimen\vpic \newdimen\strutilg +\newdimen\picwd \newdimen\topheight \newdimen\ilg \newdimen\lpic +\newdimen\lwindowsep \newdimen\rwindowsep % VK 10 Feb 93 +\lwindowsep0.5\baselineskip % " +\rwindowsep0.5\baselineskip % " +\newdimen\cumpar +% Tokens +\newtoks\twa \newtoks\la \newtoks\ra \newtoks\ha \newtoks\pictoc +% Boxes +\newbox\rawtext \newbox\holder \newbox\windowbox \newbox\wartext +\newbox\finaltext \newbox\aslice \newbox\bslice \newbox\wbox +\newbox\wstrutbox \newbox\picbox \newbox\waslice \newbox\wbslice +\newbox\fslice + % Another strut +\def\wstrut{\relax\ifmmode\copy\wstrutbox\else\unhcopy\wstrutbox\fi} +% + +\def\getpic#1{\sbox{\@tempboxa}{\includegraphics{#1}}% +\newcount\tmpcta \tmpcta=\ht\@tempboxa% +\newcount\tmpctb \tmpctb=\wd\@tempboxa% +\divide\tmpctb by 100% +\divide\tmpcta by\tmpctb% +\ifnum\tmpcta>133% +\typeout{ieee: Biography picture `#1' too tall.}% +\frame{\hbox to 25mm{\hfil\resizebox{!}{32mm}{\usebox{\@tempboxa}}\hfil}}% +\else \ifnum\tmpcta<123% +\typeout{ieee: Biography picture `#1' too wide.}% +\frame{\vbox to 32mm{\vss\hbox{\resizebox{25mm}{!}{\usebox{\@tempboxa}}}\vss}}% +\else% +\resizebox{25mm}{32mm}{\usebox{\@tempboxa}} +\fi\fi} + +\long\def\biographyLyX#1{\if@non\else\begin{biography} #1\end{biography}\fi} + +\if@non + \long\def\biography{} +\else + \long\def\biography{\@ifnextchar [{\@biographyb}{\@biographya[{\unitlength + 1mm\hbox{\framebox(25,32){}}}]}} +\fi + +\long\def\@biographyb[#1]{\@biographya[\getpic{#1}]} + +\long\def\@biographya[#1]#2{\bgroup +\footnotesize\bigskip\bigskip\bigskip\parskip=0pt\par% +\rule{0pt}{35mm}\vspace*{-35mm}\par% garantees correct page breaking +\begin{main@bio}[{#1}]% +\noindent{\bf #2}% +} +\def\endbiography{\if@non\else\end{main@bio}\egroup\fi} + +\long\def\main@bio[#1]{% #1 is the material for setting a graphic box +\vskip\parskip\everypar{} +\global\cumpar=0pt +\global\cumtcl=0 + \tcd=0 + \rtside=0pt +% \hpic=\linewidth + \twa={} \la={} \ra={} \ha={} +\setbox\wbox=\hbox{(} +\computeilg +\pictoc={#1} +\setbox\windowbox=\vbox{\hbox{#1}} +\picwd=\wd\windowbox +\hpic=\picwd +\vpic=\ht\windowbox\advance\vpic\dp\windowbox +\rtside=\linewidth\advance\rtside-\picwd +\setbox\picbox=\vbox{\hsize=\hpic\vbox to\vpic{\box\windowbox}}% \vfill}}% + +\vpic=\ht\picbox\advance\vpic\dp\picbox +\ifdim\rtside>0pt\advance\rtside-\rwindowsep\fi % " +\global\br=\rtside +\ifnum\picwd=0 +\ifdim\vpic>0pt\picwd=\hpic +\else\vpic=\ht\picbox\advance\vpic\dp\picbox +\fi +\fi + \global\tcl=0 \lpic=0pt + \loop\global\advance\tcl by 1 \lpic=\tcl\baselineskip + \ifdim\lpic<\vpic\repeat + \vpic=\lpic + \global\cumtcl=\tcl +% +% Here we know exactly the number of indented lines and +% are able to generate the tokens for the \parshape list +% + \ifnum\br>0\ra={ 0pt \rtside}\fi + \ifnum\tcd>0\ha={ 0pt \linewidth}\fi + \ifnum\tcl<1\global\tcl=1\fi + \createparshapespec + \tcd=0 % restore the lintel + \global\tcdsav=0 +% +% This is a very tricky part of the package. Some day there +% will exist a detailed documentation. +% +\def\par{\\\indent} +% +% This is where we start to pick up the paragraph(s) +% + \setbox\rawtext=\vbox\bgroup\unvbox\rawtext\unskip + \clubpenalty=0\widowpenalty=0 + \ifnum\brokenpenalty<\maxdimen\else\brokenpenalty=9999\fi + \tolerance=1000 + \parshape=\tcn \the\twa } +% +\def\endmain@bio{% + %\par + \global\tcd=\tcdsav + \egroup\vskip\parskip\parshape=0 % reset parshape; end \box\rawtext + \vbadness=10000 + \splittopskip=0pt +% +% Now we build the boxes beside the window +% +\global\topheight=\tcl\baselineskip +\ifnum\br>0\setbox\holder=\vsplit\rawtext to\topheight\fi +\tcn=\tcl \nb=0 +\ifnum\br>0\nb=\tcn\fi +% +% text on the right side +% +\ifnum\nb>0 + \loop\advance\nb -1 + \setbox\bslice=\vsplit\holder to\baselineskip + \prune\bslice\rtside + \setbox\wbslice=\vbox{\unvbox\wbslice\hbox + to\rtside{\box\bslice\hfil}} + \ifdim\ht\holder>0pt\repeat +\fi +%GLP add fix to make sure bio starts at top of picture +\setbox\wbslice=\vbox to\topheight{\unvbox\wbslice\vfill\vss} +% +% fixing the dimensions of the window part +% +\topheight=\ht\wbslice +% +% ship out the window material to the main vertical list +% +\setbox\windowbox=\vbox{\hbox to\linewidth{% +\vbox to\topheight{\hrule width\picwd height0pt depth0pt\vskip0pt% +\vfill\unvbox\picbox% +\ifnum\picwd>0\vfill\fi% +\vss}\ifnum\br>0\hfill\vbox{\box\wbslice}\fi}}% +% +\unvbox\windowbox% +\loop% lines below picture.... + \setbox\bslice=\vsplit\rawtext to\baselineskip + \prune\bslice\linewidth + \setbox\wbslice=\vbox{\hbox to\linewidth{\box\bslice\hfil}} + \unvbox\wbslice + \ifdim\ht\rawtext>0pt +\repeat +%GLP +%\ifnum\nb>0\topheight=\nb\baselineskip %\advance\topheight by\ilg +%\vspace*{\topheight} +%\fi +}% FINITO +% +% What else do we need? +% +\def\prune#1#2{ +% take a \vbox containing a single \hbox, +% \unvbox it, and cancel the \lastskip +% put in a \hbox of width #2 + \unvbox#1 \setbox#1=\lastbox % \box#1 now is an \hbox + \ifdim\ht#1=\parskip + \setbox#1=\hbox to#2{\vrule height\parskip depth0pt width0pt\hfill} + \else\ifdim\ht#1=0pt\relax + \else\setbox#1=\hbox to#2{\wstrut\unhbox#1\unskip}\fi\fi} +% +% Here the token \twa is generated. +% It's not so difficult as it looks like. +% +\def\createparshapespec{% +\global\tcn=0 +\ifnum\br>0\global\tcn=\tcl\fi +\nb=0 +\ifnum\br>0\nb=\tcn\fi +\global\advance\tcn by\tcd \global\advance\tcn by1 +\ifnum\tcd>0 +\loop\twa=\expandafter{\the\twa\the\ha}\advance\tcd -1 +\ifnum\tcd>0\repeat +\fi +\ifnum\nb>0 +\loop\twa=\expandafter{\the\twa\the\ra}\advance\nb -1 +\ifnum\nb>0\repeat +\fi +\global\twa=\expandafter{\the\twa 0pt \the\linewidth}} +% +\def\computeilg{% compute the interline glue + \tcl=0\ilg=0pt\strutilg=0pt + \loop\setbox\wbox=\hbox{\char\tcl} + \ifdim\ht\wbox>\ilg\ilg=\ht\wbox\fi + \ifdim\dp\wbox>\strutilg\strutilg=\dp\wbox\fi + \advance\tcl by 1 + \ifnum\tcl<128\repeat + \ht\wbox=\ilg + \dp\wbox=\strutilg + \strutilg=\ht\wbox %\advance\strutilg by\ilg + \ifdim\strutilg>\baselineskip + \typeout{character with height greater baselineskip found in font} + \typeout{baselineskip changed to 1.5 of that height!} + \baselineskip=1.5\strutilg + \fi + \global\ilg=\baselineskip + \global\advance\ilg-\ht\wbox \global\advance\ilg-\dp\wbox + \strutilg=\ht\wbox \advance\strutilg by\ilg + \setbox\wstrutbox=\hbox{\vrule height\strutilg depth\dp\wbox width0pt}} + + +% the following code from version.sty by Stephen Bellantoni 1990, loosely +% based on "annotation.sty" by Tom Hofmann. Used to exclude "biography" from +% anonymous mode. +\begingroup +\catcode`@=11\relax% +\catcode`{=12\relax\catcode`}=12\relax% +\catcode`(=1\relax \catcode`)=2\relax% +\gdef\glpinclude#1(% + \expandafter\gdef\csname #1\endcsname% + ()% + \expandafter\gdef\csname end#1\endcsname% + ()% +)% +\gdef\glpexclude#1(% + \expandafter\gdef\csname #1\endcsname% + (\@bsphack\catcode`{=12\relax\catcode`}=12\relax\csname #1@NOTE\endcsname)% + \long\expandafter\gdef\csname #1@NOTE\endcsname ##1\end{#1}% + (\csname #1END@NOTE\endcsname)% + \expandafter\gdef\csname #1END@NOTE\endcsname% + (\@esphack\end(#1))% +)% +\endgroup + +%------- +\def\@confplacedate{\typeout{ieee: Warning! No \noexpand\confplacedate set!} +\bfseries `confplacedate' needs to be set. For example, to: Stanford, CA, USA, +September 29--30, 1991} +\def\confplacedate#1{\def\@confplacedate{#1}} + +%%%%%%%%%%%%%%%%%%%%%%%%% End of ieee.cls %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% diff --git a/cryptominisat/cppsrc/docs/satcomp16-pdf/sigproc.bib b/cryptominisat/cppsrc/docs/satcomp16-pdf/sigproc.bib new file mode 100644 index 00000000..b8fc175a --- /dev/null +++ b/cryptominisat/cppsrc/docs/satcomp16-pdf/sigproc.bib @@ -0,0 +1,2589 @@ +@BOOK{salas:calculus, + AUTHOR = "S.L. Salas and Einar Hille", + TITLE = "Calculus: One and Several Variable", + PUBLISHER = "John Wiley and Sons", + ADDRESS = "New York", + YEAR = "1978" } + +@inproceedings{804350, + author = {Thomas J. Schaefer}, + title = {The complexity of satisfiability problems}, + booktitle = {{STOC}'78}, + year = {1978}, + pages = {216--226}, + location = {San Diego, California, United States}, + doi = {http://doi.acm.org/10.1145/800133.804350}, +} + +Proceedings of the tenth annual ACM symposium on Theory of computing -- +publisher = {ACM Press}, +address = {New York, NY, USA}, + +@inproceedings{smith94phase, + author = "Barbara Smith", + title = "The Phase Transition in Constraint Satisfaction Problems: {A} {CL}oser Look at the Mushy Region", + booktitle = {{ECAI}'94}, + year = "1994" +} + +@inproceedings{swdia, + author = "Chanseok Oh", + title = "{MiniSat HACK 999ED, MiniSat HACK 1430ED and SWDiA5BY}", + booktitle = "SAT Competition 2014 Booklet", + year = "201", +} + +@inproceedings{lingeling, + author = "Armin Biere", + title = "Yet another Local Search Solver and Lingeling and Friends Entering the SAT Competition 2014", + booktitle = "SAT Competition 2014 Booklet", + year = "2014", +} + +@inproceedings{cheeseman91where, + author = "Peter Cheeseman and Bob Kanefsky and William M. Taylor", + title = "Where the Really Hard Problems Are", + booktitle = "IJCAI-91", + pages = "331--337", + year = "1991", +} +Proceedings of the Twelfth International Joint Conference on Artificial Intelligence, Sidney, Australia + +@INPROCEEDINGS{Juels-2004-scn, + author = {Juels, Ari}, + title = {Minimalist Cryptography for Low-Cost {RFID} Tags}, + booktitle = {International Conference on Security in Communication Networks --- SCN 2004}, + year = {2004}, + editor = {Blundo, Carlo and Cimato, Stelvio}, + volume = {3352}, + series = {LNCS}, + pages = {149--164}, + month = {September}, + publisher = {Springer-Verlag}, + address = {Amalfi, Italia}, +} + + +@inproceedings{achlioptas-threshold, + author = {Dimitris Achlioptas and Yuval Peres}, + title = {The Threshold for Random k-{SAT} is 2\^\ k(ln 2 - O(k))}, + booktitle = {{STOC}'03}, + year = {2003}, + isbn = {1-58113-674-9}, + pages = {223--231}, + location = {San Diego, CA, USA}, + doi = {http://doi.acm.org/10.1145/780542.780577}, +} +Proceedings of the thirty-fifth annual ACM symposium on Theory of computing -- +publisher = {ACM Press} +address = {New York, NY, USA} + +@article{DPLL, + author = {Martin Davis and Hilary Putnam}, + title = {A Computing Procedure for Quantification Theory}, + journal = {J. ACM}, + volume = {7}, + number = {3}, + year = {1960}, + issn = {0004-5411}, + pages = {201--215}, + doi = {http://doi.acm.org/10.1145/321033.321034}, +} +publisher = {ACM Press}, +address = {New York, NY, USA}, + +@inproceedings {Minisat+, + author = {E\'en, Niklas and S\"orensson, Niklas}, + title = {Translating {P}seudo-{B}oolean constraints into {SAT}}, + booktitle= {Journal on Satisfiability, Boolean Modeling and Computation}, + year = {2006}, + pages = {1-26}, + volume = {2}, +} + +@inproceedings {EenS03MiniSat, + title = {An Extensible {SAT}-solver}, + author = {Niklas E\'en and Niklas S\"{o}rensson}, + booktitle = {SAT}, + editor = {Enrico Giunchiglia and Armando Tacchella}, + pages = {502--518}, + publisher = {Springer}, + series = {LNCS}, + url = {http://dblp.uni-trier.de/db/conf/sat/sat2003.html#EenS03}, + volume = {2919}, + year = {2003}, + ee = {http://www.cs.chalmers.se/Cs/Research/FormalMethods/MiniSat/cgi/MiniSat.ps.gz.cgi}, + keywords = {2003 2004 SAT-solver ais-07w efficiency implementation }, +} + +@misc { toolbar, + author="S. Bouveret and F. Heras and S. de Givry and J. Larrosa and M. Sanchez and T. Schiex", + title="Toolbar: a state-of-the-art platform for wcsp", + url="http://www.inra.fr/mia/T/degivry/ToolBar.pdf", + year="2004" +} + +@inproceedings{1267340, + author = {Kirschenbaum, Ilan and Wool, Avishai}, + title = {How to build a low-cost, extended-range {RFID} skimmer}, + booktitle = {USENIX-SS'06: Proceedings of the 15th conference on {USENIX} Security Symposium}, + year = {2006}, + location = {Vancouver, B.C., Canada}, + publisher = {{USENIX} Association}, + address = {Berkeley, CA, USA}, +} + +@misc{Benetton-boycott, + author = {{CASPIAN - Consumers Against Supermarket Privacy Invasion and Numbering}}, + howpublished={Press release}, + note= {\url{http://www.boycottbenetton.com}}, + title = {Boycott {B}enetton}, + year = {2003}, + month = {March}, +} + +@article{ improved-deterministic, + author="Michael H. Schulz and Elisabeth Auth", + title="Improved Deterministic Test Pattern Generation with Applications to Redundancy Identification", + year="1989", + month="July", + journal="IEEE Transactions on computer-aided design", + volume="8", + number="7", + pages={811--816}, + issn="0278-0070" +} +publisher = " IEEE Circuits and Systems Society", +address="Piscataway, NJ 08854, USA", + +@inproceedings{244560, + author = {Jo\&\#227;o P. Marques Silva and Karem A. Sakallah}, + title = {{GRASP}-a new search algorithm for satisfiability}, + booktitle = {ICCAD'96}, + year = {1996}, + isbn = {0-8186-7597-7}, + pages = {220--227}, + location = {San Jose, California, United States}, + publisher = {IEEE Computer Society}, +} +Proceedings of the 1996 IEEE/ACM international conference on Computer-aided design --- +address = {Washington, DC, USA}, + + @inproceedings{ chai03fast, + author = "D. Chai and A. Kuehlmann", + title = "A fast pseudo-boolean constraint solver", + pages = {305--317}, + booktitle = "IEEE Transactions on Computer-Aided Design of Integrated Circuits and Systems 2003", + year = {2003}, + month =" mar", + volume = "24", + issue = "3", + issn = "0278-0070" +} +publisher = "IEEE Circuits and Systems Society", + +@TechReport{EPC-standard, + author = "EPCglobal", + url="http://www.epcglobalinc.org/standards/specs/13.56_MHz_ISM_Band_Class_1_RFID_Tag_Interface_Specification.pdf", + title="13.56 {MHz} {ISM} Band Class 1 Radio Frequency Identification Tag Interface Specification (2003)", + institution = "Auto-ID cetner, MIT", + year ="2003", + month = "February", + version = "1.0.0" +} +address = "77 massachusetts avenue, bldg 3-449, cambridge, ma 02139-4307, USA", + +@INPROCEEDINGS{LuLHHN-2007-percom, + author = {Lu, Li and Liu, Yunhao and Hu, Lei and Han, Jinsong and Ni, Lionel}, + title = {A Dynamic Key-Updating Private Authentication Protocol for {RFID} Systems}, + booktitle = {PerCom 2007}, + year = {2007}, + pages = {13--22}, + month = {March}, + organization = {IEEE} +} +International Conference on Pervasive Computing and Communications +publisher = {IEEE Computer Society Press} +address = {New York, USA}, + +@INPROCEEDINGS{Ohkubo04Efficient, + author = {Ohkubo, Miyako and Suzuki, Koutarou and Kinoshita, Shingo}, + title = {Efficient Hash-Chain Based {RFID} Privacy Protection Scheme}, + booktitle = {International Conference on Ubiquitous Computing --- Ubicomp 2004, Workshop Privacy: Current Status and Future Directions}, + month = {September}, + year = {2004}, + address = {Nottingham, England}, +} + +@INPROCEEDINGS{MolnarSW-2005-sac, + author = {Molnar, David and Soppera, Andrea and Wagner, David}, + title = {A Scalable, Delegatable Pseudonym Protocol Enabling Ownership Transfer of {RFID} Tags}, + booktitle = {Selected Areas in Cryptography --- SAC 2005}, + editor = {Preneel, Bart and Tavares, Stafford}, + volume = {3897}, + series = {LNCS}, + pages = {276--290}, + month = {August}, + series = {LNCS}, + publisher = {Springer-Verlag}, + year = {2005}, + address = {Kingston, Canada}, +} + +@inproceedings{DBLP:conf/otm/FeldhoferR06, + author = {Martin Feldhofer and Christian Rechberger}, + title = {A Case Against Currently Used Hash Functions in {RFID} Protocols}, + booktitle = {OTM Workshops (1)}, + year = {2006}, + pages = {372-381}, + ee = {http://dx.doi.org/10.1007/11915034_61}, + crossref = {DBLP:conf/otm/2006-w1}, + bibsource = {DBLP, http://dblp.uni-trier.de} +} + +@proceedings{DBLP:conf/otm/2006-w1, + editor = {Robert Meersman and Zahir Tari and Pilar Herrero}, + title = {On the Move to Meaningful Internet Systems 2006: OTM 2006 Workshops, OTM Confederated International Workshops and Posters, AWeSOMe, CAMS, COMINF, IS, KSinBIT, MIOS-CIAO, MONET, OnToContent, ORM, PerSys, OTM Academy Doctoral Consortium, RDDS, SWWS, and SeBGIS 2006, Montpellier, France, October 29 - November 3, 2006. Proceedings, Part I}, + booktitle = {OTM Workshops (1)}, + publisher = {Springer}, + series = {LNCS}, + volume = {4277}, + year = {2006}, + isbn = {3-540-48269-5}, + bibsource = {DBLP, http://dblp.uni-trier.de} +} + + +@INPROCEEDINGS{VajdaB-2003-ubicom, + author = {Vajda, Istv\'an and Butty\'an, Levente}, + title = {Lightweight Authentication Protocols for Low-Cost {RFID} Tags}, + booktitle = {Ubicomp 2003 Second Workshop on Security in Ubiquitous Computing}, + month = {October}, + year = {2003} +} +address = {Seattle, WA, USA}, + +@INPROCEEDINGS{LiW-2007-sec, + author = {Li, Tieyan and Wang, Guilin}, + title = {Security Analysis of Two Ultra-Lightweight {RFID} Authentication Protocols}, + booktitle = {IFIP SEC 2007}, + month = {May}, + organization = {IFIP}, +} +year = {2007}, +address = {Sandton, Gauteng, South Africa}, + +@MISC{BatinaGKMTV-2006-eprint, + author = {Batina, Lejla and Guajardo, Jorge and Kerins, Tim and Mentens, Nele and Tuyls, Pim and Verbauwhede, Ingrid}, + title = {An Elliptic Curve Processor Suitable For {RFID}-Tags}, + howpublished = {Cryptology ePrint Archive, Report 2006/227}, + year = {2006}, + organization = {IACR}, +} + +@inproceedings {AES-grain-sand, + title = {{AES} implementation on a grain of sand}, + issue = "1", + ISSN="1747-0722", + pages = {13--20}, + author="Feldhofer, M. and Wolkerstorfer, J. and Rijmen, V.", + year = "2005", + voulme="152", + booktitle = "Information Security", + organization = {IEEE}, +} +publisher = {IEEE Computer Society Press}, + +@MISC{Juels-2005-manuscript-2, + author = {Juels, Ari}, + title = {{RFID} Security and Privacy: A research Survey}, + howpublished = {Manuscript}, + year = {2005}, + month = {September}, + organization = {RSA Laboratories}, +} + +@INPROCEEDINGS{JuelsW-2007-percom, + author = {Juels, Ari and Weis, Stephen}, + title = {{Defining Strong Privacy for RFID}}, + booktitle = {International Conference on Pervasive Computing and Communications --- PerCom 2007}, + year = {2007}, + editor = {}, + volume = {}, + series = {}, + pages = {342--347}, + address = {New York City, New York, USA}, + month = {March}, + organization = {IEEE}, + publisher = {IEEE Computer Society Press}, + bibsource = {Information Security Group (GSI), UCL, Louvain-la-Neuve, Belgium}, +} + +@INPROCEEDINGS{Vaudenay-2007-asiacrypt, + author = {Vaudenay, Serge}, + title = {On Privacy Models for {RFID}}, + booktitle = {Advances in Cryptology --- Asiacrypt 2007}, + year = {2007}, + editor = {}, + volume = {4833}, + series = {LNCS}, + pages = {68--87}, + address = {Kuching, Malaysia}, + month = {December}, + organization = {}, + publisher = {Springer-Verlag}, + bibsource = {Information Security Group (GSI), UCL, Louvain-la-Neuve, Belgium}, +} + +@INPROCEEDINGS{BolotnyyR-2007-percom, + author = {Bolotnyy, Leonid and Robins, Gabriel}, + title = {Physically Unclonable Function-Based Security and Privacy in {RFID} Systems}, + booktitle = {PerCom 2007}, + year = {2007}, + pages = {211--220}, + month = {March}, + organization = {IEEE}, +} +publisher = {IEEE Computer Society Press} +International Conference on Pervasive Computing and Communications -- +address = {New York, USA}, + +@INPROCEEDINGS{JuelsRS-2003-ccs, + author = {Juels, Ari and Rivest, Ronald and Szydlo, Michael}, + title = {The Blocker Tag: Selective Blocking of {RFID} Tags for Consumer Privacy}, + booktitle = {ACM CCS 2003}, + year = {2003}, + editor = {Atluri, Vijay}, + pages = {103--111}, + month = {October}, + publisher = "ACM Press" +} +address = {Washington, DC, USA}, +Conference on Computer and Communications Security +organization = "ACM", + +@INPROCEEDINGS{JuelsW-2005-crypto, + author = {Juels, Ari and Weis, Stephen}, + title = {Authenticating Pervasive Devices with Human Protocols}, + booktitle = {Advances in Cryptology --- CRYPTO'05}, + year = {2005}, + editor = {Shoup, Victor}, + volume = {3126}, + series = {LNCS}, + pages = {293--308}, + month = {August}, + organization = {IACR}, + address = {Santa Barbara, California, USA}, + publisher = {Springer-Verlag}, + series = {LNCS}, +} + +@inproceedings{ zhang01efficient, + author = "Lintao Zhang and Conor F. Madigan and Matthew W. Moskewicz and Sharad Malik", + title = "Efficient Conflict Driven Learning in Boolean Satisfiability Solver", + booktitle = "{ICCAD}", + pages = "279-285", + year = "2001", + url = "citeseer.ist.psu.edu/article/zhang01efficient.html" } + + +@INPROCEEDINGS{ButtyanHV-2006-pet, + author = {Butty\'an, Levente and Holczer, Tam\'as and Vajda, Istv\'an}, + title = {Optimal Key-Trees for Tree-Based Private Authentication}, + booktitle = {Workshop on Privacy Enhancing Technologies --- PET 2006}, + pages = {332-350}, + month = {June}, + year = {2007}, + address = {Cambridge, United Kingdom}, +} + + +@INPROCEEDINGS{Castelluccia07Secret, + author = {Castelluccia, Claude and Soos, Mate}, + title = {Secret Shuffling: A Novel Approach to {RFID} Private Identification}, + booktitle = {{RFIDSec}'07}, + pages = {169-180}, + year = {2007}, + month = {July} +} +Proceedings of the International Conference on RFID Security 2007 + +@INPROCEEDINGS{breaking-lmap, + author = {Mihaly B\'arasz and Bal\'azs Boros and P\'eter Ligeti and Krisztina L\'oja and D\'aniel Nagy}, + title = {Breaking {LMAP}}, + pages = {69-78}, + month = {July}, + year = {2007}, + booktitle = {Conference on RFID Security --- {RFIDSec}'07}, + address = {Malaga, Spain}, +} + +@INPROCEEDINGS{Initial-SRAM, + author = {Daniel Holcom and Wayne Burleson and Kevin Fu.}, + title = {Initial {SRAM} state as a Fingerprint and Source of True Random Numbers for {RFID} Tags}, + booktitle = {{RFIDSec}'07}, + pages = {29-40}, + month = {July}, + year = {2007} +} +Proceedings of the International Conference on RFID Security 2007 + +@inproceedings{HBattack, + author = {Gilbert, Henri and Robshaw, Matt and Sibert, Herve}, + title = {An Active Attack Against {HB}$^+$ - A Provably Secure Lightweight Authentication Protocol}, + booktitle = {IEE Electronic Letters 41, 21}, + year = {2005}, + pages = {1169--1170} +} + +@INPROCEEDINGS{KatzS-2006-eurocrypt, + author = {Katz, Jonathan and Sun Shin, Ji}, + title = {Parallel and Concurrent Security of the {HB} and {HB}$^{+}$ Protocols}, + booktitle = {Advances in Cryptology --- EUROCRYPT '06}, + organization = {IACR}, + year = {2006} +} +Advances in Cryptology +publisher = {Springer-Verlag}, + +@MISC{KatzS-2006-eprint, + author = {Katz, Jonathan and Smith, Adam}, + title = {Analyzing the {HB} and {HB}+ Protocols in the ``Large Error'' Case}, + howpublished = {Cryptology ePrint Archive, Report 2006/326}, + organization = {IACR}, +} + +@inproceedings{1229319, + author = {Tri Van Le and Mike Burmester and Breno de Medeiros}, + title = {Universally composable and forward-secure {RFID} authentication and authenticated key exchange}, + booktitle = {Proceedings of the 2nd ACM symposium on Information, Computer and Communications Security --- {ASIACCS}'07}, + year = {2007}, + isbn = {1-59593-574-6}, + pages = {242--252}, + location = {Singapore}, + publisher = {ACM}, + address = {New York, NY, USA}, + doi = {http://doi.acm.org/10.1145/1229285.1229319}, +} + + + +@INPROCEEDINGS{PUF-based-RNG, + author = {Charles W. O'Donnell and G. Edward Suh and Srinivas Devadas}, + title = {{PUF}-Based Random Number Generation}, + booktitle = {MIT CSAIL CSG Technical Memo 481}, + url = {http://csg.csail.mit.edu/pubs/memos/Memo-481/Memo-481.pdf}, + year = {2004}, + month = {November} +} + +@book{Ipatov05Spread, + author = {Valeri P. Ipatov}, + year = {2005}, + month = {May}, + title = {Spread Spectrum and {CDMA}: {P}rinciples and Applications}, + publisher = {John Wiley \& Sons, Ltd.}, + ISBN = {978-0470091784}, +} + +@article{DBLP:journals/ijwmc/HellJM07, + author = {Martin Hell and + Thomas Johansson and + Willi Meier}, + title = {Grain: a stream cipher for constrained environments}, + journal = {IJWMC}, + volume = {2}, + number = {1}, + year = {2007}, + pages = {86-93}, + ee = {http://dx.doi.org/10.1504/IJWMC.2007.013798}, + bibsource = {DBLP, http://dblp.uni-trier.de} +} + +@book{applied-crypto, + year= {1996}, + ISBN ={0-8493-8523-7}, + author={Alfred J. Menezes and Paul C. van Oorschot and Scott A. Vanstone}, + title ={Handbook of applied cryptography}, + publisher={CRC Press}, + address={Boca Raton, Florida}, +} +url={http://cacr.math.uwaterloo.ca/hac} + +@inproceedings{DiPietro07Information, + author={Roberto Di Pietro and Refik Molva}, + title={Information confinement, privacy, and security in {RFID} systems}, + month={September}, + booktitle={Proceedings of the 12th European Symposium On Research In Computer Security}, + year={2007}, + pages={187-202}, +} + +@inproceedings{PerisHER-2006-rfidsec, + author = {Peris-Lopez, Pedro and Hernandez-Castro, Julio Cesar and Estevez-Tapiador, Juan and Ribagorda, Arturo}, + title = {{LMAP}: A Real Lightweight Mutual Authentication Protocol for Low-cost {RFID} tags}, + booktitle = {Proceedings of {RFIDSec}'06}, + year = {2006}, + month = {July}, + address = {Graz, Austria}, + organization = {Ecrypt}, +} + +@INPROCEEDINGS{BringerCD-2006-secperu, + author = {Bringer, Julien and Chabanne, Herv\'e and Dottax Emmanuelle}, + title = {{HB}$^{++}$: a Lightweight Authentication Protocol Secure against Some Attacks}, + booktitle = {{IEEE} SecPerU 2006}, + year = {2006}, + month = {June}, + organization = {IEEE}, +} +International Conference on Pervasive Services, Workshop on Security, Privacy and Trust in Pervasive and Ubiquitous Computing +address = {Lyon, France}, +publisher = {IEEE Computer Society Press}, + +@INPROCEEDINGS{PerisHER-2006-uic, + author = {Peris-Lopez, Pedro and Hernandez-Castro, Julio Cesar and Estevez-Tapiador, Juan and Ribagorda, Arturo}, + title = {{M2AP}: A Minimalist Mutual-Authentication Protocol for Low-cost {RFID} Tags}, + booktitle = {International Conference on Ubiquitous Intelligence and Computing --- {UIC}’06}, + year = {2006}, + editor = {}, + volume = {4159}, + pages = {912--923}, + month = {September}, + series = {LNCS}, + publisher = {Springer-Verlag}, +} + + +@INPROCEEDINGS{M2AP-break, + author={Mih\'aly B\'ar\'asz and Bal\'azs Boros and P\'eter Ligeti and Krisztina L\'oja and D\'aniel A. Nagy}, + title={Passive Attack Against the {M2AP} Mutual Authentication Protocol for {RFID} Tags}, + year = {2007}, + month= {September}, + date = {24-25}, + booktitle={{RFID} 2007 --- The First International {EURASIP} Workshop on {RFID} Technology}, + country = {Austria}, + city={Vienna} +} + +@INPROCEEDINGS{HBppbreak, + author= {Henri Gilbert and Matthew J.B. Robshaw and Yannick Seurin}, + title={Good Variants of {HB}+ are Hard to Find}, + year={2008}, + month={January}, + booktitle={Financial Cryptography}, + publisher={Springer}, + country={Mexico} +} + +@inproceedings{MAGMA, + author = {Wieb Bosma and John Cannon and Graham Matthews}, + title = {Programming with algebraic structures: design of the {MAGMA} language}, + booktitle = {Proceedings of the international symposium on Symbolic and algebraic computation --- ISSAC '94}, + year = {1994}, + isbn = {0-89791-638-7}, + pages = {52--57}, + location = {Oxford, United Kingdom}, + doi = {http://doi.acm.org/10.1145/190347.190362}, + publisher = {ACM}, + address = {New York, NY, USA}, +} + +@inproceedings{Singular, + author = {Gert-Martin Greuel and Gerhard Pfister and Hans Sch\"{o}nemann}, + title = {{SINGULAR} --- A computer algebra system for polynomial computations}, + booktitle = {Symbolic computation and automated reasoning}, + year = {2001}, + isbn = {1-56881-145-4}, + pages = {227--233}, + publisher = {A. K. Peters, Ltd.}, + address = {Natick, MA, USA}, +} + +@misc{SAGE, + author = {{The SAGE Group}}, + year = {2008}, + title = {{SAGE} Mathematics Software}, + note = {\url{http://www.sagemath.org}}, +} + +@misc{new-sparse-technique, + author={H{\aa}vard Raddum and Igor Semae}, + title={New Technique for Solving Sparse Equation Systems}, + month={January}, + year={2006}, + note={\url{eprint.iacr.org/2006/475/}}, +} + +@TechReport{algebraic-DES, + author={Nicolas T. Courtois and Gregory V. Bard}, + title={Algebraic Cryptanalysis of the {D}ata {E}ncryption {S}tandard}, + year={2006}, + institution = {IACR E-print}, + number = {2006/402}, + month={November}, + booktitle={IACR E-print, \url{http://eprint.iacr.org/2006/402}}, +} + + + +@inproceedings{early-DES-algebraic, + author={Chaum, David and Evertse, Jan-Hendrik}, + title={Cryptanalysis of {DES} with a Reduced Number of Rounds}, + booktitle = {Advances in Cryptology --- {CRYPTO}'85}, + year = {1986}, + pages = {192--211}, + publisher = {Springer-Verlag} +} + +@InProceedings{Bofilletal2008CAV, + author = {M. Bofill and R. Nieuwenhuis and A. Oliveras and E. Rodr\'\i guez-Carbonell and A. Rubio}, + title = {The {B}arcelogic {SMT} Solver}, + pages = {294-298}, + booktitle = {{CAV}'08}, + year = {2008}, + series = {LNCS}, + volume = {5123}, + publisher = {Springer}, + editor = {A. Gupta and S. Malik}, +} + +@techreport{RSAT, + author = {Knot Pipatsrisawat and Adnan Darwiche}, + institution = {Automated Reasoning Group, Computer Science}, + title = {{RS}at 2.0: {SAT} Solver Description}, + year = {2007}, +} + +@inproceedings{DBLP:conf/fse/CourtoisBW08, + author = {Nicolas Courtois and Gregory V. Bard and David Wagner}, + title = {Algebraic and Slide Attacks on {K}ee{L}oq}, + booktitle = {FSE}, + year = {2008}, + pages = {97-115}, + ee = {http://dx.doi.org/10.1007/978-3-540-71039-4_6}, + crossref = {DBLP:conf/fse/2008}, + bibsource = {DBLP, http://dblp.uni-trier.de} +} + +@TechReport{cryptoeprint:2008:166, + author = {Nicolas T. Courtois and Karsten Nohl and Sean O'Neil}, + title = {Algebraic Attacks on the {C}rypto-1 Stream Cipher in {Mifare} {C}lassic and {O}yster Cards}, + number = {2008/166}, + institution = {Cryptology ePrint Archive}, + year = {2008}, +} +howpublished = {Cryptology ePrint Archive, Report 2008/166}, +note = {\url{http://eprint.iacr.org/}}, + +@INPROCEEDINGS{Biere99symbolicmodel, + author = {Armin Biere and A. Cimatti and E. M. Clarke and M. Fujita and Y. Zhu}, + title = {Symbolic Model Checking Using {SAT} Procedures instead of {BDDs}}, + booktitle = {Proc. of Design Automation Conference ({DAC}'99)}, + year = {1999}, + pages = {317--320} +} + +@INPROCEEDINGS{temporalinduction, + author = {E\'en, Niklas and S\"orensson, Niklas}, + title = {Temporal Induction by Incremental {SAT} Solving}, + booktitle={Proc. of First Intrenational Workshop on Bounded Model Checking}, + year={2003}, + volume={89}, + issue={4}, + series={ENTCS}, + publisher={Elsevier} +} + +@inproceedings{ARMS02, + author = {Fadi A. Aloul and Arathi Ramani and Igor Markov and Karem Sakallah}, + title = {Generic {ILP} versus Specialized 0-1 {ILP}: an Update}, + booktitle = {Proc. ACM/IEEE Intl. Conf. Comp.-Aided Design}, + pages = {450 - 457}, + month = {November}, + year = {2002}, + URL = {http://www.gigascale.org/pubs/190.html} +} + +@inproceedings{knowledge-compiling, + author={Adnan Dawiche}, + title={New advances in compiling {CNF} to decomposable negation normal form}, + booktitle={Proc. of European Conference on Artificial Intelligence}, + year={2004}, + pages={328 - 332}, +} + +@InProceedings{S-Match, + author = {Fausto Giunchiglia and Pavel Shvaiko and Mikalai Yatskevich}, + title = {S-{M}atch: an algorithm and an implementation of semantic matching}, + booktitle = {Semantic Interoperability and Integration}, + year = {2005}, + number = {04391}, + series = {Dagstuhl Seminar Proceedings}, + ISSN = {1862-4405}, + publisher = {IBFI}, + note = {\url{http://drops.dagstuhl.de/opus/volltexte/2005/37}}, + editor = {Y. Kalfoglou and M. Schorlemmer and A. Sheth and S. Staab and M. Uschold}, +} +publisher = {Internationales Begegnungs- und Forschungszentrum fuer Informatik (IBFI)}, + + + +@techreport{bard-thesis, + author = {Gregory V. Bard}, + title = {Algorithms for the Solution of Polynomial and Linear Systems of Equations over Finite Fields, with an Application to the Cryptanalysis of {K}ee{L}oq}, + institution={University of Maryland Dissertation}, + month={April}, + year={2008}, + note = {Ph.D. Thesis}, +} + +@inproceedings{Toyocrypt-nicolas-attack, + author={Nicolas T. Courtois}, + title={Higher Order Correlation Attacks, {XL} algorithm and Cryptanalysis of {T}oyocrypt ({A}n updated version)}, + booktitle={ICISC 2002}, + series={LNCS}, + volume={2587}, + publisher={Springer}, + year={2002}, +} + +@inproceedings{General-LFSR-attacks, + author={Nicolas T. Courtois and Willi Meier}, + title={Algebraic Attacks on Stream Ciphers with Linear Feedback}, + booktitle={Advances in Cryptology --- EUROCRYPT '03}, + series={LNCS}, + volume={2656}, + pages={345–359}, + publisher={Springer}, + address = {Warsaw, Poland} +} + +@inproceedings{Canniere06Trivium, + author = {Christophe De Canni{\`e}re}, + title = {Trivium: A Stream Cipher Construction Inspired by Block Cipher Design Principles}, + booktitle = {ISC}, + year = {2006}, + pages = {171-186}, + ee = {http://dx.doi.org/10.1007/11836810_13}, + crossref = {DBLP:conf/isw/2006}, + bibsource = {DBLP, http://dblp.uni-trier.de} +} + +@proceedings{DBLP:conf/isw/2006, + editor = {Sokratis K. Katsikas and et al}, + title = {Information Security, 9th International Conference, ISC 2006, Samos Island, Greece, August 30 - September 2, 2006, Proceedings}, + booktitle = {ISC}, + publisher = {Springer}, + series = {LNCS}, + volume = {4176}, + year = {2006}, + isbn = {3-540-38341-7}, + bibsource = {DBLP, http://dblp.uni-trier.de} +} +and +Javier Lopez and +Michael Backes and +Stefanos Gritzalis and +Bart Preneel + +@inproceedings{BiviumWithSATsolvers, + author = {Tobias Eibach and Enrico Pilz and Gunnar V{\"o}lkel}, + title = {Attacking {B}ivium Using {SAT} Solvers}, + booktitle = {SAT}, + year = {2008}, + pages = {63-76}, + ee = {http://dx.doi.org/10.1007/978-3-540-79719-7_7}, + crossref = {DBLP:conf/sat/2008}, + bibsource = {DBLP, http://dblp.uni-trier.de} +} + +@proceedings{DBLP:conf/sat/2008, + editor = {Hans Kleine B{\"u}ning and Xishun Zhao}, + title = {Theory and Applications of Satisfiability Testing - SAT 2008, 11th International Conference, SAT 2008, Guangzhou, China, May 12-15, 2008. Proceedings}, + booktitle = {SAT}, + publisher = {Springer}, + series = {LNCS}, + volume = {4996}, + year = {2008}, + isbn = {978-3-540-79718-0}, + bibsource = {DBLP, http://dblp.uni-trier.de} +} + +@TechReport{Bivium, + author={Havard Raddum}, + title={Cryptanalytic results on {T}rivium}, + institution = {ECRYPT Stream Cipher Project}, + year={2006}, + number={2006/039}, + note = {\url{www.ecrypt.eu.org/stream/papersdir/2006/039.ps}}, +} + +@misc{using-equation-solvers, + author = {Havard Raddum and Igor Semaev}, + title = {New Technique for Solving Sparse Equation Systems}, + howpublished = {Cryptology ePrint Archive, Report 2006/475}, + year = {2006}, + note = {\url{http://eprint.iacr.org/}}, +} + + +@TechReport{BiviumWithMiniSat, + author={Cameron McDonald and Chris Charnes and Josef Pieprzyk}, + title={Attacking {B}ivium with {M}ini{S}at}, + institution = {ECRYPT Stream Cipher Project}, + year={2007}, + number={2007/040} +} + +@inproceedings{FaugereF5, + author = {Jean-Charles Faug\`{e}re}, + title = {A new efficient algorithm for computing {G}r\"{o}bner bases without reduction to zero ({F}5)}, + booktitle = {ISSAC '02}, + year = {2002}, + isbn = {1-58113-484-3}, + pages = {75--83}, + location = {Lille, France}, + doi = {http://doi.acm.org/10.1145/780506.780516}, + publisher = {ACM}, + } +ISSAC '02: Proceedings of the 2002 international symposium on Symbolic and algebraic computation +address = {New York, NY, USA}, + + +@article{FaugereF4, + author = {Jean-Charles Faug\`{e}re}, + title = {A new efficient algorithm for computing {G}r\"{o}bner bases ({F}4)}, + journal = {Journal of Pure and Applied Algebra}, + year = {1999}, + month = {June}, + pages = {61--88}, + volume = {1}, + number = {139}, +} + +@inproceedings{DismantlingMifare, + author = {Flavio D. Garcia and et al.}, + title = {Dismantling {MIFARE} {C}lassic}, + booktitle = {ESORICS}, + year = {2008}, + pages = {97-114}, + ee = {http://dx.doi.org/10.1007/978-3-540-88313-5_7}, + crossref = {DBLP:conf/esorics/2008}, + bibsource = {DBLP, http://dblp.uni-trier.de} +} +and +Gerhard de Koning Gans and +Ruben Muijrers and +Peter van Rossum and +Roel Verdult and +Ronny Wichers Schreur and +Bart Jacobs + +@proceedings{DBLP:conf/esorics/2008, + editor = {Sushil Jajodia and Javier L{\'o}pez}, + title = {Computer Security - ESORICS 2008, 13th European Symposium on Research in Computer Security, M{\'a}laga, Spain, October 6-8, 2008. Proceedings}, + booktitle = {ESORICS}, + publisher = {Springer}, + series = {LNCS}, + volume = {5283}, + year = {2008}, + isbn = {978-3-540-88312-8}, + bibsource = {DBLP, http://dblp.uni-trier.de} +} + +@misc{Karsten-webpage-HiTag2, + author={Karsten Nohl}, + title={Description of {H}i{T}ag2}, + howpublished={Press release}, + note= {\url{http://cryptolib.com/ciphers/hitag2/}}, + month={March}, + day = {12}, + year={2008}, +} + +@InProceedings{Ouafi08Privacy, + address = {Berlin}, + affiliation = {EPFL}, + author = {Ouafi, Khaled and Phan, Raphael C.-W.}, + booktitle = {Information {S}ecurity {P}ractice and {E}xperience, 4th {I}nternational {C}onference, {ISPEC} 2008}, + location = {Sydney, Australia}, + oai-id = {oai:infoscience.epfl.ch:126418}, + oai-set = {conf; fulltext; fulltext-public}, + pages = {263--277}, + publisher = {Springer}, + review = {REVIEWED}, + series = {LNCS}, + status = {PUBLISHED}, + title = {Privacy of {R}ecent {RFID} {A}uthentication {P}rotocols}, + unit = {LASEC}, + year = {2008}, + keywords = {RFID; authentication protocols, ; privacy; untraceability; provably secure}, + details = {http://infoscience.epfl.ch/record/126418}, + documenturl = {http://infoscience.epfl.ch/getfile.py?recid=126418&mode=best}, +} + +@INPROCEEDINGS{Ohkubo04Cryptographic, + author = {Miyako Ohkubo Koutarou and Koutarou Suzuki and Shingo Kinoshita}, + title = {Cryptographic Approach to "Privacy-Friendly" Tags}, + booktitle = {RFID Privacy Workshop}, + year = {2003}, + address = {MIT, Massachusetts, USA}, + month = {November}, +} + +@article{Lamport81Password, + author = {Lamport,, Leslie}, + title = {Password authentication with insecure communication}, + journal = {Commun. ACM}, + volume = {24}, + number = {11}, + year = {1981}, + issn = {0001-0782}, + pages = {770--772}, + doi = {http://doi.acm.org/10.1145/358790.358797}, + publisher = {ACM}, + address = {New York, NY, USA}, + } + +@InProceedings{OSK_Avoine, + affiliation = {EPFL}, + author = {Avoine, Gildas and Oechslin, Philippe}, + booktitle = {The 2nd {IEEE} {I}nternational {W}orkshop on {P}ervasive {C}omputing and {C}ommunication {S}ecurity - {P}er{S}ec 2005}, + details = {http://infoscience.epfl.ch/record/99461}, + documenturl = {http://infoscience.epfl.ch/getfile.py?recid=99461&mode=best}, + keywords = {NCCR-MICS; NCCR-MICS/CL3}, + location = {Kauai island, Hawaii, USA}, + oai-id = {oai:infoscience.epfl.ch:99461}, + oai-set = {conf; fulltext; fulltext-public}, + pages = {110--114}, + review = {REVIEWED}, + status = {PUBLISHED}, + title = {A {S}calable and {P}rovably {S}ecure {H}ash-{B}ased {RFID} {P}rotocol}, + unit = {LASEC}, + year = 2005 +} + +@inproceedings{Trade-off-Hellman, + author = {Hellman, Martin E.}, + title = {A cryptanalytic time-memory trade off}, + booktitle = {{IEEE} Transactions on Information Theory}, + volume = {IT-26/4}, + pages = {401--406}, + year = {1980}, +} + +@inproceedings{Faster-crypto-time-memory, + author = {Oechslin, Philippe }, + booktitle = {Advances in Cryptology --- CRYPTO 2003}, + series = {LNCS}, + volume = {2729}, + publisher = {Springer}, + pages = {617--630}, + posted-at = {2008-07-07 15:11:06}, + priority = {2}, + title = {Making a Faster Cryptanalytic Time-Memory Trade-Off}, + url = {http://www.springerlink.com/content/u9gxwd29p2tnx3wl}, + year = {2003} +} + +@inproceedings{Molnar04Keytrees, + address = {New York, NY, USA}, + author = {Molnar, David and Wagner, David }, + booktitle = {CCS '04: Proceedings of the 11th ACM conference on Computer and communications security}, + citeulike-article-id = {202290}, + doi = {10.1145/1030083.1030112}, + isbn = {1581139616}, + keywords = {libraries, privacy}, + pages = {210--219}, + posted-at = {2007-12-25 21:42:23}, + priority = {5}, + publisher = {ACM Press}, + title = {Privacy and security in library {RFID}: issues, practices, and architectures}, + url = {http://dx.doi.org/10.1145/1030083.1030112}, + year = {2004} +} + +@INPROCEEDINGS{NohlE-2008-sec, + author = {Nohl, Karsten and Evans, David}, + title = {{Hiding in Groups: On the Expressiveness of Privacy Distributions}}, + booktitle = {Proceedings of The Ifip Tc 11 23rd International Information Security Conference --- SEC 2008}, + year = {2008}, + editor = {}, + volume = {278}, + series = {LNCS}, + pages = {1--15}, + address = {Milan, Italia}, + month = {September}, + organization = {}, + publisher = {Springer}, + bibsource = {Information Security Group (GIS), UCL, Louvain-la-Neuve, Belgium}, +} + +@inproceedings{DBLP:conf/fse/Shamir08, + author = {Adi Shamir}, + title = {{SQUASH} --- A New {MAC} with Provable Security Properties for Highly Constrained Devices Such as {RFID} Tags}, + booktitle = {FSE}, + year = {2008}, + pages = {144-157}, + ee = {http://dx.doi.org/10.1007/978-3-540-71039-4_9}, + crossref = {DBLP:conf/fse/2008}, + bibsource = {DBLP, http://dblp.uni-trier.de} +} + +@proceedings{DBLP:conf/fse/2008, + editor = {Kaisa Nyberg}, + title = {Fast Software Encryption, 15th International Workshop, {FSE} 2008, Lausanne, Switzerland, February 10-13, 2008, Revised Selected Papers}, + booktitle = {FSE}, + publisher = {Springer}, + series = {LNCS}, + volume = {5086}, + year = {2008}, + isbn = {978-3-540-71038-7}, + bibsource = {DBLP, http://dblp.uni-trier.de} +} + +@inproceedings{Oren2008WIPRPublic, +author = {Yossef Oren and Martin Feldhofer}, +title = {{WIPR} --- a Public Key Implementation on Two Grains of Sand}, +booktitle = {Workshop on RFID Security 2008}, +year = {2008}, +editor = {Sandra Dominikus}, +pages = {15 - 27}, +} + +@incollection{drat, +year={2014}, +isbn={978-3-319-09283-6}, +booktitle={Theory and Applications of Satisfiability Testing – SAT 2014}, +volume={8561}, +series={Lecture Notes in Computer Science}, +editor={Sinz, Carsten and Egly, Uwe}, +doi={10.1007/978-3-319-09284-3_31}, +title={DRAT-trim: Efficient Checking and Trimming Using Expressive Clausal Proofs}, +url={http://dx.doi.org/10.1007/978-3-319-09284-3_31}, +publisher={Springer International Publishing}, +author={Wetzler, Nathan and Heule, MarijnJ.H. and Hunt, WarrenA., Jr.}, +pages={422-429}, +language={English} +} + + +@inproceedings{DBLP:conf/ctrsa/McLooneR07, + author = {M{\'a}ire McLoone and Matthew J. B. Robshaw}, + title = {Public Key Cryptography and {RFID} Tags}, + booktitle = {CT-RSA}, + year = {2007}, + pages = {372-384}, + ee = {http://dx.doi.org/10.1007/11967668_24}, + crossref = {DBLP:conf/ctrsa/2007}, + bibsource = {DBLP, http://dblp.uni-trier.de} +} + +@proceedings{DBLP:conf/ctrsa/2007, + editor = {Masayuki Abe}, + title = {Topics in Cryptology - CT-RSA 2007, The Cryptographers' Track at the RSA Conference 2007, San Francisco, CA, USA, February 5-9, 2007, Proceedings}, + booktitle = {CT-RSA}, + publisher = {Springer}, + series = {LNCS}, + volume = {4377}, + year = {2006}, + isbn = {3-540-69327-0}, + bibsource = {DBLP, http://dblp.uni-trier.de} +} + + + +@proceedings{DBLP:conf/eurocrypt/91, + editor = {Donald W. Davies}, + title = {Advances in Cryptology --- EUROCRYPT '91, Workshop on the Theory and Application of of Cryptographic Techniques, Brighton, UK, April 8-11, 1991, Proceedings}, + booktitle = {Advances in Cryptology --- EUROCRYPT '91}, + publisher = {Springer}, + series = {LNCS}, + volume = {547}, + year = {1991}, + isbn = {3-540-54620-0}, +} + +@inproceedings{DBLP:conf/eurocrypt/Girault91, + author = {Marc Girault}, + title = {Self-Certified Public Keys}, + booktitle = {Advances in Cryptology --- EUROCRYPT '91}, + year = {1991}, + pages = {490-497}, + ee = {http://link.springer.de/link/service/series/0558/bibs/0547/05470490.htm}, + bibsource = {DBLP, http://dblp.uni-trier.de} +} + +@inproceedings{DBLP:conf/cardis/Girault00, + author = {Marc Girault}, + title = {Low-Size Coupons for Low-Cost {IC} Cards}, + booktitle = {CARDIS}, + year = {2000}, + pages = {39-50}, + crossref = {DBLP:conf/cardis/2000}, + bibsource = {DBLP, http://dblp.uni-trier.de} +} + +@proceedings{DBLP:conf/cardis/2000, + editor = {Josep Domingo-Ferrer and David Chan and Anthony Watson}, + title = {Smart Card Research and Advanced Applications, Proceedings of the Fourth Working Conference on Smart Card Research and Advanced Applications, CARDIS 2000, September 20-22, 2000, Bristol, UK}, + booktitle = {CARDIS}, + publisher = {Kluwer}, + series = {IFIP Conference Proceedings}, + volume = {180}, + year = {2000}, + isbn = {0-7923-7953-5}, + bibsource = {DBLP, http://dblp.uni-trier.de} +} + +@inproceedings{Secure-human-ID, + author = {Hopper,, Nicholas J. and Blum,, Manuel}, + title = {Secure Human Identification Protocols}, + booktitle = {ASIACRYPT '01: Proceedings of the 7th International Conference on the Theory and Application of Cryptology and Information Security}, + year = {2001}, + isbn = {3-540-42987-5}, + pages = {52--66}, + publisher = {Springer-Verlag}, + address = {London, UK}, +} + +@ARTICLE{Inherent-intracability, +title={On the inherent intractability of certain coding problems (Corresp.)}, +author={ Berlekamp, E. and McEliece, R. and van Tilborg, H.}, +journal={Information Theory, IEEE Transactions on}, +year={1978}, +month={May}, +volume={24}, +number={3}, +pages={ 384-386}, +keywords={null Decoding, Linear codes}, +doi={}, +ISSN={0018-9448}, +} + +@article{Noise-tolerant-learning, + author = {Blum,, Avrim and Kalai,, Adam and Wasserman,, Hal}, + title = {Noise-tolerant learning, the parity problem, and the statistical query model}, + journal = {J. ACM}, + volume = {50}, + number = {4}, + year = {2003}, + issn = {0004-5411}, + pages = {506--519}, + doi = {http://doi.acm.org/10.1145/792538.792543}, + publisher = {ACM}, + address = {New York, NY, USA}, +} + + +@INPROCEEDINGS{To06anovel, + author = {Marc P. C. Fossorier and Miodrag J. Mihaljević and Hideki Imai and Yang Cui and Kanta Matsuura}, + title = {A Novel Algorithm for Solving the {LPN} Problem and Its Applicatio to Security Evaluation of the {HB} Protocol for {RFID} Authentication}, + booktitle = {INDOCRYPT}, + editor = {Rana Barua and Tanja Lange}, + volume = {4329}, + series = {LNCS}, + year = {2006}, + pages = {48--62}, + publisher = {Springer} +} + +@INPROCEEDINGS{Levieil_animproved, + author = {Éric Levieil and Pierre-Alain Fouque}, + title = {An improved {LPN} algorithm}, + editor = {Roberto De Prisco and Moti Yung}, + booktitle = {Security and Cryptography for Networks --- SCN}, + volume = {4116}, + series = {LNCS}, + year = {2006}, + pages = {348--359}, + Publisher = {Springer Berlin / Heidelberg}, + ISSN = {0302-9743}, +} + +@INPROCEEDINGS{HBpp, +title={{HB}$^{++}$: a Lightweight Authentication Protocol Secure against Some Attacks}, +author={Bringer, J. and Chabanne, H. and Dottax, E.}, +booktitle={Security, Privacy and Trust in Pervasive and Ubiquitous Computing, 2006 --- SecPerU 2006}, +year={2006}, +month={June}, +volume={}, +number={}, +pages={28--33}, +doi={10.1109/SECPERU.2006.10}, +} + +@inproceedings{DBLP:conf/eurocrypt/GilbertRS08, + author = {Henri Gilbert and Matthew J. B. Robshaw and Yannick Seurin}, + title = {{HB}$^{\mbox{\#}}$: Increasing the Security and Efficiency of {HB}$^{\mbox{+}}$}, + booktitle = {Advances in Cryptology --- EUROCRYPT '08}, + year = {2008}, + pages = {361-378}, + ee = {http://dx.doi.org/10.1007/978-3-540-78967-3_21}, + crossref = {DBLP:conf/eurocrypt/2008}, + bibsource = {DBLP, http://dblp.uni-trier.de} +} + +@proceedings{DBLP:conf/eurocrypt/2008, + editor = {Nigel P. Smart}, + title = {Advances in Cryptology --- EUROCRYPT 2008, 27th Annual International Conference on the Theory and Applications of Cryptographic Techniques, Istanbul, Turkey, April 13-17, 2008. Proceedings}, + booktitle = {Advances in Cryptology --- EUROCRYPT '08}, + publisher = {Springer}, + series = {LNCS}, + volume = {4965}, + year = {2008}, + isbn = {978-3-540-78966-6}, + bibsource = {DBLP, http://dblp.uni-trier.de} +} + +@proceedings{DBLP:conf/fse/2001, + editor = {Mitsuru Matsui}, + title = {Fast Software Encryption, 8th International Workshop, FSE 2001 Yokohama, Japan, April 2-4, 2001, Revised Papers}, + booktitle = {FSE}, + publisher = {Springer}, + series = {LNCS}, + volume = {2355}, + year = {2002}, + isbn = {3-540-43869-6}, + bibsource = {DBLP, http://dblp.uni-trier.de} +} + +@techreport{Rabin79Digitalized, + author = {Rabin, M. O.}, + title = {Digitalized Signatures and Public-Key Functions as Intractable as Factorization}, + year = {1979}, + institution = {Massachusetts Institute of Technology}, + address = {Cambridge, MA, USA}, + } + +@article{HBmp, + author = {Munilla,, J. and Peinado,, A.}, + title = {{HB}-{MP}: A further step in the HB-family of lightweight authentication protocols}, + journal = {Comput. Netw.}, + volume = {51}, + number = {9}, + year = {2007}, + issn = {1389-1286}, + pages = {2262--2267}, + doi = {http://dx.doi.org/10.1016/j.comnet.2007.01.011}, + publisher = {Elsevier North-Holland, Inc.}, + address = {New York, NY, USA}, + } + +@article{HBstar, + author={D.N. Duc and K. Kim}, + title={Securing {HB}$^+$ Against {GRS} Man-in-the-Middle Attack}, + journal={Institute of Electronics, Information and Communication Engineers, Symposium on Cryptography and Information, Security}, + date = {January 23--26}, + year = {2007}, +} + +@INPROCEEDINGS{OuafiOV-2008-asiacrypt, + author = {Ouafi, Khaled and Overbeck, Raphael and Vaudenay, Serge}, + title = {On the Security of {HB\#} against a Man-in-the-Middle Attack}, + booktitle = {Advances in Cryptology --- Asiacrypt 2008}, + year = {2008}, + editor = {}, + volume = {5350}, + series = {LNCS}, + pages = {108--124}, + address = {Melbourne, Australia}, + month = {December}, + organization = {}, + publisher = {Springer}, + bibsource = {Information Security Group (GSI), UCL, Louvain-la-Neuve, Belgium}, +} + +@INPROCEEDINGS{PRESENT, + author = {Bogdanov, Andrey and Knudsen, Lars Ramkilde and Leander, Gregor and Paar, Christof and Poschmann, Axel and Robshaw, Matthew J.B. and Seurin, Yannick and Vikkelsoe, C.}, + title = {{PRESENT}: An Ultra-Lightweight Block Cipher}, + booktitle = {Workshop on Cryptographic Hardware and Embedded Systems --- CHES 2007}, + year = {2007}, + editor = {Paillier, Pascal and Verbauwhede, Ingrid}, + volume = {4727}, + series = {LNCS}, + pages = {450--466}, + address = {Vienna, Austria}, + month = {September}, + organization = {}, + publisher = {Springer-Verlag}, + bibsource = {Information Security Group (GSI), UCL, Louvain-la-Neuve, Belgium}, +} + +@INPROCEEDINGS{ChoiKKK-2006-isce, + author = {Choi, Yongje and Kim, Mooseop and Kim, Taesung and Kim, Howon}, + title = {Low power implementation of {SHA}-1 algorithm for {RFID} system}, + booktitle = {IEEE Tenth International Symposium on Consumer Electronics --- ISCE '06}, + year = {2006}, + editor = {}, + volume = {}, + series = {}, + pages = {1--5}, + address = {St.Petersburg, Russia}, + month = {September}, + organization = {}, + publisher = {}, + bibsource = {Information Security Group (GSI), UCL, Louvain-la-Neuve, Belgium}, +} + +@INPROCEEDINGS{DES-RFID-implement, + author = {Axel Poschmann and Gregor Le and Kai Schramm and Christof Paar}, + title = {A Family of Light-Weight Block Ciphers Based on {DES} Suited for {RFID} Applications}, + booktitle = {Proceedings of FSE 2007, LNCS}, + year = {2006}, + publisher = {Springer-Verlag} +} + +@article{4253019, +title={Strong Crypto for {RFID} Tags - A Comparison of Low-Power Hardware Implementations}, +author={Feldhofer, M. and Wolkerstorfer, J.}, +journal={Circuits and Systems, 2007. ISCAS 2007. IEEE International Symposium on}, +year={2007}, +month={May}, +volume={}, +number={}, +pages={1839-1842}, +keywords={cryptographic protocols, radiofrequency identificationAES-128, ECC-192, MD5, SHA-1, SHA-256, implementation efficiency, passive RFID tags, security protocols, standardized cryptographic algorithms, strong cryptography}, +doi={10.1109/ISCAS.2007.378272}, +ISSN={}, +} + +@techreport{PUF-optical, + author= {P. Ravinkanth}, + title= {Physical One-Way Functions}, + note = {Ph.D. Thesis}, + institution = {MIT}, + year={2001} +} + +@inproceedings{PUF-silicon, + author={B. Gassend and D. Clarke and M. van Dijk and S. Devadas}, + title = {Controlled Physical Random Functions}, + booktitle = {Proceedings of the 18th Annual Computer Security Applications Conference --- ACSAC '02}, + year = {2002}, + ISBN = {0-7695-1828-1}, + page = {149}, + publisher = {IEEE}, +} + +@article{PUF-circ-secret-key, + author = {D. Lim and J. W. Lee and B. Gassend and G. E. Suh and M. van Dijk and S. Devadas}, + title = {Extracting Secret Keys From Integrated Circuits}, + journal = {IEEE Transactions on Very Large Scale Integration (VLSI) Systems}, + pages = {1200--1205}, + year = {2005}, + issue = {13 (10)}, +} + + +@INPROCEEDINGS{Li99equivalencyreasoning, + author = {Chu Min Li}, + title = {Equivalency reasoning to solve a class of hard {SAT} problems}, + booktitle = {Information Processing Letters}, + year = {1999}, + pages = {76--1} +} + +@INPROCEEDINGS{Silva96conflictanalysis, + author = {Joo P. Marques and Silva Karem and A. Sakallah}, + title = {Conflict analysis in search algorithms for propositional satisfiability}, + booktitle = {Proc. of the IEEE Intl. Conf. on Tools with Artificial Intelligence}, + year = {1996} +} + +@article{Chaff01, + author = {Sharad Malik and Ying Zhao and Conor F. Madigan and Lintao Zhang and Matthew W. Moskewicz}, + title = {Chaff: Engineering an Efficient {SAT} Solver}, + journal ={Design Automation Conference}, + year = {2001}, + pages = {530-535}, + doi = {http://doi.ieeecomputersociety.org/10.1109/DAC.2001.935565}, + publisher = {IEEE Computer Society}, + address = {Los Alamitos, CA, USA}, +} +volume = {0}, +isbn = {}, + +@article{visualizingDPLL, + author = {Sinz, Carsten}, + title = {Visualizing {SAT} Instances and Runs of the {DPLL} Algorithm}, + journal = {J. Autom. Reason.}, + volume = {39}, + number = {2}, + year = {2007}, + issn = {0168-7433}, + pages = {219--243}, + doi = {http://dx.doi.org/10.1007/s10817-007-9074-1}, + publisher = {Kluwer Academic Publishers}, + address = {Hingham, MA, USA}, + } + +@inproceedings{nicolas.linear_feedback, + author={Nicolas T. Courtois}, + title={Fast Algebraic Attacks on Stream Ciphers with Linear Feedback}, + booktitle={Advances in Cryptology --- {CRYPTO} 2003}, + year={2003}, + pages={176-194}, + volume={2729/2003}, + series={LNCS}, + publisher={Springer}, +} + +@misc{Karsten-webpage-Cyrpto-1, + author={Karsten Nohl}, + title={Cryptanalysis of {C}rypto-1}, + howpublished={Press release}, + month={March}, + day = {12}, + year={2008}, + note= {\url{http://www.cs.virginia.edu/~kn5f/Mifare.Cryptanalysis.htm}} +} + +@Misc{Radboud-Mifare-press, + author = {{Digital {S}ecurity group, {R}adboud {U}niversity {N}ijmegen}}, + title = {Security Flaw in {M}ifare {C}lassic}, + howpublished = {Press release}, + month = {March}, + day = {12}, + year = {2008}, + note = {\url{http://www.ru.nl/english/general/radboud_university/vm/security_flaw_in/}}, +} + +@ARTICLE{Massacci00logicalcryptanalysis, + author = {Fabio Massacci and Laura Marraro}, + title = {Logical cryptanalysis as a {SAT}-problem: Encoding and analysis}, + journal = {Journal of Automated Reasoning}, + year = {2000}, + volume = {24}, + pages = {165--203} +} + +@article{Monte-Carlo-method, + abstract = {We shall present here the motivation and a general description of a method dealing with a class of problems in mathematical physics. The method is, essentially, a statistical approach to the study of differential equations, or more generally, of integro-differential equations that occur in various branches of the natural sciences.}, + author = {Metropolis, Nicholas and Ulam, S. }, + citeulike-article-id = {1886002}, + doi = {10.2307/2280232}, + journal = {Journal of the American Statistical Association}, + keywords = {random, sampling}, + number = {247}, + pages = {335--341}, + posted-at = {2009-04-12 22:32:37}, + priority = {2}, + title = {The {M}onte {C}arlo Method}, + url = {http://dx.doi.org/10.2307/2280232}, + volume = {44}, + year = {1949} +} + +@article{Rabin-primality-test, + author = {Rabin, Michael O. }, + citeulike-article-id = {1505894}, + doi = {10.1016/0022-314X(80)90084-0}, + journal = {J. Number Theory}, + mrnumber = {MR566880}, + number = {1}, + pages = {128--138}, + posted-at = {2007-07-27 00:11:40}, + priority = {2}, + title = {Probabilistic algorithm for testing primality}, + url = {http://dx.doi.org/10.1016/0022-314X(80)90084-0}, + volume = {12}, + year = {1980} +} + +@article{Mersenne-Twister, + address = {New York, NY, USA}, + author = {Matsumoto, Makoto and Nishimura, Takuji }, + citeulike-article-id = {611171}, + doi = {10.1145/272991.272995}, + issn = {1049-3301}, + journal = {ACM Trans. Model. Comput. Simul.}, + keywords = {algorithm}, + month = {January}, + number = {1}, + pages = {3--30}, + posted-at = {2008-10-26 00:03:42}, + priority = {0}, + publisher = {ACM Press}, + title = {Mersenne twister: a 623-dimensionally equidistributed uniform pseudo-random number generator}, + url = {http://dx.doi.org/10.1145/272991.272995}, + volume = {8}, + year = {1998} +} + +@inproceedings{L'Ecuyer98randomnumber, + author = {Pierre L'Ecuyer and Peter Hellekalek}, + title = {Random Number Generators: Selection Criteria and Testing}, + booktitle = {Random and Quasi-Random Point Sets}, + series = {Lecture Notes in Statistics}, + volume = {138}, + publisher = {Springer-Verlag}, + address = {New York}, + pages = {223--266}, + year = {1998}, +} + +@inproceedings{DBLP:conf/sat/SinzD05, + author = {Carsten Sinz and Edda-Maria Dieringer}, + title = {{DP}vis --- {A} Tool to Visualize the Structure of {SAT} Instances}, + booktitle = {SAT}, + year = {2005}, + pages = {257-268}, + ee = {http://dx.doi.org/10.1007/11499107_19}, + crossref = {DBLP:conf/sat/2005}, + bibsource = {DBLP, http://dblp.uni-trier.de} +} + + +@article{gomes00heavytailed, + author = {Carla P. Gomes and Bart Selman and Nuno Crato and Henry A. Kautz}, + title = {Heavy-Tailed Phenomena in Satisfiability and Constraint Satisfaction Problems}, + journal = {Journal of Automated Reasoning}, + volume = {24}, + number = {1/2}, + pages = {67--100}, + year = {2000}, + url = {citeseer.ist.psu.edu/article/gomes99heavytailed.html} +} + +@article{Mandelbrot60Pareto, + author = {Benoît B. Mandelbrot}, + title = {The Pareto-Lévy law and the distribution of income}, + journal = {Internat. Econom. Rev.}, + volume = {1}, + year = {1960}, + pages = {79--106} +} + +@inproceedings{Moura07tutorial, + author = {Leonardo de Moura, Bruno Dutertre and Natarajan Shankar}, + title = {A Tutorial on Satisfiability Modulo Theories}, + series = {LNCS}, + publisher = {Springer Berlin / Heidelberg}, + issn = {0302-9743}, + volume = {4590/2007}, + year = {2007}, + isbn = {978-3-540-73367-6}, + pages = {20--36}, + booktitle = {Computer Aided Verification}, +} + doi = {10.1007/978-3-540-73368-3}, + +@article{Karnaugh53Logic, + author = {Karnaugh, Maurice}, + year = {1953}, + month = {November}, + title = {The Map Method for Synthesis of Combinational Logic Circuits}, + journal = {Transactions of American Institute of Electrical Engineers part I}, + volume = {72}, + number = {9}, + pages = {593--599}, +} + +@inproceedings{Li00Integrating, + author = {Li, Chu Min}, + title = {Integrating Equivalency Reasoning into Davis-Putnam Procedure}, + booktitle = {Proceedings of the Seventeenth National Conference on Artificial Intelligence and Twelfth Conference on Innovative Applications of Artificial Intelligence}, + year = {2000}, + isbn = {0-262-51112-6}, + pages = {291--296}, + publisher = {AAAI Press / The MIT Press}, +} + +@article{Warners99TwoPhase, + author = {Joost P. Warners and Hans Van Maaren}, + title = {A Two Phase Algorithm for Solving a Class of Hard Satisfiability Problems}, + journal = {Operations Research Letters}, + year = {1999}, + volume = {23}, + number = {3--5}, + pages = {81--88} +} + +@inproceedings{Massacci00Taming, + author = {Peter Baumgartner and Fabio Massacci}, + title = {The Taming of the {(X)OR}}, + series = {LNCS}, + publisher = {Springer Berlin / Heidelberg}, + ISSN = {0302-9743}, + volume = {1861/2000}, + booktitle = {Computational Logic — CL 2000}, + doi = {10.1007/3-540-44957-4}, + year = {2000}, + isbn = {978-3-540-67797-0}, + pages = {508--522}, +} + +@inproceedings{Massacci99Using, + author = {Fabio Massacci}, + title = {Using {W}alk-{SAT} and {R}el-sat for cryptographic key search}, + booktitle = {Proc. of IJCAI-99}, + year = {1999}, + editor = {Morgan Kaufmann}, + pages = {290--295}, +} + +@inproceedings{Girault04Public, +author = {Marc Girault and David Lefranc}, +title = {Public Key Authentication with One (Online) Single Addition}, +series = {LNCS}, +bublisher = {Springer Berlin / Heidelberg}, +ISSN = {0302-9743}, +volume = {3156/2004}, +booktitle = {Cryptographic Hardware and Embedded Systems - CHES 2004}, +doi ={10.1007/b99451}, +year = {2004}, +isbn = {978-3-540-22666-6}, +pages = {967--984} +} + +@article{Hsieh72OnOptimal, + author = {Hsieh, H. Y. and Ghausi, M. S.}, + title = {On optimal-pivoting algorithms in sparse matrices}, + journal = {IEEE Trans. Circuit Theory}, + volume = {CT-19}, + pages = {93--96}, + month = {January}, + year = {1972} +} + +@article{HerasetalJAIR2008, + author = {Federico Heras and Javier Larrosa and Albert Oliveras}, + title = {{MiniMaxSAT: An efficient Weighted Max-SAT Solver}}, + journal = {Journal of Artificial Intelligence Research}, + volume = {31}, + year = {2008}, + pages = {1--32} + } + +@techreport{Wieringa07MiniMarch, + title = {{M}ini{M}arch --- {E}mbedding lookahead direction heuristics in a conflict driven solver}, + author = {Siert Wieringa}, + institution = {Technische Universiteit Delft}, + note = {Research Report}, + year = {2007}, + url = {http://www.st.ewi.tudelft.nl/sat/theses/minimarch.pdf}, +} + +techreport{OSI-MIT-Licence, +url = {http://www.opensource.org/licenses/mit-license.php} + + +@techreport{eStream, + title = {The e{STREAM} Portfolio}, + author = {Steve Babbage and Christophe De Canniere and Anne Canteaut and Carlos Cid and Henri Gilbert and Thomas Johansson and Christof Paar and Matthew Parker and Bart Preneel and Vincent Rijmen and Matt Robshaw and Hongjun Wu}, + url = {http://www.ecrypt.eu.org/stream/portfolio.pdf}, + institution = {eStream Project}, + year = {2008}, + month = {September}, + day = {8}, +} + +@techreport{Kibria08MiniSat, + author = {Raihan Kibria}, + title = {Midi{S}AT - {A}n extension of {M}ini{SAT}}, + institution = {Department of Electrical and Computer Engineering, Darmstadt University of Technology}, + year = {2005}, + month = {April}, + day = {26}, + url = {www.lri.fr/~simon/contest/results/descriptions/solvers/midisat_static.pdf}, +} + +@incollection{DaemenR05Rijndael, + author = {Joan Daemen and Vincent Rijmen}, + title = {Rijndael/AES}, + booktitle = {Encyclopedia of Cryptography and Security}, + year = {2005}, + ee = {http://dx.doi.org/10.1007/0-387-23483-7_358}, + crossref = {DBLP:reference/crypt/2005}, + bibsource = {DBLP, http://dblp.uni-trier.de} +} + +@book{DBLP:reference/crypt/2005, + editor = {Henk C. A. van Tilborg}, + title = {Encyclopedia of Cryptography and Security}, + publisher = {Springer}, + year = {2005}, + isbn = {978-0-387-23473-1}, + bibsource = {DBLP, http://dblp.uni-trier.de} +} + +@article{Strassen69Gaussian, + author = {Volker Strassen}, + title = {Gaussian Elimination is Not Optimal}, + journal = {Numerische Mathematik}, + volume = {13}, + pages = {354--356}, + year = {1969} +} + +@techreport{Crawford94TheMinimal, + author = {Crawford, J. M. and Kearns, M. J. and Shapire, R. E.}, + title = {The Minimal Disagreement Parity Problem as a Hard Satisfiability Problem}, + institution = {Computational Intelligence Research Laboratory and {AT\&T} {B}ell {L}abs}, + month = {February}, + year = {1994}, +} + +@inproceedings{OuafiV09Smashing, + author = {Khaled Ouafi and Serge Vaudenay}, + title = {Smashing {SQUASH}-0}, + volume = {5479}, + crossref = {DBLP:conf/eurocrypt/2009}, +} + +@inproceedings{ShamirRFIDSecLecture, +author = {Adi Shamir}, +title = {{SQUASH}: {A} new one-way hash function with provable security properties for higley contrained devices such as {RFID} tags}, +booktitle = {Invited lecture to the RFID Securty 2007 Workshop}, +year = {2007}, +} + +@misc{DES77, + author = {{National Bureau of Standards}}, + year = {1977}, + title = {Data {E}ncryption {S}tandard}, + institution = {U. S. Department of Commerce, National Bureau of Standards, Standards Publication (FIPS PUB) 46}, + address = {Washington, DC}, +}s + +@INPROCEEDINGS{Tsudik06Yet, + author = {Tsudik, Gene}, + title = {{YA-TRAP}: Yet Another Trivial {RFID} Authentication Protocol}, + booktitle = {International Conference on Pervasive Computing and Communications --- PerCom 2006}, + year = {2006}, + editor = {}, + volume = {}, + series = {}, + pages = {640--643}, + address = {Pisa, Italy}, + month = {March}, + organization = {IEEE}, + publisher = {IEEE Computer Society Press}, + bibsource = {Information Security Group (GSI), UCL, Louvain-la-Neuve, Belgium}, +} + + +@INPROCEEDINGS{Conti07RIPP, + author = {Conti, Mauro and Pietro, Roberto~Di and Mancini, Luigi~Vincenzo and Spognardi, Angelo}, + title = {{RIPP-FS}: an {RFID} Identification, Privacy Preserving Protocol with Forward Secrecy}, + booktitle = {International Workshop on Pervasive Computing and Communication Security --- PerSec '07}, + year = {2007}, + editor = {}, + volume = {}, + series = {}, + pages = {229--234}, + address = {New York City, New York, USA}, + month = {March}, + organization = {IEEE}, + publisher = {IEEE Computer Society Press}, + bibsource = {Information Security Group (GSI), UCL, Louvain-la-Neuve, Belgium}, +} + +@INPROCEEDINGS{Burmester06Provably, + author = {Burmester, Mike and Le, Tri van and Medeiros, Breno de}, + title = {Provably Secure Ubiquitous Systems: Universally Composable {RFID} Authentication Protocols}, + booktitle = {Conference on Security and Privacy for Emerging Areas in Communication Networks --- SecureComm '06}, + year = {2006}, + editor = {}, + volume = {}, + series = {}, + pages = {}, + address = {Baltimore, Maryland, USA}, + month = {August-September}, + organization = {IEEE}, + publisher = {}, + bibsource = {Information Security Group (GSI), UCL, Louvain-la-Neuve, Belgium}, +} + +@misc{ISO14443-standard, + author = {ISO/IEC}, + title = {14443-3 --- {I}dentification cards -- {C}ontactless integrated circuit(s) cards -- {P}roximity cards -- {P}art 3: {I}nitialization and anticollision}, + year = {2001, Stage: 90.92 --- 2007-12-11}, + institution = {International Organization for Standardization}, + address = {Geneva, Switzerland}, + url = {http://www.isotopicmaps.org/sam/sam-model/YYYY-MM-DD/}, +} + +@INPROCEEDINGS{Bailey05Shoehorning, + author = {Bailey, Daniel and Juels, Ari}, + title = {{Shoehorning Security into the EPC Standard}}, + booktitle = {International Conference on Security in Communication Networks --- SCN 2006}, + year = {2006}, + editor = {De~Prisco, Roberto and Yung, Moti}, + volume = {4116}, + series = {LNCS}, + pages = {303--320}, + address = {Maiori, Italy}, + month = {September}, + organization = {}, + publisher = {Springer-Verlag}, + bibsource = {Information Security Group (GSI), UCL, Louvain-la-Neuve, Belgium}, +} + +@INPROCEEDINGS{Soos08Analysing, + author = {Soos, Mate}, + title = {{Analysing the {M}olva and {D}i {P}ietro Private {RFID} Authentication Scheme}}, + booktitle = {Workshop on RFID Security --- RFIDSec'08}, + year = {2008}, + editor = {}, + volume = {}, + series = {}, + pages = {}, + address = {Budapest, Hungary}, + month = {July}, + organization = {}, + publisher = {}, +} + +@inproceedings{DBLP:conf/ccs/BurmesterMM08, + author = {Mike Burmester and Breno de Medeiros and Rossana Motta}, + title = {Robust, anonymous {RFID} authentication with constant key-lookup}, + booktitle = {ASIACCS}, + year = {2008}, + pages = {283-291}, + ee = {http://doi.acm.org/10.1145/1368310.1368351}, + crossref = {DBLP:conf/ccs/2008asia}, + bibsource = {DBLP, http://dblp.uni-trier.de} +} + +@proceedings{DBLP:conf/ccs/2008asia, + editor = {Masayuki Abe and Virgil D. Gligor}, + title = {Proceedings of the 2008 ACM Symposium on Information, Computer and Communications Security, ASIACCS 2008, Tokyo, Japan, March 18-20, 2008}, + booktitle = {ASIACCS}, + publisher = {ACM}, + year = {2008}, + isbn = {978-1-59593-979-1}, + bibsource = {DBLP, http://dblp.uni-trier.de} +} + +@INPROCEEDINGS{Blass09Ff, + author = {Blass, Erik-Oliver and Kurmus, Anil and Molva, Refik and Noubir, Guevara and Shikfa, Abdullatif}, + title = {{The {F}f-Family of Protocols for {RFID}-Privacy and Authentication}}, + booktitle = {Workshop on RFID Security --- RFIDSec'09}, + year = {2009}, + editor = {}, + volume = {}, + series = {}, + pages = {}, + address = {Leuven, Belgium}, + month = {July}, + organization = {}, + publisher = {}, + bibsource = {Information Security Group (GSI), UCL, Louvain-la-Neuve, Belgium}, +} + +@inproceedings{DBLP:conf/cardis/CastellucciaA06, + author = {Claude Castelluccia and Gildas Avoine}, + title = {Noisy Tags: {A} Pretty Good Key Exchange Protocol for {RFID} Tags}, + booktitle = {CARDIS}, + year = {2006}, + pages = {289-299}, + ee = {http://dx.doi.org/10.1007/11733447_21}, + crossref = {DBLP:conf/cardis/2006}, + bibsource = {DBLP, http://dblp.uni-trier.de} +} + +@proceedings{DBLP:conf/cardis/2006, + editor = {Josep Domingo-Ferrer and + Joachim Posegga and + Daniel Schreckling}, + title = {Smart Card Research and Advanced Applications, 7th IFIP + WG 8.8/11.2 International Conference, CARDIS 2006, Tarragona, + Spain, April 19-21, 2006, Proceedings}, + booktitle = {CARDIS}, + publisher = {Springer}, + series = {LNCS}, + volume = {3928}, + year = {2006}, + isbn = {3-540-33311-8}, + bibsource = {DBLP, http://dblp.uni-trier.de} +} + + +@inproceedings{DBLP:conf/ches/SavryPDRR07, + author = {O. Savry and F. Pebay-Peyroula and F. Dehmas and G. Robert and J. Reverdy}, + title = {{RFID} Noisy Reader --- {H}ow to Prevent from Eavesdropping on the Communication?}, + booktitle = {CHES}, + year = {2007}, + pages = {334-345}, + ee = {http://dx.doi.org/10.1007/978-3-540-74735-2_23}, + crossref = {DBLP:conf/ches/2007}, + bibsource = {DBLP, http://dblp.uni-trier.de} +} + +@proceedings{DBLP:conf/ches/2007, + editor = {Pascal Paillier and Ingrid Verbauwhede}, + title = {Cryptographic Hardware and Embedded Systems --- {CHES} 2007, + 9th International Workshop, Vienna, Austria, September 10-13, + 2007, Proceedings}, + booktitle = {CHES}, + publisher = {Springer}, + series = {LNCS}, + volume = {4727}, + year = {2007}, + isbn = {978-3-540-74734-5}, + bibsource = {DBLP, http://dblp.uni-trier.de} +} + +@article{Hancke07Modulating, + author = {G. Hancke}, + title = {Modulating a noisy carrier signal for eavesdropping-resistant {HF RFID}}, + journal = {e\&i --- Elektrotechnik und Informationstechnik}, + year = {2007}, + volume = {124}, + number = {11}, + month = {November}, + pages = {404--408}, + publisher = {Springer Wien}, + ISSN = {0932-383X}, + DOI = {10.1007/s00502-007-0479-7} +} + +@inproceedings{1423361, + author = {Babbage, Steve and Dodd, Matthew}, + title = {The {MICKEY} Stream Ciphers}, + booktitle = {New Stream Cipher Designs: The e{STREAM} Finalists}, + year = {2008}, + isbn = {978-3-540-68350-6}, + pages = {191--209}, + doi = {http://dx.doi.org/10.1007/978-3-540-68351-3_15}, + publisher = {Springer-Verlag}, + address = {Berlin, Heidelberg}, + } + +@inproceedings{DBLP:conf/wistp/DeursenMR08, + author = {Ton van Deursen and Sjouke Mauw and Sasa Radomirovic}, + title = {Untraceability of {RFID} Protocols}, + booktitle = {WISTP}, + year = {2008}, + pages = {1-15}, + ee = {http://dx.doi.org/10.1007/978-3-540-79966-5_1}, + crossref = {DBLP:conf/wistp/2008}, + bibsource = {DBLP, http://dblp.uni-trier.de} +} + +@proceedings{DBLP:conf/wistp/2008, + editor = {Jose Antonio Onieva and Damien Sauveron and Serge Chaumette and Dieter Gollmann and Constantinos Markantonakis}, + title = {Information Security Theory and Practices. Smart Devices, Convergence and Next Generation Networks, Second {IFIP WG} 11.2 International Workshop, {WISTP} 2008, Seville, Spain, May 13-16, 2008. Proceedings}, + booktitle = {WISTP}, + publisher = {Springer}, + series = {LNCS}, + volume = {5019}, + year = {2008}, + isbn = {978-3-540-79965-8}, + bibsource = {DBLP, http://dblp.uni-trier.de} +} + +@misc{A51, + author = {Ross Anderson}, + title = {A5 (was: Hacking digital phones)}, + howpublished = {Newsgroup Communication}, + year = {1994}, +} + +@inproceedings{DBLP:conf/cardis/GansHG08, + author = {Gerhard de Koning Gans and Jaap-Henk Hoepman and Flavio D. Garcia}, + title = {A Practical Attack on the {MIFARE} {C}lassic}, + booktitle = {CARDIS}, + year = {2008}, + pages = {267-282}, + ee = {http://dx.doi.org/10.1007/978-3-540-85893-5_20}, + crossref = {DBLP:conf/cardis/2008}, + bibsource = {DBLP, http://dblp.uni-trier.de} +} + +@proceedings{DBLP:conf/cardis/2008, + editor = {Gilles Grimaud and Fran\c{c}ois-Xavier Standaert}, + title = {Smart Card Research and Advanced Applications, 8th IFIP WG 8.8/11.2 International Conference, CARDIS 2008, London, UK, September 8-11, 2008. Proceedings}, + booktitle = {CARDIS}, + publisher = {Springer}, + series = {LNCS}, + volume = {5189}, + year = {2008}, + isbn = {978-3-540-85892-8}, + bibsource = {DBLP, http://dblp.uni-trier.de} +} + +@inproceedings{DBLP:conf/ima/CourtoisB07, + author = {Nicolas T. Courtois and Gregory V. Bard}, + title = {Algebraic Cryptanalysis of the {D}ata {E}ncryption {S}tandard}, + booktitle = {{IMA} Int. Conf.}, + year = {2007}, + pages = {152-169}, + ee = {http://dx.doi.org/10.1007/978-3-540-77272-9_10}, + crossref = {DBLP:conf/ima/2007}, + bibsource = {DBLP, http://dblp.uni-trier.de} +} + +@proceedings{DBLP:conf/ima/2007, + editor = {Steven D. Galbraith}, + title = {Cryptography and Coding, 11th IMA International Conference, Cirencester, UK, December 18-20, 2007, Proceedings}, + booktitle = {IMA Int. Conf.}, + publisher = {Springer}, + series = {LNCS}, + volume = {4887}, + year = {2007}, + isbn = {978-3-540-77271-2}, + bibsource = {DBLP, http://dblp.uni-trier.de} +} + +@book{Bard-algebraic, + title = {Algebraic Cryptanalysis}, + author = {Gregory V. Bard}, + year = {2009}, + pages = {392}, + volume = {XXXIV}, + series = {Security and Cryptology}, + ISBN = {978-0-387-88756-2}, + publisher = {Springer}, +} + +@inproceedings{Graphviz, + author = {John Ellson and Emden R. Gansner and Eleftherios Koutsofios and Stephen C. North and Gordon Woodhull}, + year = {2001}, + title = {Graphviz --- open source graph drawing tools}, + pages = {483--484}, + crossref = {DBLP:conf/gd/2001}, +} + +@proceedings{DBLP:conf/gd/2001, + editor = {Petra Mutzel and Michael J{\"u}nger and Sebastian Leipert}, + title = {Graph Drawing, 9th International Symposium, GD 2001 Vienna, Austria, September 23--26, 2001, Revised Papers}, + booktitle = {Graph Drawing}, + publisher = {Springer}, + series = {LNCS}, + volume = {2265}, + year = {2002}, + isbn = {3-540-43309-0}, + bibsource = {DBLP, http://dblp.uni-trier.de} +} + +@inproceedings{Borghoff09Mixed, + booktitle = {WEWoRC --- Western European Workshop on Research in Cryptology}, + title = {Bivium as a Mixed-0-1 Linear Programming Problem}, + author = {Julia Borghoff and Lars R. Knudsen and Mathias Stolpe}, + month = {July}, + year = {2009}, + address = {Graz, Austria}, +} + +@inproceedings{DBLP:conf/eurocrypt/DinurS09, + author = {Itai Dinur and Adi Shamir}, + title = {Cube Attacks on Tweakable Black Box Polynomials}, + booktitle = {EUROCRYPT}, + year = {2009}, + pages = {278--299}, + ee = {http://dx.doi.org/10.1007/978-3-642-01001-9_16}, + crossref = {DBLP:conf/eurocrypt/2009}, + bibsource = {DBLP, http://dblp.uni-trier.de} +} + +@proceedings{DBLP:conf/eurocrypt/2009, + editor = {Antoine Joux}, + title = {Advances in Cryptology --- EUROCRYPT 2009, 28th Annual International Conference on the Theory and Applications of Cryptographic Techniques, Cologne, Germany, April 26--30, 2009. Proceedings}, + booktitle = {EUROCRYPT}, + publisher = {Springer}, + series = {LNCS}, + volume = {5479}, + year = {2009}, + isbn = {978-3-642-01000-2}, + ee = {http://dx.doi.org/10.1007/978-3-642-01001-9}, + bibsource = {DBLP, http://dblp.uni-trier.de} +} + +@book{eStreamFinalists, + title = {The e{STREAM} Finalists}, + editor = {Matthew Robshaw and Olivier Billet}, + series = {LNCS}, + subseries = {Security and Cryptology}, + volume = {4986}, + year = {2008}, + pages = {295}, + isbn = {978-3-540-68350-6}, + publisher = {Springer}, +} + +@article{diffie76new, + author = "Whitfield Diffie and Martin E. Hellman", + title = "New Directions in Cryptography", + journal = "IEEE Transactions on Information Theory", + volume = "IT-22", + number = "6", + pages = "644--654", + date = "November 1976", + year = "1976", + url = "citeseer.ist.psu.edu/diffie76new.html" +} + +@ARTICLE{Rivest78amethod, + author = {Ron L. Rivest and Adi Shamir and Leonard Max Adleman}, + title = {A Method for Obtaining Digital Signatures and Public-Key Cryptosystems}, + journal = {Communications of the ACM}, + year = {1978}, + volume = {21}, + pages = {120--126} +} + +@inproceedings{Pfizmann01Anonimity, + author = {Andreas Pfitzmann and Marit Köhntopp}, + title = {Anonymity, Unobservability, and Pseudonymity --- {A} Proposal for Terminology}, + series = {LNCS}, + publisher = {Springer Berlin / Heidelberg}, + issn = {0302-9743}, + volume = {2009}, + year = {2001}, + booktitle = {Designing Privacy Enhancing Technologies}, + doi = {10.1007/3-540-44702-4}, + isbn = {978-3-540-41724-8}, + pages = {1--9}, +} + +@misc{Bard07efficientmethods, + author = {Gregory V. Bard and Nicolas T. Courtois and Chris Jefferson}, + title = {Efficient Methods for Conversion and Solution of Sparse Systems of Low-Degree Multivariate Polynomials over {GF}(2) via {SAT}-Solvers}, + howpublished = {Cryptology ePrint Archive, Report 2007/024, \url{http://eprint.iacr.org/2007/024}}, + year = {2007}, + organization = {IACR}, +} + +@inproceedings{DBLP:conf/sat/SoosNC09, + author = {Mate Soos and + Karsten Nohl and + Claude Castelluccia}, + title = {Extending {SAT} Solvers to Cryptographic Problems}, + booktitle = {SAT}, + year = {2009}, + pages = {244--257}, + ee = {http://dx.doi.org/10.1007/978-3-642-02777-2_24}, + crossref = {DBLP:conf/sat/2009}, + bibsource = {DBLP, http://dblp.uni-trier.de} +} + +@inproceedings{DBLP:conf/cav/GaneshD07, + author = {Vijay Ganesh and + David L. Dill}, + title = {A Decision Procedure for Bit-Vectors and Arrays}, + booktitle = {CAV}, + year = {2007}, + pages = {519-531}, + ee = {http://dx.doi.org/10.1007/978-3-540-73368-3_52}, + crossref = {DBLP:conf/cav/2007}, + bibsource = {DBLP, http://dblp.uni-trier.de} +} + +@proceedings{DBLP:conf/cav/2007, + editor = {Werner Damm and + Holger Hermanns}, + title = {Computer Aided Verification, 19th International Conference, + CAV 2007, Berlin, Germany, July 3-7, 2007, Proceedings}, + booktitle = {CAV}, + publisher = {Springer}, + series = {LNCS}, + volume = {4590}, + year = {2007}, + isbn = {978-3-540-73367-6}, + bibsource = {DBLP, http://dblp.uni-trier.de} +} + +@misc{Logic2CNF, + author = {Edd Barrett}, + title = {Logic2{CNF} Logic Solver and Converter}, + note = {\url{http://projects.cs.kent.ac.uk/projects/logic2cnf/trac/wiki/WikiStart}}, + year = {2010}, + month = {March}, +} + +@misc{CryptoMiniSat, + author = {Mate Soos}, + title = {Crypto{M}ini{S}at --- a {SAT} solver for cryptographic problems}, + note = {\url{http://planete.inrialpes.fr/~soos/CryptoMiniSat/index.html}}, + year = {2009}, +} + +@inproceedings{DBLP:conf/sat/EenB05, + author = {Niklas E{\'e}n and + Armin Biere}, + title = {Effective Preprocessing in {SAT} Through Variable and Clause + Elimination}, + booktitle = {SAT}, + year = {2005}, + pages = {61-75}, + ee = {http://dx.doi.org/10.1007/11499107_5}, + crossref = {DBLP:conf/sat/2005}, + bibsource = {DBLP, http://dblp.uni-trier.de} +} + +@inproceedings{glucose, + author = {Gilles Audemard and Laurent Simon}, + title = {{GLUCOSE}: a solver that predicts learnt clauses quality}, + booktitle = {SAT 2009 competitive events booklet}, + year = {2009}, + pages = {7--8}, +} + +@inproceedings{precosat, + author = {Armin Biere}, + title = {P\{re,i\}coSAT@SC’09}, + booktitle = {SAT 2009 competitive events booklet}, + year = {2009}, + pages = {41--42}, +} + +@inproceedings{DBLP:conf/sat/HeuleM04a, + author = {Marijn Heule and + Hans van Maaren}, + title = {Aligning {CNF}- and Equivalence-Reasoning}, + booktitle = {SAT (Selected Papers}, + year = {2004}, + pages = {145--156}, + ee = {http://dx.doi.org/10.1007/11527695_12}, + crossref = {DBLP:conf/sat/2004lncs}, + bibsource = {DBLP, http://dblp.uni-trier.de} +} + +@proceedings{DBLP:conf/sat/2004lncs, + editor = {Holger H. Hoos and + David G. Mitchell}, + title = {Theory and Applications of Satisfiability Testing, 7th International + Conference, SAT 2004, Vancouver, BC, Canada, May 10-13, + 2004, Revised Selected Papers}, + booktitle = {SAT (Selected Papers)}, + publisher = {Springer}, + series = {LNCS}, + volume = {3542}, + year = {2005}, + isbn = {3-540-27829-X}, + bibsource = {DBLP, http://dblp.uni-trier.de} +} + +@techreport{Heule-thesis, + author = {Marijn Heule}, + title = {{m}arch: Towards a lookahead Sat solver for general purposes}, + institution={Technische Universiteit Delft}, + month={February}, + year={2004}, +} + +@techreport{Heule-phd, + author = {Marijn J.H. Heule}, + title = {Smart solving: Tool and techniques for satisfiability solvers}, + institution={Technische Universiteit Delft}, + year={2008}, +} + +@article{DBLP:journals/amai/JeroslowW90, + author = {Robert G. Jeroslow and + Jinchang Wang}, + title = {Solving Propositional Satisfiability Problems}, + journal = {Ann. Math. Artif. Intell.}, + volume = {1}, + year = {1990}, + pages = {167-187}, + bibsource = {DBLP, http://dblp.uni-trier.de} +} + +@inproceedings{DBLP:conf/sat/PipatsrisawatD07, + author = {Knot Pipatsrisawat and + Adnan Darwiche}, + title = {A Lightweight Component Caching Scheme for Satisfiability + Solvers}, + booktitle = {SAT}, + year = {2007}, + pages = {294-299}, + ee = {http://dx.doi.org/10.1007/978-3-540-72788-0_28}, + crossref = {DBLP:conf/sat/2007}, + bibsource = {DBLP, http://dblp.uni-trier.de} +} + +@proceedings{DBLP:conf/sat/2007, + editor = {Jo{\~a}o Marques-Silva and + Karem A. Sakallah}, + title = {Theory and Applications of Satisfiability Testing --- SAT + 2007, 10th International Conference, Lisbon, Portugal, May + 28-31, 2007, Proceedings}, + booktitle = {SAT}, + publisher = {Springer}, + series = {LNCS}, + volume = {4501}, + year = {2007}, + isbn = {978-3-540-72787-3}, + bibsource = {DBLP, http://dblp.uni-trier.de} +} + +@inproceedings{DBLP:conf/ijcai/AudemardS09, + author = {Gilles Audemard and + Laurent Simon}, + title = {Predicting Learnt Clauses Quality in Modern {SAT} Solvers}, + booktitle = {IJCAI}, + year = {2009}, + pages = {399-404}, + ee = {http://ijcai.org/papers09/Papers/IJCAI09-074.pdf}, + crossref = {DBLP:conf/ijcai/2009}, + bibsource = {DBLP, http://dblp.uni-trier.de} +} + +@proceedings{DBLP:conf/ijcai/2009, + editor = {Craig Boutilier}, + title = {IJCAI 2009, Proceedings of the 21st International Joint + Conference on Artificial Intelligence, Pasadena, California, + USA, July 11-17, 2009}, + booktitle = {IJCAI}, + year = {2009}, + bibsource = {DBLP, http://dblp.uni-trier.de} +} + + +@inproceedings{DBLP:conf/tacas/JarvisaloBH10, + author = {Matti J{\"a}rvisalo and + Armin Biere and + Marijn Heule}, + title = {Blocked Clause Elimination}, + booktitle = {TACAS}, + year = {2010}, + pages = {129-144}, + ee = {http://dx.doi.org/10.1007/978-3-642-12002-2_10}, + crossref = {DBLP:conf/tacas/2010}, + bibsource = {DBLP, http://dblp.uni-trier.de} +} + +@proceedings{DBLP:conf/tacas/2010, + editor = {Javier Esparza and + Rupak Majumdar}, + title = {Tools and Algorithms for the Construction and Analysis of + Systems, 16th International Conference, TACAS 2010, Held + as Part of the Joint European Conferences on Theory and + Practice of Software, ETAPS 2010, Paphos, Cyprus, March + 20-28, 2010. Proceedings}, + booktitle = {TACAS}, + publisher = {Springer}, + series = {LNCS}, + volume = {6015}, + year = {2010}, + isbn = {978-3-642-12001-5}, + ee = {http://dx.doi.org/10.1007/978-3-642-12002-2}, + bibsource = {DBLP, http://dblp.uni-trier.de} +} + +@article{DBLP:journals/dam/Li03, + author = {Chu Min Li}, + title = {Equivalent literal propagation in the {DLL} procedure}, + journal = {Discrete Applied Mathematics}, + volume = {130}, + number = {2}, + year = {2003}, + pages = {251-276}, + ee = {http://dx.doi.org/10.1016/S0166-218X(02)00407-9}, + bibsource = {DBLP, http://dblp.uni-trier.de} +} + +@misc{Grid5000, + author = {{The Grid'5000 team}}, + title = {The {G}rid'5000 project}, + note = {\url{https://www.grid5000.fr}}, +} + year = {2008}, + +@article{DBLP:journals/endm/Berre01, + author = {Daniel Le Berre}, + title = {Exploiting the real power of unit propagation lookahead}, + journal = {Electronic Notes in Discrete Mathematics}, + volume = {9}, + year = {2001}, + pages = {59-80}, + ee = {http://dx.doi.org/10.1016/S1571-0653(04)00314-2}, + bibsource = {DBLP, http://dblp.uni-trier.de} +} + +@inproceedings{DBLP:conf/sat/GershmanS05, + author = {Roman Gershman and Ofer Strichman}, + title = {Cost-Effective Hyper-Resolution for Preprocessing {CNF} Formulas}, + booktitle = {SAT}, + year = {2005}, + pages = {423-429}, + ee = {http://dx.doi.org/10.1007/11499107_34}, + crossref = {DBLP:conf/sat/2005}, + bibsource = {DBLP, http://dblp.uni-trier.de} +} + + +@inproceedings{DBLP:conf/sat/HeuleJB11, + author = {Marijn Heule and + Matti J{\"a}rvisalo and + Armin Biere}, + title = {Efficient {CNF} Simplification Based on Binary Implication + Graphs}, + booktitle = {SAT}, + year = {2011}, + pages = {201-215}, + ee = {http://dx.doi.org/10.1007/978-3-642-21581-0_17}, + crossref = {DBLP:conf/sat/2011}, + bibsource = {DBLP, http://dblp.uni-trier.de} +} +@proceedings{DBLP:conf/sat/2011, + editor = {Karem A. Sakallah and + Laurent Simon}, + title = {Theory and Applications of Satisfiability Testing - SAT + 2011 - 14th International Conference, SAT 2011, Ann Arbor, + MI, USA, June 19-22, 2011. Proceedings}, + booktitle = {SAT}, + publisher = {Springer}, + series = {LNCS}, + volume = {6695}, + year = {2011}, + isbn = {978-3-642-21580-3}, + ee = {http://dx.doi.org/10.1007/978-3-642-21581-0}, + bibsource = {DBLP, http://dblp.uni-trier.de} +} + + +@inproceedings{DBLP:conf/ecai/PietteHS08, + author = {C{\'e}dric Piette and + Youssef Hamadi and + Lakhdar Sais}, + title = {Vivifying Propositional Clausal Formulae}, + booktitle = {ECAI}, + year = {2008}, + pages = {525-529}, + ee = {http://dx.doi.org/10.3233/978-1-58603-891-5-525}, + crossref = {DBLP:conf/ecai/2008}, + bibsource = {DBLP, http://dblp.uni-trier.de} +} +@proceedings{DBLP:conf/ecai/2008, + editor = {Malik Ghallab and + Constantine D. Spyropoulos and + Nikos Fakotakis and + Nikolaos M. Avouris}, + title = {ECAI 2008 - 18th European Conference on Artificial Intelligence, + Patras, Greece, July 21-25, 2008, Proceedings}, + booktitle = {ECAI}, + publisher = {IOS Press}, + series = {Frontiers in Artificial Intelligence and Applications}, + volume = {178}, + year = {2008}, + isbn = {978-1-58603-891-5}, + ee = {http://www.booksonline.iospress.nl/Content/View.aspx?piid=9905}, + bibsource = {DBLP, http://dblp.uni-trier.de} +} + +@inproceedings{DBLP:conf/sat/HanS09, + author = {HyoJung Han and + Fabio Somenzi}, + title = {On-the-Fly Clause Improvement}, + booktitle = {SAT}, + year = {2009}, + pages = {209-222}, + ee = {http://dx.doi.org/10.1007/978-3-642-02777-2_21}, + crossref = {DBLP:conf/sat/2009}, + bibsource = {DBLP, http://dblp.uni-trier.de} +} + + +@inproceedings{DBLP:conf/sat/SorenssonB09, + author = {Niklas S{\"o}rensson and + Armin Biere}, + title = {Minimizing Learned Clauses}, + booktitle = {SAT}, + year = {2009}, + pages = {237-243}, + ee = {http://dx.doi.org/10.1007/978-3-642-02777-2_23}, + crossref = {DBLP:conf/sat/2009}, + bibsource = {DBLP, http://dblp.uni-trier.de} +} + +@inproceedings{DBLP:conf/sat/BacchusW03, + author = {Fahiem Bacchus and + Jonathan Winter}, + title = {Effective Preprocessing with Hyper-Resolution and Equality + Reduction}, + booktitle = {SAT}, + year = {2003}, + pages = {341-355}, + ee = {http://dx.doi.org/10.1007/978-3-540-24605-3_26}, + crossref = {DBLP:conf/sat/2003}, + bibsource = {DBLP, http://dblp.uni-trier.de} +} +@proceedings{DBLP:conf/sat/2003, + editor = {Enrico Giunchiglia and + Armando Tacchella}, + title = {Theory and Applications of Satisfiability Testing, 6th International + Conference, SAT 2003. Santa Margherita Ligure, Italy, May + 5-8, 2003 Selected Revised Papers}, + booktitle = {SAT}, + publisher = {Springer}, + series = {LNCS}, + volume = {2919}, + year = {2004}, + isbn = {3-540-20851-8}, + bibsource = {DBLP, http://dblp.uni-trier.de} +} + +@proceedings{DBLP:conf/sat/2005, + editor = {Fahiem Bacchus and + Toby Walsh}, + title = {Theory and Applications of Satisfiability Testing, 8th International + Conference, SAT 2005, St. Andrews, UK, June 19-23, 2005, + Proceedings}, + booktitle = {SAT}, + publisher = {Springer}, + series = {LNCS}, + volume = {3569}, + year = {2005}, + isbn = {3-540-26276-8}, + bibsource = {DBLP, http://dblp.uni-trier.de} +} + +@proceedings{DBLP:conf/sat/2009, + editor = {Oliver Kullmann}, + title = {Theory and Applications of Satisfiability Testing - SAT + 2009, 12th International Conference, SAT 2009, Swansea, + UK, June 30 - July 3, 2009. Proceedings}, + booktitle = {SAT}, + publisher = {Springer}, + series = {Lecture Notes in Computer Science}, + volume = {5584}, + year = {2009}, + isbn = {978-3-642-02776-5}, + ee = {http://dx.doi.org/10.1007/978-3-642-02777-2}, + bibsource = {DBLP, http://dblp.uni-trier.de} +} + +@inproceedings{DBLP:conf/hvc/MantheyHB12, + author = {Norbert Manthey and + Marijn Heule and + Armin Biere}, + title = {Automated Reencoding of Boolean Formulas}, + booktitle = {Haifa Verification Conference}, + year = {2012}, + pages = {102-117}, + ee = {http://dx.doi.org/10.1007/978-3-642-39611-3_14}, + crossref = {DBLP:conf/hvc/2012}, + bibsource = {DBLP, http://dblp.uni-trier.de} +} + +@proceedings{DBLP:conf/hvc/2012, + editor = {Armin Biere and + Amir Nahir and + Tanja E. J. Vos}, + title = {Hardware and Software: Verification and Testing - 8th International + Haifa Verification Conference, HVC 2012, Haifa, Israel, + November 6-8, 2012. Revised Selected Papers}, + booktitle = {Haifa Verification Conference}, + publisher = {Springer}, + series = {Lecture Notes in Computer Science}, + volume = {7857}, + year = {2013}, + isbn = {978-3-642-39610-6}, + ee = {http://dx.doi.org/10.1007/978-3-642-39611-3}, + bibsource = {DBLP, http://dblp.uni-trier.de} +} + +@book{Quinlan:1993:CPM:152181, + author = {Quinlan, J. Ross}, + title = {C4.5: Programs for Machine Learning}, + year = {1993}, + isbn = {1-55860-238-0}, + publisher = {Morgan Kaufmann Publishers Inc.}, + address = {San Francisco, CA, USA}, +} diff --git a/cryptominisat/cppsrc/docs/satcomp16-pdf/splncs03.bst b/cryptominisat/cppsrc/docs/satcomp16-pdf/splncs03.bst new file mode 100644 index 00000000..32791691 --- /dev/null +++ b/cryptominisat/cppsrc/docs/satcomp16-pdf/splncs03.bst @@ -0,0 +1,1519 @@ +%% BibTeX bibliography style `splncs03' +%% +%% BibTeX bibliography style for use with numbered references in +%% Springer Verlag's "Lecture Notes in Computer Science" series. +%% (See Springer's documentation for llncs.cls for +%% more details of the suggested reference format.) Note that this +%% file will not work for author-year style citations. +%% +%% Use \documentclass{llncs} and \bibliographystyle{splncs03}, and cite +%% a reference with (e.g.) \cite{smith77} to get a "[1]" in the text. +%% +%% This file comes to you courtesy of Maurizio "Titto" Patrignani of +%% Dipartimento di Informatica e Automazione Universita' Roma Tre +%% +%% ================================================================================================ +%% This was file `titto-lncs-02.bst' produced on Wed Apr 1, 2009 +%% Edited by hand by titto based on `titto-lncs-01.bst' (see below) +%% +%% CHANGES (with respect to titto-lncs-01.bst): +%% - Removed the call to \urlprefix (thus no "URL" string is added to the output) +%% ================================================================================================ +%% This was file `titto-lncs-01.bst' produced on Fri Aug 22, 2008 +%% Edited by hand by titto based on `titto.bst' (see below) +%% +%% CHANGES (with respect to titto.bst): +%% - Removed the "capitalize" command for editors string "(eds.)" and "(ed.)" +%% - Introduced the functions titto.bbl.pages and titto.bbl.page for journal pages (without "pp.") +%% - Added a new.sentence command to separate with a dot booktitle and series in the inproceedings +%% - Commented all new.block commands before urls and notes (to separate them with a comma) +%% - Introduced the functions titto.bbl.volume for handling journal volumes (without "vol." label) +%% - Used for editors the same name conventions used for authors (see function format.in.ed.booktitle) +%% - Removed a \newblock to avoid long spaces between title and "In: ..." +%% - Added function titto.space.prefix to add a space instead of "~" after the (removed) "vol." label +%% ================================================================================================ +%% This was file `titto.bst', +%% generated with the docstrip utility. +%% +%% The original source files were: +%% +%% merlin.mbs (with options: `vonx,nm-rvvc,yr-par,jttl-rm,volp-com,jwdpg,jwdvol,numser,ser-vol,jnm-x,btit-rm,bt-rm,edparxc,bkedcap,au-col,in-col,fin-bare,pp,ed,abr,mth-bare,xedn,jabr,and-com,and-com-ed,xand,url,url-blk,em-x,nfss,') +%% ---------------------------------------- +%% *** Tentative .bst file for Springer LNCS *** +%% +%% Copyright 1994-2007 Patrick W Daly + % =============================================================== + % IMPORTANT NOTICE: + % This bibliographic style (bst) file has been generated from one or + % more master bibliographic style (mbs) files, listed above. + % + % This generated file can be redistributed and/or modified under the terms + % of the LaTeX Project Public License Distributed from CTAN + % archives in directory macros/latex/base/lppl.txt; either + % version 1 of the License, or any later version. + % =============================================================== + % Name and version information of the main mbs file: + % \ProvidesFile{merlin.mbs}[2007/04/24 4.20 (PWD, AO, DPC)] + % For use with BibTeX version 0.99a or later + %------------------------------------------------------------------- + % This bibliography style file is intended for texts in ENGLISH + % This is a numerical citation style, and as such is standard LaTeX. + % It requires no extra package to interface to the main text. + % The form of the \bibitem entries is + % \bibitem{key}... + % Usage of \cite is as follows: + % \cite{key} ==>> [#] + % \cite[chap. 2]{key} ==>> [#, chap. 2] + % where # is a number determined by the ordering in the reference list. + % The order in the reference list is alphabetical by authors. + %--------------------------------------------------------------------- + +ENTRY + { address + author + booktitle + chapter + edition + editor + eid + howpublished + institution + journal + key + month + note + number + organization + pages + publisher + school + series + title + type + url + volume + year + } + {} + { label } +INTEGERS { output.state before.all mid.sentence after.sentence after.block } +FUNCTION {init.state.consts} +{ #0 'before.all := + #1 'mid.sentence := + #2 'after.sentence := + #3 'after.block := +} +STRINGS { s t} +FUNCTION {output.nonnull} +{ 's := + output.state mid.sentence = + { ", " * write$ } + { output.state after.block = + { add.period$ write$ +% newline$ +% "\newblock " write$ % removed for titto-lncs-01 + " " write$ % to avoid long spaces between title and "In: ..." + } + { output.state before.all = + 'write$ + { add.period$ " " * write$ } + if$ + } + if$ + mid.sentence 'output.state := + } + if$ + s +} +FUNCTION {output} +{ duplicate$ empty$ + 'pop$ + 'output.nonnull + if$ +} +FUNCTION {output.check} +{ 't := + duplicate$ empty$ + { pop$ "empty " t * " in " * cite$ * warning$ } + 'output.nonnull + if$ +} +FUNCTION {fin.entry} +{ duplicate$ empty$ + 'pop$ + 'write$ + if$ + newline$ +} + +FUNCTION {new.block} +{ output.state before.all = + 'skip$ + { after.block 'output.state := } + if$ +} +FUNCTION {new.sentence} +{ output.state after.block = + 'skip$ + { output.state before.all = + 'skip$ + { after.sentence 'output.state := } + if$ + } + if$ +} +FUNCTION {add.blank} +{ " " * before.all 'output.state := +} + + +FUNCTION {add.colon} +{ duplicate$ empty$ + 'skip$ + { ":" * add.blank } + if$ +} + +FUNCTION {date.block} +{ + new.block +} + +FUNCTION {not} +{ { #0 } + { #1 } + if$ +} +FUNCTION {and} +{ 'skip$ + { pop$ #0 } + if$ +} +FUNCTION {or} +{ { pop$ #1 } + 'skip$ + if$ +} +STRINGS {z} +FUNCTION {remove.dots} +{ 'z := + "" + { z empty$ not } + { z #1 #1 substring$ + z #2 global.max$ substring$ 'z := + duplicate$ "." = 'pop$ + { * } + if$ + } + while$ +} +FUNCTION {new.block.checka} +{ empty$ + 'skip$ + 'new.block + if$ +} +FUNCTION {new.block.checkb} +{ empty$ + swap$ empty$ + and + 'skip$ + 'new.block + if$ +} +FUNCTION {new.sentence.checka} +{ empty$ + 'skip$ + 'new.sentence + if$ +} +FUNCTION {new.sentence.checkb} +{ empty$ + swap$ empty$ + and + 'skip$ + 'new.sentence + if$ +} +FUNCTION {field.or.null} +{ duplicate$ empty$ + { pop$ "" } + 'skip$ + if$ +} +FUNCTION {emphasize} +{ skip$ } +FUNCTION {tie.or.space.prefix} +{ duplicate$ text.length$ #3 < + { "~" } + { " " } + if$ + swap$ +} +FUNCTION {titto.space.prefix} % always introduce a space +{ duplicate$ text.length$ #3 < + { " " } + { " " } + if$ + swap$ +} + + +FUNCTION {capitalize} +{ "u" change.case$ "t" change.case$ } + +FUNCTION {space.word} +{ " " swap$ * " " * } + % Here are the language-specific definitions for explicit words. + % Each function has a name bbl.xxx where xxx is the English word. + % The language selected here is ENGLISH +FUNCTION {bbl.and} +{ "and"} + +FUNCTION {bbl.etal} +{ "et~al." } + +FUNCTION {bbl.editors} +{ "eds." } + +FUNCTION {bbl.editor} +{ "ed." } + +FUNCTION {bbl.edby} +{ "edited by" } + +FUNCTION {bbl.edition} +{ "edn." } + +FUNCTION {bbl.volume} +{ "vol." } + +FUNCTION {titto.bbl.volume} % for handling journals +{ "" } + +FUNCTION {bbl.of} +{ "of" } + +FUNCTION {bbl.number} +{ "no." } + +FUNCTION {bbl.nr} +{ "no." } + +FUNCTION {bbl.in} +{ "in" } + +FUNCTION {bbl.pages} +{ "pp." } + +FUNCTION {bbl.page} +{ "p." } + +FUNCTION {titto.bbl.pages} % for journals +{ "" } + +FUNCTION {titto.bbl.page} % for journals +{ "" } + +FUNCTION {bbl.chapter} +{ "chap." } + +FUNCTION {bbl.techrep} +{ "Tech. Rep." } + +FUNCTION {bbl.mthesis} +{ "Master's thesis" } + +FUNCTION {bbl.phdthesis} +{ "Ph.D. thesis" } + +MACRO {jan} {"Jan."} + +MACRO {feb} {"Feb."} + +MACRO {mar} {"Mar."} + +MACRO {apr} {"Apr."} + +MACRO {may} {"May"} + +MACRO {jun} {"Jun."} + +MACRO {jul} {"Jul."} + +MACRO {aug} {"Aug."} + +MACRO {sep} {"Sep."} + +MACRO {oct} {"Oct."} + +MACRO {nov} {"Nov."} + +MACRO {dec} {"Dec."} + +MACRO {acmcs} {"ACM Comput. Surv."} + +MACRO {acta} {"Acta Inf."} + +MACRO {cacm} {"Commun. ACM"} + +MACRO {ibmjrd} {"IBM J. Res. Dev."} + +MACRO {ibmsj} {"IBM Syst.~J."} + +MACRO {ieeese} {"IEEE Trans. Software Eng."} + +MACRO {ieeetc} {"IEEE Trans. Comput."} + +MACRO {ieeetcad} + {"IEEE Trans. Comput. Aid. Des."} + +MACRO {ipl} {"Inf. Process. Lett."} + +MACRO {jacm} {"J.~ACM"} + +MACRO {jcss} {"J.~Comput. Syst. Sci."} + +MACRO {scp} {"Sci. Comput. Program."} + +MACRO {sicomp} {"SIAM J. Comput."} + +MACRO {tocs} {"ACM Trans. Comput. Syst."} + +MACRO {tods} {"ACM Trans. Database Syst."} + +MACRO {tog} {"ACM Trans. Graphic."} + +MACRO {toms} {"ACM Trans. Math. Software"} + +MACRO {toois} {"ACM Trans. Office Inf. Syst."} + +MACRO {toplas} {"ACM Trans. Progr. Lang. Syst."} + +MACRO {tcs} {"Theor. Comput. Sci."} + +FUNCTION {bibinfo.check} +{ swap$ + duplicate$ missing$ + { + pop$ pop$ + "" + } + { duplicate$ empty$ + { + swap$ pop$ + } + { swap$ + pop$ + } + if$ + } + if$ +} +FUNCTION {bibinfo.warn} +{ swap$ + duplicate$ missing$ + { + swap$ "missing " swap$ * " in " * cite$ * warning$ pop$ + "" + } + { duplicate$ empty$ + { + swap$ "empty " swap$ * " in " * cite$ * warning$ + } + { swap$ + pop$ + } + if$ + } + if$ +} +FUNCTION {format.url} +{ url empty$ + { "" } +% { "\urlprefix\url{" url * "}" * } + { "\url{" url * "}" * } % changed in titto-lncs-02.bst + if$ +} + +INTEGERS { nameptr namesleft numnames } + + +STRINGS { bibinfo} + +FUNCTION {format.names} +{ 'bibinfo := + duplicate$ empty$ 'skip$ { + 's := + "" 't := + #1 'nameptr := + s num.names$ 'numnames := + numnames 'namesleft := + { namesleft #0 > } + { s nameptr + "{vv~}{ll}{, jj}{, f{.}.}" + format.name$ + bibinfo bibinfo.check + 't := + nameptr #1 > + { + namesleft #1 > + { ", " * t * } + { + s nameptr "{ll}" format.name$ duplicate$ "others" = + { 't := } + { pop$ } + if$ + "," * + t "others" = + { + " " * bbl.etal * + } + { " " * t * } + if$ + } + if$ + } + 't + if$ + nameptr #1 + 'nameptr := + namesleft #1 - 'namesleft := + } + while$ + } if$ +} +FUNCTION {format.names.ed} +{ + 'bibinfo := + duplicate$ empty$ 'skip$ { + 's := + "" 't := + #1 'nameptr := + s num.names$ 'numnames := + numnames 'namesleft := + { namesleft #0 > } + { s nameptr + "{f{.}.~}{vv~}{ll}{ jj}" + format.name$ + bibinfo bibinfo.check + 't := + nameptr #1 > + { + namesleft #1 > + { ", " * t * } + { + s nameptr "{ll}" format.name$ duplicate$ "others" = + { 't := } + { pop$ } + if$ + "," * + t "others" = + { + + " " * bbl.etal * + } + { " " * t * } + if$ + } + if$ + } + 't + if$ + nameptr #1 + 'nameptr := + namesleft #1 - 'namesleft := + } + while$ + } if$ +} +FUNCTION {format.authors} +{ author "author" format.names +} +FUNCTION {get.bbl.editor} +{ editor num.names$ #1 > 'bbl.editors 'bbl.editor if$ } + +FUNCTION {format.editors} +{ editor "editor" format.names duplicate$ empty$ 'skip$ + { + " " * + get.bbl.editor +% capitalize + "(" swap$ * ")" * + * + } + if$ +} +FUNCTION {format.note} +{ + note empty$ + { "" } + { note #1 #1 substring$ + duplicate$ "{" = + 'skip$ + { output.state mid.sentence = + { "l" } + { "u" } + if$ + change.case$ + } + if$ + note #2 global.max$ substring$ * "note" bibinfo.check + } + if$ +} + +FUNCTION {format.title} +{ title + duplicate$ empty$ 'skip$ + { "t" change.case$ } + if$ + "title" bibinfo.check +} +FUNCTION {output.bibitem} +{ newline$ + "\bibitem{" write$ + cite$ write$ + "}" write$ + newline$ + "" + before.all 'output.state := +} + +FUNCTION {n.dashify} +{ + 't := + "" + { t empty$ not } + { t #1 #1 substring$ "-" = + { t #1 #2 substring$ "--" = not + { "--" * + t #2 global.max$ substring$ 't := + } + { { t #1 #1 substring$ "-" = } + { "-" * + t #2 global.max$ substring$ 't := + } + while$ + } + if$ + } + { t #1 #1 substring$ * + t #2 global.max$ substring$ 't := + } + if$ + } + while$ +} + +FUNCTION {word.in} +{ bbl.in capitalize + ":" * + " " * } + +FUNCTION {format.date} +{ + month "month" bibinfo.check + duplicate$ empty$ + year "year" bibinfo.check duplicate$ empty$ + { swap$ 'skip$ + { "there's a month but no year in " cite$ * warning$ } + if$ + * + } + { swap$ 'skip$ + { + swap$ + " " * swap$ + } + if$ + * + remove.dots + } + if$ + duplicate$ empty$ + 'skip$ + { + before.all 'output.state := + " (" swap$ * ")" * + } + if$ +} +FUNCTION {format.btitle} +{ title "title" bibinfo.check + duplicate$ empty$ 'skip$ + { + } + if$ +} +FUNCTION {either.or.check} +{ empty$ + 'pop$ + { "can't use both " swap$ * " fields in " * cite$ * warning$ } + if$ +} +FUNCTION {format.bvolume} +{ volume empty$ + { "" } + { bbl.volume volume tie.or.space.prefix + "volume" bibinfo.check * * + series "series" bibinfo.check + duplicate$ empty$ 'pop$ + { emphasize ", " * swap$ * } + if$ + "volume and number" number either.or.check + } + if$ +} +FUNCTION {format.number.series} +{ volume empty$ + { number empty$ + { series field.or.null } + { output.state mid.sentence = + { bbl.number } + { bbl.number capitalize } + if$ + number tie.or.space.prefix "number" bibinfo.check * * + series empty$ + { "there's a number but no series in " cite$ * warning$ } + { bbl.in space.word * + series "series" bibinfo.check * + } + if$ + } + if$ + } + { "" } + if$ +} + +FUNCTION {format.edition} +{ edition duplicate$ empty$ 'skip$ + { + output.state mid.sentence = + { "l" } + { "t" } + if$ change.case$ + "edition" bibinfo.check + " " * bbl.edition * + } + if$ +} +INTEGERS { multiresult } +FUNCTION {multi.page.check} +{ 't := + #0 'multiresult := + { multiresult not + t empty$ not + and + } + { t #1 #1 substring$ + duplicate$ "-" = + swap$ duplicate$ "," = + swap$ "+" = + or or + { #1 'multiresult := } + { t #2 global.max$ substring$ 't := } + if$ + } + while$ + multiresult +} +FUNCTION {format.pages} +{ pages duplicate$ empty$ 'skip$ + { duplicate$ multi.page.check + { + bbl.pages swap$ + n.dashify + } + { + bbl.page swap$ + } + if$ + tie.or.space.prefix + "pages" bibinfo.check + * * + } + if$ +} +FUNCTION {format.journal.pages} +{ pages duplicate$ empty$ 'pop$ + { swap$ duplicate$ empty$ + { pop$ pop$ format.pages } + { + ", " * + swap$ + n.dashify + pages multi.page.check + 'titto.bbl.pages + 'titto.bbl.page + if$ + swap$ tie.or.space.prefix + "pages" bibinfo.check + * * + * + } + if$ + } + if$ +} +FUNCTION {format.journal.eid} +{ eid "eid" bibinfo.check + duplicate$ empty$ 'pop$ + { swap$ duplicate$ empty$ 'skip$ + { + ", " * + } + if$ + swap$ * + } + if$ +} +FUNCTION {format.vol.num.pages} % this function is used only for journal entries +{ volume field.or.null + duplicate$ empty$ 'skip$ + { +% bbl.volume swap$ tie.or.space.prefix + titto.bbl.volume swap$ titto.space.prefix +% rationale for the change above: for journals you don't want "vol." label +% hence it does not make sense to attach the journal number to the label when +% it is short + "volume" bibinfo.check + * * + } + if$ + number "number" bibinfo.check duplicate$ empty$ 'skip$ + { + swap$ duplicate$ empty$ + { "there's a number but no volume in " cite$ * warning$ } + 'skip$ + if$ + swap$ + "(" swap$ * ")" * + } + if$ * + eid empty$ + { format.journal.pages } + { format.journal.eid } + if$ +} + +FUNCTION {format.chapter.pages} +{ chapter empty$ + 'format.pages + { type empty$ + { bbl.chapter } + { type "l" change.case$ + "type" bibinfo.check + } + if$ + chapter tie.or.space.prefix + "chapter" bibinfo.check + * * + pages empty$ + 'skip$ + { ", " * format.pages * } + if$ + } + if$ +} + +FUNCTION {format.booktitle} +{ + booktitle "booktitle" bibinfo.check +} +FUNCTION {format.in.ed.booktitle} +{ format.booktitle duplicate$ empty$ 'skip$ + { +% editor "editor" format.names.ed duplicate$ empty$ 'pop$ % changed by titto + editor "editor" format.names duplicate$ empty$ 'pop$ + { + " " * + get.bbl.editor +% capitalize + "(" swap$ * ") " * + * swap$ + * } + if$ + word.in swap$ * + } + if$ +} +FUNCTION {empty.misc.check} +{ author empty$ title empty$ howpublished empty$ + month empty$ year empty$ note empty$ + and and and and and + key empty$ not and + { "all relevant fields are empty in " cite$ * warning$ } + 'skip$ + if$ +} +FUNCTION {format.thesis.type} +{ type duplicate$ empty$ + 'pop$ + { swap$ pop$ + "t" change.case$ "type" bibinfo.check + } + if$ +} +FUNCTION {format.tr.number} +{ number "number" bibinfo.check + type duplicate$ empty$ + { pop$ bbl.techrep } + 'skip$ + if$ + "type" bibinfo.check + swap$ duplicate$ empty$ + { pop$ "t" change.case$ } + { tie.or.space.prefix * * } + if$ +} +FUNCTION {format.article.crossref} +{ + key duplicate$ empty$ + { pop$ + journal duplicate$ empty$ + { "need key or journal for " cite$ * " to crossref " * crossref * warning$ } + { "journal" bibinfo.check emphasize word.in swap$ * } + if$ + } + { word.in swap$ * " " *} + if$ + " \cite{" * crossref * "}" * +} +FUNCTION {format.crossref.editor} +{ editor #1 "{vv~}{ll}" format.name$ + "editor" bibinfo.check + editor num.names$ duplicate$ + #2 > + { pop$ + "editor" bibinfo.check + " " * bbl.etal + * + } + { #2 < + 'skip$ + { editor #2 "{ff }{vv }{ll}{ jj}" format.name$ "others" = + { + "editor" bibinfo.check + " " * bbl.etal + * + } + { + bbl.and space.word + * editor #2 "{vv~}{ll}" format.name$ + "editor" bibinfo.check + * + } + if$ + } + if$ + } + if$ +} +FUNCTION {format.book.crossref} +{ volume duplicate$ empty$ + { "empty volume in " cite$ * "'s crossref of " * crossref * warning$ + pop$ word.in + } + { bbl.volume + capitalize + swap$ tie.or.space.prefix "volume" bibinfo.check * * bbl.of space.word * + } + if$ + editor empty$ + editor field.or.null author field.or.null = + or + { key empty$ + { series empty$ + { "need editor, key, or series for " cite$ * " to crossref " * + crossref * warning$ + "" * + } + { series emphasize * } + if$ + } + { key * } + if$ + } + { format.crossref.editor * } + if$ + " \cite{" * crossref * "}" * +} +FUNCTION {format.incoll.inproc.crossref} +{ + editor empty$ + editor field.or.null author field.or.null = + or + { key empty$ + { format.booktitle duplicate$ empty$ + { "need editor, key, or booktitle for " cite$ * " to crossref " * + crossref * warning$ + } + { word.in swap$ * } + if$ + } + { word.in key * " " *} + if$ + } + { word.in format.crossref.editor * " " *} + if$ + " \cite{" * crossref * "}" * +} +FUNCTION {format.org.or.pub} +{ 't := + "" + address empty$ t empty$ and + 'skip$ + { + t empty$ + { address "address" bibinfo.check * + } + { t * + address empty$ + 'skip$ + { ", " * address "address" bibinfo.check * } + if$ + } + if$ + } + if$ +} +FUNCTION {format.publisher.address} +{ publisher "publisher" bibinfo.warn format.org.or.pub +} + +FUNCTION {format.organization.address} +{ organization "organization" bibinfo.check format.org.or.pub +} + +FUNCTION {article} +{ output.bibitem + format.authors "author" output.check + add.colon + new.block + format.title "title" output.check + new.block + crossref missing$ + { + journal + "journal" bibinfo.check + "journal" output.check + add.blank + format.vol.num.pages output + format.date "year" output.check + } + { format.article.crossref output.nonnull + format.pages output + } + if$ +% new.block + format.url output +% new.block + format.note output + fin.entry +} +FUNCTION {book} +{ output.bibitem + author empty$ + { format.editors "author and editor" output.check + add.colon + } + { format.authors output.nonnull + add.colon + crossref missing$ + { "author and editor" editor either.or.check } + 'skip$ + if$ + } + if$ + new.block + format.btitle "title" output.check + crossref missing$ + { format.bvolume output + new.block + new.sentence + format.number.series output + format.publisher.address output + } + { + new.block + format.book.crossref output.nonnull + } + if$ + format.edition output + format.date "year" output.check +% new.block + format.url output +% new.block + format.note output + fin.entry +} +FUNCTION {booklet} +{ output.bibitem + format.authors output + add.colon + new.block + format.title "title" output.check + new.block + howpublished "howpublished" bibinfo.check output + address "address" bibinfo.check output + format.date output +% new.block + format.url output +% new.block + format.note output + fin.entry +} + +FUNCTION {inbook} +{ output.bibitem + author empty$ + { format.editors "author and editor" output.check + add.colon + } + { format.authors output.nonnull + add.colon + crossref missing$ + { "author and editor" editor either.or.check } + 'skip$ + if$ + } + if$ + new.block + format.btitle "title" output.check + crossref missing$ + { + format.bvolume output + format.chapter.pages "chapter and pages" output.check + new.block + new.sentence + format.number.series output + format.publisher.address output + } + { + format.chapter.pages "chapter and pages" output.check + new.block + format.book.crossref output.nonnull + } + if$ + format.edition output + format.date "year" output.check +% new.block + format.url output +% new.block + format.note output + fin.entry +} + +FUNCTION {incollection} +{ output.bibitem + format.authors "author" output.check + add.colon + new.block + format.title "title" output.check + new.block + crossref missing$ + { format.in.ed.booktitle "booktitle" output.check + format.bvolume output + format.chapter.pages output + new.sentence + format.number.series output + format.publisher.address output + format.edition output + format.date "year" output.check + } + { format.incoll.inproc.crossref output.nonnull + format.chapter.pages output + } + if$ +% new.block + format.url output +% new.block + format.note output + fin.entry +} +FUNCTION {inproceedings} +{ output.bibitem + format.authors "author" output.check + add.colon + new.block + format.title "title" output.check + new.block + crossref missing$ + { format.in.ed.booktitle "booktitle" output.check + new.sentence % added by titto + format.bvolume output + format.pages output + new.sentence + format.number.series output + publisher empty$ + { format.organization.address output } + { organization "organization" bibinfo.check output + format.publisher.address output + } + if$ + format.date "year" output.check + } + { format.incoll.inproc.crossref output.nonnull + format.pages output + } + if$ +% new.block + format.url output +% new.block + format.note output + fin.entry +} +FUNCTION {conference} { inproceedings } +FUNCTION {manual} +{ output.bibitem + author empty$ + { organization "organization" bibinfo.check + duplicate$ empty$ 'pop$ + { output + address "address" bibinfo.check output + } + if$ + } + { format.authors output.nonnull } + if$ + add.colon + new.block + format.btitle "title" output.check + author empty$ + { organization empty$ + { + address new.block.checka + address "address" bibinfo.check output + } + 'skip$ + if$ + } + { + organization address new.block.checkb + organization "organization" bibinfo.check output + address "address" bibinfo.check output + } + if$ + format.edition output + format.date output +% new.block + format.url output +% new.block + format.note output + fin.entry +} + +FUNCTION {mastersthesis} +{ output.bibitem + format.authors "author" output.check + add.colon + new.block + format.btitle + "title" output.check + new.block + bbl.mthesis format.thesis.type output.nonnull + school "school" bibinfo.warn output + address "address" bibinfo.check output + format.date "year" output.check +% new.block + format.url output +% new.block + format.note output + fin.entry +} + +FUNCTION {misc} +{ output.bibitem + format.authors output + add.colon + title howpublished new.block.checkb + format.title output + howpublished new.block.checka + howpublished "howpublished" bibinfo.check output + format.date output +% new.block + format.url output +% new.block + format.note output + fin.entry + empty.misc.check +} +FUNCTION {phdthesis} +{ output.bibitem + format.authors "author" output.check + add.colon + new.block + format.btitle + "title" output.check + new.block + bbl.phdthesis format.thesis.type output.nonnull + school "school" bibinfo.warn output + address "address" bibinfo.check output + format.date "year" output.check +% new.block + format.url output +% new.block + format.note output + fin.entry +} + +FUNCTION {proceedings} +{ output.bibitem + editor empty$ + { organization "organization" bibinfo.check output + } + { format.editors output.nonnull } + if$ + add.colon + new.block + format.btitle "title" output.check + format.bvolume output + editor empty$ + { publisher empty$ + { format.number.series output } + { + new.sentence + format.number.series output + format.publisher.address output + } + if$ + } + { publisher empty$ + { + new.sentence + format.number.series output + format.organization.address output } + { + new.sentence + format.number.series output + organization "organization" bibinfo.check output + format.publisher.address output + } + if$ + } + if$ + format.date "year" output.check +% new.block + format.url output +% new.block + format.note output + fin.entry +} + +FUNCTION {techreport} +{ output.bibitem + format.authors "author" output.check + add.colon + new.block + format.title + "title" output.check + new.block + format.tr.number output.nonnull + institution "institution" bibinfo.warn output + address "address" bibinfo.check output + format.date "year" output.check +% new.block + format.url output +% new.block + format.note output + fin.entry +} + +FUNCTION {unpublished} +{ output.bibitem + format.authors "author" output.check + add.colon + new.block + format.title "title" output.check + format.date output +% new.block + format.url output +% new.block + format.note "note" output.check + fin.entry +} + +FUNCTION {default.type} { misc } +READ +FUNCTION {sortify} +{ purify$ + "l" change.case$ +} +INTEGERS { len } +FUNCTION {chop.word} +{ 's := + 'len := + s #1 len substring$ = + { s len #1 + global.max$ substring$ } + 's + if$ +} +FUNCTION {sort.format.names} +{ 's := + #1 'nameptr := + "" + s num.names$ 'numnames := + numnames 'namesleft := + { namesleft #0 > } + { s nameptr + "{ll{ }}{ ff{ }}{ jj{ }}" + format.name$ 't := + nameptr #1 > + { + " " * + namesleft #1 = t "others" = and + { "zzzzz" * } + { t sortify * } + if$ + } + { t sortify * } + if$ + nameptr #1 + 'nameptr := + namesleft #1 - 'namesleft := + } + while$ +} + +FUNCTION {sort.format.title} +{ 't := + "A " #2 + "An " #3 + "The " #4 t chop.word + chop.word + chop.word + sortify + #1 global.max$ substring$ +} +FUNCTION {author.sort} +{ author empty$ + { key empty$ + { "to sort, need author or key in " cite$ * warning$ + "" + } + { key sortify } + if$ + } + { author sort.format.names } + if$ +} +FUNCTION {author.editor.sort} +{ author empty$ + { editor empty$ + { key empty$ + { "to sort, need author, editor, or key in " cite$ * warning$ + "" + } + { key sortify } + if$ + } + { editor sort.format.names } + if$ + } + { author sort.format.names } + if$ +} +FUNCTION {author.organization.sort} +{ author empty$ + { organization empty$ + { key empty$ + { "to sort, need author, organization, or key in " cite$ * warning$ + "" + } + { key sortify } + if$ + } + { "The " #4 organization chop.word sortify } + if$ + } + { author sort.format.names } + if$ +} +FUNCTION {editor.organization.sort} +{ editor empty$ + { organization empty$ + { key empty$ + { "to sort, need editor, organization, or key in " cite$ * warning$ + "" + } + { key sortify } + if$ + } + { "The " #4 organization chop.word sortify } + if$ + } + { editor sort.format.names } + if$ +} +FUNCTION {presort} +{ type$ "book" = + type$ "inbook" = + or + 'author.editor.sort + { type$ "proceedings" = + 'editor.organization.sort + { type$ "manual" = + 'author.organization.sort + 'author.sort + if$ + } + if$ + } + if$ + " " + * + year field.or.null sortify + * + " " + * + title field.or.null + sort.format.title + * + #1 entry.max$ substring$ + 'sort.key$ := +} +ITERATE {presort} +SORT +STRINGS { longest.label } +INTEGERS { number.label longest.label.width } +FUNCTION {initialize.longest.label} +{ "" 'longest.label := + #1 'number.label := + #0 'longest.label.width := +} +FUNCTION {longest.label.pass} +{ number.label int.to.str$ 'label := + number.label #1 + 'number.label := + label width$ longest.label.width > + { label 'longest.label := + label width$ 'longest.label.width := + } + 'skip$ + if$ +} +EXECUTE {initialize.longest.label} +ITERATE {longest.label.pass} +FUNCTION {begin.bib} +{ preamble$ empty$ + 'skip$ + { preamble$ write$ newline$ } + if$ + "\begin{thebibliography}{" longest.label * "}" * + write$ newline$ + "\providecommand{\url}[1]{\texttt{#1}}" + write$ newline$ + "\providecommand{\urlprefix}{URL }" + write$ newline$ +} +EXECUTE {begin.bib} +EXECUTE {init.state.consts} +ITERATE {call.type$} +FUNCTION {end.bib} +{ newline$ + "\end{thebibliography}" write$ newline$ +} +EXECUTE {end.bib} +%% End of customized bst file +%% +%% End of file `titto.bst'. + + diff --git a/cryptominisat/cppsrc/docs/satcomp18-pdf/Makefile b/cryptominisat/cppsrc/docs/satcomp18-pdf/Makefile new file mode 100644 index 00000000..c209fb87 --- /dev/null +++ b/cryptominisat/cppsrc/docs/satcomp18-pdf/Makefile @@ -0,0 +1,24 @@ +TEX = pdflatex -shell-escape -interaction=nonstopmode -file-line-error +PRE = $(TEX) -ini -job-name="preamble" "&pdflatex preamble.tex\dump" +BIB = bibtex + +all: cmsv55.pdf + +view : + okular cmsv55.pdf + +cmsv55.pdf : clean cmsv55.tex cmsv55.bbl cmsv55.blg + $(TEX) cmsv55.tex + $(TEX) cmsv55.tex + +cmsv55.bbl cmsv5.blg : cmsv55.bib cmsv55.aux + $(BIB) cmsv55 + +cmsv55.aux : cmsv55.tex + $(TEX) cmsv55.tex + +cmsv55.bib : cmsv55.tex + $(TEX) cmsv55.tex + +clean: + rm -f *.log *.pdf *.blg *.bbl *.aux *.out *.backup diff --git a/cryptominisat/cppsrc/docs/satcomp18-pdf/cmsv5.kilepr b/cryptominisat/cppsrc/docs/satcomp18-pdf/cmsv5.kilepr new file mode 100644 index 00000000..92617e20 --- /dev/null +++ b/cryptominisat/cppsrc/docs/satcomp18-pdf/cmsv5.kilepr @@ -0,0 +1,53 @@ +[General] +def_graphic_ext= +img_extIsRegExp=false +img_extensions=.eps .jpg .jpeg .png .pdf .ps .fig .gif .dvi +kileprversion=2 +kileversion=2.1.0 +lastDocument=cmsv5.tex +masterDocument= +name=auth_eloadas +pkg_extIsRegExp=false +pkg_extensions=.cls .sty .bbx .cbx .lbx +src_extIsRegExp=false +src_extensions=.tex .ltx .latex .dtx .ins .bib .mp + +[Tools] +MakeIndex= +QuickBuild= + +[document-settings,item:cmsv5.tex] +Bookmarks= +Encoding=UTF-8 +FoldedColumns= +FoldedLines= +Highlighting=LaTeX +Indentation Mode=normal +Mode=LaTeX +ReadWrite=true + +[item:cmsv5.kilepr] +archive=true +column=0 +encoding= +highlight= +line=0 +mode= +open=false +order=-1 + +[item:cmsv5.tex] +archive=true +column=1 +encoding=UTF-8 +highlight=LaTeX +line=245 +mode=LaTeX +open=true +order=0 + +[view-settings,view=0,item:cmsv5.tex] +CursorColumn=1 +CursorLine=245 +JumpList= +ViMarks= diff --git a/cryptominisat/cppsrc/docs/satcomp18-pdf/cmsv55.tex b/cryptominisat/cppsrc/docs/satcomp18-pdf/cmsv55.tex new file mode 100644 index 00000000..613e50a5 --- /dev/null +++ b/cryptominisat/cppsrc/docs/satcomp18-pdf/cmsv55.tex @@ -0,0 +1,76 @@ +%\documentclass[runningheads]{llncs} +\documentclass[final]{ieee} + +\usepackage{microtype} %This gives MUCH better PDF results! +%\usepackage[active]{srcltx} %DVI search +\usepackage[cmex10]{amsmath} +\usepackage{amssymb} +\usepackage{fnbreak} %warn for split footnotes +\usepackage{url} +%\usepackage{qtree} %for drawing trees +%\usepackage{fancybox} % if we need rounded corners +%\usepackage{pict2e} % large circles can be drawn +%\usepackage{courier} %for using courier in texttt{} +%\usepackage{nth} %allows to \nth{4} to make 1st 2nd, etc. +%\usepackage{subfigure} %allows to have side-by-side figures +%\usepackage{booktabs} %nice tables +%\usepackage{multirow} %allow multiple cells with rows in tabular +\usepackage[utf8]{inputenc} % allows to write Faugere correctly +\usepackage[bookmarks=true, citecolor=black, linkcolor=black, colorlinks=true]{hyperref} +\hypersetup{ +pdfauthor = {Mate Soos}, +pdftitle = {CryptoMiniSat v5.5}, +pdfsubject = {SAT Competition 2018}, +pdfkeywords = {SAT Solver, DPLL}, +pdfcreator = {PdfLaTeX with hyperref package}, +pdfproducer = {PdfLaTex}} +%\usepackage{butterma} + +%\usepackage{pstricks} +\usepackage{graphicx,epsfig,xcolor} + +\begin{document} +\title{The CryptoMiniSat 5.5 set of solvers at the SAT Competition 2018} +\author{Mate Soos, National University of Singapore} + +\maketitle +\thispagestyle{empty} +\pagestyle{empty} + +\section{Introduction} +This paper presents the conflict-driven clause-learning SAT solver CryptoMiniSat v5.5 (\emph{CMS}) as submitted to SAT Competition 2018. CMS aims to be a modern, open-source SAT solver that allows for multi-threaded in-processing techniques while still retaining a strong CDCL component. In general, CMS is a inprocessing SAT solver that uses optimised data structures and finely-tuned timeouts to have good control over both memory and time usage of simplification steps. Below are the changes to CMS compared to the SAT Competition 2016 version. + +\section{Major Improvements} +\subsection{Careful code review} +Over the years, much cruft has accumulated in CryptoMiniSat. This has left serious bugs in the implementation in important parts of the solver such as clause cleaning and restarting. This has lead to low performance. A code review of the most important parts of the solver such as bounded variable elimination, restarting, clause cleaning and variable activities has been conducted. + +\subsection{Integration of ideas from Maple\_LCM\_Dist} +Some of the ideas from Maple\_LCM\_Dist\cite{maple}\cite{learning-based-maple} have been included into CMS. In particular, the clause cleaning system, the radical in-process distillation and the Maple-based variable activities are all used. + +\subsection{Cluster Tuning} +The author has been generously given time on the ASPIRE-1 cluster of the National Supercomputing Centre Singapore\cite{nscc}. This allowed experimentation and tuning that would have been impossible otherwise. CMS has not been tuned on a cluster for over 6 years and the difference shows. A slightly interesting side-effect is that the parameters suggested by the cluster are non-intuitive, such as not simplifying the CNF straight away, but rather CDCL-solving it first. Another interesting effect is that intree probing\cite{HeuleJB13} seems to be very important. + +\subsection{Parallel Solving} +As in previous competitions, CMS only shares unit and binary clauses, and shares them very rarely. The different threads, however, are run with very different, hoping to be orthogonal, parameters varying everything from clause cleaning strategies to default polarities. + +\subsection{Automatic Tuning} +The "autotune" version of the solver measures internal solving parameters and re-configures itself after a preset number of conflicts to a configuration that has been suggested by the parameters and the machine learning algorithm C4.5\cite{Salzberg1994}. + +\section{General Notes} +\subsection{On-the-fly Gaussian Elimination} +On-the-fly Gaussian elimination is again part of CryptoMiniSat. This is explicitly disabled for the competition, but the code is available and well-tested. This allows for special uses of the solver that other solvers, without on-the-fly Gaussian elimination, are not capable of. + +\subsection{Robustness} +CMS aims to be usable in both industry and academia. CMS has over 150 test cases and over 2000 lines of Python just for fuzzing orchestration, and runs without fault under both the ASAN and UBSAN sanitisers of clang. It also compiles and runs under Windows, Linux and MacOS X. This is in contrast many academic winning SAT solvers that produce results that are non-reproducible, cannot be compiled on anything but a few select systems, and/or produce segmentation faults if used as a library. CryptoMiniSat has extensive fuzzing setup for library usage and is very robust under strange/unexpected use cases. + +\section{Thanks} +This work was supported in part by NUS ODPRT Grant, R-252-000-685-133. The computational work for this article was performed on resources of the National Supercomputing Centre, Singapore\cite{nscc}. The author would also like to thank all the users of CryptoMiniSat who have submitted over 400 issues and many pull requests to the GitHub CMS repository\cite{CMS}. + + +\bibliographystyle{splncs03} +\bibliography{sigproc} + +\vfill +\pagebreak + +\end{document} diff --git a/cryptominisat/cppsrc/docs/satcomp18-pdf/ieee.cls b/cryptominisat/cppsrc/docs/satcomp18-pdf/ieee.cls new file mode 100644 index 00000000..3c57bba5 --- /dev/null +++ b/cryptominisat/cppsrc/docs/satcomp18-pdf/ieee.cls @@ -0,0 +1,1497 @@ +% Copyright 2014 IEEEE +% for terms of use see https://www.ieee.org/publications_standards/publications/rights/copyrightpolicy.html + +% ========================================================================= +% ------------------------------------------------------------------------- +% XX X +% X +% XX XXX XXX XXX XXX X XXXX +% X X X X X X X X X X X +% X XXXXX XXXXX XXXXX X X XXX +% X X X X XX X X X X +% XXX XXX XXX XXX XX XXX X XXXX +% ------------------------------------------------------------------------- +% ========================================================================= +% ieee.cls --- For formatting IEEE conference & journal papers +% --- Compiled by Gregory Plett, Sept 1997 +% +% This class was inspired by one first compiled by Gerry Murray and +% Silvano Balemi for LaTeX209. It was later updated for use with +% LaTeX2e, and some bugs were fixed, all by Istvan Kollar. Lastly, +% I have tried to make the class easier to use by paper authors. +% Significant new functionality has been added. Many routines are +% "borrowed" from other people's packages and modified extensively. +% When I rembered where I got the routines from, I gave the author +% credit. +% +% After I made many changes on my own, I found a version by Peter +% N"uchter, and tried to retain some amount of compatibility with his +% version. To be completely compatible with him, you may need to +% manually: +% \usepackage{rawfonts}\usepackage{oldlfont} +% \AtBeginDocument{\parindent1.0em} (?) +% +%=========================================================================== +% +% Usage: +% \documentclass[main-mode,sub-mode,misc-options]{ieee} +% \usepackage{your own packages} +% \begin{document} +% \bibliographystyle{IEEEbib} +% \title[short]{regular} +% \author[short]{full} +% \maketitle +% \begin{abstract}...\end{abstract} +% \begin{keywords}...\end{keywords} +% \section{...} +% \PARstart ... or \PARstartCal ... +% ... +% \begin{biography}[picname.ps]{Author's name}...\end{biography} +% \end{document} +% +% The document class options are: +% +% main-mode: One of the following is required. (draft is the default) +% draft: Double-spaced, single column with date/time stamp. +% submission: Double-spaced, suitable for submission for review. +% compressed: Same as "submission", only single spaced. +% final: Double-column, for assessing page-length and +% format of final version. +% +% sub-mode: +% techreport: This can modify "final" to produce a two-col +% technical report. +% internal: This can modify "submission", "compressed" or "final". +% It changes the header to notify the reader that +% this is a version of the manuscript to be used for +% internal review processes only, and not to be +% distributed. +% submitted: This can modify "compressed" or "final". It changes +% the header to notify the reader that this +% is a preprint and not to be distributed. +% inpress: This can modify "compressed" or "final". It changes the +% header to notify the reader that this paper has +% been accepted for publishing, but it is not yet to be +% distributed. +% reprint: This can modify "final". It changes the header +% to notify the reader where the paper is reprinted from. +% +% misc-options: +% narroweqnarray: Changes the spacing around the "=" sign in +% equation arrays to make it the same as in displayed math. +% inline: Compresses the horizontal spacing of inline math equations. +% notitlepage: No separate title page. (default) +% titlepage: Separate title page. +% anonymous: Omit all author information from main part of paper. +% Author info only prints on titlepage. +% 9pt,10pt,11pt,12pt: Choose the appropriate type size. You should +% not need to do this as the "correct" size is automatically +% chosen. However, if you want, you may use these to change +% the type size of the main text. "9pt" is a bit of a hack +% to retain backward-compatibility. +% invited: If the paper is an "invited" paper, then this option +% prints "(Invited Paper)" under the authors' names. +% +% For regular IEEE submissions, define the journal name as: +% \journal{IEEE Trans. Inst. Meas.} +% +% To specify the conference place and date: +% \confplacedate{Ottawa, Canada, May 19--21, 1997} +% +% Before \maketitle, define: +% \title{Title of paper} +% \author{Author1\member{Fellow}\authorinfo{Department of +% Electrical Engineering\\ Some University, Somewhere, CA 94305 +% USA} \and Author2\member{Senior Member}\authorinfo{Deptartment of +% Measurement and Instrument Eng., Another University, ...}} +% +% Note, the contents of \authorinfo tends to vary depending on if it is +% a conference or journal paper. The amount of manual changes are +% small, and must be done by a human anyway. The example given is for an +% IMTC conference. +% +% See also IEEEbib.bst and ieeefig.sty +% Also very useful for document preparation is the style file "endfloat", +% available on all CTAN TeX archives. +% +%=========================================================================== +% modified 14 October 2002: +% - fixed bibliography listing of [#] when # < 10 and number of +% references is greater than 9. Thanks for Janos Markus for finding +% this bug and suggesting a solution. +% modified 15 January 2000: +% - "fixed" narroweqnarray. Never implemented! Now it is... +% modified 12 January 2000: +% - modified so only first \title and \author commands are recognized. +% This allows LyX to have \title and \author with full syntax in +% header, but dummy \title and \author show up in GUI. +% - added "\date" so the \date command can change "submitted" and +% "draft" date headers. +% modified 11 January 2000: +% - added PARstartLyX and PARstartCalLyX for LyX compatibility +% - added biographyLyX +% modified 1 Dec 1997: +% - fixed first page in reprint mode to be same length as other pages +% - added "invited" misc-option +% modified 5 Sept 1997: +% - added the inpress, reprint and internal sub-modes +% - removed IMTC-conf and CDC-conf to separate files +% modified 1 Sept 1997: +% - included Babel package compatibility +% - removed paper title from header on first page of draft +% manuscript +% - removed the fixed option "letterpaper" to allow a4paper (etc) +% modified 1 Aug 1997: +% - included the CDC-conf option +%=========================================================================== +% ************************************************************************** +% ****** ****************************************** +% ***** LaTeX2e INITIALIZATION ***************************************** +% ****** ****************************************** +% ************************************************************************** +\typeout{Document Class `ieee' .} +\NeedsTeXFormat{LaTeX2e}[1993/11/11] % Oldest acceptable version of LaTeX2e +\ProvidesClass{ieee}[2000/01/11] % Name of package provided, date +\def\i@@@cls{exists} + +% Initial Code & Declaration of Options +% ------------------------------------- +\newif\ifev@l \ev@lfalse % true if "final" mode. +\newif\ifsubm@t \subm@tfalse % true if "submission" mode. +\newif\ifdr@ft \dr@fttrue % true if "draft" mode. +\newif\ifc@mpress \c@mpressfalse % true if "compressed" mode. + +\newif\if@technote \@technotefalse % true if "technote" sub-mode. +\newif\ifintern@l \intern@lfalse % true if "internal" sub-mode. +\newif\ifprepr@nt \prepr@ntfalse % true if "preprint" sub-mode. +\newif\ifinpr@ss \inpr@ssfalse % true if "inpress" sub-mode. +\newif\ifrepr@nt \repr@ntfalse % true if "reprint" sub-mode. + +\newif\iftitlep@ge \titlep@gefalse % true if has own titlepage +\newif\if@non \@nonfalse % true if anonymous +\newif\ifixpt \ixptfalse % true if trying to do 9 pt +\newif\if@nvited \@nvitedfalse % true if an invited paper + +% Main options +% ------------ +\DeclareOption{draft}{\ev@lfalse\subm@tfalse\dr@fttrue% + \typeout{ieee: `Draft' mode selected.}} +\DeclareOption{submission}{\ev@lfalse\dr@ftfalse\subm@ttrue% + \typeout{ieee: `Submission' mode selected.}} +\DeclareOption{compressed}{\ev@lfalse\dr@ftfalse\subm@tfalse\c@mpresstrue% + \typeout{ieee: `Compressed' mode selected.}} +\DeclareOption{final}{\ev@ltrue\dr@ftfalse\subm@tfalse% + \typeout{ieee: `Final' mode selected.}} +\DeclareOption{evaluation}{\ev@ltrue\dr@ftfalse\subm@tfalse% + \typeout{ieee: `Final' mode selected.}} % synonym for final + +% Sub options +% ----------- +\DeclareOption{technote}{\@technotetrue% + \typeout{ieee: `Technote' sub-mode selected.}} +\DeclareOption{internal}{\intern@ltrue\prepr@ntfalse\inpr@ssfalse\repr@ntfalse% + \typeout{ieee: `Internal-Review' sub-mode selected.}} +\DeclareOption{submitted}{\intern@lfalse\prepr@nttrue\inpr@ssfalse\repr@ntfalse% + \typeout{ieee: `Submitted' sub-mode selected.}} +\DeclareOption{preprint}{\intern@lfalse\prepr@nttrue\inpr@ssfalse\repr@ntfalse% + \typeout{ieee: `Submitted' sub-mode selected.}} % synonym for submitted +\DeclareOption{inpress}{\intern@lfalse\prepr@ntfalse\inpr@sstrue\repr@ntfalse% + \typeout{ieee: `Inpress' sub-mode selected.}} +\DeclareOption{reprint}{\intern@lfalse\prepr@ntfalse\inpr@ssfalse\repr@nttrue% + \typeout{ieee: `Reprint' sub-mode selected.}} + +% Misc options +% ------------ + % regular or compressed "=" spacing in +\def\eqnarr@ysep{\arraycolsep} % eqnarray (this is the default) + % NOTE: we must use "def" and not "=" + % as arraycolsep not yet defined. +\DeclareOption{narroweqnarray}{\gdef\eqnarr@ysep{0.28em\relax}% + \typeout{ieee: Narrow equation arrays selected.}} +\DeclareOption{inline}{\everymath{\thinmuskip=2mu plus 1mu + \medmuskip=3mu plus 1mu minus 2mu + \thickmuskip=4mu plus 2mu\relax}% + \typeout{ieee: Narrower inline equations selected.}} +\DeclareOption{notitlepage}{\titlep@gefalse% + \typeout{ieee: No separate title page.}} +\DeclareOption{titlepage}{\titlep@getrue% + \typeout{ieee: Use separate title page.}} +\DeclareOption{anonymous}{\@nontrue\AtBeginDocument{\glpexclude{biography}} + \typeout{ieee: Omit author information from paper.}} +\DeclareOption{invited}{\@nvitedtrue% + \typeout{ieee: (Invited Paper).}} + +\DeclareOption{9pt}{\ixpttrue% + \typeout{ieee: Trying to emulate old `9pt' document class.}} + +\DeclareOption*{\PassOptionsToClass{\CurrentOption}{article}} + +% Execution of Options/Package Loading +% ------------------------------------ +\newlength\narrowcol +\newlength\parindentsave % recover parindent in blsone text + +\ProcessOptions +\ifev@l % if "final" mode... + \if@technote\ixpttrue\typeout{ieee: Trying to emulate old `9pt' + document class.}\fi% + \LoadClass[twoside,final,twocolumn,10pt]{article} +\else % if "draft"/"submission"/(compressed) mode... + \ifixpt + \LoadClass[oneside,final,onecolumn,10pt]{article} + \else + \LoadClass[oneside,final,onecolumn,12pt]{article} + \fi +\fi +\RequirePackage[final]{graphicx} +\RequirePackage{ifthen} + +% Re-Definitions of English words which must be done before +% the Babel package (optional) is loaded. +% --------------------------------------------------------- +\def\keywordsname{Index Terms} +\def\indexterms#1{\def\keywordsname{#1}} +\def\appendicesname{Appendices} +\def\figurename{Fig.} + +% ************************************************************************** +% ***** Check Sub-Options for Compatibility w/ Main-Options ************ +% ************************************************************************** +\if@technote\ifev@l\else\ClassError{ieee}{`technote' sub-mode may be + used only with the `final' ^^Jmain-mode. It may not be used + with either the `draft,' `submission,' or ^^J`compressed' + main-modes}{}\endinput\fi\fi +\ifintern@l\ifdr@ft\ClassError{ieee}{`internal' sub-mode may be + used only with the ^^J`submission,' `compressed,' or `final' main-modes. + It may not be used ^^Jwith the `draft' main-mode}{}\endinput\fi\fi +\ifprepr@nt\ifc@mpress\else\ifev@l\else\ClassError{ieee}{`submitted' + sub-mode may be used only with the ^^J`compressed' or `final' + main-modes. It may not be used with either the ^^J`draft' or + `submission' main-modes}{}\endinput\fi\fi\fi +\ifinpr@ss\ifc@mpress\else\ifev@l\else\ClassError{ieee}{`inpress' + sub-mode may be used only with the `compressed' ^^Jor `final' + main-modes. It may not be used with either the `draft' or + ^^J`submission' main-modes}{}\endinput\fi\fi\fi +\ifrepr@nt\ifev@l\else\ClassError{ieee}{`reprint' + sub-mode may be used only with the `final' ^^Jmain-mode. It may not be + used with either the `draft,' `submission,' or ^^J`compressed' + main-modes}{}\endinput\fi\fi + +% ************************************************************************** +% ***** Page Layout Definition ***************************************** +% ************************************************************************** +%% Layout definitions (mostly) common to all options. + +\hoffset 0in \voffset 0in +\headheight 12pt \headsep 7mm +\marginparsep 10pt \marginparwidth 20pt +\marginparpush 25pt +\columnsep 4mm +\parindent 1.0em +\lineskip 1pt +\normallineskip 1pt +\def\baselinestretch{1} + +\partopsep \z@ +\topsep 1.3ex +\parsep \z@ +\itemsep \z@ + +\setlength{\parindentsave}{\parindent} + +\ifev@l % if "evaluation" mode + % if camera-ready or A4paper ... + \ifdim\paperwidth<211mm + \oddsidemargin -11.4mm \evensidemargin -11.4mm + % for regular US Letter, not camera-ready + \else + \oddsidemargin -8.45mm \evensidemargin -8.45mm + \fi + \ifrepr@nt + \textheight 237.5mm % leave 6mm for cpyright on first page + \else + \textheight 243.5mm + \fi + \voffset -0.5in + \textwidth 182.0mm + \topmargin -12pt + \setlength{\narrowcol}{89mm} +\else % if "draft"/"submission" mode... + \ifc@mpress % and "compressed" + \oddsidemargin -0.25in \evensidemargin -0.25in + \textheight 9in \textwidth 7in + \topmargin -0.25in + \setlength{\narrowcol}{7in} + \else % and NOT "compressed" + \renewcommand\baselinestretch{1.8}\renewcommand{\arraystretch}{0.8} + \parindent=1.8\parindent + \oddsidemargin 0pt \evensidemargin 0pt + \headheight 12pt \headsep 0.375in + \topmargin 0pt + \textheight 8.5in \textwidth 6.5in + \marginparsep 0in \marginparwidth 0pt + \marginparpush 5pt + \setlength{\narrowcol}{6.5in} + \fi +\fi + +\def\normalstyle{\rmfamily} + +% ************************************************************************** +% ***** Font Definition ************************************************ +% ************************************************************************** +%% The 9-point option is being faked since it is not supported by the +%% article base class. + +%% Check if we have selected 9 points +\ifixpt +\typeout{-- This is a 9 point document} +\gdef\@ptsize{9} +\def\@normalsize{\@setsize\normalsize{10.7pt}\ixpt\@ixpt +\abovedisplayskip 1em plus2pt minus5pt\belowdisplayskip \abovedisplayskip +\abovedisplayshortskip \z@ plus3pt\belowdisplayshortskip .6em plus3pt minus3pt +\topsep \belowdisplayshortskip%!PN +} +\def\small{\@setsize\small{9.12pt}\viiipt\@viipt} +\def\footnotesize{\@setsize\footnotesize{8.15pt}\viipt\@vipt} +\def\scriptsize{\@setsize\scriptsize{8pt}\vipt\@vpt} +\def\tiny{\@setsize\tiny{5pt}\vpt\@vpt} +\def\large{\@setsize\large{12pt}\xpt\@xpt} +\def\Large{\@setsize\Large{14pt}\xiipt\@xiipt} +\def\LARGE{\@setsize\LARGE{18pt}\xivpt\@xivpt} +\def\huge{\@setsize\huge{22pt}\xviipt\@xviipt} +\def\Huge{\@setsize\Huge{25pt}\xxpt\@xxpt} +\fi +%% +%% Check if we have selected 10 points +\def\@tempa{0}\if\@ptsize\@tempa +\typeout{-- This is a 10 point document} +\def\@normalsize{\@setsize\normalsize{11.9pt}\xpt\@xpt +\abovedisplayskip 1em plus2pt minus5pt\belowdisplayskip \abovedisplayskip +\abovedisplayshortskip \z@ plus3pt\belowdisplayshortskip .6em plus3pt minus3pt +\topsep \belowdisplayshortskip%!PN +} +\def\small{\@setsize\small{9.2pt}\viiipt\@viiipt} +\def\footnotesize{\@setsize\footnotesize{8.8pt}\viiipt\@viiipt} +\def\scriptsize{\@setsize\scriptsize{8pt}\viipt\@viipt} +\def\tiny{\@setsize\tiny{6pt}\vpt\@vpt} +\def\normalsize{\@setsize\normalsize{11.9pt}\xpt\@xpt} +\def\large{\@setsize\large{14pt}\xiipt\@xiipt} +\def\Large{\@setsize\Large{18pt}\xivpt\@xivpt} +\def\LARGE{\@setsize\LARGE{22pt}\xviipt\@xviipt} +\def\huge{\@setsize\huge{22pt}\xxpt\@xxpt} +\def\Huge{\@setsize\Huge{28pt}\xxvpt\@xxvpt} +\fi +%% +%% Check if we have selected 11 points +\def\@tempa{1}\if\@ptsize\@tempa +\typeout{-- This is an 11 point document} +\def\@normalsize{\@setsize\normalsize{13.6pt}\xipt\@xipt +\abovedisplayskip 1em plus2pt minus5pt\belowdisplayskip \abovedisplayskip +\abovedisplayshortskip \z@ plus3pt\belowdisplayshortskip .6em plus3pt minus3pt +\topsep \belowdisplayshortskip%!PN +} +\def\small{\@setsize\small{12pt}\xpt\@xpt} +\def\footnotesize{\@setsize\footnotesize{11pt}\ixpt\@ixpt} +\def\scriptsize{\@setsize\scriptsize{9.5pt}\viiipt\@viiipt} +\def\tiny{\@setsize\tiny{7pt}\vipt\@vipt} +\def\normalsize{\@setsize\normalsize{13.6pt}\xipt\@xipt} +\def\large{\@setsize\large{14pt}\xiipt\@xiipt} +\def\Large{\@setsize\Large{18pt}\xivpt\@xivpt} +\def\LARGE{\@setsize\LARGE{22pt}\xviipt\@xviipt} +\def\huge{\@setsize\huge{25pt}\xxpt\@xxpt} +\def\Huge{\@setsize\Huge{30pt}\xxvpt\@xxvpt} +\fi +%% +%% Check if we have selected 12 points +\def\@tempa{2}\if\@ptsize\@tempa +\typeout{-- This is a 12 point document} +\def\@normalsize{\@setsize\normalsize{14pt}\xiipt\@xiipt +\abovedisplayskip 1em plus3pt minus6pt\belowdisplayskip \abovedisplayskip +\abovedisplayshortskip \z@ plus3pt\belowdisplayshortskip .6em plus4pt minus4pt +\topsep \belowdisplayshortskip%!PN +} +\def\small{\@setsize\small{11.4pt}\xpt\@xpt} +\def\footnotesize{\@setsize\footnotesize{10pt}\ixpt\@ixpt} +\def\scriptsize{\@setsize\scriptsize{9pt}\viiipt\@viiipt} +\def\tiny{\@setsize\tiny{8pt}\vipt\@vipt} +\def\normalsize{\@setsize\normalsize{14pt}\xiipt\@xiipt} +\def\large{\@setsize\large{18pt}\xivpt\@xivpt} +\def\Large{\@setsize\Large{22pt}\xviipt\@xviipt} +\def\LARGE{\@setsize\LARGE{25pt}\xxpt\@xxpt} +\def\huge{\@setsize\huge{30pt}\xxvpt\@xxvpt} +\let\Huge=\huge +\fi + +\AtBeginDocument{\normalsize\normalstyle\ps@headings\pagenumbering{arabic}} + +% ************************************************************************** +% ***** List Definition ************************************************ +% ************************************************************************** +%% Change aspect of lists with +%% 1) \itemindent, label indentation wrt to left list margin +%% 2) \leftmargini, the indentation of the whole list (on left, first level) +\ifev@l + \itemindent -1em + \leftmargini 2em + \leftmarginii 1em + \leftmarginiii 1.5em + \leftmarginiv 1.5em + \leftmarginv 1.0em + \leftmarginvi 1.0em +\else + \itemindent -1em + \leftmargini 3em + \leftmarginii 3em + \leftmarginiii 3em + \leftmarginiv 3em + \leftmarginv 3em + \leftmarginvi 3em +\fi +%\itemindent 2em % Alternative values: sometimes used.. +%\leftmargini 0em +\labelsep 5pt +\leftmargin\leftmargini +\labelwidth \z@ + +\def\@listI{\leftmargin\leftmargini} \@listI +\def\@listi{\leftmargin\leftmargini \topsep \z@ plus 1pt minus 1pt} +\def\@listii{\leftmargin\leftmarginii\labelwidth\leftmarginii + \advance\labelwidth-\labelsep \topsep \z@} +\def\@listiii{\leftmargin\leftmarginiii\labelwidth\leftmarginiii + \advance\labelwidth-\labelsep \topsep \z@} +\def\@listiv{\leftmargin\leftmarginiv\labelwidth\leftmarginiv + \advance\labelwidth-\labelsep \topsep \z@} +\def\@listv{\leftmargin\leftmarginv\labelwidth\leftmarginv + \advance\labelwidth-\labelsep \topsep \z@} +\def\@listvi{\leftmargin\leftmarginvi\labelwidth\leftmarginvi + \advance\labelwidth-\labelsep \topsep \z@} + +\def\labelenumi{\theenumi.} \def\theenumi{\arabic{enumi}} +\def\labelenumii{(\theenumii)} \def\theenumii{\alph{enumii}} +\def\labelenumiii{\theenumiii.} \def\theenumiii{\roman{enumiii}} +\def\labelenumiv{\theenumiv.} \def\theenumiv{\Alph{enumiv}} +\def\p@enumii{\theenumi} +\def\p@enumiii{\theenumi(\theenumii)} +\def\p@enumiv{\p@enumiii\theenumiii} + +\def\labelitemi{$\scriptstyle\bullet$} +\def\labelitemii{\bf --} +\def\labelitemiii{$\ast$} +\def\labelitemiv{$\cdot$} + +%% \itemindent is set to \z@ by list, so define new temporary variable +\newdimen\tmpitemindent +\def\verse{\let\\=\@centercr + \list{}{\itemsep\z@ \itemindent -1.5em \listparindent \itemindent + \rightmargin\leftmargin\advance\leftmargin 1.5em}\item[]} +\let\endverse\endlist +\def\quotation{\list{}{\listparindent 1.5em \itemindent\listparindent + \rightmargin\leftmargin \parsep 0pt plus 1pt}\item[]} +\let\endquotation=\endlist +\def\quote{\list{}{\rightmargin\leftmargin}\item[]} +\let\endquote=\endlist +\def\@mklab#1{#1} +\def\description{\tmpitemindent\itemindent\list{}{\itemindent\tmpitemindent + \labelwidth\z@\def\makelabel##1{\hspace\labelsep\emph{##1}}}} +\def\enddescription{\endlist\par} +\def\enumerate{\tmpitemindent\itemindent\ifnum \@enumdepth >3 \@toodeep\else + \advance\@enumdepth \@ne \edef\@enumctr{enum\romannumeral\the\@enumdepth}% + \list{\csname label\@enumctr\endcsname}{\itemindent\tmpitemindent + \usecounter{\@enumctr}\def\makelabel##1{\hspace\labelsep\hfil{##1}}}\fi} +\def\endenumerate{\endlist\par} +\def\itemize{\tmpitemindent\itemindent\ifnum \@itemdepth >3 \@toodeep\else + \advance\@itemdepth\@ne + \edef\@itemitem{labelitem\romannumeral\the\@itemdepth}% + \list{\csname\@itemitem\endcsname}{\itemindent\tmpitemindent + \def\makelabel##1{\hspace\labelsep\hfil\emph{##1}}}\fi} +\def\enditemize{\endlist\par} + +\newif\if@restonecol +\def\titlepage{\@restonecolfalse\if@twocolumn\@restonecoltrue\onecolumn + \else \newpage \fi \thispagestyle{coverpagestyle}\c@page\z@} +\def\endtitlepage{\if@restonecol\twocolumn \else \newpage \fi% +\if@twoside\mbox{}\thispagestyle{coverpagestyle}\c@page\z@\cleardoublepage\fi} + +\arraycolsep 5pt +\tabcolsep 6pt +\arrayrulewidth .4pt +\doublerulesep 2pt +\tabbingsep\labelsep + +% ************************************************************************** +% ***** Footnote Definition ******************************************** +% ************************************************************************** +\skip\footins 10pt plus 5pt minus 2pt +\footnotesep 7pt +\footskip 6mm +\skip\@mpfootins = \skip\footins +\fboxsep = 3pt \fboxrule = .4pt +\long\def\@makefntext#1{\parindent .8em\indent$^{\@thefnmark}$#1} +\def\footnoterule{} + +% Reset baselinestretch within footnotes. +% Originally stolen from Stanford University thesis style. +% -------------------------------------------------------- +\long\def\@footnotetext#1{\insert\footins{\blsone% + \footnotesize\interlinepenalty\interfootnotelinepenalty + \splittopskip\footnotesep + \splitmaxdepth \dp\strutbox \floatingpenalty \@MM + \hsize\columnwidth \@parboxrestore + \edef\@currentlabel{\csname p@footnote\endcsname\@thefnmark}\@makefntext + \let\par\\ + {\rule{\z@}{\footnotesep}\ignorespaces + #1\strut}}} + +% ************************************************************************** +% ***** Keep track of Sections ***************************************** +% ************************************************************************** +\if@technote + \setcounter{secnumdepth}{3} +\else + \setcounter{secnumdepth}{4} +\fi + +\def\thesection{\@Roman\c@section} +\def\thesubsection{\Alph{subsection}} +\def\thesubsubsection{\thesubsection.\arabic{subsubsection}} +\def\thesubsubsectiondis{\Alph{subsection}.\arabic{subsubsection}} +\def\theparagraph{\thesubsubsection.\alph{paragraph}} +\def\theparagraphdis{\thesubsubsectiondis.\alph{paragraph}} + +\def\theequation{\arabic{equation}} + +% ************************************************************************** +% ***** Table of Contents, List of Figures/Tables Definitions ********** +% ************************************************************************** +\def\@pnumwidth{1.55em} +\def\@tocrmarg {2.55em} +\def\@dotsep{4.5} +\setcounter{tocdepth}{3} + +\def\tableofcontents{\section*{\contentsname}\@starttoc{toc}} +\def\l@section#1#2{\addpenalty{\@secpenalty} \addvspace{1.0em plus 1pt} + \@tempdima 1.8em \begingroup \parindent \z@ \rightskip \@pnumwidth + \parfillskip-\@pnumwidth \bf\leavevmode #1\hfil\hbox to\@pnumwidth{\hss #2} + \par \endgroup} +\def\l@subsection{\@dottedtocline{2}{1.5em}{2.3em}} +\def\l@subsubsection{\@dottedtocline{3}{3.8em}{3.2em}} +\def\listoffigures{\section*{\listfigurename}\@starttoc{lof}} +\def\l@figure{\@dottedtocline{1}{1em}{1.8em}} +\def\listoftables{\section*{\listtablename}\@starttoc{lot}} +\let\l@table\l@figure + +% ************************************************************************** +% ***** Float Definitions ********************************************** +% ************************************************************************** +%% Normal Floats %% Double Column Floats +\floatsep 12pt plus 2pt minus 2pt \dblfloatsep 12pt plus 2pt minus 2pt +\textfloatsep 20pt plus 2pt minus 4pt \dbltextfloatsep 20pt plus 2pt minus 4pt +%\@maxsep 20pt \@dblmaxsep 20pt %!PN +\@fptop 0pt plus 1fil \@dblfptop 0pt plus 1fil +\@fpsep 8pt plus 2fil \@dblfpsep 8pt plus 2fil +\@fpbot 0pt plus 1fil \@dblfpbot 0pt plus 1fil +\def\topfraction{1.0} \def\dbltopfraction{1.0} +\def\floatpagefraction{0.8} \def\dblfloatpagefraction{0.8} +\setcounter{topnumber}{2} \setcounter{dbltopnumber}{4} +% +\intextsep 12pt plus 2pt minus 2pt +\setcounter{bottomnumber}{2} +\def\bottomfraction{.4} +\setcounter{totalnumber}{4} +\def\textfraction{.2} + +% Reset baselinestretch within floats. +% Originally stolen from Stanford University thesis style. +% -------------------------------------------------------- +\def\@xfloat#1[#2]{\ifhmode \@bsphack\@floatpenalty -\@Mii\else + \@floatpenalty-\@Miii\fi\def\@captype{#1}\ifinner + \@parmoderr\@floatpenalty\z@ + \else\@next\@currbox\@freelist{\@tempcnta\csname ftype@#1\endcsname + \multiply\@tempcnta\@xxxii\advance\@tempcnta\sixt@@n + \@tfor \@tempa :=#2\do + {\if\@tempa h\advance\@tempcnta \@ne\fi + \if\@tempa t\advance\@tempcnta \tw@\fi + \if\@tempa b\advance\@tempcnta 4\relax\fi + \if\@tempa p\advance\@tempcnta 8\relax\fi + }\global\count\@currbox\@tempcnta}\@fltovf\fi + \global\setbox\@currbox\vbox\bgroup + \def\baselinestretch{1}\small\normalsize + \hsize\columnwidth \@parboxrestore} + +% ************************************************************************** +% ***** Caption Definition ********************************************* +% ************************************************************************** +% some journals do not have centered captions for figures. +\newif\ifc@ptionleft \c@ptionlefttrue +\def\leftfigcaptions{\c@ptionlefttrue} +\def\centerfigcaptions{\c@ptionleftfalse} + +\long\def\caption{\refstepcounter\@captype \@dblarg{\@caption\@captype}} + +\long\def\@caption#1[#2]#3{\par\addcontentsline{\csname ext@#1\endcsname}{#1}{% + \protect\numberline{\csname the#1\endcsname}{\ignorespaces #2}} + \begingroup \@parboxrestore \normalsize + \@makecaption{\csname fnum@#1\endcsname}{\ignorespaces #3}{#1}\par + \endgroup} + +\def\tablestring{table} +\def\figurestring{figure} + +% changed by GLP to allow table captions to be set to a specific maximum +% width "\captionwidth", if defined. +\newlength{\captionindent} +\long\def\@makecaption#1#2#3{ +\ifx\figurestring#3 + \vskip 5pt + \setbox\@tempboxa\hbox{\small #1.~ #2} + \ifdim \wd\@tempboxa >\hsize + \setbox\@tempboxa\hbox{\small #1.~ } + %\setlength\captionindent{\wd\@tempboxa} \divide\captionindent by 2 + %\parbox[t]{\hsize}{\small \hangindent \captionindent \hangafter=1% + \parbox[t]{\hsize}{\small + \unhbox\@tempboxa#2} + \else \hbox + to\hsize{\small\ifc@ptionleft\else\hfil\fi\box\@tempboxa\hfil} + \fi +\else + \begin{center} + \ifx\captionwidth\undefined {\small #1}\\{\small\scshape #2} + \else + \begin{minipage}{\captionwidth} + \begin{center}{\small #1}\\{\small\scshape #2}\end{center} + \end{minipage} + \fi + \end{center}\vskip 4pt +\fi} + +\def\thefigure{\@arabic\c@figure} +\def\fps@figure{tbp} +\def\ftype@figure{1} +\def\ext@figure{lof} +\def\fnum@figure{\figurename\ \thefigure} +%\def\figure{\@float{figure}} % GLP +%\let\endfigure\end@float +\@namedef{figure*}{\@dblfloat{figure}} +\@namedef{endfigure*}{\end@dblfloat} + +\def\thetable{\@Roman\c@table} +\def\fps@table{tbp} +\def\ftype@table{2} +\def\ext@table{lot} +\def\fnum@table{TABLE~\thetable} +\def\table{\@float{table}} +\let\endtable\end@float +\@namedef{table*}{\@dblfloat{table}} +\@namedef{endtable*}{\end@dblfloat} + +% ************************************************************************** +% ***** Header/Footer Definition *************************************** +% ************************************************************************** +% compute the time in hours and minutes; make new vars \timehh and \timemm +\newcount\timehh\newcount\timemm\timehh=\time\divide\timehh by 60 +\timemm=\time\count255=\timehh\multiply\count255 by-60 +\advance\timemm by \count255 +\ifnum\timehh=12\def\apm{pm}\else +\ifnum\timehh>12\def\apm{pm}\advance\timehh by-12\else +\def\apm{am}\fi\fi +\def\t@me{\number\timehh\,:\,\ifnum\timemm<10 0\fi\number\timemm\,\apm} + +% default definitions +% ------------------- +\def\theevenhe@d{\footnotesize\thepage \hfil \leftmark\hbox{}} +\def\theoddhe@d{\hbox{}\footnotesize\rightmark \hfil \thepage} +\def\theevenf@@t{} +\def\theoddf@@t{} + +\def\theeventphe@d{\footnotesize\thepage \hfil \hbox{}} +\def\theoddtphe@d{\hbox{}\footnotesize \hfil \thepage} +\def\theeventpf@@t{} +\def\theoddtpf@@t{} + +\def\theevencphe@d{} +\def\theoddcphe@d{} +\def\theevencpf@@t{} +\def\theoddcpf@@t{} + +\def\internalmsg{Preliminary version for evaluation: Please do not + circulate without the permission of the author(s)} +\def\submittedmsg{SUBMITTED FOR PUBLICATION TO:} +\def\acceptedmsg{ACCEPTED FOR PUBLICATION:} +\def\inpressmsg{(IN PRESS)} +\def\reprintmsg{REPRINTED FROM:} + +% default cover page style (optional cover page) +% ---------------------------------------------- +\def\ps@coverpagestyle{ + \def\@oddhead{\theoddcphe@d} \def\@evenhead{\theevencphe@d} + \def\@oddfoot{\theoddcpf@@t} \def\@evenfoot{\theevencpf@@t} +} + +% default title page style (first page of paper) +% ---------------------------------------------- +\def\ps@titlepagestyle{ + \def\@oddhead{\theoddtphe@d} \def\@evenhead{\theeventphe@d} + \def\@oddfoot{\theoddtpf@@t} \def\@evenfoot{\theeventpf@@t} +} + +% default regular page style +% -------------------------- +\if@twoside + \def\ps@headings{ + \def\@oddhead{\theoddhe@d} + \def\@evenhead{\theevenhe@d} + \def\@oddfoot{\theoddf@@t} \def\@evenfoot{\theevenf@@t} + } +\else + \def\ps@headings{ + \def\@oddhead{\theoddhe@d} + \def\@oddfoot{\theoddf@@t} + \def\@evenhead{} \def\@evenfoot{} + } +\fi + +% For draft mode (no sub-modes allowed) +% ------------------------------------- +\ifdr@ft + \def\leftmark{\sh@rttitle}\let\rightmark\leftmark + \def\theoddf@@t{\footnotesize\today---\t@me\hfil DRAFT} + \def\theevenf@@t{\footnotesize DRAFT\hfil\today---\t@me} + \def\theoddtpf@@t{\footnotesize\today---\t@me\hfil DRAFT} + \def\theeventpf@@t{\footnotesize DRAFT\hfil\today---\t@me} +\fi + +% For submission mode (default plus internal sub-modes allowed) +% ------------------------------------------------------------- +\ifsubm@t + \def\leftmark{\sh@rttitle}\def\rightmark{\titl@line} + \ifintern@l + \def\theeventphe@d{\footnotesize\thepage \hfil \rightmark\hbox{}} + \def\theoddtphe@d{\hbox{}\footnotesize\rightmark \hfil \thepage} + \def\rightmark{\vbox to 0pt{\vss\hbox{\internalmsg} \hbox{\sh@rttitle}}} + \def\leftmark{\vbox to 0pt{\vss\hbox{\internalmsg} + \hbox{\phantom{\internalmsg}\llap{\sh@rttitle}}}} + \else % put date on first page. + \edef\TODAY{\uppercase{\today}} + \def\theeventphe@d{\footnotesize\thepage \hfil \submittedmsg\ + \@journal\@titletext, \TODAY} + \def\theoddtphe@d{\footnotesize\submittedmsg\ + \@journal\@titletext, \TODAY\hfil \thepage} + \def\theevencphe@d{\footnotesize\hbox{} \hfil \submittedmsg\ + \@journal\@titletext, \TODAY} + \def\theoddcphe@d{\footnotesize\submittedmsg\ + \@journal\@titletext, \TODAY\hfil \hbox{}} + \fi +\fi + +% For compressed mode (default, internal, submitted and +% inpress sub-modes allowed) +% ----------------------------------------------------- +\ifc@mpress + \def\leftmark{\sh@rttitle}\def\rightmark{\titl@line} + \ifintern@l + \def\theeventphe@d{\footnotesize\thepage \hfil \rightmark\hbox{}} + \def\theoddtphe@d{\hbox{}\footnotesize\rightmark \hfil \thepage} + \def\rightmark{\vbox to 0pt{\vss\hbox{\internalmsg} \hbox{\sh@rttitle}}} + \def\leftmark{\vbox to 0pt{\vss\hbox{\internalmsg} + \hbox{\phantom{\internalmsg}\llap{\sh@rttitle}}}} + \fi + \ifprepr@nt + \edef\TODAY{\uppercase{\today}} + \def\theeventphe@d{\footnotesize\thepage \hfil \submittedmsg\ + \@journal\@titletext, \TODAY} + \def\theoddtphe@d{\footnotesize\submittedmsg\ + \@journal\@titletext, \TODAY\hfil \thepage} + \def\theevencphe@d{\footnotesize\hbox{} \hfil \submittedmsg\ + \@journal\@titletext, \TODAY} + \def\theoddcphe@d{\footnotesize\submittedmsg\ + \@journal\@titletext, \TODAY\hfil \hbox{}} + \fi + \ifinpr@ss + \def\leftmark{\acceptedmsg\ \@journal\@titletext, \inpressmsg} + \def\theeventphe@d{\footnotesize\thepage \hfil \leftmark\hbox{}} + \def\theoddtphe@d{\hbox{}\footnotesize\leftmark \hfil \thepage} + \fi +\fi + +% For final (evaluate) mode (default, techreport, internal, +% submitted, inpress and reprint sub-modes allowed) +% --------------------------------------------------------- +\ifev@l + \edef\TODAY{\uppercase{\today}} + \def\leftmark{\@journal\@titletext}\def\rightmark{\titl@line} + \def\theeventphe@d{\footnotesize\thepage \hfil \leftmark\hbox{}} + \def\theoddtphe@d{\hbox{}\footnotesize\leftmark \hfil \thepage} + \if@technote % make header a little bigger + \def\theevenhe@d{\small\thepage \hfil \leftmark\hbox{}} + \def\theoddhe@d{\hbox{}\small\rightmark \hfil \thepage} + \def\theeventphe@d{\small\thepage \hfil \leftmark\hbox{}} + \def\theoddtphe@d{\hbox{}\small\leftmark \hfil \thepage} + \fi + \ifintern@l + \def\theeventphe@d{\footnotesize\thepage \hfil \rightmark\hbox{}} + \def\theoddtphe@d{\hbox{}\footnotesize\rightmark \hfil \thepage} + \def\rightmark{\vbox to 0pt{\vss\hbox{\internalmsg} \hbox{\sh@rttitle}}} + \def\leftmark{\vbox to 0pt{\vss\hbox{\internalmsg} + \hbox{\phantom{\internalmsg}\llap{\sh@rttitle}}}} + \fi + \ifprepr@nt + \def\leftmark{\submittedmsg\ \@journal\@titletext, \TODAY} + \fi + \ifinpr@ss + \def\leftmark{\acceptedmsg\ \@journal\@titletext, \inpressmsg} + \fi + \ifrepr@nt + % reset page size on second and following pages b/c no copyright info + \let\oldshipout\shipout + \gdef\shipout{\global\textheight 243.5mm\oldshipout} + \def\theeventpf@@t{\footnotesize\hfil\@ieeecopyright\hfil} + \def\theoddtpf@@t{\footnotesize\hfil\@ieeecopyright\hfil} + \def\leftmark{\reprintmsg\ \@journal\@titletext} + \fi +\fi + +%% Defines the command for putting the header. footernote{TEXT} is the same +%% as markboth{TEXT}{TEXT}. Here for compatibility with other style files. +\def\markboth#1#2{\def\leftmark{#1}\def\rightmark{#2}} +\def\footernote#1{\markboth{#1}{#1}} + +% ************************************************************************** +% ***** Citation/Bibliography Definitions ****************************** +% ************************************************************************** +%% separate citations with "], [" +\def\@citex[#1]#2{\if@filesw\immediate\write\@auxout{\string\citation{#2}}\fi +\def\@citea{}\@cite{\@for\@citeb:=#2\do {\@citea\def\@citea{], +[}\@ifundefined {b@\@citeb}{{\bf ?}\@warning {Citation `\@citeb' on +page \thepage \space undefined}}% +{\csname b@\@citeb\endcsname}}}{#1}} + +\def\@cite#1#2{[{#1\if@tempswa, #2\fi}]} + +%% Allow short (name-less) citations, when used in conjunction with a +%% bibliography style that creates labels like \citename{, } +\let\@internalcite\cite +\def\cite{\def\citename##1{##1}\@internalcite} +\def\shortcite{\def\citename##1{}\@internalcite} +\def\@biblabel#1{\def\citename##1{##1}[#1]\hfill} + +\def\thebibliography#1{\section*{\refname}\footnotesize\list + {\hss[\arabic{enumi}]}{\settowidth\labelwidth{[#1]}\leftmargin\labelwidth + \advance\leftmargin\labelsep \itemsep 0pt plus .5pt + \usecounter{enumi}} + \def\newblock{\hskip .11em plus .33em minus .07em} + \sloppy\clubpenalty4000\widowpenalty4000 + \sfcode`\.=1000\relax + \ifev@l\else\normalsize\fi %added by GLP +} +\let\endthebibliography=\endlist + +% ************************************************************************** +% ***** Appendix/Appendices Definitions ******************************** +% ************************************************************************** +\newcounter{numappendices}\setcounter{numappendices}{0} +\newif\ifappendix \appendixfalse +%% appendix command for one single appendix +\def\appendix{\par + \appendixtrue + \typeout{appendices: \arabic{numappendices}} + \setcounter{section}{0}\setcounter{subsection}{0} + \gdef\thesection{\Alph{section}} + \ifnum \value{numappendices}>1 + \section*{\appendicesname} + \else + \section*{\appendixname} + \fi + \setcounter{numappendices}{0} +} +%% appendices command for multiple appendicies +\def\appendices{\par + \appendixtrue + \typeout{appendices: \arabic{numappendices}} + \setcounter{section}{0}\setcounter{subsection}{0} + \gdef\thesection{\Alph{section}} \section*{\appendicesname} + \setcounter{numappendices}{0} +} +\AtEndDocument{\if@filesw\immediate\write\@auxout{\string\setcounter{numappendices}{\arabic{numappendices}}}\fi} + +% ************************************************************************** +% ***** Title Definitions ********************************************** +% ************************************************************************** +\def\titl@line{\sh@rttitle} %for the header at the top of the page. + +\def\@title{\typeout{ieee: Warning! No \noexpand\title given!}} +\def\title{\@ifnextchar [{\titlea}{\titleb}}%] + +\def\set@title#1{\gdef\@title{#1}\global\def\set@title##1{}} +\def\setsh@rttitle#1{\gdef\sh@rttitle{#1}\global\def\setsh@rttitle##1{}} +\def\titlea[#1]#2{\set@title{#2}\setsh@rttitle{\uppercase{#1}}} +\def\titleb#1{\set@title{#1}\setsh@rttitle{\uppercase{#1}}} + +\def\authorinfo#1{\let\\\relax\thanks{#1}} + +\ifev@l + \if@technote + \def\member#1{} + \else + \def\member#1{, \emph{#1, IEEE}} + \fi +\else + \def\member#1{} +\fi + +\def\and{\unskip% % \begin{tabular} +\end{tabular}% +\hskip 0pt plus 0.1pt% +\begin{tabular}[t]{@{}c@{}}\ }% + +\def\@author{\typeout{ieee: Warning! No \noexpand\author given!}} +\def\author{\@ifnextchar [{\authora}{\authorb}}%] +\def\set@author#1{\gdef\@author{#1}\global\def\set@author##1{}} +\def\settitl@line#1{\gdef\titl@line{#1}\global\def\settitl@line##1{}} +\def\authora[#1]#2{\set@author{#2}\if@non\else\settitl@line{#1: \sh@rttitle}\fi} +\def\authorb#1{\set@author{#1}} + +\def\date#1{\def\today{#1}\edef\TODAY{\uppercase{\today}}} + +\long\def\maketitle{% + \begingroup + \let\@thanks\@empty + \renewcommand\thefootnote{} % the \thanks{} mark type is empty + \iftitlep@ge\begin{titlepage}\@maketitlepage\@thanks\end{titlepage}% + \let\@thanks\@empty\fi + \thispagestyle{titlepagestyle} + \if@twocolumn + \if@technote + %\if@twoside\newpage\cleardoublepage\else\newpage\fi% + \newpage\global\@topnum\z@ + \ifrepr@nt + \ifx\@loginfo\undefined\typeout{ieee: Warning! No \noexpand\loginfo + given!}\else\let\\\relax\thanks{\@loginfo}\fi% + \fi + \@maketitle + \else + \ifnum \col@number=\@ne + \ifrepr@nt + \ifx\@loginfo\undefined\typeout{ieee: Warning! No \noexpand\loginfo + given!}\else\let\\\relax\thanks{\@loginfo}\fi% + \fi + \@maketitle + \else \twocolumn[% + \ifrepr@nt% + \ifx\@loginfo\undefined\typeout{ieee: Warning! No \noexpand\loginfo% + given!}\else\let\\\relax\thanks{\@loginfo}\fi% + \fi% + \@maketitle]% + \fi + \fi + \else + \newpage + \global\@topnum\z@ % Prevents figures from going at top of page. + \ifrepr@nt + \ifx\@loginfo\undefined\typeout{ieee: Warning! No \noexpand\loginfo + given!}\else\let\\\relax\thanks{\@loginfo}\fi + \fi + \@maketitle + \fi + \thispagestyle{titlepagestyle}% + \@thanks + \endgroup + \setcounter{footnote}{0}% + \global\let\thanks\relax \global\let\maketitle\relax + \global\let\@maketitle\relax \global\let\@thanks\@empty + \global\let\@author\@empty \global\let\@date\@empty + \global\let\@title\@empty \global\let\title\relax + \global\let\author\relax \global\let\date\relax + \global\let\and\relax +} + +\long\def\@maketitle{\unskip\newpage% + \begin{center}\blsone + \let \footnote \thanks + \if@technote + {\bfseries\@title\par}\if@non\else\vskip 1.3em{\lineskip .5em + \noindent\begin{tabular}[t]{@{}c@{}}\@author\end{tabular}}\fi\par + \else\unskip + \noindent{\Huge\@title\par}% + \if@non\else\vskip1.0em% + \noindent{\large\lineskip .5em% + \begin{tabular}[t]{@{}c@{}}\@author\end{tabular}}% + \fi\par% + \if@nvited\vskip1.0em\noindent\emph{\large(Invited Paper)}\par\fi + \fi + \ifrepr@nt + \ifx\@lognumber\undefined\typeout{ieee: Warning! No + \noexpand\pubitemident or \noexpand\lognumber + given!}\else\thanks{\@lognumber}\fi% + \fi + \end{center}\par\vskip 0.5em}% + +\long\def\@maketitlepage{\newpage% + \mbox{}\vfil + \begin{center}\blsone + \let \footnote \thanks + \if@technote + {\bfseries\@title\par}\vskip 1.3em{\lineskip .5em + \noindent\begin{tabular}[t]{@{}c@{}}\@author\end{tabular}\par} + \else + \vskip0.2em{\Huge\@title\par}\vskip1.0em% + \iftitlep@ge\vfil\fi + \noindent{\large\lineskip .5em% + \begin{tabular}[t]{@{}c@{}}\@author\end{tabular}\par}% + \fi + \end{center}\par\vfil\mbox{}} + +\def\@journal{\typeout{ieee: Warning! No \noexpand\journal given!}} +\def\journal#1{\def\@journal{\uppercase{#1}}} + +\def\@ieeecopyright{\typeout{ieee: Warning! No \noexpand\ieeecopyright given!}} +\def\ieeecopyright#1{\def\@ieeecopyright{#1}} + +\def\lognumber#1{\def\@lognumber{IEEE Log Number #1.}} +\def\pubitemident#1{\def\@lognumber{Publisher Item Identifier #1.}} +\long\def\loginfo#1{\long\def\@loginfo{\hbox{\vrule height 3ex width \z@}#1}} + +\def\sh@rttitle{} +\def\@titletext{} +\def\titletext#1{\def\@titletext{#1}} + +\def\firstpage#1{\setcounter{page}{#1}} + +% ************************************************************************** +% ***** Abstract Definition ******************************************** +% ************************************************************************** +\def\abstract{% + \if@twocolumn + \small\bfseries{\itshape\abstractname\/---}% + \else + \begin{center}\vspace{-0.8em}\small\bf\abstractname\end{center} + \quotation\small + \fi\ignorespaces} +\def\endabstract{\vspace{0.6em}\par\if@twocolumn\else\endquotation\fi + \normalsize\normalstyle} + +% ************************************************************************** +% ***** Keywords Definition ******************************************** +% ************************************************************************** +\def\keywords{\vspace{-.3em} + \if@twocolumn + \small\bfseries{\itshape\keywordsname\/---}% + \else + \begin{center}\small\bf\keywordsname\end{center}\quotation\small + \fi\ignorespaces} +\def\endkeywords{\vspace{0.6em}\par\if@twocolumn\else\endquotation\fi + \normalsize\normalstyle} + +% ************************************************************************** +% ***** Fix Section Numbering ****************************************** +% ************************************************************************** +\gdef\@punct{.\ \ } % Punctuation after run-in section heading +\def\@sect#1#2#3#4#5#6[#7]#8{% + \ifnum #2>\c@secnumdepth + \def\@svsec\@empty + \else + \refstepcounter{#1}% + \protected@edef\@svsec{% + %\ifnum #2=1\Roman{#1}.\fi\ifnum #2=2\Alph{#1}.\fi + \ifnum #2=1\thesection.\fi + \ifnum #2=2\thesubsection.\fi + \ifnum #2>2{\csname the#1dis\endcsname}\if@technote.\fi\fi \hskip .5em} + \ifnum #2=1\ifappendix\stepcounter{numappendices}\fi\fi + \fi + \@tempskipa #5\relax + \ifdim \@tempskipa>\z@ + \begingroup #6\relax + \@hangfrom{\hskip #3\relax\@svsec}{\interlinepenalty \@M #8\par} + \endgroup + \csname #1mark\endcsname{#7} + \addcontentsline{toc}{#1}{\ifnum #2>\c@secnumdepth\else + \protect\numberline{\csname the#1\endcsname}\fi#7} + \else + \def\@svsechd{#6\hskip #3\@svsec #8\@punct\csname #1mark\endcsname{#7} + \addcontentsline{toc}{#1}{\ifnum #2>\c@secnumdepth \else + \protect\numberline{\csname the#1\endcsname}\fi#7}} + \fi + \@xsect{#5}} + +\def\@ssect#1#2#3#4#5{\@tempskipa #3\relax + \ifdim \@tempskipa>\z@ + \begingroup #4\@hangfrom{\hskip #1}{\interlinepenalty \@M #5\par}\endgroup + \else \def\@svsechd{#4\hskip #1\relax #5\@punct}\fi + \@xsect{#3}} + +% ************************************************************************** +% ***** Section Definitions ******************************************** +% ************************************************************************** +\def\section{\@startsection{section}{1}{\z@}{2.0ex plus .5ex + minus .2ex}{1.0ex plus .2ex}{\centering\scshape}} +\def\subsection{\@startsection{subsection}{2}{\z@}{2.0ex plus .5ex + minus .2ex}{1.0ex plus .2ex}{\itshape}} +\if@technote + \def\subsubsection{\@startsection{subsubsection}{3}{\z@}{2.0ex plus .5ex + minus .1ex}{0pt}{\itshape}} +\else + \def\subsubsection{\@startsection{subsubsection}{3}{\z@}{2.0ex plus .5ex + minus .2ex}{1.0ex plus .2ex}{\normalstyle}} + \def\paragraph{\@startsection{paragraph}{4}{\z@}{1.0ex plus .5ex + minus .2ex}{0ex}{\normalstyle}} +\fi + +% ************************************************************************** +% ***** Special Environment Definitions ******************************** +% ************************************************************************** +\def\QED{\mbox{\rule[0pt]{1.5ex}{1.5ex}}} +\def\proof{\noindent\hspace{1em}{\it Proof: }} +\def\endproof{\hspace*{\fill}~\QED\par\endtrivlist\unskip} +\def\@begintheorem#1#2{\tmpitemindent\itemindent\topsep 0pt\normalstyle\trivlist + \item[\hskip \labelsep{\indent\it #1\ #2:}]\itemindent\tmpitemindent} +\def\@opargbegintheorem#1#2#3{\tmpitemindent\itemindent\topsep 0pt\normalstyle \trivlist + \item[\hskip\labelsep{\indent\it #1\ #2\ \normalstyle(#3)}]\itemindent\tmpitemindent} +\def\@endtheorem{\endtrivlist\unskip} + +% ************************************************************************** +% ***** Special Environment Definitions ******************************** +% ************************************************************************** +\if@twoside\else\raggedbottom\fi + +%% Definition for Big letter at the beginning of a paragraph +%% +\def\PARstart#1#2 {\begingroup\def\par{\endgraf\endgroup\lineskiplimit=0pt} + \setbox2=\hbox{\uppercase{#2} }\newdimen\tmpht \tmpht \ht2 + \advance\tmpht by \baselineskip\font\hhuge=cmr10 at \tmpht + \setbox1=\hbox{{\hhuge #1}} + \count7=\tmpht \count8=\ht1\divide\count8 by 1000 \divide\count7 by\count8 + \tmpht=.001\tmpht\multiply\tmpht by \count7\font\hhuge=cmr10 at \tmpht + \setbox1=\hbox{{\hhuge #1}} \noindent \hangindent1.05\wd1 + \hangafter=-2 {\hskip-\hangindent \lower1\ht1\hbox{\raise1.0\ht2\copy1}% + \kern-0\wd1}\copy2\lineskiplimit=-1000pt} + +\def\PARstartCal#1#2 {\begingroup\def\par{\endgraf\endgroup\lineskiplimit=0pt} + \setbox2=\hbox{\uppercase{#2} }\newdimen\tmpht \tmpht \ht2 + \advance\tmpht by \baselineskip\font\hhuge=cmsy10 at \tmpht + \setbox1=\hbox{{\hhuge #1\/}} + \count7=\tmpht \count8=\ht1\divide\count8 by 1000 \divide\count7 by\count8 + \tmpht=.001\tmpht\multiply\tmpht by \count7\font\hhuge=cmsy10 at \tmpht + \setbox1=\hbox{{\hhuge #1\/}} \noindent \hangindent1.05\wd1 + \hangafter=-2 {\hskip-\hangindent \lower1\ht1\hbox{\raise1.0\ht2\copy1}% + \kern-0\wd1}\copy2\lineskiplimit=-1000pt} + +\def\PARstartLyX#1{\PARstart #1} +\def\PARstartCalLyX#1{\PARstartCal #1} + +\if@technote\def\PARstart#1#2{#1#2}\fi % if technical note, disable it +\if@technote\def\PARstartCal#1#2{#1#2}\fi % if technical note, disable it +\if@technote\def\PARstartLyX#1{#1}\fi % if technical note, disable it +\if@technote\def\PARstartCalLyx#1{#1}\fi % if technical note, disable it + +% ************************************************************************** +% ***** Misc. Definitions ********************************************** +% ************************************************************************** +%Restore single spacing +\newcommand{\blsone}{\renewcommand\baselinestretch{1}% + \renewcommand\arraystretch{1.2}\setlength{\parindent}{\parindentsave}% + \normalsize} +\newcommand{\capitem}[1]{{\hspace{0.2ex}(#1)}~} +\newcommand{\insdate}{} + +% ************************************************************************** +% ***** MATH Definitions *********************************************** +% ************************************************************************** +\def\eqnarray{% + \stepcounter{equation}% + \def\@currentlabel{\p@equation\theequation}% + \global\@eqnswtrue + \m@th + \global\@eqcnt\z@ + \tabskip\@centering + \let\\\@eqncr + $$\everycr{}\halign to\displaywidth\bgroup + \hskip\@centering$\displaystyle\tabskip\z@skip{##}$\@eqnsel + &\global\@eqcnt\@ne\hskip \eqnarr@ysep\hfil${##}$\hfil + &\global\@eqcnt\tw@ \hskip \eqnarr@ysep + $\displaystyle{##}$\hfil\tabskip\@centering + &\global\@eqcnt\thr@@ \hb@xt@\z@\bgroup\hss##\egroup + \tabskip\z@skip + \cr +} +\def\endeqnarray{% + \@@eqncr + \egroup + \global\advance\c@equation\m@ne + $$\@ignoretrue +} + +% ************************************************************************** +% ***** Biography Definitions ****************************************** +% ************************************************************************** +% This is the main code for the biography environment of the IEEE +% transactions class. The previous biography code had some known +% problems which were difficult to fix. The crux of the issue was that +% the photo frame was overlaid by text when \baselinestretch>1 or when +% the biography consisted of multiple short paragraphs. +% +% The fix was done by extracting code from the excellent package: +% 'picinpar.sty' version 1.2a as of july 13, 1993 +% by Friedhelm Sowa +% +% (At least most of) The bugs you find in this code were introduced +% unwittingly by myself. +% +%---------------- +% Known problems: +% +% - Don't use multiple blank lines to separate paragraphs. A single +% blank line works well, but multiple blank lines will confuse +% the code. This has something to do with the \def\par{\\\indent} +% line, but I can't think of an appropriate fix. Similarly, make +% sure the environment doesn't end with an extra blank line. +% - Don't use \samepage +% - Use \footnotemark within and \footnotetext outside the +% window-environment instead of \footnote +% - When using the epic-package load picinpar before epic +% like \documentstyle[...,picinpar,epic]{...} +% +% Counts +\newcount\br \newcount\nb \newcount\tcdsav \newcount\tcl \newcount\tcd +\newcount\tcn \newcount\cumtcl +% Dimens +\newdimen\rtside \newdimen\hpic \newdimen\vpic \newdimen\strutilg +\newdimen\picwd \newdimen\topheight \newdimen\ilg \newdimen\lpic +\newdimen\lwindowsep \newdimen\rwindowsep % VK 10 Feb 93 +\lwindowsep0.5\baselineskip % " +\rwindowsep0.5\baselineskip % " +\newdimen\cumpar +% Tokens +\newtoks\twa \newtoks\la \newtoks\ra \newtoks\ha \newtoks\pictoc +% Boxes +\newbox\rawtext \newbox\holder \newbox\windowbox \newbox\wartext +\newbox\finaltext \newbox\aslice \newbox\bslice \newbox\wbox +\newbox\wstrutbox \newbox\picbox \newbox\waslice \newbox\wbslice +\newbox\fslice + % Another strut +\def\wstrut{\relax\ifmmode\copy\wstrutbox\else\unhcopy\wstrutbox\fi} +% + +\def\getpic#1{\sbox{\@tempboxa}{\includegraphics{#1}}% +\newcount\tmpcta \tmpcta=\ht\@tempboxa% +\newcount\tmpctb \tmpctb=\wd\@tempboxa% +\divide\tmpctb by 100% +\divide\tmpcta by\tmpctb% +\ifnum\tmpcta>133% +\typeout{ieee: Biography picture `#1' too tall.}% +\frame{\hbox to 25mm{\hfil\resizebox{!}{32mm}{\usebox{\@tempboxa}}\hfil}}% +\else \ifnum\tmpcta<123% +\typeout{ieee: Biography picture `#1' too wide.}% +\frame{\vbox to 32mm{\vss\hbox{\resizebox{25mm}{!}{\usebox{\@tempboxa}}}\vss}}% +\else% +\resizebox{25mm}{32mm}{\usebox{\@tempboxa}} +\fi\fi} + +\long\def\biographyLyX#1{\if@non\else\begin{biography} #1\end{biography}\fi} + +\if@non + \long\def\biography{} +\else + \long\def\biography{\@ifnextchar [{\@biographyb}{\@biographya[{\unitlength + 1mm\hbox{\framebox(25,32){}}}]}} +\fi + +\long\def\@biographyb[#1]{\@biographya[\getpic{#1}]} + +\long\def\@biographya[#1]#2{\bgroup +\footnotesize\bigskip\bigskip\bigskip\parskip=0pt\par% +\rule{0pt}{35mm}\vspace*{-35mm}\par% garantees correct page breaking +\begin{main@bio}[{#1}]% +\noindent{\bf #2}% +} +\def\endbiography{\if@non\else\end{main@bio}\egroup\fi} + +\long\def\main@bio[#1]{% #1 is the material for setting a graphic box +\vskip\parskip\everypar{} +\global\cumpar=0pt +\global\cumtcl=0 + \tcd=0 + \rtside=0pt +% \hpic=\linewidth + \twa={} \la={} \ra={} \ha={} +\setbox\wbox=\hbox{(} +\computeilg +\pictoc={#1} +\setbox\windowbox=\vbox{\hbox{#1}} +\picwd=\wd\windowbox +\hpic=\picwd +\vpic=\ht\windowbox\advance\vpic\dp\windowbox +\rtside=\linewidth\advance\rtside-\picwd +\setbox\picbox=\vbox{\hsize=\hpic\vbox to\vpic{\box\windowbox}}% \vfill}}% + +\vpic=\ht\picbox\advance\vpic\dp\picbox +\ifdim\rtside>0pt\advance\rtside-\rwindowsep\fi % " +\global\br=\rtside +\ifnum\picwd=0 +\ifdim\vpic>0pt\picwd=\hpic +\else\vpic=\ht\picbox\advance\vpic\dp\picbox +\fi +\fi + \global\tcl=0 \lpic=0pt + \loop\global\advance\tcl by 1 \lpic=\tcl\baselineskip + \ifdim\lpic<\vpic\repeat + \vpic=\lpic + \global\cumtcl=\tcl +% +% Here we know exactly the number of indented lines and +% are able to generate the tokens for the \parshape list +% + \ifnum\br>0\ra={ 0pt \rtside}\fi + \ifnum\tcd>0\ha={ 0pt \linewidth}\fi + \ifnum\tcl<1\global\tcl=1\fi + \createparshapespec + \tcd=0 % restore the lintel + \global\tcdsav=0 +% +% This is a very tricky part of the package. Some day there +% will exist a detailed documentation. +% +\def\par{\\\indent} +% +% This is where we start to pick up the paragraph(s) +% + \setbox\rawtext=\vbox\bgroup\unvbox\rawtext\unskip + \clubpenalty=0\widowpenalty=0 + \ifnum\brokenpenalty<\maxdimen\else\brokenpenalty=9999\fi + \tolerance=1000 + \parshape=\tcn \the\twa } +% +\def\endmain@bio{% + %\par + \global\tcd=\tcdsav + \egroup\vskip\parskip\parshape=0 % reset parshape; end \box\rawtext + \vbadness=10000 + \splittopskip=0pt +% +% Now we build the boxes beside the window +% +\global\topheight=\tcl\baselineskip +\ifnum\br>0\setbox\holder=\vsplit\rawtext to\topheight\fi +\tcn=\tcl \nb=0 +\ifnum\br>0\nb=\tcn\fi +% +% text on the right side +% +\ifnum\nb>0 + \loop\advance\nb -1 + \setbox\bslice=\vsplit\holder to\baselineskip + \prune\bslice\rtside + \setbox\wbslice=\vbox{\unvbox\wbslice\hbox + to\rtside{\box\bslice\hfil}} + \ifdim\ht\holder>0pt\repeat +\fi +%GLP add fix to make sure bio starts at top of picture +\setbox\wbslice=\vbox to\topheight{\unvbox\wbslice\vfill\vss} +% +% fixing the dimensions of the window part +% +\topheight=\ht\wbslice +% +% ship out the window material to the main vertical list +% +\setbox\windowbox=\vbox{\hbox to\linewidth{% +\vbox to\topheight{\hrule width\picwd height0pt depth0pt\vskip0pt% +\vfill\unvbox\picbox% +\ifnum\picwd>0\vfill\fi% +\vss}\ifnum\br>0\hfill\vbox{\box\wbslice}\fi}}% +% +\unvbox\windowbox% +\loop% lines below picture.... + \setbox\bslice=\vsplit\rawtext to\baselineskip + \prune\bslice\linewidth + \setbox\wbslice=\vbox{\hbox to\linewidth{\box\bslice\hfil}} + \unvbox\wbslice + \ifdim\ht\rawtext>0pt +\repeat +%GLP +%\ifnum\nb>0\topheight=\nb\baselineskip %\advance\topheight by\ilg +%\vspace*{\topheight} +%\fi +}% FINITO +% +% What else do we need? +% +\def\prune#1#2{ +% take a \vbox containing a single \hbox, +% \unvbox it, and cancel the \lastskip +% put in a \hbox of width #2 + \unvbox#1 \setbox#1=\lastbox % \box#1 now is an \hbox + \ifdim\ht#1=\parskip + \setbox#1=\hbox to#2{\vrule height\parskip depth0pt width0pt\hfill} + \else\ifdim\ht#1=0pt\relax + \else\setbox#1=\hbox to#2{\wstrut\unhbox#1\unskip}\fi\fi} +% +% Here the token \twa is generated. +% It's not so difficult as it looks like. +% +\def\createparshapespec{% +\global\tcn=0 +\ifnum\br>0\global\tcn=\tcl\fi +\nb=0 +\ifnum\br>0\nb=\tcn\fi +\global\advance\tcn by\tcd \global\advance\tcn by1 +\ifnum\tcd>0 +\loop\twa=\expandafter{\the\twa\the\ha}\advance\tcd -1 +\ifnum\tcd>0\repeat +\fi +\ifnum\nb>0 +\loop\twa=\expandafter{\the\twa\the\ra}\advance\nb -1 +\ifnum\nb>0\repeat +\fi +\global\twa=\expandafter{\the\twa 0pt \the\linewidth}} +% +\def\computeilg{% compute the interline glue + \tcl=0\ilg=0pt\strutilg=0pt + \loop\setbox\wbox=\hbox{\char\tcl} + \ifdim\ht\wbox>\ilg\ilg=\ht\wbox\fi + \ifdim\dp\wbox>\strutilg\strutilg=\dp\wbox\fi + \advance\tcl by 1 + \ifnum\tcl<128\repeat + \ht\wbox=\ilg + \dp\wbox=\strutilg + \strutilg=\ht\wbox %\advance\strutilg by\ilg + \ifdim\strutilg>\baselineskip + \typeout{character with height greater baselineskip found in font} + \typeout{baselineskip changed to 1.5 of that height!} + \baselineskip=1.5\strutilg + \fi + \global\ilg=\baselineskip + \global\advance\ilg-\ht\wbox \global\advance\ilg-\dp\wbox + \strutilg=\ht\wbox \advance\strutilg by\ilg + \setbox\wstrutbox=\hbox{\vrule height\strutilg depth\dp\wbox width0pt}} + + +% the following code from version.sty by Stephen Bellantoni 1990, loosely +% based on "annotation.sty" by Tom Hofmann. Used to exclude "biography" from +% anonymous mode. +\begingroup +\catcode`@=11\relax% +\catcode`{=12\relax\catcode`}=12\relax% +\catcode`(=1\relax \catcode`)=2\relax% +\gdef\glpinclude#1(% + \expandafter\gdef\csname #1\endcsname% + ()% + \expandafter\gdef\csname end#1\endcsname% + ()% +)% +\gdef\glpexclude#1(% + \expandafter\gdef\csname #1\endcsname% + (\@bsphack\catcode`{=12\relax\catcode`}=12\relax\csname #1@NOTE\endcsname)% + \long\expandafter\gdef\csname #1@NOTE\endcsname ##1\end{#1}% + (\csname #1END@NOTE\endcsname)% + \expandafter\gdef\csname #1END@NOTE\endcsname% + (\@esphack\end(#1))% +)% +\endgroup + +%------- +\def\@confplacedate{\typeout{ieee: Warning! No \noexpand\confplacedate set!} +\bfseries `confplacedate' needs to be set. For example, to: Stanford, CA, USA, +September 29--30, 1991} +\def\confplacedate#1{\def\@confplacedate{#1}} + +%%%%%%%%%%%%%%%%%%%%%%%%% End of ieee.cls %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% diff --git a/cryptominisat/cppsrc/docs/satcomp18-pdf/sigproc.bib b/cryptominisat/cppsrc/docs/satcomp18-pdf/sigproc.bib new file mode 100644 index 00000000..27e27cf1 --- /dev/null +++ b/cryptominisat/cppsrc/docs/satcomp18-pdf/sigproc.bib @@ -0,0 +1,2681 @@ +@BOOK{salas:calculus, + AUTHOR = "S.L. Salas and Einar Hille", + TITLE = "Calculus: One and Several Variable", + PUBLISHER = "John Wiley and Sons", + ADDRESS = "New York", + YEAR = "1978" } + +@inproceedings{804350, + author = {Thomas J. Schaefer}, + title = {The complexity of satisfiability problems}, + booktitle = {{STOC}'78}, + year = {1978}, + pages = {216--226}, + location = {San Diego, California, United States}, + doi = {http://doi.acm.org/10.1145/800133.804350}, +} + +@InProceedings{learning-based-maple, +author="Liang, Jia Hui +and Ganesh, Vijay +and Poupart, Pascal +and Czarnecki, Krzysztof", +editor="Creignou, Nadia +and Le Berre, Daniel", +title="{Learning Rate Based Branching Heuristic for SAT Solvers}", +booktitle="{Theory and Applications of Satisfiability Testing -- SAT 2016}", +year="2016", +publisher="Springer International Publishing", +address="Cham", +pages="123--140", +isbn="978-3-319-40970-2" +} + +@Article{Salzberg1994, +author="Salzberg, Steven L.", +title="{C4.5: Programs for Machine Learning by J. Ross Quinlan. Morgan Kaufmann Publishers, Inc., 1993}", +journal="Machine Learning", +year="1994", +month="Sep", +day="01", +volume="16", +number="3", +pages="235--240", +issn="1573-0565", +doi="10.1007/BF00993309", +url="https://doi.org/10.1007/BF00993309" +} + + + +@inproceedings{HeuleJB13, + author = {Marijn Heule and + Matti J{\"{a}}rvisalo and + Armin Biere}, + title = {Revisiting {H}yper-{B}inary {R}esolution}, + booktitle = {Integration of {AI} and {OR} Techniques in Constraint Programming + for Combinatorial Optimization Problems, 10th International Conference, + {CPAIOR} 2013, Yorktown Heights, NY, USA, May 18-22, 2013. Proceedings}, + pages = {77--93}, + year = {2013}, + crossref = {DBLP:conf/cpaior/2013}, + url = {https://doi.org/10.1007/978-3-642-38171-3_6}, + doi = {10.1007/978-3-642-38171-3_6}, + timestamp = {Thu, 15 Jun 2017 21:38:39 +0200}, + biburl = {https://dblp.org/rec/bib/conf/cpaior/HeuleJB13}, + bibsource = {dblp computer science bibliography, https://dblp.org} +} + +@proceedings{DBLP:conf/cpaior/2013, + editor = {Carla P. Gomes and + Meinolf Sellmann}, + title = {Integration of {AI} and {OR} Techniques in Constraint Programming + for Combinatorial Optimization Problems, 10th International Conference, + {CPAIOR} 2013, Yorktown Heights, NY, USA, May 18-22, 2013. Proceedings}, + series = {Lecture Notes in Computer Science}, + volume = {7874}, + publisher = {Springer}, + year = {2013}, + url = {https://doi.org/10.1007/978-3-642-38171-3}, + doi = {10.1007/978-3-642-38171-3}, + isbn = {978-3-642-38170-6}, + timestamp = {Wed, 17 May 2017 14:24:38 +0200}, + biburl = {https://dblp.org/rec/bib/conf/cpaior/2013}, + bibsource = {dblp computer science bibliography, https://dblp.org} +} + +Proceedings of the tenth annual ACM symposium on Theory of computing -- +publisher = {ACM Press}, +address = {New York, NY, USA}, + +@inproceedings{smith94phase, + author = "Barbara Smith", + title = "The Phase Transition in Constraint Satisfaction Problems: {A} {CL}oser Look at the Mushy Region", + booktitle = {{ECAI}'94}, + year = "1994" +} + +@inproceedings{swdia, + author = "Chanseok Oh", + title = "{MiniSat HACK 999ED, MiniSat HACK 1430ED and SWDiA5BY}", + booktitle = "SAT Competition 2014 Booklet", + year = "201", +} + +@inproceedings{lingeling, + author = "Armin Biere", + title = "Yet another Local Search Solver and Lingeling and Friends Entering the SAT Competition 2014", + booktitle = "SAT Competition 2014 Booklet", + year = "2014", +} + +@inproceedings{maple, + author="Tomas Balyo and Marijn J. H. Heule and Matti Jarvisalo", + title="{MapleLRB\_LCM, Maple\_LCM, Maple\_LCM\_Dist, MapleLRB\_LCMoccRestart and Glucose-3.0+width in SAT Competition 2017}", + booktitle = "Proceedings of SAT Competition 2017", + year="2018" +} + +@misc {nscc, + author="ASTAR and NTU and NUS and SUTD", + title="{National Supercomputing Centre (NSCC)} {S}ingapore", + url="https://www.nscc.sg/about-nscc/overview/", + year="2018" +} + +@misc {CMS, + author="Mate Soos", + title="{CryptoMiniSat SAT solver GitHub page}", + url="https://github.com/msoos/cryptominisat", + year="2018" +} + + \url{https://github.com/msoos/cryptominisat} + +@inproceedings{cheeseman91where, + author = "Peter Cheeseman and Bob Kanefsky and William M. Taylor", + title = "Where the Really Hard Problems Are", + booktitle = "IJCAI-91", + pages = "331--337", + year = "1991", +} +Proceedings of the Twelfth International Joint Conference on Artificial Intelligence, Sidney, Australia + +@INPROCEEDINGS{Juels-2004-scn, + author = {Juels, Ari}, + title = {Minimalist Cryptography for Low-Cost {RFID} Tags}, + booktitle = {International Conference on Security in Communication Networks --- SCN 2004}, + year = {2004}, + editor = {Blundo, Carlo and Cimato, Stelvio}, + volume = {3352}, + series = {LNCS}, + pages = {149--164}, + month = {September}, + publisher = {Springer-Verlag}, + address = {Amalfi, Italia}, +} + + +@inproceedings{achlioptas-threshold, + author = {Dimitris Achlioptas and Yuval Peres}, + title = {The Threshold for Random k-{SAT} is 2\^\ k(ln 2 - O(k))}, + booktitle = {{STOC}'03}, + year = {2003}, + isbn = {1-58113-674-9}, + pages = {223--231}, + location = {San Diego, CA, USA}, + doi = {http://doi.acm.org/10.1145/780542.780577}, +} +Proceedings of the thirty-fifth annual ACM symposium on Theory of computing -- +publisher = {ACM Press} +address = {New York, NY, USA} + +@article{DPLL, + author = {Martin Davis and Hilary Putnam}, + title = {A Computing Procedure for Quantification Theory}, + journal = {J. ACM}, + volume = {7}, + number = {3}, + year = {1960}, + issn = {0004-5411}, + pages = {201--215}, + doi = {http://doi.acm.org/10.1145/321033.321034}, +} +publisher = {ACM Press}, +address = {New York, NY, USA}, + +@inproceedings {Minisat+, + author = {E\'en, Niklas and S\"orensson, Niklas}, + title = {Translating {P}seudo-{B}oolean constraints into {SAT}}, + booktitle= {Journal on Satisfiability, Boolean Modeling and Computation}, + year = {2006}, + pages = {1-26}, + volume = {2}, +} + +@inproceedings {EenS03MiniSat, + title = {An Extensible {SAT}-solver}, + author = {Niklas E\'en and Niklas S\"{o}rensson}, + booktitle = {SAT}, + editor = {Enrico Giunchiglia and Armando Tacchella}, + pages = {502--518}, + publisher = {Springer}, + series = {LNCS}, + url = {http://dblp.uni-trier.de/db/conf/sat/sat2003.html#EenS03}, + volume = {2919}, + year = {2003}, + ee = {http://www.cs.chalmers.se/Cs/Research/FormalMethods/MiniSat/cgi/MiniSat.ps.gz.cgi}, + keywords = {2003 2004 SAT-solver ais-07w efficiency implementation }, +} + +@misc { toolbar, + author="S. Bouveret and F. Heras and S. de Givry and J. Larrosa and M. Sanchez and T. Schiex", + title="Toolbar: a state-of-the-art platform for wcsp", + url="http://www.inra.fr/mia/T/degivry/ToolBar.pdf", + year="2004" +} + +@inproceedings{1267340, + author = {Kirschenbaum, Ilan and Wool, Avishai}, + title = {How to build a low-cost, extended-range {RFID} skimmer}, + booktitle = {USENIX-SS'06: Proceedings of the 15th conference on {USENIX} Security Symposium}, + year = {2006}, + location = {Vancouver, B.C., Canada}, + publisher = {{USENIX} Association}, + address = {Berkeley, CA, USA}, +} + +@misc{Benetton-boycott, + author = {{CASPIAN - Consumers Against Supermarket Privacy Invasion and Numbering}}, + howpublished={Press release}, + note= {\url{http://www.boycottbenetton.com}}, + title = {Boycott {B}enetton}, + year = {2003}, + month = {March}, +} + +@article{ improved-deterministic, + author="Michael H. Schulz and Elisabeth Auth", + title="Improved Deterministic Test Pattern Generation with Applications to Redundancy Identification", + year="1989", + month="July", + journal="IEEE Transactions on computer-aided design", + volume="8", + number="7", + pages={811--816}, + issn="0278-0070" +} +publisher = " IEEE Circuits and Systems Society", +address="Piscataway, NJ 08854, USA", + +@inproceedings{244560, + author = {Jo\&\#227;o P. Marques Silva and Karem A. Sakallah}, + title = {{GRASP}-a new search algorithm for satisfiability}, + booktitle = {ICCAD'96}, + year = {1996}, + isbn = {0-8186-7597-7}, + pages = {220--227}, + location = {San Jose, California, United States}, + publisher = {IEEE Computer Society}, +} +Proceedings of the 1996 IEEE/ACM international conference on Computer-aided design --- +address = {Washington, DC, USA}, + + @inproceedings{ chai03fast, + author = "D. Chai and A. Kuehlmann", + title = "A fast pseudo-boolean constraint solver", + pages = {305--317}, + booktitle = "IEEE Transactions on Computer-Aided Design of Integrated Circuits and Systems 2003", + year = {2003}, + month =" mar", + volume = "24", + issue = "3", + issn = "0278-0070" +} +publisher = "IEEE Circuits and Systems Society", + +@TechReport{EPC-standard, + author = "EPCglobal", + url="http://www.epcglobalinc.org/standards/specs/13.56_MHz_ISM_Band_Class_1_RFID_Tag_Interface_Specification.pdf", + title="13.56 {MHz} {ISM} Band Class 1 Radio Frequency Identification Tag Interface Specification (2003)", + institution = "Auto-ID cetner, MIT", + year ="2003", + month = "February", + version = "1.0.0" +} +address = "77 massachusetts avenue, bldg 3-449, cambridge, ma 02139-4307, USA", + +@INPROCEEDINGS{LuLHHN-2007-percom, + author = {Lu, Li and Liu, Yunhao and Hu, Lei and Han, Jinsong and Ni, Lionel}, + title = {A Dynamic Key-Updating Private Authentication Protocol for {RFID} Systems}, + booktitle = {PerCom 2007}, + year = {2007}, + pages = {13--22}, + month = {March}, + organization = {IEEE} +} +International Conference on Pervasive Computing and Communications +publisher = {IEEE Computer Society Press} +address = {New York, USA}, + +@INPROCEEDINGS{Ohkubo04Efficient, + author = {Ohkubo, Miyako and Suzuki, Koutarou and Kinoshita, Shingo}, + title = {Efficient Hash-Chain Based {RFID} Privacy Protection Scheme}, + booktitle = {International Conference on Ubiquitous Computing --- Ubicomp 2004, Workshop Privacy: Current Status and Future Directions}, + month = {September}, + year = {2004}, + address = {Nottingham, England}, +} + +@INPROCEEDINGS{MolnarSW-2005-sac, + author = {Molnar, David and Soppera, Andrea and Wagner, David}, + title = {A Scalable, Delegatable Pseudonym Protocol Enabling Ownership Transfer of {RFID} Tags}, + booktitle = {Selected Areas in Cryptography --- SAC 2005}, + editor = {Preneel, Bart and Tavares, Stafford}, + volume = {3897}, + series = {LNCS}, + pages = {276--290}, + month = {August}, + series = {LNCS}, + publisher = {Springer-Verlag}, + year = {2005}, + address = {Kingston, Canada}, +} + +@inproceedings{DBLP:conf/otm/FeldhoferR06, + author = {Martin Feldhofer and Christian Rechberger}, + title = {A Case Against Currently Used Hash Functions in {RFID} Protocols}, + booktitle = {OTM Workshops (1)}, + year = {2006}, + pages = {372-381}, + ee = {http://dx.doi.org/10.1007/11915034_61}, + crossref = {DBLP:conf/otm/2006-w1}, + bibsource = {DBLP, http://dblp.uni-trier.de} +} + +@proceedings{DBLP:conf/otm/2006-w1, + editor = {Robert Meersman and Zahir Tari and Pilar Herrero}, + title = {On the Move to Meaningful Internet Systems 2006: OTM 2006 Workshops, OTM Confederated International Workshops and Posters, AWeSOMe, CAMS, COMINF, IS, KSinBIT, MIOS-CIAO, MONET, OnToContent, ORM, PerSys, OTM Academy Doctoral Consortium, RDDS, SWWS, and SeBGIS 2006, Montpellier, France, October 29 - November 3, 2006. Proceedings, Part I}, + booktitle = {OTM Workshops (1)}, + publisher = {Springer}, + series = {LNCS}, + volume = {4277}, + year = {2006}, + isbn = {3-540-48269-5}, + bibsource = {DBLP, http://dblp.uni-trier.de} +} + + +@INPROCEEDINGS{VajdaB-2003-ubicom, + author = {Vajda, Istv\'an and Butty\'an, Levente}, + title = {Lightweight Authentication Protocols for Low-Cost {RFID} Tags}, + booktitle = {Ubicomp 2003 Second Workshop on Security in Ubiquitous Computing}, + month = {October}, + year = {2003} +} +address = {Seattle, WA, USA}, + +@INPROCEEDINGS{LiW-2007-sec, + author = {Li, Tieyan and Wang, Guilin}, + title = {Security Analysis of Two Ultra-Lightweight {RFID} Authentication Protocols}, + booktitle = {IFIP SEC 2007}, + month = {May}, + organization = {IFIP}, +} +year = {2007}, +address = {Sandton, Gauteng, South Africa}, + +@MISC{BatinaGKMTV-2006-eprint, + author = {Batina, Lejla and Guajardo, Jorge and Kerins, Tim and Mentens, Nele and Tuyls, Pim and Verbauwhede, Ingrid}, + title = {An Elliptic Curve Processor Suitable For {RFID}-Tags}, + howpublished = {Cryptology ePrint Archive, Report 2006/227}, + year = {2006}, + organization = {IACR}, +} + +@inproceedings {AES-grain-sand, + title = {{AES} implementation on a grain of sand}, + issue = "1", + ISSN="1747-0722", + pages = {13--20}, + author="Feldhofer, M. and Wolkerstorfer, J. and Rijmen, V.", + year = "2005", + voulme="152", + booktitle = "Information Security", + organization = {IEEE}, +} +publisher = {IEEE Computer Society Press}, + +@MISC{Juels-2005-manuscript-2, + author = {Juels, Ari}, + title = {{RFID} Security and Privacy: A research Survey}, + howpublished = {Manuscript}, + year = {2005}, + month = {September}, + organization = {RSA Laboratories}, +} + +@INPROCEEDINGS{JuelsW-2007-percom, + author = {Juels, Ari and Weis, Stephen}, + title = {{Defining Strong Privacy for RFID}}, + booktitle = {International Conference on Pervasive Computing and Communications --- PerCom 2007}, + year = {2007}, + editor = {}, + volume = {}, + series = {}, + pages = {342--347}, + address = {New York City, New York, USA}, + month = {March}, + organization = {IEEE}, + publisher = {IEEE Computer Society Press}, + bibsource = {Information Security Group (GSI), UCL, Louvain-la-Neuve, Belgium}, +} + +@INPROCEEDINGS{Vaudenay-2007-asiacrypt, + author = {Vaudenay, Serge}, + title = {On Privacy Models for {RFID}}, + booktitle = {Advances in Cryptology --- Asiacrypt 2007}, + year = {2007}, + editor = {}, + volume = {4833}, + series = {LNCS}, + pages = {68--87}, + address = {Kuching, Malaysia}, + month = {December}, + organization = {}, + publisher = {Springer-Verlag}, + bibsource = {Information Security Group (GSI), UCL, Louvain-la-Neuve, Belgium}, +} + +@INPROCEEDINGS{BolotnyyR-2007-percom, + author = {Bolotnyy, Leonid and Robins, Gabriel}, + title = {Physically Unclonable Function-Based Security and Privacy in {RFID} Systems}, + booktitle = {PerCom 2007}, + year = {2007}, + pages = {211--220}, + month = {March}, + organization = {IEEE}, +} +publisher = {IEEE Computer Society Press} +International Conference on Pervasive Computing and Communications -- +address = {New York, USA}, + +@INPROCEEDINGS{JuelsRS-2003-ccs, + author = {Juels, Ari and Rivest, Ronald and Szydlo, Michael}, + title = {The Blocker Tag: Selective Blocking of {RFID} Tags for Consumer Privacy}, + booktitle = {ACM CCS 2003}, + year = {2003}, + editor = {Atluri, Vijay}, + pages = {103--111}, + month = {October}, + publisher = "ACM Press" +} +address = {Washington, DC, USA}, +Conference on Computer and Communications Security +organization = "ACM", + +@INPROCEEDINGS{JuelsW-2005-crypto, + author = {Juels, Ari and Weis, Stephen}, + title = {Authenticating Pervasive Devices with Human Protocols}, + booktitle = {Advances in Cryptology --- CRYPTO'05}, + year = {2005}, + editor = {Shoup, Victor}, + volume = {3126}, + series = {LNCS}, + pages = {293--308}, + month = {August}, + organization = {IACR}, + address = {Santa Barbara, California, USA}, + publisher = {Springer-Verlag}, + series = {LNCS}, +} + +@inproceedings{ zhang01efficient, + author = "Lintao Zhang and Conor F. Madigan and Matthew W. Moskewicz and Sharad Malik", + title = "Efficient Conflict Driven Learning in Boolean Satisfiability Solver", + booktitle = "{ICCAD}", + pages = "279-285", + year = "2001", + url = "citeseer.ist.psu.edu/article/zhang01efficient.html" } + + +@INPROCEEDINGS{ButtyanHV-2006-pet, + author = {Butty\'an, Levente and Holczer, Tam\'as and Vajda, Istv\'an}, + title = {Optimal Key-Trees for Tree-Based Private Authentication}, + booktitle = {Workshop on Privacy Enhancing Technologies --- PET 2006}, + pages = {332-350}, + month = {June}, + year = {2007}, + address = {Cambridge, United Kingdom}, +} + + +@INPROCEEDINGS{Castelluccia07Secret, + author = {Castelluccia, Claude and Soos, Mate}, + title = {Secret Shuffling: A Novel Approach to {RFID} Private Identification}, + booktitle = {{RFIDSec}'07}, + pages = {169-180}, + year = {2007}, + month = {July} +} +Proceedings of the International Conference on RFID Security 2007 + +@INPROCEEDINGS{breaking-lmap, + author = {Mihaly B\'arasz and Bal\'azs Boros and P\'eter Ligeti and Krisztina L\'oja and D\'aniel Nagy}, + title = {Breaking {LMAP}}, + pages = {69-78}, + month = {July}, + year = {2007}, + booktitle = {Conference on RFID Security --- {RFIDSec}'07}, + address = {Malaga, Spain}, +} + +@INPROCEEDINGS{Initial-SRAM, + author = {Daniel Holcom and Wayne Burleson and Kevin Fu.}, + title = {Initial {SRAM} state as a Fingerprint and Source of True Random Numbers for {RFID} Tags}, + booktitle = {{RFIDSec}'07}, + pages = {29-40}, + month = {July}, + year = {2007} +} +Proceedings of the International Conference on RFID Security 2007 + +@inproceedings{HBattack, + author = {Gilbert, Henri and Robshaw, Matt and Sibert, Herve}, + title = {An Active Attack Against {HB}$^+$ - A Provably Secure Lightweight Authentication Protocol}, + booktitle = {IEE Electronic Letters 41, 21}, + year = {2005}, + pages = {1169--1170} +} + +@INPROCEEDINGS{KatzS-2006-eurocrypt, + author = {Katz, Jonathan and Sun Shin, Ji}, + title = {Parallel and Concurrent Security of the {HB} and {HB}$^{+}$ Protocols}, + booktitle = {Advances in Cryptology --- EUROCRYPT '06}, + organization = {IACR}, + year = {2006} +} +Advances in Cryptology +publisher = {Springer-Verlag}, + +@MISC{KatzS-2006-eprint, + author = {Katz, Jonathan and Smith, Adam}, + title = {Analyzing the {HB} and {HB}+ Protocols in the ``Large Error'' Case}, + howpublished = {Cryptology ePrint Archive, Report 2006/326}, + organization = {IACR}, +} + +@inproceedings{1229319, + author = {Tri Van Le and Mike Burmester and Breno de Medeiros}, + title = {Universally composable and forward-secure {RFID} authentication and authenticated key exchange}, + booktitle = {Proceedings of the 2nd ACM symposium on Information, Computer and Communications Security --- {ASIACCS}'07}, + year = {2007}, + isbn = {1-59593-574-6}, + pages = {242--252}, + location = {Singapore}, + publisher = {ACM}, + address = {New York, NY, USA}, + doi = {http://doi.acm.org/10.1145/1229285.1229319}, +} + + + +@INPROCEEDINGS{PUF-based-RNG, + author = {Charles W. O'Donnell and G. Edward Suh and Srinivas Devadas}, + title = {{PUF}-Based Random Number Generation}, + booktitle = {MIT CSAIL CSG Technical Memo 481}, + url = {http://csg.csail.mit.edu/pubs/memos/Memo-481/Memo-481.pdf}, + year = {2004}, + month = {November} +} + +@book{Ipatov05Spread, + author = {Valeri P. Ipatov}, + year = {2005}, + month = {May}, + title = {Spread Spectrum and {CDMA}: {P}rinciples and Applications}, + publisher = {John Wiley \& Sons, Ltd.}, + ISBN = {978-0470091784}, +} + +@article{DBLP:journals/ijwmc/HellJM07, + author = {Martin Hell and + Thomas Johansson and + Willi Meier}, + title = {Grain: a stream cipher for constrained environments}, + journal = {IJWMC}, + volume = {2}, + number = {1}, + year = {2007}, + pages = {86-93}, + ee = {http://dx.doi.org/10.1504/IJWMC.2007.013798}, + bibsource = {DBLP, http://dblp.uni-trier.de} +} + +@book{applied-crypto, + year= {1996}, + ISBN ={0-8493-8523-7}, + author={Alfred J. Menezes and Paul C. van Oorschot and Scott A. Vanstone}, + title ={Handbook of applied cryptography}, + publisher={CRC Press}, + address={Boca Raton, Florida}, +} +url={http://cacr.math.uwaterloo.ca/hac} + +@inproceedings{DiPietro07Information, + author={Roberto Di Pietro and Refik Molva}, + title={Information confinement, privacy, and security in {RFID} systems}, + month={September}, + booktitle={Proceedings of the 12th European Symposium On Research In Computer Security}, + year={2007}, + pages={187-202}, +} + +@inproceedings{PerisHER-2006-rfidsec, + author = {Peris-Lopez, Pedro and Hernandez-Castro, Julio Cesar and Estevez-Tapiador, Juan and Ribagorda, Arturo}, + title = {{LMAP}: A Real Lightweight Mutual Authentication Protocol for Low-cost {RFID} tags}, + booktitle = {Proceedings of {RFIDSec}'06}, + year = {2006}, + month = {July}, + address = {Graz, Austria}, + organization = {Ecrypt}, +} + +@INPROCEEDINGS{BringerCD-2006-secperu, + author = {Bringer, Julien and Chabanne, Herv\'e and Dottax Emmanuelle}, + title = {{HB}$^{++}$: a Lightweight Authentication Protocol Secure against Some Attacks}, + booktitle = {{IEEE} SecPerU 2006}, + year = {2006}, + month = {June}, + organization = {IEEE}, +} +International Conference on Pervasive Services, Workshop on Security, Privacy and Trust in Pervasive and Ubiquitous Computing +address = {Lyon, France}, +publisher = {IEEE Computer Society Press}, + +@INPROCEEDINGS{PerisHER-2006-uic, + author = {Peris-Lopez, Pedro and Hernandez-Castro, Julio Cesar and Estevez-Tapiador, Juan and Ribagorda, Arturo}, + title = {{M2AP}: A Minimalist Mutual-Authentication Protocol for Low-cost {RFID} Tags}, + booktitle = {International Conference on Ubiquitous Intelligence and Computing --- {UIC}’06}, + year = {2006}, + editor = {}, + volume = {4159}, + pages = {912--923}, + month = {September}, + series = {LNCS}, + publisher = {Springer-Verlag}, +} + + +@INPROCEEDINGS{M2AP-break, + author={Mih\'aly B\'ar\'asz and Bal\'azs Boros and P\'eter Ligeti and Krisztina L\'oja and D\'aniel A. Nagy}, + title={Passive Attack Against the {M2AP} Mutual Authentication Protocol for {RFID} Tags}, + year = {2007}, + month= {September}, + date = {24-25}, + booktitle={{RFID} 2007 --- The First International {EURASIP} Workshop on {RFID} Technology}, + country = {Austria}, + city={Vienna} +} + +@INPROCEEDINGS{HBppbreak, + author= {Henri Gilbert and Matthew J.B. Robshaw and Yannick Seurin}, + title={Good Variants of {HB}+ are Hard to Find}, + year={2008}, + month={January}, + booktitle={Financial Cryptography}, + publisher={Springer}, + country={Mexico} +} + +@inproceedings{MAGMA, + author = {Wieb Bosma and John Cannon and Graham Matthews}, + title = {Programming with algebraic structures: design of the {MAGMA} language}, + booktitle = {Proceedings of the international symposium on Symbolic and algebraic computation --- ISSAC '94}, + year = {1994}, + isbn = {0-89791-638-7}, + pages = {52--57}, + location = {Oxford, United Kingdom}, + doi = {http://doi.acm.org/10.1145/190347.190362}, + publisher = {ACM}, + address = {New York, NY, USA}, +} + +@inproceedings{Singular, + author = {Gert-Martin Greuel and Gerhard Pfister and Hans Sch\"{o}nemann}, + title = {{SINGULAR} --- A computer algebra system for polynomial computations}, + booktitle = {Symbolic computation and automated reasoning}, + year = {2001}, + isbn = {1-56881-145-4}, + pages = {227--233}, + publisher = {A. K. Peters, Ltd.}, + address = {Natick, MA, USA}, +} + +@misc{SAGE, + author = {{The SAGE Group}}, + year = {2008}, + title = {{SAGE} Mathematics Software}, + note = {\url{http://www.sagemath.org}}, +} + +@misc{new-sparse-technique, + author={H{\aa}vard Raddum and Igor Semae}, + title={New Technique for Solving Sparse Equation Systems}, + month={January}, + year={2006}, + note={\url{eprint.iacr.org/2006/475/}}, +} + +@TechReport{algebraic-DES, + author={Nicolas T. Courtois and Gregory V. Bard}, + title={Algebraic Cryptanalysis of the {D}ata {E}ncryption {S}tandard}, + year={2006}, + institution = {IACR E-print}, + number = {2006/402}, + month={November}, + booktitle={IACR E-print, \url{http://eprint.iacr.org/2006/402}}, +} + + + +@inproceedings{early-DES-algebraic, + author={Chaum, David and Evertse, Jan-Hendrik}, + title={Cryptanalysis of {DES} with a Reduced Number of Rounds}, + booktitle = {Advances in Cryptology --- {CRYPTO}'85}, + year = {1986}, + pages = {192--211}, + publisher = {Springer-Verlag} +} + +@InProceedings{Bofilletal2008CAV, + author = {M. Bofill and R. Nieuwenhuis and A. Oliveras and E. Rodr\'\i guez-Carbonell and A. Rubio}, + title = {The {B}arcelogic {SMT} Solver}, + pages = {294-298}, + booktitle = {{CAV}'08}, + year = {2008}, + series = {LNCS}, + volume = {5123}, + publisher = {Springer}, + editor = {A. Gupta and S. Malik}, +} + +@techreport{RSAT, + author = {Knot Pipatsrisawat and Adnan Darwiche}, + institution = {Automated Reasoning Group, Computer Science}, + title = {{RS}at 2.0: {SAT} Solver Description}, + year = {2007}, +} + +@inproceedings{DBLP:conf/fse/CourtoisBW08, + author = {Nicolas Courtois and Gregory V. Bard and David Wagner}, + title = {Algebraic and Slide Attacks on {K}ee{L}oq}, + booktitle = {FSE}, + year = {2008}, + pages = {97-115}, + ee = {http://dx.doi.org/10.1007/978-3-540-71039-4_6}, + crossref = {DBLP:conf/fse/2008}, + bibsource = {DBLP, http://dblp.uni-trier.de} +} + +@TechReport{cryptoeprint:2008:166, + author = {Nicolas T. Courtois and Karsten Nohl and Sean O'Neil}, + title = {Algebraic Attacks on the {C}rypto-1 Stream Cipher in {Mifare} {C}lassic and {O}yster Cards}, + number = {2008/166}, + institution = {Cryptology ePrint Archive}, + year = {2008}, +} +howpublished = {Cryptology ePrint Archive, Report 2008/166}, +note = {\url{http://eprint.iacr.org/}}, + +@INPROCEEDINGS{Biere99symbolicmodel, + author = {Armin Biere and A. Cimatti and E. M. Clarke and M. Fujita and Y. Zhu}, + title = {Symbolic Model Checking Using {SAT} Procedures instead of {BDDs}}, + booktitle = {Proc. of Design Automation Conference ({DAC}'99)}, + year = {1999}, + pages = {317--320} +} + +@INPROCEEDINGS{temporalinduction, + author = {E\'en, Niklas and S\"orensson, Niklas}, + title = {Temporal Induction by Incremental {SAT} Solving}, + booktitle={Proc. of First Intrenational Workshop on Bounded Model Checking}, + year={2003}, + volume={89}, + issue={4}, + series={ENTCS}, + publisher={Elsevier} +} + +@inproceedings{ARMS02, + author = {Fadi A. Aloul and Arathi Ramani and Igor Markov and Karem Sakallah}, + title = {Generic {ILP} versus Specialized 0-1 {ILP}: an Update}, + booktitle = {Proc. ACM/IEEE Intl. Conf. Comp.-Aided Design}, + pages = {450 - 457}, + month = {November}, + year = {2002}, + URL = {http://www.gigascale.org/pubs/190.html} +} + +@inproceedings{knowledge-compiling, + author={Adnan Dawiche}, + title={New advances in compiling {CNF} to decomposable negation normal form}, + booktitle={Proc. of European Conference on Artificial Intelligence}, + year={2004}, + pages={328 - 332}, +} + +@InProceedings{S-Match, + author = {Fausto Giunchiglia and Pavel Shvaiko and Mikalai Yatskevich}, + title = {S-{M}atch: an algorithm and an implementation of semantic matching}, + booktitle = {Semantic Interoperability and Integration}, + year = {2005}, + number = {04391}, + series = {Dagstuhl Seminar Proceedings}, + ISSN = {1862-4405}, + publisher = {IBFI}, + note = {\url{http://drops.dagstuhl.de/opus/volltexte/2005/37}}, + editor = {Y. Kalfoglou and M. Schorlemmer and A. Sheth and S. Staab and M. Uschold}, +} +publisher = {Internationales Begegnungs- und Forschungszentrum fuer Informatik (IBFI)}, + + + +@techreport{bard-thesis, + author = {Gregory V. Bard}, + title = {Algorithms for the Solution of Polynomial and Linear Systems of Equations over Finite Fields, with an Application to the Cryptanalysis of {K}ee{L}oq}, + institution={University of Maryland Dissertation}, + month={April}, + year={2008}, + note = {Ph.D. Thesis}, +} + +@inproceedings{Toyocrypt-nicolas-attack, + author={Nicolas T. Courtois}, + title={Higher Order Correlation Attacks, {XL} algorithm and Cryptanalysis of {T}oyocrypt ({A}n updated version)}, + booktitle={ICISC 2002}, + series={LNCS}, + volume={2587}, + publisher={Springer}, + year={2002}, +} + +@inproceedings{General-LFSR-attacks, + author={Nicolas T. Courtois and Willi Meier}, + title={Algebraic Attacks on Stream Ciphers with Linear Feedback}, + booktitle={Advances in Cryptology --- EUROCRYPT '03}, + series={LNCS}, + volume={2656}, + pages={345–359}, + publisher={Springer}, + address = {Warsaw, Poland} +} + +@inproceedings{Canniere06Trivium, + author = {Christophe De Canni{\`e}re}, + title = {Trivium: A Stream Cipher Construction Inspired by Block Cipher Design Principles}, + booktitle = {ISC}, + year = {2006}, + pages = {171-186}, + ee = {http://dx.doi.org/10.1007/11836810_13}, + crossref = {DBLP:conf/isw/2006}, + bibsource = {DBLP, http://dblp.uni-trier.de} +} + +@proceedings{DBLP:conf/isw/2006, + editor = {Sokratis K. Katsikas and et al}, + title = {Information Security, 9th International Conference, ISC 2006, Samos Island, Greece, August 30 - September 2, 2006, Proceedings}, + booktitle = {ISC}, + publisher = {Springer}, + series = {LNCS}, + volume = {4176}, + year = {2006}, + isbn = {3-540-38341-7}, + bibsource = {DBLP, http://dblp.uni-trier.de} +} +and +Javier Lopez and +Michael Backes and +Stefanos Gritzalis and +Bart Preneel + +@inproceedings{BiviumWithSATsolvers, + author = {Tobias Eibach and Enrico Pilz and Gunnar V{\"o}lkel}, + title = {Attacking {B}ivium Using {SAT} Solvers}, + booktitle = {SAT}, + year = {2008}, + pages = {63-76}, + ee = {http://dx.doi.org/10.1007/978-3-540-79719-7_7}, + crossref = {DBLP:conf/sat/2008}, + bibsource = {DBLP, http://dblp.uni-trier.de} +} + +@proceedings{DBLP:conf/sat/2008, + editor = {Hans Kleine B{\"u}ning and Xishun Zhao}, + title = {Theory and Applications of Satisfiability Testing - SAT 2008, 11th International Conference, SAT 2008, Guangzhou, China, May 12-15, 2008. Proceedings}, + booktitle = {SAT}, + publisher = {Springer}, + series = {LNCS}, + volume = {4996}, + year = {2008}, + isbn = {978-3-540-79718-0}, + bibsource = {DBLP, http://dblp.uni-trier.de} +} + +@TechReport{Bivium, + author={Havard Raddum}, + title={Cryptanalytic results on {T}rivium}, + institution = {ECRYPT Stream Cipher Project}, + year={2006}, + number={2006/039}, + note = {\url{www.ecrypt.eu.org/stream/papersdir/2006/039.ps}}, +} + +@misc{using-equation-solvers, + author = {Havard Raddum and Igor Semaev}, + title = {New Technique for Solving Sparse Equation Systems}, + howpublished = {Cryptology ePrint Archive, Report 2006/475}, + year = {2006}, + note = {\url{http://eprint.iacr.org/}}, +} + + +@TechReport{BiviumWithMiniSat, + author={Cameron McDonald and Chris Charnes and Josef Pieprzyk}, + title={Attacking {B}ivium with {M}ini{S}at}, + institution = {ECRYPT Stream Cipher Project}, + year={2007}, + number={2007/040} +} + +@inproceedings{FaugereF5, + author = {Jean-Charles Faug\`{e}re}, + title = {A new efficient algorithm for computing {G}r\"{o}bner bases without reduction to zero ({F}5)}, + booktitle = {ISSAC '02}, + year = {2002}, + isbn = {1-58113-484-3}, + pages = {75--83}, + location = {Lille, France}, + doi = {http://doi.acm.org/10.1145/780506.780516}, + publisher = {ACM}, + } +ISSAC '02: Proceedings of the 2002 international symposium on Symbolic and algebraic computation +address = {New York, NY, USA}, + + +@article{FaugereF4, + author = {Jean-Charles Faug\`{e}re}, + title = {A new efficient algorithm for computing {G}r\"{o}bner bases ({F}4)}, + journal = {Journal of Pure and Applied Algebra}, + year = {1999}, + month = {June}, + pages = {61--88}, + volume = {1}, + number = {139}, +} + +@inproceedings{DismantlingMifare, + author = {Flavio D. Garcia and et al.}, + title = {Dismantling {MIFARE} {C}lassic}, + booktitle = {ESORICS}, + year = {2008}, + pages = {97-114}, + ee = {http://dx.doi.org/10.1007/978-3-540-88313-5_7}, + crossref = {DBLP:conf/esorics/2008}, + bibsource = {DBLP, http://dblp.uni-trier.de} +} +and +Gerhard de Koning Gans and +Ruben Muijrers and +Peter van Rossum and +Roel Verdult and +Ronny Wichers Schreur and +Bart Jacobs + +@proceedings{DBLP:conf/esorics/2008, + editor = {Sushil Jajodia and Javier L{\'o}pez}, + title = {Computer Security - ESORICS 2008, 13th European Symposium on Research in Computer Security, M{\'a}laga, Spain, October 6-8, 2008. Proceedings}, + booktitle = {ESORICS}, + publisher = {Springer}, + series = {LNCS}, + volume = {5283}, + year = {2008}, + isbn = {978-3-540-88312-8}, + bibsource = {DBLP, http://dblp.uni-trier.de} +} + +@misc{Karsten-webpage-HiTag2, + author={Karsten Nohl}, + title={Description of {H}i{T}ag2}, + howpublished={Press release}, + note= {\url{http://cryptolib.com/ciphers/hitag2/}}, + month={March}, + day = {12}, + year={2008}, +} + +@InProceedings{Ouafi08Privacy, + address = {Berlin}, + affiliation = {EPFL}, + author = {Ouafi, Khaled and Phan, Raphael C.-W.}, + booktitle = {Information {S}ecurity {P}ractice and {E}xperience, 4th {I}nternational {C}onference, {ISPEC} 2008}, + location = {Sydney, Australia}, + oai-id = {oai:infoscience.epfl.ch:126418}, + oai-set = {conf; fulltext; fulltext-public}, + pages = {263--277}, + publisher = {Springer}, + review = {REVIEWED}, + series = {LNCS}, + status = {PUBLISHED}, + title = {Privacy of {R}ecent {RFID} {A}uthentication {P}rotocols}, + unit = {LASEC}, + year = {2008}, + keywords = {RFID; authentication protocols, ; privacy; untraceability; provably secure}, + details = {http://infoscience.epfl.ch/record/126418}, + documenturl = {http://infoscience.epfl.ch/getfile.py?recid=126418&mode=best}, +} + +@INPROCEEDINGS{Ohkubo04Cryptographic, + author = {Miyako Ohkubo Koutarou and Koutarou Suzuki and Shingo Kinoshita}, + title = {Cryptographic Approach to "Privacy-Friendly" Tags}, + booktitle = {RFID Privacy Workshop}, + year = {2003}, + address = {MIT, Massachusetts, USA}, + month = {November}, +} + +@article{Lamport81Password, + author = {Lamport,, Leslie}, + title = {Password authentication with insecure communication}, + journal = {Commun. ACM}, + volume = {24}, + number = {11}, + year = {1981}, + issn = {0001-0782}, + pages = {770--772}, + doi = {http://doi.acm.org/10.1145/358790.358797}, + publisher = {ACM}, + address = {New York, NY, USA}, + } + +@InProceedings{OSK_Avoine, + affiliation = {EPFL}, + author = {Avoine, Gildas and Oechslin, Philippe}, + booktitle = {The 2nd {IEEE} {I}nternational {W}orkshop on {P}ervasive {C}omputing and {C}ommunication {S}ecurity - {P}er{S}ec 2005}, + details = {http://infoscience.epfl.ch/record/99461}, + documenturl = {http://infoscience.epfl.ch/getfile.py?recid=99461&mode=best}, + keywords = {NCCR-MICS; NCCR-MICS/CL3}, + location = {Kauai island, Hawaii, USA}, + oai-id = {oai:infoscience.epfl.ch:99461}, + oai-set = {conf; fulltext; fulltext-public}, + pages = {110--114}, + review = {REVIEWED}, + status = {PUBLISHED}, + title = {A {S}calable and {P}rovably {S}ecure {H}ash-{B}ased {RFID} {P}rotocol}, + unit = {LASEC}, + year = 2005 +} + +@inproceedings{Trade-off-Hellman, + author = {Hellman, Martin E.}, + title = {A cryptanalytic time-memory trade off}, + booktitle = {{IEEE} Transactions on Information Theory}, + volume = {IT-26/4}, + pages = {401--406}, + year = {1980}, +} + +@inproceedings{Faster-crypto-time-memory, + author = {Oechslin, Philippe }, + booktitle = {Advances in Cryptology --- CRYPTO 2003}, + series = {LNCS}, + volume = {2729}, + publisher = {Springer}, + pages = {617--630}, + posted-at = {2008-07-07 15:11:06}, + priority = {2}, + title = {Making a Faster Cryptanalytic Time-Memory Trade-Off}, + url = {http://www.springerlink.com/content/u9gxwd29p2tnx3wl}, + year = {2003} +} + +@inproceedings{Molnar04Keytrees, + address = {New York, NY, USA}, + author = {Molnar, David and Wagner, David }, + booktitle = {CCS '04: Proceedings of the 11th ACM conference on Computer and communications security}, + citeulike-article-id = {202290}, + doi = {10.1145/1030083.1030112}, + isbn = {1581139616}, + keywords = {libraries, privacy}, + pages = {210--219}, + posted-at = {2007-12-25 21:42:23}, + priority = {5}, + publisher = {ACM Press}, + title = {Privacy and security in library {RFID}: issues, practices, and architectures}, + url = {http://dx.doi.org/10.1145/1030083.1030112}, + year = {2004} +} + +@INPROCEEDINGS{NohlE-2008-sec, + author = {Nohl, Karsten and Evans, David}, + title = {{Hiding in Groups: On the Expressiveness of Privacy Distributions}}, + booktitle = {Proceedings of The Ifip Tc 11 23rd International Information Security Conference --- SEC 2008}, + year = {2008}, + editor = {}, + volume = {278}, + series = {LNCS}, + pages = {1--15}, + address = {Milan, Italia}, + month = {September}, + organization = {}, + publisher = {Springer}, + bibsource = {Information Security Group (GIS), UCL, Louvain-la-Neuve, Belgium}, +} + +@inproceedings{DBLP:conf/fse/Shamir08, + author = {Adi Shamir}, + title = {{SQUASH} --- A New {MAC} with Provable Security Properties for Highly Constrained Devices Such as {RFID} Tags}, + booktitle = {FSE}, + year = {2008}, + pages = {144-157}, + ee = {http://dx.doi.org/10.1007/978-3-540-71039-4_9}, + crossref = {DBLP:conf/fse/2008}, + bibsource = {DBLP, http://dblp.uni-trier.de} +} + +@proceedings{DBLP:conf/fse/2008, + editor = {Kaisa Nyberg}, + title = {Fast Software Encryption, 15th International Workshop, {FSE} 2008, Lausanne, Switzerland, February 10-13, 2008, Revised Selected Papers}, + booktitle = {FSE}, + publisher = {Springer}, + series = {LNCS}, + volume = {5086}, + year = {2008}, + isbn = {978-3-540-71038-7}, + bibsource = {DBLP, http://dblp.uni-trier.de} +} + +@inproceedings{Oren2008WIPRPublic, +author = {Yossef Oren and Martin Feldhofer}, +title = {{WIPR} --- a Public Key Implementation on Two Grains of Sand}, +booktitle = {Workshop on RFID Security 2008}, +year = {2008}, +editor = {Sandra Dominikus}, +pages = {15 - 27}, +} + +@incollection{drat, +year={2014}, +isbn={978-3-319-09283-6}, +booktitle={Theory and Applications of Satisfiability Testing – SAT 2014}, +volume={8561}, +series={Lecture Notes in Computer Science}, +editor={Sinz, Carsten and Egly, Uwe}, +doi={10.1007/978-3-319-09284-3_31}, +title={DRAT-trim: Efficient Checking and Trimming Using Expressive Clausal Proofs}, +url={http://dx.doi.org/10.1007/978-3-319-09284-3_31}, +publisher={Springer International Publishing}, +author={Wetzler, Nathan and Heule, MarijnJ.H. and Hunt, WarrenA., Jr.}, +pages={422-429}, +language={English} +} + + +@inproceedings{DBLP:conf/ctrsa/McLooneR07, + author = {M{\'a}ire McLoone and Matthew J. B. Robshaw}, + title = {Public Key Cryptography and {RFID} Tags}, + booktitle = {CT-RSA}, + year = {2007}, + pages = {372-384}, + ee = {http://dx.doi.org/10.1007/11967668_24}, + crossref = {DBLP:conf/ctrsa/2007}, + bibsource = {DBLP, http://dblp.uni-trier.de} +} + +@proceedings{DBLP:conf/ctrsa/2007, + editor = {Masayuki Abe}, + title = {Topics in Cryptology - CT-RSA 2007, The Cryptographers' Track at the RSA Conference 2007, San Francisco, CA, USA, February 5-9, 2007, Proceedings}, + booktitle = {CT-RSA}, + publisher = {Springer}, + series = {LNCS}, + volume = {4377}, + year = {2006}, + isbn = {3-540-69327-0}, + bibsource = {DBLP, http://dblp.uni-trier.de} +} + + + +@proceedings{DBLP:conf/eurocrypt/91, + editor = {Donald W. Davies}, + title = {Advances in Cryptology --- EUROCRYPT '91, Workshop on the Theory and Application of of Cryptographic Techniques, Brighton, UK, April 8-11, 1991, Proceedings}, + booktitle = {Advances in Cryptology --- EUROCRYPT '91}, + publisher = {Springer}, + series = {LNCS}, + volume = {547}, + year = {1991}, + isbn = {3-540-54620-0}, +} + +@inproceedings{DBLP:conf/eurocrypt/Girault91, + author = {Marc Girault}, + title = {Self-Certified Public Keys}, + booktitle = {Advances in Cryptology --- EUROCRYPT '91}, + year = {1991}, + pages = {490-497}, + ee = {http://link.springer.de/link/service/series/0558/bibs/0547/05470490.htm}, + bibsource = {DBLP, http://dblp.uni-trier.de} +} + +@inproceedings{DBLP:conf/cardis/Girault00, + author = {Marc Girault}, + title = {Low-Size Coupons for Low-Cost {IC} Cards}, + booktitle = {CARDIS}, + year = {2000}, + pages = {39-50}, + crossref = {DBLP:conf/cardis/2000}, + bibsource = {DBLP, http://dblp.uni-trier.de} +} + +@proceedings{DBLP:conf/cardis/2000, + editor = {Josep Domingo-Ferrer and David Chan and Anthony Watson}, + title = {Smart Card Research and Advanced Applications, Proceedings of the Fourth Working Conference on Smart Card Research and Advanced Applications, CARDIS 2000, September 20-22, 2000, Bristol, UK}, + booktitle = {CARDIS}, + publisher = {Kluwer}, + series = {IFIP Conference Proceedings}, + volume = {180}, + year = {2000}, + isbn = {0-7923-7953-5}, + bibsource = {DBLP, http://dblp.uni-trier.de} +} + +@inproceedings{Secure-human-ID, + author = {Hopper,, Nicholas J. and Blum,, Manuel}, + title = {Secure Human Identification Protocols}, + booktitle = {ASIACRYPT '01: Proceedings of the 7th International Conference on the Theory and Application of Cryptology and Information Security}, + year = {2001}, + isbn = {3-540-42987-5}, + pages = {52--66}, + publisher = {Springer-Verlag}, + address = {London, UK}, +} + +@ARTICLE{Inherent-intracability, +title={On the inherent intractability of certain coding problems (Corresp.)}, +author={ Berlekamp, E. and McEliece, R. and van Tilborg, H.}, +journal={Information Theory, IEEE Transactions on}, +year={1978}, +month={May}, +volume={24}, +number={3}, +pages={ 384-386}, +keywords={null Decoding, Linear codes}, +doi={}, +ISSN={0018-9448}, +} + +@article{Noise-tolerant-learning, + author = {Blum,, Avrim and Kalai,, Adam and Wasserman,, Hal}, + title = {Noise-tolerant learning, the parity problem, and the statistical query model}, + journal = {J. ACM}, + volume = {50}, + number = {4}, + year = {2003}, + issn = {0004-5411}, + pages = {506--519}, + doi = {http://doi.acm.org/10.1145/792538.792543}, + publisher = {ACM}, + address = {New York, NY, USA}, +} + + +@INPROCEEDINGS{To06anovel, + author = {Marc P. C. Fossorier and Miodrag J. Mihaljević and Hideki Imai and Yang Cui and Kanta Matsuura}, + title = {A Novel Algorithm for Solving the {LPN} Problem and Its Applicatio to Security Evaluation of the {HB} Protocol for {RFID} Authentication}, + booktitle = {INDOCRYPT}, + editor = {Rana Barua and Tanja Lange}, + volume = {4329}, + series = {LNCS}, + year = {2006}, + pages = {48--62}, + publisher = {Springer} +} + +@INPROCEEDINGS{Levieil_animproved, + author = {Éric Levieil and Pierre-Alain Fouque}, + title = {An improved {LPN} algorithm}, + editor = {Roberto De Prisco and Moti Yung}, + booktitle = {Security and Cryptography for Networks --- SCN}, + volume = {4116}, + series = {LNCS}, + year = {2006}, + pages = {348--359}, + Publisher = {Springer Berlin / Heidelberg}, + ISSN = {0302-9743}, +} + +@INPROCEEDINGS{HBpp, +title={{HB}$^{++}$: a Lightweight Authentication Protocol Secure against Some Attacks}, +author={Bringer, J. and Chabanne, H. and Dottax, E.}, +booktitle={Security, Privacy and Trust in Pervasive and Ubiquitous Computing, 2006 --- SecPerU 2006}, +year={2006}, +month={June}, +volume={}, +number={}, +pages={28--33}, +doi={10.1109/SECPERU.2006.10}, +} + +@inproceedings{DBLP:conf/eurocrypt/GilbertRS08, + author = {Henri Gilbert and Matthew J. B. Robshaw and Yannick Seurin}, + title = {{HB}$^{\mbox{\#}}$: Increasing the Security and Efficiency of {HB}$^{\mbox{+}}$}, + booktitle = {Advances in Cryptology --- EUROCRYPT '08}, + year = {2008}, + pages = {361-378}, + ee = {http://dx.doi.org/10.1007/978-3-540-78967-3_21}, + crossref = {DBLP:conf/eurocrypt/2008}, + bibsource = {DBLP, http://dblp.uni-trier.de} +} + +@proceedings{DBLP:conf/eurocrypt/2008, + editor = {Nigel P. Smart}, + title = {Advances in Cryptology --- EUROCRYPT 2008, 27th Annual International Conference on the Theory and Applications of Cryptographic Techniques, Istanbul, Turkey, April 13-17, 2008. Proceedings}, + booktitle = {Advances in Cryptology --- EUROCRYPT '08}, + publisher = {Springer}, + series = {LNCS}, + volume = {4965}, + year = {2008}, + isbn = {978-3-540-78966-6}, + bibsource = {DBLP, http://dblp.uni-trier.de} +} + +@proceedings{DBLP:conf/fse/2001, + editor = {Mitsuru Matsui}, + title = {Fast Software Encryption, 8th International Workshop, FSE 2001 Yokohama, Japan, April 2-4, 2001, Revised Papers}, + booktitle = {FSE}, + publisher = {Springer}, + series = {LNCS}, + volume = {2355}, + year = {2002}, + isbn = {3-540-43869-6}, + bibsource = {DBLP, http://dblp.uni-trier.de} +} + +@techreport{Rabin79Digitalized, + author = {Rabin, M. O.}, + title = {Digitalized Signatures and Public-Key Functions as Intractable as Factorization}, + year = {1979}, + institution = {Massachusetts Institute of Technology}, + address = {Cambridge, MA, USA}, + } + +@article{HBmp, + author = {Munilla,, J. and Peinado,, A.}, + title = {{HB}-{MP}: A further step in the HB-family of lightweight authentication protocols}, + journal = {Comput. Netw.}, + volume = {51}, + number = {9}, + year = {2007}, + issn = {1389-1286}, + pages = {2262--2267}, + doi = {http://dx.doi.org/10.1016/j.comnet.2007.01.011}, + publisher = {Elsevier North-Holland, Inc.}, + address = {New York, NY, USA}, + } + +@article{HBstar, + author={D.N. Duc and K. Kim}, + title={Securing {HB}$^+$ Against {GRS} Man-in-the-Middle Attack}, + journal={Institute of Electronics, Information and Communication Engineers, Symposium on Cryptography and Information, Security}, + date = {January 23--26}, + year = {2007}, +} + +@INPROCEEDINGS{OuafiOV-2008-asiacrypt, + author = {Ouafi, Khaled and Overbeck, Raphael and Vaudenay, Serge}, + title = {On the Security of {HB\#} against a Man-in-the-Middle Attack}, + booktitle = {Advances in Cryptology --- Asiacrypt 2008}, + year = {2008}, + editor = {}, + volume = {5350}, + series = {LNCS}, + pages = {108--124}, + address = {Melbourne, Australia}, + month = {December}, + organization = {}, + publisher = {Springer}, + bibsource = {Information Security Group (GSI), UCL, Louvain-la-Neuve, Belgium}, +} + +@INPROCEEDINGS{PRESENT, + author = {Bogdanov, Andrey and Knudsen, Lars Ramkilde and Leander, Gregor and Paar, Christof and Poschmann, Axel and Robshaw, Matthew J.B. and Seurin, Yannick and Vikkelsoe, C.}, + title = {{PRESENT}: An Ultra-Lightweight Block Cipher}, + booktitle = {Workshop on Cryptographic Hardware and Embedded Systems --- CHES 2007}, + year = {2007}, + editor = {Paillier, Pascal and Verbauwhede, Ingrid}, + volume = {4727}, + series = {LNCS}, + pages = {450--466}, + address = {Vienna, Austria}, + month = {September}, + organization = {}, + publisher = {Springer-Verlag}, + bibsource = {Information Security Group (GSI), UCL, Louvain-la-Neuve, Belgium}, +} + +@INPROCEEDINGS{ChoiKKK-2006-isce, + author = {Choi, Yongje and Kim, Mooseop and Kim, Taesung and Kim, Howon}, + title = {Low power implementation of {SHA}-1 algorithm for {RFID} system}, + booktitle = {IEEE Tenth International Symposium on Consumer Electronics --- ISCE '06}, + year = {2006}, + editor = {}, + volume = {}, + series = {}, + pages = {1--5}, + address = {St.Petersburg, Russia}, + month = {September}, + organization = {}, + publisher = {}, + bibsource = {Information Security Group (GSI), UCL, Louvain-la-Neuve, Belgium}, +} + +@INPROCEEDINGS{DES-RFID-implement, + author = {Axel Poschmann and Gregor Le and Kai Schramm and Christof Paar}, + title = {A Family of Light-Weight Block Ciphers Based on {DES} Suited for {RFID} Applications}, + booktitle = {Proceedings of FSE 2007, LNCS}, + year = {2006}, + publisher = {Springer-Verlag} +} + +@article{4253019, +title={Strong Crypto for {RFID} Tags - A Comparison of Low-Power Hardware Implementations}, +author={Feldhofer, M. and Wolkerstorfer, J.}, +journal={Circuits and Systems, 2007. ISCAS 2007. IEEE International Symposium on}, +year={2007}, +month={May}, +volume={}, +number={}, +pages={1839-1842}, +keywords={cryptographic protocols, radiofrequency identificationAES-128, ECC-192, MD5, SHA-1, SHA-256, implementation efficiency, passive RFID tags, security protocols, standardized cryptographic algorithms, strong cryptography}, +doi={10.1109/ISCAS.2007.378272}, +ISSN={}, +} + +@techreport{PUF-optical, + author= {P. Ravinkanth}, + title= {Physical One-Way Functions}, + note = {Ph.D. Thesis}, + institution = {MIT}, + year={2001} +} + +@inproceedings{PUF-silicon, + author={B. Gassend and D. Clarke and M. van Dijk and S. Devadas}, + title = {Controlled Physical Random Functions}, + booktitle = {Proceedings of the 18th Annual Computer Security Applications Conference --- ACSAC '02}, + year = {2002}, + ISBN = {0-7695-1828-1}, + page = {149}, + publisher = {IEEE}, +} + +@article{PUF-circ-secret-key, + author = {D. Lim and J. W. Lee and B. Gassend and G. E. Suh and M. van Dijk and S. Devadas}, + title = {Extracting Secret Keys From Integrated Circuits}, + journal = {IEEE Transactions on Very Large Scale Integration (VLSI) Systems}, + pages = {1200--1205}, + year = {2005}, + issue = {13 (10)}, +} + + +@INPROCEEDINGS{Li99equivalencyreasoning, + author = {Chu Min Li}, + title = {Equivalency reasoning to solve a class of hard {SAT} problems}, + booktitle = {Information Processing Letters}, + year = {1999}, + pages = {76--1} +} + +@INPROCEEDINGS{Silva96conflictanalysis, + author = {Joo P. Marques and Silva Karem and A. Sakallah}, + title = {Conflict analysis in search algorithms for propositional satisfiability}, + booktitle = {Proc. of the IEEE Intl. Conf. on Tools with Artificial Intelligence}, + year = {1996} +} + +@article{Chaff01, + author = {Sharad Malik and Ying Zhao and Conor F. Madigan and Lintao Zhang and Matthew W. Moskewicz}, + title = {Chaff: Engineering an Efficient {SAT} Solver}, + journal ={Design Automation Conference}, + year = {2001}, + pages = {530-535}, + doi = {http://doi.ieeecomputersociety.org/10.1109/DAC.2001.935565}, + publisher = {IEEE Computer Society}, + address = {Los Alamitos, CA, USA}, +} +volume = {0}, +isbn = {}, + +@article{visualizingDPLL, + author = {Sinz, Carsten}, + title = {Visualizing {SAT} Instances and Runs of the {DPLL} Algorithm}, + journal = {J. Autom. Reason.}, + volume = {39}, + number = {2}, + year = {2007}, + issn = {0168-7433}, + pages = {219--243}, + doi = {http://dx.doi.org/10.1007/s10817-007-9074-1}, + publisher = {Kluwer Academic Publishers}, + address = {Hingham, MA, USA}, + } + +@inproceedings{nicolas.linear_feedback, + author={Nicolas T. Courtois}, + title={Fast Algebraic Attacks on Stream Ciphers with Linear Feedback}, + booktitle={Advances in Cryptology --- {CRYPTO} 2003}, + year={2003}, + pages={176-194}, + volume={2729/2003}, + series={LNCS}, + publisher={Springer}, +} + +@misc{Karsten-webpage-Cyrpto-1, + author={Karsten Nohl}, + title={Cryptanalysis of {C}rypto-1}, + howpublished={Press release}, + month={March}, + day = {12}, + year={2008}, + note= {\url{http://www.cs.virginia.edu/~kn5f/Mifare.Cryptanalysis.htm}} +} + +@Misc{Radboud-Mifare-press, + author = {{Digital {S}ecurity group, {R}adboud {U}niversity {N}ijmegen}}, + title = {Security Flaw in {M}ifare {C}lassic}, + howpublished = {Press release}, + month = {March}, + day = {12}, + year = {2008}, + note = {\url{http://www.ru.nl/english/general/radboud_university/vm/security_flaw_in/}}, +} + +@ARTICLE{Massacci00logicalcryptanalysis, + author = {Fabio Massacci and Laura Marraro}, + title = {Logical cryptanalysis as a {SAT}-problem: Encoding and analysis}, + journal = {Journal of Automated Reasoning}, + year = {2000}, + volume = {24}, + pages = {165--203} +} + +@article{Monte-Carlo-method, + abstract = {We shall present here the motivation and a general description of a method dealing with a class of problems in mathematical physics. The method is, essentially, a statistical approach to the study of differential equations, or more generally, of integro-differential equations that occur in various branches of the natural sciences.}, + author = {Metropolis, Nicholas and Ulam, S. }, + citeulike-article-id = {1886002}, + doi = {10.2307/2280232}, + journal = {Journal of the American Statistical Association}, + keywords = {random, sampling}, + number = {247}, + pages = {335--341}, + posted-at = {2009-04-12 22:32:37}, + priority = {2}, + title = {The {M}onte {C}arlo Method}, + url = {http://dx.doi.org/10.2307/2280232}, + volume = {44}, + year = {1949} +} + +@article{Rabin-primality-test, + author = {Rabin, Michael O. }, + citeulike-article-id = {1505894}, + doi = {10.1016/0022-314X(80)90084-0}, + journal = {J. Number Theory}, + mrnumber = {MR566880}, + number = {1}, + pages = {128--138}, + posted-at = {2007-07-27 00:11:40}, + priority = {2}, + title = {Probabilistic algorithm for testing primality}, + url = {http://dx.doi.org/10.1016/0022-314X(80)90084-0}, + volume = {12}, + year = {1980} +} + +@article{Mersenne-Twister, + address = {New York, NY, USA}, + author = {Matsumoto, Makoto and Nishimura, Takuji }, + citeulike-article-id = {611171}, + doi = {10.1145/272991.272995}, + issn = {1049-3301}, + journal = {ACM Trans. Model. Comput. Simul.}, + keywords = {algorithm}, + month = {January}, + number = {1}, + pages = {3--30}, + posted-at = {2008-10-26 00:03:42}, + priority = {0}, + publisher = {ACM Press}, + title = {Mersenne twister: a 623-dimensionally equidistributed uniform pseudo-random number generator}, + url = {http://dx.doi.org/10.1145/272991.272995}, + volume = {8}, + year = {1998} +} + +@inproceedings{L'Ecuyer98randomnumber, + author = {Pierre L'Ecuyer and Peter Hellekalek}, + title = {Random Number Generators: Selection Criteria and Testing}, + booktitle = {Random and Quasi-Random Point Sets}, + series = {Lecture Notes in Statistics}, + volume = {138}, + publisher = {Springer-Verlag}, + address = {New York}, + pages = {223--266}, + year = {1998}, +} + +@inproceedings{DBLP:conf/sat/SinzD05, + author = {Carsten Sinz and Edda-Maria Dieringer}, + title = {{DP}vis --- {A} Tool to Visualize the Structure of {SAT} Instances}, + booktitle = {SAT}, + year = {2005}, + pages = {257-268}, + ee = {http://dx.doi.org/10.1007/11499107_19}, + crossref = {DBLP:conf/sat/2005}, + bibsource = {DBLP, http://dblp.uni-trier.de} +} + + +@article{gomes00heavytailed, + author = {Carla P. Gomes and Bart Selman and Nuno Crato and Henry A. Kautz}, + title = {Heavy-Tailed Phenomena in Satisfiability and Constraint Satisfaction Problems}, + journal = {Journal of Automated Reasoning}, + volume = {24}, + number = {1/2}, + pages = {67--100}, + year = {2000}, + url = {citeseer.ist.psu.edu/article/gomes99heavytailed.html} +} + +@article{Mandelbrot60Pareto, + author = {Benoît B. Mandelbrot}, + title = {The Pareto-Lévy law and the distribution of income}, + journal = {Internat. Econom. Rev.}, + volume = {1}, + year = {1960}, + pages = {79--106} +} + +@inproceedings{Moura07tutorial, + author = {Leonardo de Moura, Bruno Dutertre and Natarajan Shankar}, + title = {A Tutorial on Satisfiability Modulo Theories}, + series = {LNCS}, + publisher = {Springer Berlin / Heidelberg}, + issn = {0302-9743}, + volume = {4590/2007}, + year = {2007}, + isbn = {978-3-540-73367-6}, + pages = {20--36}, + booktitle = {Computer Aided Verification}, +} + doi = {10.1007/978-3-540-73368-3}, + +@article{Karnaugh53Logic, + author = {Karnaugh, Maurice}, + year = {1953}, + month = {November}, + title = {The Map Method for Synthesis of Combinational Logic Circuits}, + journal = {Transactions of American Institute of Electrical Engineers part I}, + volume = {72}, + number = {9}, + pages = {593--599}, +} + +@inproceedings{Li00Integrating, + author = {Li, Chu Min}, + title = {Integrating Equivalency Reasoning into Davis-Putnam Procedure}, + booktitle = {Proceedings of the Seventeenth National Conference on Artificial Intelligence and Twelfth Conference on Innovative Applications of Artificial Intelligence}, + year = {2000}, + isbn = {0-262-51112-6}, + pages = {291--296}, + publisher = {AAAI Press / The MIT Press}, +} + +@article{Warners99TwoPhase, + author = {Joost P. Warners and Hans Van Maaren}, + title = {A Two Phase Algorithm for Solving a Class of Hard Satisfiability Problems}, + journal = {Operations Research Letters}, + year = {1999}, + volume = {23}, + number = {3--5}, + pages = {81--88} +} + +@inproceedings{Massacci00Taming, + author = {Peter Baumgartner and Fabio Massacci}, + title = {The Taming of the {(X)OR}}, + series = {LNCS}, + publisher = {Springer Berlin / Heidelberg}, + ISSN = {0302-9743}, + volume = {1861/2000}, + booktitle = {Computational Logic — CL 2000}, + doi = {10.1007/3-540-44957-4}, + year = {2000}, + isbn = {978-3-540-67797-0}, + pages = {508--522}, +} + +@inproceedings{Massacci99Using, + author = {Fabio Massacci}, + title = {Using {W}alk-{SAT} and {R}el-sat for cryptographic key search}, + booktitle = {Proc. of IJCAI-99}, + year = {1999}, + editor = {Morgan Kaufmann}, + pages = {290--295}, +} + +@inproceedings{Girault04Public, +author = {Marc Girault and David Lefranc}, +title = {Public Key Authentication with One (Online) Single Addition}, +series = {LNCS}, +bublisher = {Springer Berlin / Heidelberg}, +ISSN = {0302-9743}, +volume = {3156/2004}, +booktitle = {Cryptographic Hardware and Embedded Systems - CHES 2004}, +doi ={10.1007/b99451}, +year = {2004}, +isbn = {978-3-540-22666-6}, +pages = {967--984} +} + +@article{Hsieh72OnOptimal, + author = {Hsieh, H. Y. and Ghausi, M. S.}, + title = {On optimal-pivoting algorithms in sparse matrices}, + journal = {IEEE Trans. Circuit Theory}, + volume = {CT-19}, + pages = {93--96}, + month = {January}, + year = {1972} +} + +@article{HerasetalJAIR2008, + author = {Federico Heras and Javier Larrosa and Albert Oliveras}, + title = {{MiniMaxSAT: An efficient Weighted Max-SAT Solver}}, + journal = {Journal of Artificial Intelligence Research}, + volume = {31}, + year = {2008}, + pages = {1--32} + } + +@techreport{Wieringa07MiniMarch, + title = {{M}ini{M}arch --- {E}mbedding lookahead direction heuristics in a conflict driven solver}, + author = {Siert Wieringa}, + institution = {Technische Universiteit Delft}, + note = {Research Report}, + year = {2007}, + url = {http://www.st.ewi.tudelft.nl/sat/theses/minimarch.pdf}, +} + +techreport{OSI-MIT-Licence, +url = {http://www.opensource.org/licenses/mit-license.php} + + +@techreport{eStream, + title = {The e{STREAM} Portfolio}, + author = {Steve Babbage and Christophe De Canniere and Anne Canteaut and Carlos Cid and Henri Gilbert and Thomas Johansson and Christof Paar and Matthew Parker and Bart Preneel and Vincent Rijmen and Matt Robshaw and Hongjun Wu}, + url = {http://www.ecrypt.eu.org/stream/portfolio.pdf}, + institution = {eStream Project}, + year = {2008}, + month = {September}, + day = {8}, +} + +@techreport{Kibria08MiniSat, + author = {Raihan Kibria}, + title = {Midi{S}AT - {A}n extension of {M}ini{SAT}}, + institution = {Department of Electrical and Computer Engineering, Darmstadt University of Technology}, + year = {2005}, + month = {April}, + day = {26}, + url = {www.lri.fr/~simon/contest/results/descriptions/solvers/midisat_static.pdf}, +} + +@incollection{DaemenR05Rijndael, + author = {Joan Daemen and Vincent Rijmen}, + title = {Rijndael/AES}, + booktitle = {Encyclopedia of Cryptography and Security}, + year = {2005}, + ee = {http://dx.doi.org/10.1007/0-387-23483-7_358}, + crossref = {DBLP:reference/crypt/2005}, + bibsource = {DBLP, http://dblp.uni-trier.de} +} + +@book{DBLP:reference/crypt/2005, + editor = {Henk C. A. van Tilborg}, + title = {Encyclopedia of Cryptography and Security}, + publisher = {Springer}, + year = {2005}, + isbn = {978-0-387-23473-1}, + bibsource = {DBLP, http://dblp.uni-trier.de} +} + +@article{Strassen69Gaussian, + author = {Volker Strassen}, + title = {Gaussian Elimination is Not Optimal}, + journal = {Numerische Mathematik}, + volume = {13}, + pages = {354--356}, + year = {1969} +} + +@techreport{Crawford94TheMinimal, + author = {Crawford, J. M. and Kearns, M. J. and Shapire, R. E.}, + title = {The Minimal Disagreement Parity Problem as a Hard Satisfiability Problem}, + institution = {Computational Intelligence Research Laboratory and {AT\&T} {B}ell {L}abs}, + month = {February}, + year = {1994}, +} + +@inproceedings{OuafiV09Smashing, + author = {Khaled Ouafi and Serge Vaudenay}, + title = {Smashing {SQUASH}-0}, + volume = {5479}, + crossref = {DBLP:conf/eurocrypt/2009}, +} + +@inproceedings{ShamirRFIDSecLecture, +author = {Adi Shamir}, +title = {{SQUASH}: {A} new one-way hash function with provable security properties for higley contrained devices such as {RFID} tags}, +booktitle = {Invited lecture to the RFID Securty 2007 Workshop}, +year = {2007}, +} + +@misc{DES77, + author = {{National Bureau of Standards}}, + year = {1977}, + title = {Data {E}ncryption {S}tandard}, + institution = {U. S. Department of Commerce, National Bureau of Standards, Standards Publication (FIPS PUB) 46}, + address = {Washington, DC}, +}s + +@INPROCEEDINGS{Tsudik06Yet, + author = {Tsudik, Gene}, + title = {{YA-TRAP}: Yet Another Trivial {RFID} Authentication Protocol}, + booktitle = {International Conference on Pervasive Computing and Communications --- PerCom 2006}, + year = {2006}, + editor = {}, + volume = {}, + series = {}, + pages = {640--643}, + address = {Pisa, Italy}, + month = {March}, + organization = {IEEE}, + publisher = {IEEE Computer Society Press}, + bibsource = {Information Security Group (GSI), UCL, Louvain-la-Neuve, Belgium}, +} + + +@INPROCEEDINGS{Conti07RIPP, + author = {Conti, Mauro and Pietro, Roberto~Di and Mancini, Luigi~Vincenzo and Spognardi, Angelo}, + title = {{RIPP-FS}: an {RFID} Identification, Privacy Preserving Protocol with Forward Secrecy}, + booktitle = {International Workshop on Pervasive Computing and Communication Security --- PerSec '07}, + year = {2007}, + editor = {}, + volume = {}, + series = {}, + pages = {229--234}, + address = {New York City, New York, USA}, + month = {March}, + organization = {IEEE}, + publisher = {IEEE Computer Society Press}, + bibsource = {Information Security Group (GSI), UCL, Louvain-la-Neuve, Belgium}, +} + +@INPROCEEDINGS{Burmester06Provably, + author = {Burmester, Mike and Le, Tri van and Medeiros, Breno de}, + title = {Provably Secure Ubiquitous Systems: Universally Composable {RFID} Authentication Protocols}, + booktitle = {Conference on Security and Privacy for Emerging Areas in Communication Networks --- SecureComm '06}, + year = {2006}, + editor = {}, + volume = {}, + series = {}, + pages = {}, + address = {Baltimore, Maryland, USA}, + month = {August-September}, + organization = {IEEE}, + publisher = {}, + bibsource = {Information Security Group (GSI), UCL, Louvain-la-Neuve, Belgium}, +} + +@misc{ISO14443-standard, + author = {ISO/IEC}, + title = {14443-3 --- {I}dentification cards -- {C}ontactless integrated circuit(s) cards -- {P}roximity cards -- {P}art 3: {I}nitialization and anticollision}, + year = {2001, Stage: 90.92 --- 2007-12-11}, + institution = {International Organization for Standardization}, + address = {Geneva, Switzerland}, + url = {http://www.isotopicmaps.org/sam/sam-model/YYYY-MM-DD/}, +} + +@INPROCEEDINGS{Bailey05Shoehorning, + author = {Bailey, Daniel and Juels, Ari}, + title = {{Shoehorning Security into the EPC Standard}}, + booktitle = {International Conference on Security in Communication Networks --- SCN 2006}, + year = {2006}, + editor = {De~Prisco, Roberto and Yung, Moti}, + volume = {4116}, + series = {LNCS}, + pages = {303--320}, + address = {Maiori, Italy}, + month = {September}, + organization = {}, + publisher = {Springer-Verlag}, + bibsource = {Information Security Group (GSI), UCL, Louvain-la-Neuve, Belgium}, +} + +@INPROCEEDINGS{Soos08Analysing, + author = {Soos, Mate}, + title = {{Analysing the {M}olva and {D}i {P}ietro Private {RFID} Authentication Scheme}}, + booktitle = {Workshop on RFID Security --- RFIDSec'08}, + year = {2008}, + editor = {}, + volume = {}, + series = {}, + pages = {}, + address = {Budapest, Hungary}, + month = {July}, + organization = {}, + publisher = {}, +} + +@inproceedings{DBLP:conf/ccs/BurmesterMM08, + author = {Mike Burmester and Breno de Medeiros and Rossana Motta}, + title = {Robust, anonymous {RFID} authentication with constant key-lookup}, + booktitle = {ASIACCS}, + year = {2008}, + pages = {283-291}, + ee = {http://doi.acm.org/10.1145/1368310.1368351}, + crossref = {DBLP:conf/ccs/2008asia}, + bibsource = {DBLP, http://dblp.uni-trier.de} +} + +@proceedings{DBLP:conf/ccs/2008asia, + editor = {Masayuki Abe and Virgil D. Gligor}, + title = {Proceedings of the 2008 ACM Symposium on Information, Computer and Communications Security, ASIACCS 2008, Tokyo, Japan, March 18-20, 2008}, + booktitle = {ASIACCS}, + publisher = {ACM}, + year = {2008}, + isbn = {978-1-59593-979-1}, + bibsource = {DBLP, http://dblp.uni-trier.de} +} + +@INPROCEEDINGS{Blass09Ff, + author = {Blass, Erik-Oliver and Kurmus, Anil and Molva, Refik and Noubir, Guevara and Shikfa, Abdullatif}, + title = {{The {F}f-Family of Protocols for {RFID}-Privacy and Authentication}}, + booktitle = {Workshop on RFID Security --- RFIDSec'09}, + year = {2009}, + editor = {}, + volume = {}, + series = {}, + pages = {}, + address = {Leuven, Belgium}, + month = {July}, + organization = {}, + publisher = {}, + bibsource = {Information Security Group (GSI), UCL, Louvain-la-Neuve, Belgium}, +} + +@inproceedings{DBLP:conf/cardis/CastellucciaA06, + author = {Claude Castelluccia and Gildas Avoine}, + title = {Noisy Tags: {A} Pretty Good Key Exchange Protocol for {RFID} Tags}, + booktitle = {CARDIS}, + year = {2006}, + pages = {289-299}, + ee = {http://dx.doi.org/10.1007/11733447_21}, + crossref = {DBLP:conf/cardis/2006}, + bibsource = {DBLP, http://dblp.uni-trier.de} +} + +@proceedings{DBLP:conf/cardis/2006, + editor = {Josep Domingo-Ferrer and + Joachim Posegga and + Daniel Schreckling}, + title = {Smart Card Research and Advanced Applications, 7th IFIP + WG 8.8/11.2 International Conference, CARDIS 2006, Tarragona, + Spain, April 19-21, 2006, Proceedings}, + booktitle = {CARDIS}, + publisher = {Springer}, + series = {LNCS}, + volume = {3928}, + year = {2006}, + isbn = {3-540-33311-8}, + bibsource = {DBLP, http://dblp.uni-trier.de} +} + + +@inproceedings{DBLP:conf/ches/SavryPDRR07, + author = {O. Savry and F. Pebay-Peyroula and F. Dehmas and G. Robert and J. Reverdy}, + title = {{RFID} Noisy Reader --- {H}ow to Prevent from Eavesdropping on the Communication?}, + booktitle = {CHES}, + year = {2007}, + pages = {334-345}, + ee = {http://dx.doi.org/10.1007/978-3-540-74735-2_23}, + crossref = {DBLP:conf/ches/2007}, + bibsource = {DBLP, http://dblp.uni-trier.de} +} + +@proceedings{DBLP:conf/ches/2007, + editor = {Pascal Paillier and Ingrid Verbauwhede}, + title = {Cryptographic Hardware and Embedded Systems --- {CHES} 2007, + 9th International Workshop, Vienna, Austria, September 10-13, + 2007, Proceedings}, + booktitle = {CHES}, + publisher = {Springer}, + series = {LNCS}, + volume = {4727}, + year = {2007}, + isbn = {978-3-540-74734-5}, + bibsource = {DBLP, http://dblp.uni-trier.de} +} + +@article{Hancke07Modulating, + author = {G. Hancke}, + title = {Modulating a noisy carrier signal for eavesdropping-resistant {HF RFID}}, + journal = {e\&i --- Elektrotechnik und Informationstechnik}, + year = {2007}, + volume = {124}, + number = {11}, + month = {November}, + pages = {404--408}, + publisher = {Springer Wien}, + ISSN = {0932-383X}, + DOI = {10.1007/s00502-007-0479-7} +} + +@inproceedings{1423361, + author = {Babbage, Steve and Dodd, Matthew}, + title = {The {MICKEY} Stream Ciphers}, + booktitle = {New Stream Cipher Designs: The e{STREAM} Finalists}, + year = {2008}, + isbn = {978-3-540-68350-6}, + pages = {191--209}, + doi = {http://dx.doi.org/10.1007/978-3-540-68351-3_15}, + publisher = {Springer-Verlag}, + address = {Berlin, Heidelberg}, + } + +@inproceedings{DBLP:conf/wistp/DeursenMR08, + author = {Ton van Deursen and Sjouke Mauw and Sasa Radomirovic}, + title = {Untraceability of {RFID} Protocols}, + booktitle = {WISTP}, + year = {2008}, + pages = {1-15}, + ee = {http://dx.doi.org/10.1007/978-3-540-79966-5_1}, + crossref = {DBLP:conf/wistp/2008}, + bibsource = {DBLP, http://dblp.uni-trier.de} +} + +@proceedings{DBLP:conf/wistp/2008, + editor = {Jose Antonio Onieva and Damien Sauveron and Serge Chaumette and Dieter Gollmann and Constantinos Markantonakis}, + title = {Information Security Theory and Practices. Smart Devices, Convergence and Next Generation Networks, Second {IFIP WG} 11.2 International Workshop, {WISTP} 2008, Seville, Spain, May 13-16, 2008. Proceedings}, + booktitle = {WISTP}, + publisher = {Springer}, + series = {LNCS}, + volume = {5019}, + year = {2008}, + isbn = {978-3-540-79965-8}, + bibsource = {DBLP, http://dblp.uni-trier.de} +} + +@misc{A51, + author = {Ross Anderson}, + title = {A5 (was: Hacking digital phones)}, + howpublished = {Newsgroup Communication}, + year = {1994}, +} + +@inproceedings{DBLP:conf/cardis/GansHG08, + author = {Gerhard de Koning Gans and Jaap-Henk Hoepman and Flavio D. Garcia}, + title = {A Practical Attack on the {MIFARE} {C}lassic}, + booktitle = {CARDIS}, + year = {2008}, + pages = {267-282}, + ee = {http://dx.doi.org/10.1007/978-3-540-85893-5_20}, + crossref = {DBLP:conf/cardis/2008}, + bibsource = {DBLP, http://dblp.uni-trier.de} +} + +@proceedings{DBLP:conf/cardis/2008, + editor = {Gilles Grimaud and Fran\c{c}ois-Xavier Standaert}, + title = {Smart Card Research and Advanced Applications, 8th IFIP WG 8.8/11.2 International Conference, CARDIS 2008, London, UK, September 8-11, 2008. Proceedings}, + booktitle = {CARDIS}, + publisher = {Springer}, + series = {LNCS}, + volume = {5189}, + year = {2008}, + isbn = {978-3-540-85892-8}, + bibsource = {DBLP, http://dblp.uni-trier.de} +} + +@inproceedings{DBLP:conf/ima/CourtoisB07, + author = {Nicolas T. Courtois and Gregory V. Bard}, + title = {Algebraic Cryptanalysis of the {D}ata {E}ncryption {S}tandard}, + booktitle = {{IMA} Int. Conf.}, + year = {2007}, + pages = {152-169}, + ee = {http://dx.doi.org/10.1007/978-3-540-77272-9_10}, + crossref = {DBLP:conf/ima/2007}, + bibsource = {DBLP, http://dblp.uni-trier.de} +} + +@proceedings{DBLP:conf/ima/2007, + editor = {Steven D. Galbraith}, + title = {Cryptography and Coding, 11th IMA International Conference, Cirencester, UK, December 18-20, 2007, Proceedings}, + booktitle = {IMA Int. Conf.}, + publisher = {Springer}, + series = {LNCS}, + volume = {4887}, + year = {2007}, + isbn = {978-3-540-77271-2}, + bibsource = {DBLP, http://dblp.uni-trier.de} +} + +@book{Bard-algebraic, + title = {Algebraic Cryptanalysis}, + author = {Gregory V. Bard}, + year = {2009}, + pages = {392}, + volume = {XXXIV}, + series = {Security and Cryptology}, + ISBN = {978-0-387-88756-2}, + publisher = {Springer}, +} + +@inproceedings{Graphviz, + author = {John Ellson and Emden R. Gansner and Eleftherios Koutsofios and Stephen C. North and Gordon Woodhull}, + year = {2001}, + title = {Graphviz --- open source graph drawing tools}, + pages = {483--484}, + crossref = {DBLP:conf/gd/2001}, +} + +@proceedings{DBLP:conf/gd/2001, + editor = {Petra Mutzel and Michael J{\"u}nger and Sebastian Leipert}, + title = {Graph Drawing, 9th International Symposium, GD 2001 Vienna, Austria, September 23--26, 2001, Revised Papers}, + booktitle = {Graph Drawing}, + publisher = {Springer}, + series = {LNCS}, + volume = {2265}, + year = {2002}, + isbn = {3-540-43309-0}, + bibsource = {DBLP, http://dblp.uni-trier.de} +} + +@inproceedings{Borghoff09Mixed, + booktitle = {WEWoRC --- Western European Workshop on Research in Cryptology}, + title = {Bivium as a Mixed-0-1 Linear Programming Problem}, + author = {Julia Borghoff and Lars R. Knudsen and Mathias Stolpe}, + month = {July}, + year = {2009}, + address = {Graz, Austria}, +} + +@inproceedings{DBLP:conf/eurocrypt/DinurS09, + author = {Itai Dinur and Adi Shamir}, + title = {Cube Attacks on Tweakable Black Box Polynomials}, + booktitle = {EUROCRYPT}, + year = {2009}, + pages = {278--299}, + ee = {http://dx.doi.org/10.1007/978-3-642-01001-9_16}, + crossref = {DBLP:conf/eurocrypt/2009}, + bibsource = {DBLP, http://dblp.uni-trier.de} +} + +@proceedings{DBLP:conf/eurocrypt/2009, + editor = {Antoine Joux}, + title = {Advances in Cryptology --- EUROCRYPT 2009, 28th Annual International Conference on the Theory and Applications of Cryptographic Techniques, Cologne, Germany, April 26--30, 2009. Proceedings}, + booktitle = {EUROCRYPT}, + publisher = {Springer}, + series = {LNCS}, + volume = {5479}, + year = {2009}, + isbn = {978-3-642-01000-2}, + ee = {http://dx.doi.org/10.1007/978-3-642-01001-9}, + bibsource = {DBLP, http://dblp.uni-trier.de} +} + +@book{eStreamFinalists, + title = {The e{STREAM} Finalists}, + editor = {Matthew Robshaw and Olivier Billet}, + series = {LNCS}, + subseries = {Security and Cryptology}, + volume = {4986}, + year = {2008}, + pages = {295}, + isbn = {978-3-540-68350-6}, + publisher = {Springer}, +} + +@article{diffie76new, + author = "Whitfield Diffie and Martin E. Hellman", + title = "New Directions in Cryptography", + journal = "IEEE Transactions on Information Theory", + volume = "IT-22", + number = "6", + pages = "644--654", + date = "November 1976", + year = "1976", + url = "citeseer.ist.psu.edu/diffie76new.html" +} + +@ARTICLE{Rivest78amethod, + author = {Ron L. Rivest and Adi Shamir and Leonard Max Adleman}, + title = {A Method for Obtaining Digital Signatures and Public-Key Cryptosystems}, + journal = {Communications of the ACM}, + year = {1978}, + volume = {21}, + pages = {120--126} +} + +@inproceedings{Pfizmann01Anonimity, + author = {Andreas Pfitzmann and Marit Köhntopp}, + title = {Anonymity, Unobservability, and Pseudonymity --- {A} Proposal for Terminology}, + series = {LNCS}, + publisher = {Springer Berlin / Heidelberg}, + issn = {0302-9743}, + volume = {2009}, + year = {2001}, + booktitle = {Designing Privacy Enhancing Technologies}, + doi = {10.1007/3-540-44702-4}, + isbn = {978-3-540-41724-8}, + pages = {1--9}, +} + +@misc{Bard07efficientmethods, + author = {Gregory V. Bard and Nicolas T. Courtois and Chris Jefferson}, + title = {Efficient Methods for Conversion and Solution of Sparse Systems of Low-Degree Multivariate Polynomials over {GF}(2) via {SAT}-Solvers}, + howpublished = {Cryptology ePrint Archive, Report 2007/024, \url{http://eprint.iacr.org/2007/024}}, + year = {2007}, + organization = {IACR}, +} + +@inproceedings{DBLP:conf/sat/SoosNC09, + author = {Mate Soos and + Karsten Nohl and + Claude Castelluccia}, + title = {Extending {SAT} Solvers to Cryptographic Problems}, + booktitle = {SAT}, + year = {2009}, + pages = {244--257}, + ee = {http://dx.doi.org/10.1007/978-3-642-02777-2_24}, + crossref = {DBLP:conf/sat/2009}, + bibsource = {DBLP, http://dblp.uni-trier.de} +} + +@inproceedings{DBLP:conf/cav/GaneshD07, + author = {Vijay Ganesh and + David L. Dill}, + title = {A Decision Procedure for Bit-Vectors and Arrays}, + booktitle = {CAV}, + year = {2007}, + pages = {519-531}, + ee = {http://dx.doi.org/10.1007/978-3-540-73368-3_52}, + crossref = {DBLP:conf/cav/2007}, + bibsource = {DBLP, http://dblp.uni-trier.de} +} + +@proceedings{DBLP:conf/cav/2007, + editor = {Werner Damm and + Holger Hermanns}, + title = {Computer Aided Verification, 19th International Conference, + CAV 2007, Berlin, Germany, July 3-7, 2007, Proceedings}, + booktitle = {CAV}, + publisher = {Springer}, + series = {LNCS}, + volume = {4590}, + year = {2007}, + isbn = {978-3-540-73367-6}, + bibsource = {DBLP, http://dblp.uni-trier.de} +} + +@misc{Logic2CNF, + author = {Edd Barrett}, + title = {Logic2{CNF} Logic Solver and Converter}, + note = {\url{http://projects.cs.kent.ac.uk/projects/logic2cnf/trac/wiki/WikiStart}}, + year = {2010}, + month = {March}, +} + +@misc{CryptoMiniSat, + author = {Mate Soos}, + title = {Crypto{M}ini{S}at --- a {SAT} solver for cryptographic problems}, + note = {\url{http://planete.inrialpes.fr/~soos/CryptoMiniSat/index.html}}, + year = {2009}, +} + +@inproceedings{DBLP:conf/sat/EenB05, + author = {Niklas E{\'e}n and + Armin Biere}, + title = {Effective Preprocessing in {SAT} Through Variable and Clause + Elimination}, + booktitle = {SAT}, + year = {2005}, + pages = {61-75}, + ee = {http://dx.doi.org/10.1007/11499107_5}, + crossref = {DBLP:conf/sat/2005}, + bibsource = {DBLP, http://dblp.uni-trier.de} +} + +@inproceedings{glucose, + author = {Gilles Audemard and Laurent Simon}, + title = {{GLUCOSE}: a solver that predicts learnt clauses quality}, + booktitle = {SAT 2009 competitive events booklet}, + year = {2009}, + pages = {7--8}, +} + +@inproceedings{precosat, + author = {Armin Biere}, + title = {P\{re,i\}coSAT@SC’09}, + booktitle = {SAT 2009 competitive events booklet}, + year = {2009}, + pages = {41--42}, +} + +@inproceedings{DBLP:conf/sat/HeuleM04a, + author = {Marijn Heule and + Hans van Maaren}, + title = {Aligning {CNF}- and Equivalence-Reasoning}, + booktitle = {SAT (Selected Papers}, + year = {2004}, + pages = {145--156}, + ee = {http://dx.doi.org/10.1007/11527695_12}, + crossref = {DBLP:conf/sat/2004lncs}, + bibsource = {DBLP, http://dblp.uni-trier.de} +} + +@proceedings{DBLP:conf/sat/2004lncs, + editor = {Holger H. Hoos and + David G. Mitchell}, + title = {Theory and Applications of Satisfiability Testing, 7th International + Conference, SAT 2004, Vancouver, BC, Canada, May 10-13, + 2004, Revised Selected Papers}, + booktitle = {SAT (Selected Papers)}, + publisher = {Springer}, + series = {LNCS}, + volume = {3542}, + year = {2005}, + isbn = {3-540-27829-X}, + bibsource = {DBLP, http://dblp.uni-trier.de} +} + +@techreport{Heule-thesis, + author = {Marijn Heule}, + title = {{m}arch: Towards a lookahead Sat solver for general purposes}, + institution={Technische Universiteit Delft}, + month={February}, + year={2004}, +} + +@techreport{Heule-phd, + author = {Marijn J.H. Heule}, + title = {Smart solving: Tool and techniques for satisfiability solvers}, + institution={Technische Universiteit Delft}, + year={2008}, +} + +@article{DBLP:journals/amai/JeroslowW90, + author = {Robert G. Jeroslow and + Jinchang Wang}, + title = {Solving Propositional Satisfiability Problems}, + journal = {Ann. Math. Artif. Intell.}, + volume = {1}, + year = {1990}, + pages = {167-187}, + bibsource = {DBLP, http://dblp.uni-trier.de} +} + +@inproceedings{DBLP:conf/sat/PipatsrisawatD07, + author = {Knot Pipatsrisawat and + Adnan Darwiche}, + title = {A Lightweight Component Caching Scheme for Satisfiability + Solvers}, + booktitle = {SAT}, + year = {2007}, + pages = {294-299}, + ee = {http://dx.doi.org/10.1007/978-3-540-72788-0_28}, + crossref = {DBLP:conf/sat/2007}, + bibsource = {DBLP, http://dblp.uni-trier.de} +} + +@proceedings{DBLP:conf/sat/2007, + editor = {Jo{\~a}o Marques-Silva and + Karem A. Sakallah}, + title = {Theory and Applications of Satisfiability Testing --- SAT + 2007, 10th International Conference, Lisbon, Portugal, May + 28-31, 2007, Proceedings}, + booktitle = {SAT}, + publisher = {Springer}, + series = {LNCS}, + volume = {4501}, + year = {2007}, + isbn = {978-3-540-72787-3}, + bibsource = {DBLP, http://dblp.uni-trier.de} +} + +@inproceedings{DBLP:conf/ijcai/AudemardS09, + author = {Gilles Audemard and + Laurent Simon}, + title = {Predicting Learnt Clauses Quality in Modern {SAT} Solvers}, + booktitle = {IJCAI}, + year = {2009}, + pages = {399-404}, + ee = {http://ijcai.org/papers09/Papers/IJCAI09-074.pdf}, + crossref = {DBLP:conf/ijcai/2009}, + bibsource = {DBLP, http://dblp.uni-trier.de} +} + +@proceedings{DBLP:conf/ijcai/2009, + editor = {Craig Boutilier}, + title = {IJCAI 2009, Proceedings of the 21st International Joint + Conference on Artificial Intelligence, Pasadena, California, + USA, July 11-17, 2009}, + booktitle = {IJCAI}, + year = {2009}, + bibsource = {DBLP, http://dblp.uni-trier.de} +} + + +@inproceedings{DBLP:conf/tacas/JarvisaloBH10, + author = {Matti J{\"a}rvisalo and + Armin Biere and + Marijn Heule}, + title = {Blocked Clause Elimination}, + booktitle = {TACAS}, + year = {2010}, + pages = {129-144}, + ee = {http://dx.doi.org/10.1007/978-3-642-12002-2_10}, + crossref = {DBLP:conf/tacas/2010}, + bibsource = {DBLP, http://dblp.uni-trier.de} +} + +@proceedings{DBLP:conf/tacas/2010, + editor = {Javier Esparza and + Rupak Majumdar}, + title = {Tools and Algorithms for the Construction and Analysis of + Systems, 16th International Conference, TACAS 2010, Held + as Part of the Joint European Conferences on Theory and + Practice of Software, ETAPS 2010, Paphos, Cyprus, March + 20-28, 2010. Proceedings}, + booktitle = {TACAS}, + publisher = {Springer}, + series = {LNCS}, + volume = {6015}, + year = {2010}, + isbn = {978-3-642-12001-5}, + ee = {http://dx.doi.org/10.1007/978-3-642-12002-2}, + bibsource = {DBLP, http://dblp.uni-trier.de} +} + +@article{DBLP:journals/dam/Li03, + author = {Chu Min Li}, + title = {Equivalent literal propagation in the {DLL} procedure}, + journal = {Discrete Applied Mathematics}, + volume = {130}, + number = {2}, + year = {2003}, + pages = {251-276}, + ee = {http://dx.doi.org/10.1016/S0166-218X(02)00407-9}, + bibsource = {DBLP, http://dblp.uni-trier.de} +} + +@misc{Grid5000, + author = {{The Grid'5000 team}}, + title = {The {G}rid'5000 project}, + note = {\url{https://www.grid5000.fr}}, +} + year = {2008}, + +@article{DBLP:journals/endm/Berre01, + author = {Daniel Le Berre}, + title = {Exploiting the real power of unit propagation lookahead}, + journal = {Electronic Notes in Discrete Mathematics}, + volume = {9}, + year = {2001}, + pages = {59-80}, + ee = {http://dx.doi.org/10.1016/S1571-0653(04)00314-2}, + bibsource = {DBLP, http://dblp.uni-trier.de} +} + +@inproceedings{DBLP:conf/sat/GershmanS05, + author = {Roman Gershman and Ofer Strichman}, + title = {Cost-Effective Hyper-Resolution for Preprocessing {CNF} Formulas}, + booktitle = {SAT}, + year = {2005}, + pages = {423-429}, + ee = {http://dx.doi.org/10.1007/11499107_34}, + crossref = {DBLP:conf/sat/2005}, + bibsource = {DBLP, http://dblp.uni-trier.de} +} + + +@inproceedings{DBLP:conf/sat/HeuleJB11, + author = {Marijn Heule and + Matti J{\"a}rvisalo and + Armin Biere}, + title = {Efficient {CNF} Simplification Based on Binary Implication + Graphs}, + booktitle = {SAT}, + year = {2011}, + pages = {201-215}, + ee = {http://dx.doi.org/10.1007/978-3-642-21581-0_17}, + crossref = {DBLP:conf/sat/2011}, + bibsource = {DBLP, http://dblp.uni-trier.de} +} +@proceedings{DBLP:conf/sat/2011, + editor = {Karem A. Sakallah and + Laurent Simon}, + title = {Theory and Applications of Satisfiability Testing - SAT + 2011 - 14th International Conference, SAT 2011, Ann Arbor, + MI, USA, June 19-22, 2011. Proceedings}, + booktitle = {SAT}, + publisher = {Springer}, + series = {LNCS}, + volume = {6695}, + year = {2011}, + isbn = {978-3-642-21580-3}, + ee = {http://dx.doi.org/10.1007/978-3-642-21581-0}, + bibsource = {DBLP, http://dblp.uni-trier.de} +} + + +@inproceedings{DBLP:conf/ecai/PietteHS08, + author = {C{\'e}dric Piette and + Youssef Hamadi and + Lakhdar Sais}, + title = {Vivifying Propositional Clausal Formulae}, + booktitle = {ECAI}, + year = {2008}, + pages = {525-529}, + ee = {http://dx.doi.org/10.3233/978-1-58603-891-5-525}, + crossref = {DBLP:conf/ecai/2008}, + bibsource = {DBLP, http://dblp.uni-trier.de} +} +@proceedings{DBLP:conf/ecai/2008, + editor = {Malik Ghallab and + Constantine D. Spyropoulos and + Nikos Fakotakis and + Nikolaos M. Avouris}, + title = {ECAI 2008 - 18th European Conference on Artificial Intelligence, + Patras, Greece, July 21-25, 2008, Proceedings}, + booktitle = {ECAI}, + publisher = {IOS Press}, + series = {Frontiers in Artificial Intelligence and Applications}, + volume = {178}, + year = {2008}, + isbn = {978-1-58603-891-5}, + ee = {http://www.booksonline.iospress.nl/Content/View.aspx?piid=9905}, + bibsource = {DBLP, http://dblp.uni-trier.de} +} + +@inproceedings{DBLP:conf/sat/HanS09, + author = {HyoJung Han and + Fabio Somenzi}, + title = {On-the-Fly Clause Improvement}, + booktitle = {SAT}, + year = {2009}, + pages = {209-222}, + ee = {http://dx.doi.org/10.1007/978-3-642-02777-2_21}, + crossref = {DBLP:conf/sat/2009}, + bibsource = {DBLP, http://dblp.uni-trier.de} +} + + +@inproceedings{DBLP:conf/sat/SorenssonB09, + author = {Niklas S{\"o}rensson and + Armin Biere}, + title = {Minimizing Learned Clauses}, + booktitle = {SAT}, + year = {2009}, + pages = {237-243}, + ee = {http://dx.doi.org/10.1007/978-3-642-02777-2_23}, + crossref = {DBLP:conf/sat/2009}, + bibsource = {DBLP, http://dblp.uni-trier.de} +} + +@inproceedings{DBLP:conf/sat/BacchusW03, + author = {Fahiem Bacchus and + Jonathan Winter}, + title = {Effective Preprocessing with Hyper-Resolution and Equality + Reduction}, + booktitle = {SAT}, + year = {2003}, + pages = {341-355}, + ee = {http://dx.doi.org/10.1007/978-3-540-24605-3_26}, + crossref = {DBLP:conf/sat/2003}, + bibsource = {DBLP, http://dblp.uni-trier.de} +} +@proceedings{DBLP:conf/sat/2003, + editor = {Enrico Giunchiglia and + Armando Tacchella}, + title = {Theory and Applications of Satisfiability Testing, 6th International + Conference, SAT 2003. Santa Margherita Ligure, Italy, May + 5-8, 2003 Selected Revised Papers}, + booktitle = {SAT}, + publisher = {Springer}, + series = {LNCS}, + volume = {2919}, + year = {2004}, + isbn = {3-540-20851-8}, + bibsource = {DBLP, http://dblp.uni-trier.de} +} + +@proceedings{DBLP:conf/sat/2005, + editor = {Fahiem Bacchus and + Toby Walsh}, + title = {Theory and Applications of Satisfiability Testing, 8th International + Conference, SAT 2005, St. Andrews, UK, June 19-23, 2005, + Proceedings}, + booktitle = {SAT}, + publisher = {Springer}, + series = {LNCS}, + volume = {3569}, + year = {2005}, + isbn = {3-540-26276-8}, + bibsource = {DBLP, http://dblp.uni-trier.de} +} + +@proceedings{DBLP:conf/sat/2009, + editor = {Oliver Kullmann}, + title = {Theory and Applications of Satisfiability Testing - SAT + 2009, 12th International Conference, SAT 2009, Swansea, + UK, June 30 - July 3, 2009. Proceedings}, + booktitle = {SAT}, + publisher = {Springer}, + series = {Lecture Notes in Computer Science}, + volume = {5584}, + year = {2009}, + isbn = {978-3-642-02776-5}, + ee = {http://dx.doi.org/10.1007/978-3-642-02777-2}, + bibsource = {DBLP, http://dblp.uni-trier.de} +} + +@inproceedings{DBLP:conf/hvc/MantheyHB12, + author = {Norbert Manthey and + Marijn Heule and + Armin Biere}, + title = {Automated Reencoding of Boolean Formulas}, + booktitle = {Haifa Verification Conference}, + year = {2012}, + pages = {102-117}, + ee = {http://dx.doi.org/10.1007/978-3-642-39611-3_14}, + crossref = {DBLP:conf/hvc/2012}, + bibsource = {DBLP, http://dblp.uni-trier.de} +} + +@proceedings{DBLP:conf/hvc/2012, + editor = {Armin Biere and + Amir Nahir and + Tanja E. J. Vos}, + title = {Hardware and Software: Verification and Testing - 8th International + Haifa Verification Conference, HVC 2012, Haifa, Israel, + November 6-8, 2012. Revised Selected Papers}, + booktitle = {Haifa Verification Conference}, + publisher = {Springer}, + series = {Lecture Notes in Computer Science}, + volume = {7857}, + year = {2013}, + isbn = {978-3-642-39610-6}, + ee = {http://dx.doi.org/10.1007/978-3-642-39611-3}, + bibsource = {DBLP, http://dblp.uni-trier.de} +} + +@book{Quinlan:1993:CPM:152181, + author = {Quinlan, J. Ross}, + title = {C4.5: Programs for Machine Learning}, + year = {1993}, + isbn = {1-55860-238-0}, + publisher = {Morgan Kaufmann Publishers Inc.}, + address = {San Francisco, CA, USA}, +} diff --git a/cryptominisat/cppsrc/docs/satcomp18-pdf/splncs03.bst b/cryptominisat/cppsrc/docs/satcomp18-pdf/splncs03.bst new file mode 100644 index 00000000..32791691 --- /dev/null +++ b/cryptominisat/cppsrc/docs/satcomp18-pdf/splncs03.bst @@ -0,0 +1,1519 @@ +%% BibTeX bibliography style `splncs03' +%% +%% BibTeX bibliography style for use with numbered references in +%% Springer Verlag's "Lecture Notes in Computer Science" series. +%% (See Springer's documentation for llncs.cls for +%% more details of the suggested reference format.) Note that this +%% file will not work for author-year style citations. +%% +%% Use \documentclass{llncs} and \bibliographystyle{splncs03}, and cite +%% a reference with (e.g.) \cite{smith77} to get a "[1]" in the text. +%% +%% This file comes to you courtesy of Maurizio "Titto" Patrignani of +%% Dipartimento di Informatica e Automazione Universita' Roma Tre +%% +%% ================================================================================================ +%% This was file `titto-lncs-02.bst' produced on Wed Apr 1, 2009 +%% Edited by hand by titto based on `titto-lncs-01.bst' (see below) +%% +%% CHANGES (with respect to titto-lncs-01.bst): +%% - Removed the call to \urlprefix (thus no "URL" string is added to the output) +%% ================================================================================================ +%% This was file `titto-lncs-01.bst' produced on Fri Aug 22, 2008 +%% Edited by hand by titto based on `titto.bst' (see below) +%% +%% CHANGES (with respect to titto.bst): +%% - Removed the "capitalize" command for editors string "(eds.)" and "(ed.)" +%% - Introduced the functions titto.bbl.pages and titto.bbl.page for journal pages (without "pp.") +%% - Added a new.sentence command to separate with a dot booktitle and series in the inproceedings +%% - Commented all new.block commands before urls and notes (to separate them with a comma) +%% - Introduced the functions titto.bbl.volume for handling journal volumes (without "vol." label) +%% - Used for editors the same name conventions used for authors (see function format.in.ed.booktitle) +%% - Removed a \newblock to avoid long spaces between title and "In: ..." +%% - Added function titto.space.prefix to add a space instead of "~" after the (removed) "vol." label +%% ================================================================================================ +%% This was file `titto.bst', +%% generated with the docstrip utility. +%% +%% The original source files were: +%% +%% merlin.mbs (with options: `vonx,nm-rvvc,yr-par,jttl-rm,volp-com,jwdpg,jwdvol,numser,ser-vol,jnm-x,btit-rm,bt-rm,edparxc,bkedcap,au-col,in-col,fin-bare,pp,ed,abr,mth-bare,xedn,jabr,and-com,and-com-ed,xand,url,url-blk,em-x,nfss,') +%% ---------------------------------------- +%% *** Tentative .bst file for Springer LNCS *** +%% +%% Copyright 1994-2007 Patrick W Daly + % =============================================================== + % IMPORTANT NOTICE: + % This bibliographic style (bst) file has been generated from one or + % more master bibliographic style (mbs) files, listed above. + % + % This generated file can be redistributed and/or modified under the terms + % of the LaTeX Project Public License Distributed from CTAN + % archives in directory macros/latex/base/lppl.txt; either + % version 1 of the License, or any later version. + % =============================================================== + % Name and version information of the main mbs file: + % \ProvidesFile{merlin.mbs}[2007/04/24 4.20 (PWD, AO, DPC)] + % For use with BibTeX version 0.99a or later + %------------------------------------------------------------------- + % This bibliography style file is intended for texts in ENGLISH + % This is a numerical citation style, and as such is standard LaTeX. + % It requires no extra package to interface to the main text. + % The form of the \bibitem entries is + % \bibitem{key}... + % Usage of \cite is as follows: + % \cite{key} ==>> [#] + % \cite[chap. 2]{key} ==>> [#, chap. 2] + % where # is a number determined by the ordering in the reference list. + % The order in the reference list is alphabetical by authors. + %--------------------------------------------------------------------- + +ENTRY + { address + author + booktitle + chapter + edition + editor + eid + howpublished + institution + journal + key + month + note + number + organization + pages + publisher + school + series + title + type + url + volume + year + } + {} + { label } +INTEGERS { output.state before.all mid.sentence after.sentence after.block } +FUNCTION {init.state.consts} +{ #0 'before.all := + #1 'mid.sentence := + #2 'after.sentence := + #3 'after.block := +} +STRINGS { s t} +FUNCTION {output.nonnull} +{ 's := + output.state mid.sentence = + { ", " * write$ } + { output.state after.block = + { add.period$ write$ +% newline$ +% "\newblock " write$ % removed for titto-lncs-01 + " " write$ % to avoid long spaces between title and "In: ..." + } + { output.state before.all = + 'write$ + { add.period$ " " * write$ } + if$ + } + if$ + mid.sentence 'output.state := + } + if$ + s +} +FUNCTION {output} +{ duplicate$ empty$ + 'pop$ + 'output.nonnull + if$ +} +FUNCTION {output.check} +{ 't := + duplicate$ empty$ + { pop$ "empty " t * " in " * cite$ * warning$ } + 'output.nonnull + if$ +} +FUNCTION {fin.entry} +{ duplicate$ empty$ + 'pop$ + 'write$ + if$ + newline$ +} + +FUNCTION {new.block} +{ output.state before.all = + 'skip$ + { after.block 'output.state := } + if$ +} +FUNCTION {new.sentence} +{ output.state after.block = + 'skip$ + { output.state before.all = + 'skip$ + { after.sentence 'output.state := } + if$ + } + if$ +} +FUNCTION {add.blank} +{ " " * before.all 'output.state := +} + + +FUNCTION {add.colon} +{ duplicate$ empty$ + 'skip$ + { ":" * add.blank } + if$ +} + +FUNCTION {date.block} +{ + new.block +} + +FUNCTION {not} +{ { #0 } + { #1 } + if$ +} +FUNCTION {and} +{ 'skip$ + { pop$ #0 } + if$ +} +FUNCTION {or} +{ { pop$ #1 } + 'skip$ + if$ +} +STRINGS {z} +FUNCTION {remove.dots} +{ 'z := + "" + { z empty$ not } + { z #1 #1 substring$ + z #2 global.max$ substring$ 'z := + duplicate$ "." = 'pop$ + { * } + if$ + } + while$ +} +FUNCTION {new.block.checka} +{ empty$ + 'skip$ + 'new.block + if$ +} +FUNCTION {new.block.checkb} +{ empty$ + swap$ empty$ + and + 'skip$ + 'new.block + if$ +} +FUNCTION {new.sentence.checka} +{ empty$ + 'skip$ + 'new.sentence + if$ +} +FUNCTION {new.sentence.checkb} +{ empty$ + swap$ empty$ + and + 'skip$ + 'new.sentence + if$ +} +FUNCTION {field.or.null} +{ duplicate$ empty$ + { pop$ "" } + 'skip$ + if$ +} +FUNCTION {emphasize} +{ skip$ } +FUNCTION {tie.or.space.prefix} +{ duplicate$ text.length$ #3 < + { "~" } + { " " } + if$ + swap$ +} +FUNCTION {titto.space.prefix} % always introduce a space +{ duplicate$ text.length$ #3 < + { " " } + { " " } + if$ + swap$ +} + + +FUNCTION {capitalize} +{ "u" change.case$ "t" change.case$ } + +FUNCTION {space.word} +{ " " swap$ * " " * } + % Here are the language-specific definitions for explicit words. + % Each function has a name bbl.xxx where xxx is the English word. + % The language selected here is ENGLISH +FUNCTION {bbl.and} +{ "and"} + +FUNCTION {bbl.etal} +{ "et~al." } + +FUNCTION {bbl.editors} +{ "eds." } + +FUNCTION {bbl.editor} +{ "ed." } + +FUNCTION {bbl.edby} +{ "edited by" } + +FUNCTION {bbl.edition} +{ "edn." } + +FUNCTION {bbl.volume} +{ "vol." } + +FUNCTION {titto.bbl.volume} % for handling journals +{ "" } + +FUNCTION {bbl.of} +{ "of" } + +FUNCTION {bbl.number} +{ "no." } + +FUNCTION {bbl.nr} +{ "no." } + +FUNCTION {bbl.in} +{ "in" } + +FUNCTION {bbl.pages} +{ "pp." } + +FUNCTION {bbl.page} +{ "p." } + +FUNCTION {titto.bbl.pages} % for journals +{ "" } + +FUNCTION {titto.bbl.page} % for journals +{ "" } + +FUNCTION {bbl.chapter} +{ "chap." } + +FUNCTION {bbl.techrep} +{ "Tech. Rep." } + +FUNCTION {bbl.mthesis} +{ "Master's thesis" } + +FUNCTION {bbl.phdthesis} +{ "Ph.D. thesis" } + +MACRO {jan} {"Jan."} + +MACRO {feb} {"Feb."} + +MACRO {mar} {"Mar."} + +MACRO {apr} {"Apr."} + +MACRO {may} {"May"} + +MACRO {jun} {"Jun."} + +MACRO {jul} {"Jul."} + +MACRO {aug} {"Aug."} + +MACRO {sep} {"Sep."} + +MACRO {oct} {"Oct."} + +MACRO {nov} {"Nov."} + +MACRO {dec} {"Dec."} + +MACRO {acmcs} {"ACM Comput. Surv."} + +MACRO {acta} {"Acta Inf."} + +MACRO {cacm} {"Commun. ACM"} + +MACRO {ibmjrd} {"IBM J. Res. Dev."} + +MACRO {ibmsj} {"IBM Syst.~J."} + +MACRO {ieeese} {"IEEE Trans. Software Eng."} + +MACRO {ieeetc} {"IEEE Trans. Comput."} + +MACRO {ieeetcad} + {"IEEE Trans. Comput. Aid. Des."} + +MACRO {ipl} {"Inf. Process. Lett."} + +MACRO {jacm} {"J.~ACM"} + +MACRO {jcss} {"J.~Comput. Syst. Sci."} + +MACRO {scp} {"Sci. Comput. Program."} + +MACRO {sicomp} {"SIAM J. Comput."} + +MACRO {tocs} {"ACM Trans. Comput. Syst."} + +MACRO {tods} {"ACM Trans. Database Syst."} + +MACRO {tog} {"ACM Trans. Graphic."} + +MACRO {toms} {"ACM Trans. Math. Software"} + +MACRO {toois} {"ACM Trans. Office Inf. Syst."} + +MACRO {toplas} {"ACM Trans. Progr. Lang. Syst."} + +MACRO {tcs} {"Theor. Comput. Sci."} + +FUNCTION {bibinfo.check} +{ swap$ + duplicate$ missing$ + { + pop$ pop$ + "" + } + { duplicate$ empty$ + { + swap$ pop$ + } + { swap$ + pop$ + } + if$ + } + if$ +} +FUNCTION {bibinfo.warn} +{ swap$ + duplicate$ missing$ + { + swap$ "missing " swap$ * " in " * cite$ * warning$ pop$ + "" + } + { duplicate$ empty$ + { + swap$ "empty " swap$ * " in " * cite$ * warning$ + } + { swap$ + pop$ + } + if$ + } + if$ +} +FUNCTION {format.url} +{ url empty$ + { "" } +% { "\urlprefix\url{" url * "}" * } + { "\url{" url * "}" * } % changed in titto-lncs-02.bst + if$ +} + +INTEGERS { nameptr namesleft numnames } + + +STRINGS { bibinfo} + +FUNCTION {format.names} +{ 'bibinfo := + duplicate$ empty$ 'skip$ { + 's := + "" 't := + #1 'nameptr := + s num.names$ 'numnames := + numnames 'namesleft := + { namesleft #0 > } + { s nameptr + "{vv~}{ll}{, jj}{, f{.}.}" + format.name$ + bibinfo bibinfo.check + 't := + nameptr #1 > + { + namesleft #1 > + { ", " * t * } + { + s nameptr "{ll}" format.name$ duplicate$ "others" = + { 't := } + { pop$ } + if$ + "," * + t "others" = + { + " " * bbl.etal * + } + { " " * t * } + if$ + } + if$ + } + 't + if$ + nameptr #1 + 'nameptr := + namesleft #1 - 'namesleft := + } + while$ + } if$ +} +FUNCTION {format.names.ed} +{ + 'bibinfo := + duplicate$ empty$ 'skip$ { + 's := + "" 't := + #1 'nameptr := + s num.names$ 'numnames := + numnames 'namesleft := + { namesleft #0 > } + { s nameptr + "{f{.}.~}{vv~}{ll}{ jj}" + format.name$ + bibinfo bibinfo.check + 't := + nameptr #1 > + { + namesleft #1 > + { ", " * t * } + { + s nameptr "{ll}" format.name$ duplicate$ "others" = + { 't := } + { pop$ } + if$ + "," * + t "others" = + { + + " " * bbl.etal * + } + { " " * t * } + if$ + } + if$ + } + 't + if$ + nameptr #1 + 'nameptr := + namesleft #1 - 'namesleft := + } + while$ + } if$ +} +FUNCTION {format.authors} +{ author "author" format.names +} +FUNCTION {get.bbl.editor} +{ editor num.names$ #1 > 'bbl.editors 'bbl.editor if$ } + +FUNCTION {format.editors} +{ editor "editor" format.names duplicate$ empty$ 'skip$ + { + " " * + get.bbl.editor +% capitalize + "(" swap$ * ")" * + * + } + if$ +} +FUNCTION {format.note} +{ + note empty$ + { "" } + { note #1 #1 substring$ + duplicate$ "{" = + 'skip$ + { output.state mid.sentence = + { "l" } + { "u" } + if$ + change.case$ + } + if$ + note #2 global.max$ substring$ * "note" bibinfo.check + } + if$ +} + +FUNCTION {format.title} +{ title + duplicate$ empty$ 'skip$ + { "t" change.case$ } + if$ + "title" bibinfo.check +} +FUNCTION {output.bibitem} +{ newline$ + "\bibitem{" write$ + cite$ write$ + "}" write$ + newline$ + "" + before.all 'output.state := +} + +FUNCTION {n.dashify} +{ + 't := + "" + { t empty$ not } + { t #1 #1 substring$ "-" = + { t #1 #2 substring$ "--" = not + { "--" * + t #2 global.max$ substring$ 't := + } + { { t #1 #1 substring$ "-" = } + { "-" * + t #2 global.max$ substring$ 't := + } + while$ + } + if$ + } + { t #1 #1 substring$ * + t #2 global.max$ substring$ 't := + } + if$ + } + while$ +} + +FUNCTION {word.in} +{ bbl.in capitalize + ":" * + " " * } + +FUNCTION {format.date} +{ + month "month" bibinfo.check + duplicate$ empty$ + year "year" bibinfo.check duplicate$ empty$ + { swap$ 'skip$ + { "there's a month but no year in " cite$ * warning$ } + if$ + * + } + { swap$ 'skip$ + { + swap$ + " " * swap$ + } + if$ + * + remove.dots + } + if$ + duplicate$ empty$ + 'skip$ + { + before.all 'output.state := + " (" swap$ * ")" * + } + if$ +} +FUNCTION {format.btitle} +{ title "title" bibinfo.check + duplicate$ empty$ 'skip$ + { + } + if$ +} +FUNCTION {either.or.check} +{ empty$ + 'pop$ + { "can't use both " swap$ * " fields in " * cite$ * warning$ } + if$ +} +FUNCTION {format.bvolume} +{ volume empty$ + { "" } + { bbl.volume volume tie.or.space.prefix + "volume" bibinfo.check * * + series "series" bibinfo.check + duplicate$ empty$ 'pop$ + { emphasize ", " * swap$ * } + if$ + "volume and number" number either.or.check + } + if$ +} +FUNCTION {format.number.series} +{ volume empty$ + { number empty$ + { series field.or.null } + { output.state mid.sentence = + { bbl.number } + { bbl.number capitalize } + if$ + number tie.or.space.prefix "number" bibinfo.check * * + series empty$ + { "there's a number but no series in " cite$ * warning$ } + { bbl.in space.word * + series "series" bibinfo.check * + } + if$ + } + if$ + } + { "" } + if$ +} + +FUNCTION {format.edition} +{ edition duplicate$ empty$ 'skip$ + { + output.state mid.sentence = + { "l" } + { "t" } + if$ change.case$ + "edition" bibinfo.check + " " * bbl.edition * + } + if$ +} +INTEGERS { multiresult } +FUNCTION {multi.page.check} +{ 't := + #0 'multiresult := + { multiresult not + t empty$ not + and + } + { t #1 #1 substring$ + duplicate$ "-" = + swap$ duplicate$ "," = + swap$ "+" = + or or + { #1 'multiresult := } + { t #2 global.max$ substring$ 't := } + if$ + } + while$ + multiresult +} +FUNCTION {format.pages} +{ pages duplicate$ empty$ 'skip$ + { duplicate$ multi.page.check + { + bbl.pages swap$ + n.dashify + } + { + bbl.page swap$ + } + if$ + tie.or.space.prefix + "pages" bibinfo.check + * * + } + if$ +} +FUNCTION {format.journal.pages} +{ pages duplicate$ empty$ 'pop$ + { swap$ duplicate$ empty$ + { pop$ pop$ format.pages } + { + ", " * + swap$ + n.dashify + pages multi.page.check + 'titto.bbl.pages + 'titto.bbl.page + if$ + swap$ tie.or.space.prefix + "pages" bibinfo.check + * * + * + } + if$ + } + if$ +} +FUNCTION {format.journal.eid} +{ eid "eid" bibinfo.check + duplicate$ empty$ 'pop$ + { swap$ duplicate$ empty$ 'skip$ + { + ", " * + } + if$ + swap$ * + } + if$ +} +FUNCTION {format.vol.num.pages} % this function is used only for journal entries +{ volume field.or.null + duplicate$ empty$ 'skip$ + { +% bbl.volume swap$ tie.or.space.prefix + titto.bbl.volume swap$ titto.space.prefix +% rationale for the change above: for journals you don't want "vol." label +% hence it does not make sense to attach the journal number to the label when +% it is short + "volume" bibinfo.check + * * + } + if$ + number "number" bibinfo.check duplicate$ empty$ 'skip$ + { + swap$ duplicate$ empty$ + { "there's a number but no volume in " cite$ * warning$ } + 'skip$ + if$ + swap$ + "(" swap$ * ")" * + } + if$ * + eid empty$ + { format.journal.pages } + { format.journal.eid } + if$ +} + +FUNCTION {format.chapter.pages} +{ chapter empty$ + 'format.pages + { type empty$ + { bbl.chapter } + { type "l" change.case$ + "type" bibinfo.check + } + if$ + chapter tie.or.space.prefix + "chapter" bibinfo.check + * * + pages empty$ + 'skip$ + { ", " * format.pages * } + if$ + } + if$ +} + +FUNCTION {format.booktitle} +{ + booktitle "booktitle" bibinfo.check +} +FUNCTION {format.in.ed.booktitle} +{ format.booktitle duplicate$ empty$ 'skip$ + { +% editor "editor" format.names.ed duplicate$ empty$ 'pop$ % changed by titto + editor "editor" format.names duplicate$ empty$ 'pop$ + { + " " * + get.bbl.editor +% capitalize + "(" swap$ * ") " * + * swap$ + * } + if$ + word.in swap$ * + } + if$ +} +FUNCTION {empty.misc.check} +{ author empty$ title empty$ howpublished empty$ + month empty$ year empty$ note empty$ + and and and and and + key empty$ not and + { "all relevant fields are empty in " cite$ * warning$ } + 'skip$ + if$ +} +FUNCTION {format.thesis.type} +{ type duplicate$ empty$ + 'pop$ + { swap$ pop$ + "t" change.case$ "type" bibinfo.check + } + if$ +} +FUNCTION {format.tr.number} +{ number "number" bibinfo.check + type duplicate$ empty$ + { pop$ bbl.techrep } + 'skip$ + if$ + "type" bibinfo.check + swap$ duplicate$ empty$ + { pop$ "t" change.case$ } + { tie.or.space.prefix * * } + if$ +} +FUNCTION {format.article.crossref} +{ + key duplicate$ empty$ + { pop$ + journal duplicate$ empty$ + { "need key or journal for " cite$ * " to crossref " * crossref * warning$ } + { "journal" bibinfo.check emphasize word.in swap$ * } + if$ + } + { word.in swap$ * " " *} + if$ + " \cite{" * crossref * "}" * +} +FUNCTION {format.crossref.editor} +{ editor #1 "{vv~}{ll}" format.name$ + "editor" bibinfo.check + editor num.names$ duplicate$ + #2 > + { pop$ + "editor" bibinfo.check + " " * bbl.etal + * + } + { #2 < + 'skip$ + { editor #2 "{ff }{vv }{ll}{ jj}" format.name$ "others" = + { + "editor" bibinfo.check + " " * bbl.etal + * + } + { + bbl.and space.word + * editor #2 "{vv~}{ll}" format.name$ + "editor" bibinfo.check + * + } + if$ + } + if$ + } + if$ +} +FUNCTION {format.book.crossref} +{ volume duplicate$ empty$ + { "empty volume in " cite$ * "'s crossref of " * crossref * warning$ + pop$ word.in + } + { bbl.volume + capitalize + swap$ tie.or.space.prefix "volume" bibinfo.check * * bbl.of space.word * + } + if$ + editor empty$ + editor field.or.null author field.or.null = + or + { key empty$ + { series empty$ + { "need editor, key, or series for " cite$ * " to crossref " * + crossref * warning$ + "" * + } + { series emphasize * } + if$ + } + { key * } + if$ + } + { format.crossref.editor * } + if$ + " \cite{" * crossref * "}" * +} +FUNCTION {format.incoll.inproc.crossref} +{ + editor empty$ + editor field.or.null author field.or.null = + or + { key empty$ + { format.booktitle duplicate$ empty$ + { "need editor, key, or booktitle for " cite$ * " to crossref " * + crossref * warning$ + } + { word.in swap$ * } + if$ + } + { word.in key * " " *} + if$ + } + { word.in format.crossref.editor * " " *} + if$ + " \cite{" * crossref * "}" * +} +FUNCTION {format.org.or.pub} +{ 't := + "" + address empty$ t empty$ and + 'skip$ + { + t empty$ + { address "address" bibinfo.check * + } + { t * + address empty$ + 'skip$ + { ", " * address "address" bibinfo.check * } + if$ + } + if$ + } + if$ +} +FUNCTION {format.publisher.address} +{ publisher "publisher" bibinfo.warn format.org.or.pub +} + +FUNCTION {format.organization.address} +{ organization "organization" bibinfo.check format.org.or.pub +} + +FUNCTION {article} +{ output.bibitem + format.authors "author" output.check + add.colon + new.block + format.title "title" output.check + new.block + crossref missing$ + { + journal + "journal" bibinfo.check + "journal" output.check + add.blank + format.vol.num.pages output + format.date "year" output.check + } + { format.article.crossref output.nonnull + format.pages output + } + if$ +% new.block + format.url output +% new.block + format.note output + fin.entry +} +FUNCTION {book} +{ output.bibitem + author empty$ + { format.editors "author and editor" output.check + add.colon + } + { format.authors output.nonnull + add.colon + crossref missing$ + { "author and editor" editor either.or.check } + 'skip$ + if$ + } + if$ + new.block + format.btitle "title" output.check + crossref missing$ + { format.bvolume output + new.block + new.sentence + format.number.series output + format.publisher.address output + } + { + new.block + format.book.crossref output.nonnull + } + if$ + format.edition output + format.date "year" output.check +% new.block + format.url output +% new.block + format.note output + fin.entry +} +FUNCTION {booklet} +{ output.bibitem + format.authors output + add.colon + new.block + format.title "title" output.check + new.block + howpublished "howpublished" bibinfo.check output + address "address" bibinfo.check output + format.date output +% new.block + format.url output +% new.block + format.note output + fin.entry +} + +FUNCTION {inbook} +{ output.bibitem + author empty$ + { format.editors "author and editor" output.check + add.colon + } + { format.authors output.nonnull + add.colon + crossref missing$ + { "author and editor" editor either.or.check } + 'skip$ + if$ + } + if$ + new.block + format.btitle "title" output.check + crossref missing$ + { + format.bvolume output + format.chapter.pages "chapter and pages" output.check + new.block + new.sentence + format.number.series output + format.publisher.address output + } + { + format.chapter.pages "chapter and pages" output.check + new.block + format.book.crossref output.nonnull + } + if$ + format.edition output + format.date "year" output.check +% new.block + format.url output +% new.block + format.note output + fin.entry +} + +FUNCTION {incollection} +{ output.bibitem + format.authors "author" output.check + add.colon + new.block + format.title "title" output.check + new.block + crossref missing$ + { format.in.ed.booktitle "booktitle" output.check + format.bvolume output + format.chapter.pages output + new.sentence + format.number.series output + format.publisher.address output + format.edition output + format.date "year" output.check + } + { format.incoll.inproc.crossref output.nonnull + format.chapter.pages output + } + if$ +% new.block + format.url output +% new.block + format.note output + fin.entry +} +FUNCTION {inproceedings} +{ output.bibitem + format.authors "author" output.check + add.colon + new.block + format.title "title" output.check + new.block + crossref missing$ + { format.in.ed.booktitle "booktitle" output.check + new.sentence % added by titto + format.bvolume output + format.pages output + new.sentence + format.number.series output + publisher empty$ + { format.organization.address output } + { organization "organization" bibinfo.check output + format.publisher.address output + } + if$ + format.date "year" output.check + } + { format.incoll.inproc.crossref output.nonnull + format.pages output + } + if$ +% new.block + format.url output +% new.block + format.note output + fin.entry +} +FUNCTION {conference} { inproceedings } +FUNCTION {manual} +{ output.bibitem + author empty$ + { organization "organization" bibinfo.check + duplicate$ empty$ 'pop$ + { output + address "address" bibinfo.check output + } + if$ + } + { format.authors output.nonnull } + if$ + add.colon + new.block + format.btitle "title" output.check + author empty$ + { organization empty$ + { + address new.block.checka + address "address" bibinfo.check output + } + 'skip$ + if$ + } + { + organization address new.block.checkb + organization "organization" bibinfo.check output + address "address" bibinfo.check output + } + if$ + format.edition output + format.date output +% new.block + format.url output +% new.block + format.note output + fin.entry +} + +FUNCTION {mastersthesis} +{ output.bibitem + format.authors "author" output.check + add.colon + new.block + format.btitle + "title" output.check + new.block + bbl.mthesis format.thesis.type output.nonnull + school "school" bibinfo.warn output + address "address" bibinfo.check output + format.date "year" output.check +% new.block + format.url output +% new.block + format.note output + fin.entry +} + +FUNCTION {misc} +{ output.bibitem + format.authors output + add.colon + title howpublished new.block.checkb + format.title output + howpublished new.block.checka + howpublished "howpublished" bibinfo.check output + format.date output +% new.block + format.url output +% new.block + format.note output + fin.entry + empty.misc.check +} +FUNCTION {phdthesis} +{ output.bibitem + format.authors "author" output.check + add.colon + new.block + format.btitle + "title" output.check + new.block + bbl.phdthesis format.thesis.type output.nonnull + school "school" bibinfo.warn output + address "address" bibinfo.check output + format.date "year" output.check +% new.block + format.url output +% new.block + format.note output + fin.entry +} + +FUNCTION {proceedings} +{ output.bibitem + editor empty$ + { organization "organization" bibinfo.check output + } + { format.editors output.nonnull } + if$ + add.colon + new.block + format.btitle "title" output.check + format.bvolume output + editor empty$ + { publisher empty$ + { format.number.series output } + { + new.sentence + format.number.series output + format.publisher.address output + } + if$ + } + { publisher empty$ + { + new.sentence + format.number.series output + format.organization.address output } + { + new.sentence + format.number.series output + organization "organization" bibinfo.check output + format.publisher.address output + } + if$ + } + if$ + format.date "year" output.check +% new.block + format.url output +% new.block + format.note output + fin.entry +} + +FUNCTION {techreport} +{ output.bibitem + format.authors "author" output.check + add.colon + new.block + format.title + "title" output.check + new.block + format.tr.number output.nonnull + institution "institution" bibinfo.warn output + address "address" bibinfo.check output + format.date "year" output.check +% new.block + format.url output +% new.block + format.note output + fin.entry +} + +FUNCTION {unpublished} +{ output.bibitem + format.authors "author" output.check + add.colon + new.block + format.title "title" output.check + format.date output +% new.block + format.url output +% new.block + format.note "note" output.check + fin.entry +} + +FUNCTION {default.type} { misc } +READ +FUNCTION {sortify} +{ purify$ + "l" change.case$ +} +INTEGERS { len } +FUNCTION {chop.word} +{ 's := + 'len := + s #1 len substring$ = + { s len #1 + global.max$ substring$ } + 's + if$ +} +FUNCTION {sort.format.names} +{ 's := + #1 'nameptr := + "" + s num.names$ 'numnames := + numnames 'namesleft := + { namesleft #0 > } + { s nameptr + "{ll{ }}{ ff{ }}{ jj{ }}" + format.name$ 't := + nameptr #1 > + { + " " * + namesleft #1 = t "others" = and + { "zzzzz" * } + { t sortify * } + if$ + } + { t sortify * } + if$ + nameptr #1 + 'nameptr := + namesleft #1 - 'namesleft := + } + while$ +} + +FUNCTION {sort.format.title} +{ 't := + "A " #2 + "An " #3 + "The " #4 t chop.word + chop.word + chop.word + sortify + #1 global.max$ substring$ +} +FUNCTION {author.sort} +{ author empty$ + { key empty$ + { "to sort, need author or key in " cite$ * warning$ + "" + } + { key sortify } + if$ + } + { author sort.format.names } + if$ +} +FUNCTION {author.editor.sort} +{ author empty$ + { editor empty$ + { key empty$ + { "to sort, need author, editor, or key in " cite$ * warning$ + "" + } + { key sortify } + if$ + } + { editor sort.format.names } + if$ + } + { author sort.format.names } + if$ +} +FUNCTION {author.organization.sort} +{ author empty$ + { organization empty$ + { key empty$ + { "to sort, need author, organization, or key in " cite$ * warning$ + "" + } + { key sortify } + if$ + } + { "The " #4 organization chop.word sortify } + if$ + } + { author sort.format.names } + if$ +} +FUNCTION {editor.organization.sort} +{ editor empty$ + { organization empty$ + { key empty$ + { "to sort, need editor, organization, or key in " cite$ * warning$ + "" + } + { key sortify } + if$ + } + { "The " #4 organization chop.word sortify } + if$ + } + { editor sort.format.names } + if$ +} +FUNCTION {presort} +{ type$ "book" = + type$ "inbook" = + or + 'author.editor.sort + { type$ "proceedings" = + 'editor.organization.sort + { type$ "manual" = + 'author.organization.sort + 'author.sort + if$ + } + if$ + } + if$ + " " + * + year field.or.null sortify + * + " " + * + title field.or.null + sort.format.title + * + #1 entry.max$ substring$ + 'sort.key$ := +} +ITERATE {presort} +SORT +STRINGS { longest.label } +INTEGERS { number.label longest.label.width } +FUNCTION {initialize.longest.label} +{ "" 'longest.label := + #1 'number.label := + #0 'longest.label.width := +} +FUNCTION {longest.label.pass} +{ number.label int.to.str$ 'label := + number.label #1 + 'number.label := + label width$ longest.label.width > + { label 'longest.label := + label width$ 'longest.label.width := + } + 'skip$ + if$ +} +EXECUTE {initialize.longest.label} +ITERATE {longest.label.pass} +FUNCTION {begin.bib} +{ preamble$ empty$ + 'skip$ + { preamble$ write$ newline$ } + if$ + "\begin{thebibliography}{" longest.label * "}" * + write$ newline$ + "\providecommand{\url}[1]{\texttt{#1}}" + write$ newline$ + "\providecommand{\urlprefix}{URL }" + write$ newline$ +} +EXECUTE {begin.bib} +EXECUTE {init.state.consts} +ITERATE {call.type$} +FUNCTION {end.bib} +{ newline$ + "\end{thebibliography}" write$ newline$ +} +EXECUTE {end.bib} +%% End of customized bst file +%% +%% End of file `titto.bst'. + + diff --git a/cryptominisat/cppsrc/docs/satcomp20-pdf/ccanr/Makefile b/cryptominisat/cppsrc/docs/satcomp20-pdf/ccanr/Makefile new file mode 100644 index 00000000..73bfce54 --- /dev/null +++ b/cryptominisat/cppsrc/docs/satcomp20-pdf/ccanr/Makefile @@ -0,0 +1,24 @@ +TEX = pdflatex -shell-escape -interaction=nonstopmode -file-line-error +PRE = $(TEX) -ini -job-name="preamble" "&pdflatex preamble.tex\dump" +BIB = bibtex + +all: cms-ccanr.pdf + +view : + okular cms-ccanr.pdf + +cms-ccanr.pdf : clean cms-ccanr.tex cms-ccanr.bbl cms-ccanr.blg + $(TEX) cms-ccanr.tex + $(TEX) cms-ccanr.tex + +cms-ccanr.bbl cmsv5.blg : cms-ccanr.bib cms-ccanr.aux + $(BIB) cms-ccanr + +cms-ccanr.aux : cms-ccanr.tex + $(TEX) cms-ccanr.tex + +cms-ccanr.bib : cms-ccanr.tex + $(TEX) cms-ccanr.tex + +clean: + rm -f *.log *.pdf *.blg *.bbl *.aux *.out *.backup diff --git a/cryptominisat/cppsrc/docs/satcomp20-pdf/ccanr/cms-ccanr.tex b/cryptominisat/cppsrc/docs/satcomp20-pdf/ccanr/cms-ccanr.tex new file mode 100644 index 00000000..f66de773 --- /dev/null +++ b/cryptominisat/cppsrc/docs/satcomp20-pdf/ccanr/cms-ccanr.tex @@ -0,0 +1,88 @@ +\documentclass[final]{ieee} + +\usepackage{microtype} %This gives MUCH better PDF results! +\usepackage[cmex10]{amsmath} +\usepackage{amssymb} +\usepackage{fnbreak} %warn for split footnotes +\usepackage{url} +\usepackage[utf8]{inputenc} % allows to write Faugere correctly +\usepackage[bookmarks=true, citecolor=black, linkcolor=black, colorlinks=true]{hyperref} +\hypersetup{ +pdfauthor = {Mate Soos, Shaowei Cai}, +pdftitle = {CryptoMiniSat + CCAnr}, +pdfsubject = {SAT Competition 2020}, +pdfkeywords = {SAT Solver, DPLL, SLS}} +%\usepackage{butterma} + +%\usepackage{pstricks} +\usepackage{graphicx,epsfig,xcolor} + +\begin{document} +\title{CryptoMiniSat with CCAnr at the SAT Competition 2020} +\author{Mate Soos (National University of Singapore)\\ +Shaowei Cai (State Key Laboratory of Computer Science,\\ +Institute of Software, Chinese Academy of Sciences)\\ +Jo Devriendt, Stephan Gocht (Lund University \& University of Copenhagen)\\ +Arijit Shaw, Kuldeep S. Meel (National University of Singapore)} + +\maketitle +\thispagestyle{empty} +\pagestyle{empty} + +\section{Introduction} +This paper presents the conflict-driven clause-learning (CLDL) SAT solver CryptoMiniSat (\emph{CMS}) augmented with the Stochastic Local Search (SLS)~\cite{DBLP:conf/sat/CaiLS15} solver CCAnr as submitted to SAT Competition 2020. + +CryptoMiniSat aims to be a modern, open source SAT solver using inprocessing techniques, optimized data structures and finely-tuned timeouts to have good control over both memory and time usage of inprocessing steps. CryptoMiniSat is authored by Mate Soos. + +CCAnr~\cite{DBLP:conf/sat/CaiLS15} is a stochastic local search (SLS) solver for SAT, which is based on the configuration checking strategy and has good performance on non-random SAT instances. CCAnr switches between two modes: it flips a variable according to the CCA (configuration checking with aspiration) heuristic if any; otherwise, it flips a variable in a random unsatisfied clause (which we refer to as the focused local search mode). The main novelty of CCAnr lies on the greedy heuristic in the focused local search mode, which contributes significantly to its good performance on structured instances + +\section{Composing the Two Solvers} +The two solvers are composed together in a way that does \emph{not} resemble portfolio solvers. The system runs the CDCL solver CryptoMiniSat, along with its periodic inprocessing, by default. However, at every 2nd inprocessing step, CryptoMiniSat's irredundant clauses are pushed into CCAnr (in case the predicted memory use is not too high). CCAnr is then allowed to run for a predefined number of steps. This in total leads to about 1\% of all solving time dedicated to CCAnr. In case CCAnr finds a satisfying assignment, this is given back to the CDCL solver, which then performs all the necessary extension to the solution (e.g. for Bounded Variable Elimination, BVE~\cite{BVE}) and outputs the final solution. + +In case CCAnr does not find a satisfying assignment, the following takes place. Firstly, the best variable setting found by CCAnr as measured by the number of satisfied clauses, is assigned as the polarity of the variables in the CDCL SAT solver. This idea has been taken from the solver CaDiCaL~\cite{cadical} as submitted to the 2019 SAT Race by Armin Biere. +% +Secondly, after every successful execution of CCAnr, 100 variables' VSIDS are bumped in the following way. CCAnr uses a clause weighting technique and clauses with greater weight can be considered more difficult to satisfy. Once CCAnr finishes, CCAnr's clauses are sorted according to their weights. Then, these clauses' variables' VSIDS are bumped, from hardest-to-easiest clause order, until 100 variables' VSIDS have been bumped. +% +This shows clear improvement in the combined solver's performance. We believe these two integrations point to potential tighter, as-yet unexplored integration opportunities of the two solvers. + +Note that the inclusion of the SLS solver is full in the sense that assumptions-based solving, library-based solver use, and all other uses of the SAT solver is fully supported with SLS solving enabled. Hence, this is not some form of portfolio where a simple shell script determines which solver to run and then runs that solver. Instead, the SLS solver is a full member of the solver, much like any other inprocessing system, and works in tandem with it. For example, in case an inprocessing step has reduced the number of variables through BVE or increased it through BVA~\cite{BVA}, the SLS solver will then try to solve the problem thus modified. In case the SLS solver finds a solution, the main solver will then correctly manipulate it to fit the needs of the ``outside world'', i.e. the caller. + +As the two solvers are well-coupled, the combination of the two solvers can solve problems that neither system can solve on its own. Hence, \emph{the system is more than just a union of its parts} which is not the case for traditional portfolio solvers. + +\section{Gauss-Jordan Elimination} +As per the upcoming paper~\cite{birdtwo}, the Gauss-Jordan elimination of CryptoMiniSat has been significantly improved. The average speed increase for moderately sized matrices is approx 3-6x, allowing the system to be ran at all times even when the matrix is not contributing as much to the overall solving. Hence, for the first time in CryptoMiniSat's 10 year history, Gauss-Jordan elimination is turned on by default for the NoLimits track. + + +\section{Symmetry Breaking using BreakID and Bliss} +The BreakID~\cite{breakid2016} system is a cost-effective symmetry breaking preprocessor for SAT. +Classic SAT symmetry preprocessing~\cite{shatter2006} detects symmetry by converting the input formula to a graph and computing generators for this graph's automorphism group, and adds symmetry breaking clauses on a generator-by-generator basis. +On top of this, BreakID heuristically searches for structure in the automorphism group, detecting \emph{row interchangeability symmetry} (such as in the pigeonhole problem) and computing binary symmetry breaking clauses from orbits arising from the symmetry group. +The resulting symmetry breaking clauses are more effective at reducing symmetrical assignments from the search space, both from a theory point of view as well as in practical experiments. + +BreakID has been modified to work as a library. It can receive the clauses on-the-fly from the SAT solver, and produce the breaking clauses as a function return value. Various small bugs have also be fixed, such as memory leaks, which were not an issue when ran as a single executable, but created isses when ran as a library. Furthermore, the underlying highly sophisticated graph automorphism detection system, Bliss~\cite{DBLP:conf/alenex/JunttilaK07}, has been slightly improved to allow for time-outs and it, too, has been fixed not to leak memory. BreakID is fully integrated into CryptoMiniSat by calling it on every 5th inprocessing iteration, and asked to contribute breaking clauses. These are always added with an assumption literal, so they can be removed when the solving finishes. Hence, symmetry breaking also works when CryptoMiniSat is used as a library. + + +\section{Phase Selection using LSIDS} +LSIDS is a literal activity-based phase selection heuristic~\cite{shaw2020designing}. LSIDS activity is maintained for each literal, and the activity for a literal is updated in a manner similar to VSIDS. Phase selection is made based on LSIDS activity only if the last backtrack is chronological. The LSIDS based phase selection heuristic looks at the activity of both the literals of a given variable and selects the literal with higher activity. + + +\section{Further Improvements Relative to SAT Race 2019} +Many of the inprocessing parameters have been tuned. A few bugs related to clause activities have been fixed. Clause distillation (or clause vivification)~\cite{DBLP:journals/ai/LiXLMLL20} is now used a lot more, similarly to the previous years' winning solvers. The VSIDS and Maple decay factors are now iteratively changed between 0.70 and 0.90 for Maple and 0.92 and 0.99 for VSIDS. Between each iteration there is an inprocessing step, as before. This seems to add heterogeneity and avoids having to tune these parameters to a ``single best'' value. Polarity caching is still used, but once in a while, so-called ``stable'' polarities are used, as per CaDiCaL~\cite{cadical} in the SAT Race of 2019. Ternary resolution is also used at every inprocessing step, thanks to the suggestion by Armin Biere. + + +\section{Thanks} +Kuldeep S Meel, Arijit Shaw, and Mate Soos were supported in part by the National Research Foundation Singapore under its NRF Fellowship Programme[NRF-NRFFAI1-2019-0004 ] and AI Singapore Programme [AISG-RP-2018-005], and NUS ODPRT Grant [R-252-000-685-13]. + +Shaowei Cai was supported by Beijing Academy of Artificial Intelligence (BAAI), and Youth Innovation Pro-motion Association, Chinese Academy of Sciences [No. 2017150]. + +Stephan Gocht was funded by the Swedish Research Council (VR) grant \mbox{2016-00782}. + +The computational work for this article was performed on resources of the National Supercomputing Center, Singapore\cite{nscc}. Mate Soos would also like to thank all the users of CryptoMiniSat who have submitted over 600 issues and pull requests to the GitHub CMS repository\cite{CMS}. + +\bibliographystyle{splncs03} +\bibliography{sigproc} + +\vfill +\pagebreak + +\end{document} diff --git a/cryptominisat/cppsrc/docs/satcomp20-pdf/ccanr/ieee.cls b/cryptominisat/cppsrc/docs/satcomp20-pdf/ccanr/ieee.cls new file mode 100644 index 00000000..3c57bba5 --- /dev/null +++ b/cryptominisat/cppsrc/docs/satcomp20-pdf/ccanr/ieee.cls @@ -0,0 +1,1497 @@ +% Copyright 2014 IEEEE +% for terms of use see https://www.ieee.org/publications_standards/publications/rights/copyrightpolicy.html + +% ========================================================================= +% ------------------------------------------------------------------------- +% XX X +% X +% XX XXX XXX XXX XXX X XXXX +% X X X X X X X X X X X +% X XXXXX XXXXX XXXXX X X XXX +% X X X X XX X X X X +% XXX XXX XXX XXX XX XXX X XXXX +% ------------------------------------------------------------------------- +% ========================================================================= +% ieee.cls --- For formatting IEEE conference & journal papers +% --- Compiled by Gregory Plett, Sept 1997 +% +% This class was inspired by one first compiled by Gerry Murray and +% Silvano Balemi for LaTeX209. It was later updated for use with +% LaTeX2e, and some bugs were fixed, all by Istvan Kollar. Lastly, +% I have tried to make the class easier to use by paper authors. +% Significant new functionality has been added. Many routines are +% "borrowed" from other people's packages and modified extensively. +% When I rembered where I got the routines from, I gave the author +% credit. +% +% After I made many changes on my own, I found a version by Peter +% N"uchter, and tried to retain some amount of compatibility with his +% version. To be completely compatible with him, you may need to +% manually: +% \usepackage{rawfonts}\usepackage{oldlfont} +% \AtBeginDocument{\parindent1.0em} (?) +% +%=========================================================================== +% +% Usage: +% \documentclass[main-mode,sub-mode,misc-options]{ieee} +% \usepackage{your own packages} +% \begin{document} +% \bibliographystyle{IEEEbib} +% \title[short]{regular} +% \author[short]{full} +% \maketitle +% \begin{abstract}...\end{abstract} +% \begin{keywords}...\end{keywords} +% \section{...} +% \PARstart ... or \PARstartCal ... +% ... +% \begin{biography}[picname.ps]{Author's name}...\end{biography} +% \end{document} +% +% The document class options are: +% +% main-mode: One of the following is required. (draft is the default) +% draft: Double-spaced, single column with date/time stamp. +% submission: Double-spaced, suitable for submission for review. +% compressed: Same as "submission", only single spaced. +% final: Double-column, for assessing page-length and +% format of final version. +% +% sub-mode: +% techreport: This can modify "final" to produce a two-col +% technical report. +% internal: This can modify "submission", "compressed" or "final". +% It changes the header to notify the reader that +% this is a version of the manuscript to be used for +% internal review processes only, and not to be +% distributed. +% submitted: This can modify "compressed" or "final". It changes +% the header to notify the reader that this +% is a preprint and not to be distributed. +% inpress: This can modify "compressed" or "final". It changes the +% header to notify the reader that this paper has +% been accepted for publishing, but it is not yet to be +% distributed. +% reprint: This can modify "final". It changes the header +% to notify the reader where the paper is reprinted from. +% +% misc-options: +% narroweqnarray: Changes the spacing around the "=" sign in +% equation arrays to make it the same as in displayed math. +% inline: Compresses the horizontal spacing of inline math equations. +% notitlepage: No separate title page. (default) +% titlepage: Separate title page. +% anonymous: Omit all author information from main part of paper. +% Author info only prints on titlepage. +% 9pt,10pt,11pt,12pt: Choose the appropriate type size. You should +% not need to do this as the "correct" size is automatically +% chosen. However, if you want, you may use these to change +% the type size of the main text. "9pt" is a bit of a hack +% to retain backward-compatibility. +% invited: If the paper is an "invited" paper, then this option +% prints "(Invited Paper)" under the authors' names. +% +% For regular IEEE submissions, define the journal name as: +% \journal{IEEE Trans. Inst. Meas.} +% +% To specify the conference place and date: +% \confplacedate{Ottawa, Canada, May 19--21, 1997} +% +% Before \maketitle, define: +% \title{Title of paper} +% \author{Author1\member{Fellow}\authorinfo{Department of +% Electrical Engineering\\ Some University, Somewhere, CA 94305 +% USA} \and Author2\member{Senior Member}\authorinfo{Deptartment of +% Measurement and Instrument Eng., Another University, ...}} +% +% Note, the contents of \authorinfo tends to vary depending on if it is +% a conference or journal paper. The amount of manual changes are +% small, and must be done by a human anyway. The example given is for an +% IMTC conference. +% +% See also IEEEbib.bst and ieeefig.sty +% Also very useful for document preparation is the style file "endfloat", +% available on all CTAN TeX archives. +% +%=========================================================================== +% modified 14 October 2002: +% - fixed bibliography listing of [#] when # < 10 and number of +% references is greater than 9. Thanks for Janos Markus for finding +% this bug and suggesting a solution. +% modified 15 January 2000: +% - "fixed" narroweqnarray. Never implemented! Now it is... +% modified 12 January 2000: +% - modified so only first \title and \author commands are recognized. +% This allows LyX to have \title and \author with full syntax in +% header, but dummy \title and \author show up in GUI. +% - added "\date" so the \date command can change "submitted" and +% "draft" date headers. +% modified 11 January 2000: +% - added PARstartLyX and PARstartCalLyX for LyX compatibility +% - added biographyLyX +% modified 1 Dec 1997: +% - fixed first page in reprint mode to be same length as other pages +% - added "invited" misc-option +% modified 5 Sept 1997: +% - added the inpress, reprint and internal sub-modes +% - removed IMTC-conf and CDC-conf to separate files +% modified 1 Sept 1997: +% - included Babel package compatibility +% - removed paper title from header on first page of draft +% manuscript +% - removed the fixed option "letterpaper" to allow a4paper (etc) +% modified 1 Aug 1997: +% - included the CDC-conf option +%=========================================================================== +% ************************************************************************** +% ****** ****************************************** +% ***** LaTeX2e INITIALIZATION ***************************************** +% ****** ****************************************** +% ************************************************************************** +\typeout{Document Class `ieee' .} +\NeedsTeXFormat{LaTeX2e}[1993/11/11] % Oldest acceptable version of LaTeX2e +\ProvidesClass{ieee}[2000/01/11] % Name of package provided, date +\def\i@@@cls{exists} + +% Initial Code & Declaration of Options +% ------------------------------------- +\newif\ifev@l \ev@lfalse % true if "final" mode. +\newif\ifsubm@t \subm@tfalse % true if "submission" mode. +\newif\ifdr@ft \dr@fttrue % true if "draft" mode. +\newif\ifc@mpress \c@mpressfalse % true if "compressed" mode. + +\newif\if@technote \@technotefalse % true if "technote" sub-mode. +\newif\ifintern@l \intern@lfalse % true if "internal" sub-mode. +\newif\ifprepr@nt \prepr@ntfalse % true if "preprint" sub-mode. +\newif\ifinpr@ss \inpr@ssfalse % true if "inpress" sub-mode. +\newif\ifrepr@nt \repr@ntfalse % true if "reprint" sub-mode. + +\newif\iftitlep@ge \titlep@gefalse % true if has own titlepage +\newif\if@non \@nonfalse % true if anonymous +\newif\ifixpt \ixptfalse % true if trying to do 9 pt +\newif\if@nvited \@nvitedfalse % true if an invited paper + +% Main options +% ------------ +\DeclareOption{draft}{\ev@lfalse\subm@tfalse\dr@fttrue% + \typeout{ieee: `Draft' mode selected.}} +\DeclareOption{submission}{\ev@lfalse\dr@ftfalse\subm@ttrue% + \typeout{ieee: `Submission' mode selected.}} +\DeclareOption{compressed}{\ev@lfalse\dr@ftfalse\subm@tfalse\c@mpresstrue% + \typeout{ieee: `Compressed' mode selected.}} +\DeclareOption{final}{\ev@ltrue\dr@ftfalse\subm@tfalse% + \typeout{ieee: `Final' mode selected.}} +\DeclareOption{evaluation}{\ev@ltrue\dr@ftfalse\subm@tfalse% + \typeout{ieee: `Final' mode selected.}} % synonym for final + +% Sub options +% ----------- +\DeclareOption{technote}{\@technotetrue% + \typeout{ieee: `Technote' sub-mode selected.}} +\DeclareOption{internal}{\intern@ltrue\prepr@ntfalse\inpr@ssfalse\repr@ntfalse% + \typeout{ieee: `Internal-Review' sub-mode selected.}} +\DeclareOption{submitted}{\intern@lfalse\prepr@nttrue\inpr@ssfalse\repr@ntfalse% + \typeout{ieee: `Submitted' sub-mode selected.}} +\DeclareOption{preprint}{\intern@lfalse\prepr@nttrue\inpr@ssfalse\repr@ntfalse% + \typeout{ieee: `Submitted' sub-mode selected.}} % synonym for submitted +\DeclareOption{inpress}{\intern@lfalse\prepr@ntfalse\inpr@sstrue\repr@ntfalse% + \typeout{ieee: `Inpress' sub-mode selected.}} +\DeclareOption{reprint}{\intern@lfalse\prepr@ntfalse\inpr@ssfalse\repr@nttrue% + \typeout{ieee: `Reprint' sub-mode selected.}} + +% Misc options +% ------------ + % regular or compressed "=" spacing in +\def\eqnarr@ysep{\arraycolsep} % eqnarray (this is the default) + % NOTE: we must use "def" and not "=" + % as arraycolsep not yet defined. +\DeclareOption{narroweqnarray}{\gdef\eqnarr@ysep{0.28em\relax}% + \typeout{ieee: Narrow equation arrays selected.}} +\DeclareOption{inline}{\everymath{\thinmuskip=2mu plus 1mu + \medmuskip=3mu plus 1mu minus 2mu + \thickmuskip=4mu plus 2mu\relax}% + \typeout{ieee: Narrower inline equations selected.}} +\DeclareOption{notitlepage}{\titlep@gefalse% + \typeout{ieee: No separate title page.}} +\DeclareOption{titlepage}{\titlep@getrue% + \typeout{ieee: Use separate title page.}} +\DeclareOption{anonymous}{\@nontrue\AtBeginDocument{\glpexclude{biography}} + \typeout{ieee: Omit author information from paper.}} +\DeclareOption{invited}{\@nvitedtrue% + \typeout{ieee: (Invited Paper).}} + +\DeclareOption{9pt}{\ixpttrue% + \typeout{ieee: Trying to emulate old `9pt' document class.}} + +\DeclareOption*{\PassOptionsToClass{\CurrentOption}{article}} + +% Execution of Options/Package Loading +% ------------------------------------ +\newlength\narrowcol +\newlength\parindentsave % recover parindent in blsone text + +\ProcessOptions +\ifev@l % if "final" mode... + \if@technote\ixpttrue\typeout{ieee: Trying to emulate old `9pt' + document class.}\fi% + \LoadClass[twoside,final,twocolumn,10pt]{article} +\else % if "draft"/"submission"/(compressed) mode... + \ifixpt + \LoadClass[oneside,final,onecolumn,10pt]{article} + \else + \LoadClass[oneside,final,onecolumn,12pt]{article} + \fi +\fi +\RequirePackage[final]{graphicx} +\RequirePackage{ifthen} + +% Re-Definitions of English words which must be done before +% the Babel package (optional) is loaded. +% --------------------------------------------------------- +\def\keywordsname{Index Terms} +\def\indexterms#1{\def\keywordsname{#1}} +\def\appendicesname{Appendices} +\def\figurename{Fig.} + +% ************************************************************************** +% ***** Check Sub-Options for Compatibility w/ Main-Options ************ +% ************************************************************************** +\if@technote\ifev@l\else\ClassError{ieee}{`technote' sub-mode may be + used only with the `final' ^^Jmain-mode. It may not be used + with either the `draft,' `submission,' or ^^J`compressed' + main-modes}{}\endinput\fi\fi +\ifintern@l\ifdr@ft\ClassError{ieee}{`internal' sub-mode may be + used only with the ^^J`submission,' `compressed,' or `final' main-modes. + It may not be used ^^Jwith the `draft' main-mode}{}\endinput\fi\fi +\ifprepr@nt\ifc@mpress\else\ifev@l\else\ClassError{ieee}{`submitted' + sub-mode may be used only with the ^^J`compressed' or `final' + main-modes. It may not be used with either the ^^J`draft' or + `submission' main-modes}{}\endinput\fi\fi\fi +\ifinpr@ss\ifc@mpress\else\ifev@l\else\ClassError{ieee}{`inpress' + sub-mode may be used only with the `compressed' ^^Jor `final' + main-modes. It may not be used with either the `draft' or + ^^J`submission' main-modes}{}\endinput\fi\fi\fi +\ifrepr@nt\ifev@l\else\ClassError{ieee}{`reprint' + sub-mode may be used only with the `final' ^^Jmain-mode. It may not be + used with either the `draft,' `submission,' or ^^J`compressed' + main-modes}{}\endinput\fi\fi + +% ************************************************************************** +% ***** Page Layout Definition ***************************************** +% ************************************************************************** +%% Layout definitions (mostly) common to all options. + +\hoffset 0in \voffset 0in +\headheight 12pt \headsep 7mm +\marginparsep 10pt \marginparwidth 20pt +\marginparpush 25pt +\columnsep 4mm +\parindent 1.0em +\lineskip 1pt +\normallineskip 1pt +\def\baselinestretch{1} + +\partopsep \z@ +\topsep 1.3ex +\parsep \z@ +\itemsep \z@ + +\setlength{\parindentsave}{\parindent} + +\ifev@l % if "evaluation" mode + % if camera-ready or A4paper ... + \ifdim\paperwidth<211mm + \oddsidemargin -11.4mm \evensidemargin -11.4mm + % for regular US Letter, not camera-ready + \else + \oddsidemargin -8.45mm \evensidemargin -8.45mm + \fi + \ifrepr@nt + \textheight 237.5mm % leave 6mm for cpyright on first page + \else + \textheight 243.5mm + \fi + \voffset -0.5in + \textwidth 182.0mm + \topmargin -12pt + \setlength{\narrowcol}{89mm} +\else % if "draft"/"submission" mode... + \ifc@mpress % and "compressed" + \oddsidemargin -0.25in \evensidemargin -0.25in + \textheight 9in \textwidth 7in + \topmargin -0.25in + \setlength{\narrowcol}{7in} + \else % and NOT "compressed" + \renewcommand\baselinestretch{1.8}\renewcommand{\arraystretch}{0.8} + \parindent=1.8\parindent + \oddsidemargin 0pt \evensidemargin 0pt + \headheight 12pt \headsep 0.375in + \topmargin 0pt + \textheight 8.5in \textwidth 6.5in + \marginparsep 0in \marginparwidth 0pt + \marginparpush 5pt + \setlength{\narrowcol}{6.5in} + \fi +\fi + +\def\normalstyle{\rmfamily} + +% ************************************************************************** +% ***** Font Definition ************************************************ +% ************************************************************************** +%% The 9-point option is being faked since it is not supported by the +%% article base class. + +%% Check if we have selected 9 points +\ifixpt +\typeout{-- This is a 9 point document} +\gdef\@ptsize{9} +\def\@normalsize{\@setsize\normalsize{10.7pt}\ixpt\@ixpt +\abovedisplayskip 1em plus2pt minus5pt\belowdisplayskip \abovedisplayskip +\abovedisplayshortskip \z@ plus3pt\belowdisplayshortskip .6em plus3pt minus3pt +\topsep \belowdisplayshortskip%!PN +} +\def\small{\@setsize\small{9.12pt}\viiipt\@viipt} +\def\footnotesize{\@setsize\footnotesize{8.15pt}\viipt\@vipt} +\def\scriptsize{\@setsize\scriptsize{8pt}\vipt\@vpt} +\def\tiny{\@setsize\tiny{5pt}\vpt\@vpt} +\def\large{\@setsize\large{12pt}\xpt\@xpt} +\def\Large{\@setsize\Large{14pt}\xiipt\@xiipt} +\def\LARGE{\@setsize\LARGE{18pt}\xivpt\@xivpt} +\def\huge{\@setsize\huge{22pt}\xviipt\@xviipt} +\def\Huge{\@setsize\Huge{25pt}\xxpt\@xxpt} +\fi +%% +%% Check if we have selected 10 points +\def\@tempa{0}\if\@ptsize\@tempa +\typeout{-- This is a 10 point document} +\def\@normalsize{\@setsize\normalsize{11.9pt}\xpt\@xpt +\abovedisplayskip 1em plus2pt minus5pt\belowdisplayskip \abovedisplayskip +\abovedisplayshortskip \z@ plus3pt\belowdisplayshortskip .6em plus3pt minus3pt +\topsep \belowdisplayshortskip%!PN +} +\def\small{\@setsize\small{9.2pt}\viiipt\@viiipt} +\def\footnotesize{\@setsize\footnotesize{8.8pt}\viiipt\@viiipt} +\def\scriptsize{\@setsize\scriptsize{8pt}\viipt\@viipt} +\def\tiny{\@setsize\tiny{6pt}\vpt\@vpt} +\def\normalsize{\@setsize\normalsize{11.9pt}\xpt\@xpt} +\def\large{\@setsize\large{14pt}\xiipt\@xiipt} +\def\Large{\@setsize\Large{18pt}\xivpt\@xivpt} +\def\LARGE{\@setsize\LARGE{22pt}\xviipt\@xviipt} +\def\huge{\@setsize\huge{22pt}\xxpt\@xxpt} +\def\Huge{\@setsize\Huge{28pt}\xxvpt\@xxvpt} +\fi +%% +%% Check if we have selected 11 points +\def\@tempa{1}\if\@ptsize\@tempa +\typeout{-- This is an 11 point document} +\def\@normalsize{\@setsize\normalsize{13.6pt}\xipt\@xipt +\abovedisplayskip 1em plus2pt minus5pt\belowdisplayskip \abovedisplayskip +\abovedisplayshortskip \z@ plus3pt\belowdisplayshortskip .6em plus3pt minus3pt +\topsep \belowdisplayshortskip%!PN +} +\def\small{\@setsize\small{12pt}\xpt\@xpt} +\def\footnotesize{\@setsize\footnotesize{11pt}\ixpt\@ixpt} +\def\scriptsize{\@setsize\scriptsize{9.5pt}\viiipt\@viiipt} +\def\tiny{\@setsize\tiny{7pt}\vipt\@vipt} +\def\normalsize{\@setsize\normalsize{13.6pt}\xipt\@xipt} +\def\large{\@setsize\large{14pt}\xiipt\@xiipt} +\def\Large{\@setsize\Large{18pt}\xivpt\@xivpt} +\def\LARGE{\@setsize\LARGE{22pt}\xviipt\@xviipt} +\def\huge{\@setsize\huge{25pt}\xxpt\@xxpt} +\def\Huge{\@setsize\Huge{30pt}\xxvpt\@xxvpt} +\fi +%% +%% Check if we have selected 12 points +\def\@tempa{2}\if\@ptsize\@tempa +\typeout{-- This is a 12 point document} +\def\@normalsize{\@setsize\normalsize{14pt}\xiipt\@xiipt +\abovedisplayskip 1em plus3pt minus6pt\belowdisplayskip \abovedisplayskip +\abovedisplayshortskip \z@ plus3pt\belowdisplayshortskip .6em plus4pt minus4pt +\topsep \belowdisplayshortskip%!PN +} +\def\small{\@setsize\small{11.4pt}\xpt\@xpt} +\def\footnotesize{\@setsize\footnotesize{10pt}\ixpt\@ixpt} +\def\scriptsize{\@setsize\scriptsize{9pt}\viiipt\@viiipt} +\def\tiny{\@setsize\tiny{8pt}\vipt\@vipt} +\def\normalsize{\@setsize\normalsize{14pt}\xiipt\@xiipt} +\def\large{\@setsize\large{18pt}\xivpt\@xivpt} +\def\Large{\@setsize\Large{22pt}\xviipt\@xviipt} +\def\LARGE{\@setsize\LARGE{25pt}\xxpt\@xxpt} +\def\huge{\@setsize\huge{30pt}\xxvpt\@xxvpt} +\let\Huge=\huge +\fi + +\AtBeginDocument{\normalsize\normalstyle\ps@headings\pagenumbering{arabic}} + +% ************************************************************************** +% ***** List Definition ************************************************ +% ************************************************************************** +%% Change aspect of lists with +%% 1) \itemindent, label indentation wrt to left list margin +%% 2) \leftmargini, the indentation of the whole list (on left, first level) +\ifev@l + \itemindent -1em + \leftmargini 2em + \leftmarginii 1em + \leftmarginiii 1.5em + \leftmarginiv 1.5em + \leftmarginv 1.0em + \leftmarginvi 1.0em +\else + \itemindent -1em + \leftmargini 3em + \leftmarginii 3em + \leftmarginiii 3em + \leftmarginiv 3em + \leftmarginv 3em + \leftmarginvi 3em +\fi +%\itemindent 2em % Alternative values: sometimes used.. +%\leftmargini 0em +\labelsep 5pt +\leftmargin\leftmargini +\labelwidth \z@ + +\def\@listI{\leftmargin\leftmargini} \@listI +\def\@listi{\leftmargin\leftmargini \topsep \z@ plus 1pt minus 1pt} +\def\@listii{\leftmargin\leftmarginii\labelwidth\leftmarginii + \advance\labelwidth-\labelsep \topsep \z@} +\def\@listiii{\leftmargin\leftmarginiii\labelwidth\leftmarginiii + \advance\labelwidth-\labelsep \topsep \z@} +\def\@listiv{\leftmargin\leftmarginiv\labelwidth\leftmarginiv + \advance\labelwidth-\labelsep \topsep \z@} +\def\@listv{\leftmargin\leftmarginv\labelwidth\leftmarginv + \advance\labelwidth-\labelsep \topsep \z@} +\def\@listvi{\leftmargin\leftmarginvi\labelwidth\leftmarginvi + \advance\labelwidth-\labelsep \topsep \z@} + +\def\labelenumi{\theenumi.} \def\theenumi{\arabic{enumi}} +\def\labelenumii{(\theenumii)} \def\theenumii{\alph{enumii}} +\def\labelenumiii{\theenumiii.} \def\theenumiii{\roman{enumiii}} +\def\labelenumiv{\theenumiv.} \def\theenumiv{\Alph{enumiv}} +\def\p@enumii{\theenumi} +\def\p@enumiii{\theenumi(\theenumii)} +\def\p@enumiv{\p@enumiii\theenumiii} + +\def\labelitemi{$\scriptstyle\bullet$} +\def\labelitemii{\bf --} +\def\labelitemiii{$\ast$} +\def\labelitemiv{$\cdot$} + +%% \itemindent is set to \z@ by list, so define new temporary variable +\newdimen\tmpitemindent +\def\verse{\let\\=\@centercr + \list{}{\itemsep\z@ \itemindent -1.5em \listparindent \itemindent + \rightmargin\leftmargin\advance\leftmargin 1.5em}\item[]} +\let\endverse\endlist +\def\quotation{\list{}{\listparindent 1.5em \itemindent\listparindent + \rightmargin\leftmargin \parsep 0pt plus 1pt}\item[]} +\let\endquotation=\endlist +\def\quote{\list{}{\rightmargin\leftmargin}\item[]} +\let\endquote=\endlist +\def\@mklab#1{#1} +\def\description{\tmpitemindent\itemindent\list{}{\itemindent\tmpitemindent + \labelwidth\z@\def\makelabel##1{\hspace\labelsep\emph{##1}}}} +\def\enddescription{\endlist\par} +\def\enumerate{\tmpitemindent\itemindent\ifnum \@enumdepth >3 \@toodeep\else + \advance\@enumdepth \@ne \edef\@enumctr{enum\romannumeral\the\@enumdepth}% + \list{\csname label\@enumctr\endcsname}{\itemindent\tmpitemindent + \usecounter{\@enumctr}\def\makelabel##1{\hspace\labelsep\hfil{##1}}}\fi} +\def\endenumerate{\endlist\par} +\def\itemize{\tmpitemindent\itemindent\ifnum \@itemdepth >3 \@toodeep\else + \advance\@itemdepth\@ne + \edef\@itemitem{labelitem\romannumeral\the\@itemdepth}% + \list{\csname\@itemitem\endcsname}{\itemindent\tmpitemindent + \def\makelabel##1{\hspace\labelsep\hfil\emph{##1}}}\fi} +\def\enditemize{\endlist\par} + +\newif\if@restonecol +\def\titlepage{\@restonecolfalse\if@twocolumn\@restonecoltrue\onecolumn + \else \newpage \fi \thispagestyle{coverpagestyle}\c@page\z@} +\def\endtitlepage{\if@restonecol\twocolumn \else \newpage \fi% +\if@twoside\mbox{}\thispagestyle{coverpagestyle}\c@page\z@\cleardoublepage\fi} + +\arraycolsep 5pt +\tabcolsep 6pt +\arrayrulewidth .4pt +\doublerulesep 2pt +\tabbingsep\labelsep + +% ************************************************************************** +% ***** Footnote Definition ******************************************** +% ************************************************************************** +\skip\footins 10pt plus 5pt minus 2pt +\footnotesep 7pt +\footskip 6mm +\skip\@mpfootins = \skip\footins +\fboxsep = 3pt \fboxrule = .4pt +\long\def\@makefntext#1{\parindent .8em\indent$^{\@thefnmark}$#1} +\def\footnoterule{} + +% Reset baselinestretch within footnotes. +% Originally stolen from Stanford University thesis style. +% -------------------------------------------------------- +\long\def\@footnotetext#1{\insert\footins{\blsone% + \footnotesize\interlinepenalty\interfootnotelinepenalty + \splittopskip\footnotesep + \splitmaxdepth \dp\strutbox \floatingpenalty \@MM + \hsize\columnwidth \@parboxrestore + \edef\@currentlabel{\csname p@footnote\endcsname\@thefnmark}\@makefntext + \let\par\\ + {\rule{\z@}{\footnotesep}\ignorespaces + #1\strut}}} + +% ************************************************************************** +% ***** Keep track of Sections ***************************************** +% ************************************************************************** +\if@technote + \setcounter{secnumdepth}{3} +\else + \setcounter{secnumdepth}{4} +\fi + +\def\thesection{\@Roman\c@section} +\def\thesubsection{\Alph{subsection}} +\def\thesubsubsection{\thesubsection.\arabic{subsubsection}} +\def\thesubsubsectiondis{\Alph{subsection}.\arabic{subsubsection}} +\def\theparagraph{\thesubsubsection.\alph{paragraph}} +\def\theparagraphdis{\thesubsubsectiondis.\alph{paragraph}} + +\def\theequation{\arabic{equation}} + +% ************************************************************************** +% ***** Table of Contents, List of Figures/Tables Definitions ********** +% ************************************************************************** +\def\@pnumwidth{1.55em} +\def\@tocrmarg {2.55em} +\def\@dotsep{4.5} +\setcounter{tocdepth}{3} + +\def\tableofcontents{\section*{\contentsname}\@starttoc{toc}} +\def\l@section#1#2{\addpenalty{\@secpenalty} \addvspace{1.0em plus 1pt} + \@tempdima 1.8em \begingroup \parindent \z@ \rightskip \@pnumwidth + \parfillskip-\@pnumwidth \bf\leavevmode #1\hfil\hbox to\@pnumwidth{\hss #2} + \par \endgroup} +\def\l@subsection{\@dottedtocline{2}{1.5em}{2.3em}} +\def\l@subsubsection{\@dottedtocline{3}{3.8em}{3.2em}} +\def\listoffigures{\section*{\listfigurename}\@starttoc{lof}} +\def\l@figure{\@dottedtocline{1}{1em}{1.8em}} +\def\listoftables{\section*{\listtablename}\@starttoc{lot}} +\let\l@table\l@figure + +% ************************************************************************** +% ***** Float Definitions ********************************************** +% ************************************************************************** +%% Normal Floats %% Double Column Floats +\floatsep 12pt plus 2pt minus 2pt \dblfloatsep 12pt plus 2pt minus 2pt +\textfloatsep 20pt plus 2pt minus 4pt \dbltextfloatsep 20pt plus 2pt minus 4pt +%\@maxsep 20pt \@dblmaxsep 20pt %!PN +\@fptop 0pt plus 1fil \@dblfptop 0pt plus 1fil +\@fpsep 8pt plus 2fil \@dblfpsep 8pt plus 2fil +\@fpbot 0pt plus 1fil \@dblfpbot 0pt plus 1fil +\def\topfraction{1.0} \def\dbltopfraction{1.0} +\def\floatpagefraction{0.8} \def\dblfloatpagefraction{0.8} +\setcounter{topnumber}{2} \setcounter{dbltopnumber}{4} +% +\intextsep 12pt plus 2pt minus 2pt +\setcounter{bottomnumber}{2} +\def\bottomfraction{.4} +\setcounter{totalnumber}{4} +\def\textfraction{.2} + +% Reset baselinestretch within floats. +% Originally stolen from Stanford University thesis style. +% -------------------------------------------------------- +\def\@xfloat#1[#2]{\ifhmode \@bsphack\@floatpenalty -\@Mii\else + \@floatpenalty-\@Miii\fi\def\@captype{#1}\ifinner + \@parmoderr\@floatpenalty\z@ + \else\@next\@currbox\@freelist{\@tempcnta\csname ftype@#1\endcsname + \multiply\@tempcnta\@xxxii\advance\@tempcnta\sixt@@n + \@tfor \@tempa :=#2\do + {\if\@tempa h\advance\@tempcnta \@ne\fi + \if\@tempa t\advance\@tempcnta \tw@\fi + \if\@tempa b\advance\@tempcnta 4\relax\fi + \if\@tempa p\advance\@tempcnta 8\relax\fi + }\global\count\@currbox\@tempcnta}\@fltovf\fi + \global\setbox\@currbox\vbox\bgroup + \def\baselinestretch{1}\small\normalsize + \hsize\columnwidth \@parboxrestore} + +% ************************************************************************** +% ***** Caption Definition ********************************************* +% ************************************************************************** +% some journals do not have centered captions for figures. +\newif\ifc@ptionleft \c@ptionlefttrue +\def\leftfigcaptions{\c@ptionlefttrue} +\def\centerfigcaptions{\c@ptionleftfalse} + +\long\def\caption{\refstepcounter\@captype \@dblarg{\@caption\@captype}} + +\long\def\@caption#1[#2]#3{\par\addcontentsline{\csname ext@#1\endcsname}{#1}{% + \protect\numberline{\csname the#1\endcsname}{\ignorespaces #2}} + \begingroup \@parboxrestore \normalsize + \@makecaption{\csname fnum@#1\endcsname}{\ignorespaces #3}{#1}\par + \endgroup} + +\def\tablestring{table} +\def\figurestring{figure} + +% changed by GLP to allow table captions to be set to a specific maximum +% width "\captionwidth", if defined. +\newlength{\captionindent} +\long\def\@makecaption#1#2#3{ +\ifx\figurestring#3 + \vskip 5pt + \setbox\@tempboxa\hbox{\small #1.~ #2} + \ifdim \wd\@tempboxa >\hsize + \setbox\@tempboxa\hbox{\small #1.~ } + %\setlength\captionindent{\wd\@tempboxa} \divide\captionindent by 2 + %\parbox[t]{\hsize}{\small \hangindent \captionindent \hangafter=1% + \parbox[t]{\hsize}{\small + \unhbox\@tempboxa#2} + \else \hbox + to\hsize{\small\ifc@ptionleft\else\hfil\fi\box\@tempboxa\hfil} + \fi +\else + \begin{center} + \ifx\captionwidth\undefined {\small #1}\\{\small\scshape #2} + \else + \begin{minipage}{\captionwidth} + \begin{center}{\small #1}\\{\small\scshape #2}\end{center} + \end{minipage} + \fi + \end{center}\vskip 4pt +\fi} + +\def\thefigure{\@arabic\c@figure} +\def\fps@figure{tbp} +\def\ftype@figure{1} +\def\ext@figure{lof} +\def\fnum@figure{\figurename\ \thefigure} +%\def\figure{\@float{figure}} % GLP +%\let\endfigure\end@float +\@namedef{figure*}{\@dblfloat{figure}} +\@namedef{endfigure*}{\end@dblfloat} + +\def\thetable{\@Roman\c@table} +\def\fps@table{tbp} +\def\ftype@table{2} +\def\ext@table{lot} +\def\fnum@table{TABLE~\thetable} +\def\table{\@float{table}} +\let\endtable\end@float +\@namedef{table*}{\@dblfloat{table}} +\@namedef{endtable*}{\end@dblfloat} + +% ************************************************************************** +% ***** Header/Footer Definition *************************************** +% ************************************************************************** +% compute the time in hours and minutes; make new vars \timehh and \timemm +\newcount\timehh\newcount\timemm\timehh=\time\divide\timehh by 60 +\timemm=\time\count255=\timehh\multiply\count255 by-60 +\advance\timemm by \count255 +\ifnum\timehh=12\def\apm{pm}\else +\ifnum\timehh>12\def\apm{pm}\advance\timehh by-12\else +\def\apm{am}\fi\fi +\def\t@me{\number\timehh\,:\,\ifnum\timemm<10 0\fi\number\timemm\,\apm} + +% default definitions +% ------------------- +\def\theevenhe@d{\footnotesize\thepage \hfil \leftmark\hbox{}} +\def\theoddhe@d{\hbox{}\footnotesize\rightmark \hfil \thepage} +\def\theevenf@@t{} +\def\theoddf@@t{} + +\def\theeventphe@d{\footnotesize\thepage \hfil \hbox{}} +\def\theoddtphe@d{\hbox{}\footnotesize \hfil \thepage} +\def\theeventpf@@t{} +\def\theoddtpf@@t{} + +\def\theevencphe@d{} +\def\theoddcphe@d{} +\def\theevencpf@@t{} +\def\theoddcpf@@t{} + +\def\internalmsg{Preliminary version for evaluation: Please do not + circulate without the permission of the author(s)} +\def\submittedmsg{SUBMITTED FOR PUBLICATION TO:} +\def\acceptedmsg{ACCEPTED FOR PUBLICATION:} +\def\inpressmsg{(IN PRESS)} +\def\reprintmsg{REPRINTED FROM:} + +% default cover page style (optional cover page) +% ---------------------------------------------- +\def\ps@coverpagestyle{ + \def\@oddhead{\theoddcphe@d} \def\@evenhead{\theevencphe@d} + \def\@oddfoot{\theoddcpf@@t} \def\@evenfoot{\theevencpf@@t} +} + +% default title page style (first page of paper) +% ---------------------------------------------- +\def\ps@titlepagestyle{ + \def\@oddhead{\theoddtphe@d} \def\@evenhead{\theeventphe@d} + \def\@oddfoot{\theoddtpf@@t} \def\@evenfoot{\theeventpf@@t} +} + +% default regular page style +% -------------------------- +\if@twoside + \def\ps@headings{ + \def\@oddhead{\theoddhe@d} + \def\@evenhead{\theevenhe@d} + \def\@oddfoot{\theoddf@@t} \def\@evenfoot{\theevenf@@t} + } +\else + \def\ps@headings{ + \def\@oddhead{\theoddhe@d} + \def\@oddfoot{\theoddf@@t} + \def\@evenhead{} \def\@evenfoot{} + } +\fi + +% For draft mode (no sub-modes allowed) +% ------------------------------------- +\ifdr@ft + \def\leftmark{\sh@rttitle}\let\rightmark\leftmark + \def\theoddf@@t{\footnotesize\today---\t@me\hfil DRAFT} + \def\theevenf@@t{\footnotesize DRAFT\hfil\today---\t@me} + \def\theoddtpf@@t{\footnotesize\today---\t@me\hfil DRAFT} + \def\theeventpf@@t{\footnotesize DRAFT\hfil\today---\t@me} +\fi + +% For submission mode (default plus internal sub-modes allowed) +% ------------------------------------------------------------- +\ifsubm@t + \def\leftmark{\sh@rttitle}\def\rightmark{\titl@line} + \ifintern@l + \def\theeventphe@d{\footnotesize\thepage \hfil \rightmark\hbox{}} + \def\theoddtphe@d{\hbox{}\footnotesize\rightmark \hfil \thepage} + \def\rightmark{\vbox to 0pt{\vss\hbox{\internalmsg} \hbox{\sh@rttitle}}} + \def\leftmark{\vbox to 0pt{\vss\hbox{\internalmsg} + \hbox{\phantom{\internalmsg}\llap{\sh@rttitle}}}} + \else % put date on first page. + \edef\TODAY{\uppercase{\today}} + \def\theeventphe@d{\footnotesize\thepage \hfil \submittedmsg\ + \@journal\@titletext, \TODAY} + \def\theoddtphe@d{\footnotesize\submittedmsg\ + \@journal\@titletext, \TODAY\hfil \thepage} + \def\theevencphe@d{\footnotesize\hbox{} \hfil \submittedmsg\ + \@journal\@titletext, \TODAY} + \def\theoddcphe@d{\footnotesize\submittedmsg\ + \@journal\@titletext, \TODAY\hfil \hbox{}} + \fi +\fi + +% For compressed mode (default, internal, submitted and +% inpress sub-modes allowed) +% ----------------------------------------------------- +\ifc@mpress + \def\leftmark{\sh@rttitle}\def\rightmark{\titl@line} + \ifintern@l + \def\theeventphe@d{\footnotesize\thepage \hfil \rightmark\hbox{}} + \def\theoddtphe@d{\hbox{}\footnotesize\rightmark \hfil \thepage} + \def\rightmark{\vbox to 0pt{\vss\hbox{\internalmsg} \hbox{\sh@rttitle}}} + \def\leftmark{\vbox to 0pt{\vss\hbox{\internalmsg} + \hbox{\phantom{\internalmsg}\llap{\sh@rttitle}}}} + \fi + \ifprepr@nt + \edef\TODAY{\uppercase{\today}} + \def\theeventphe@d{\footnotesize\thepage \hfil \submittedmsg\ + \@journal\@titletext, \TODAY} + \def\theoddtphe@d{\footnotesize\submittedmsg\ + \@journal\@titletext, \TODAY\hfil \thepage} + \def\theevencphe@d{\footnotesize\hbox{} \hfil \submittedmsg\ + \@journal\@titletext, \TODAY} + \def\theoddcphe@d{\footnotesize\submittedmsg\ + \@journal\@titletext, \TODAY\hfil \hbox{}} + \fi + \ifinpr@ss + \def\leftmark{\acceptedmsg\ \@journal\@titletext, \inpressmsg} + \def\theeventphe@d{\footnotesize\thepage \hfil \leftmark\hbox{}} + \def\theoddtphe@d{\hbox{}\footnotesize\leftmark \hfil \thepage} + \fi +\fi + +% For final (evaluate) mode (default, techreport, internal, +% submitted, inpress and reprint sub-modes allowed) +% --------------------------------------------------------- +\ifev@l + \edef\TODAY{\uppercase{\today}} + \def\leftmark{\@journal\@titletext}\def\rightmark{\titl@line} + \def\theeventphe@d{\footnotesize\thepage \hfil \leftmark\hbox{}} + \def\theoddtphe@d{\hbox{}\footnotesize\leftmark \hfil \thepage} + \if@technote % make header a little bigger + \def\theevenhe@d{\small\thepage \hfil \leftmark\hbox{}} + \def\theoddhe@d{\hbox{}\small\rightmark \hfil \thepage} + \def\theeventphe@d{\small\thepage \hfil \leftmark\hbox{}} + \def\theoddtphe@d{\hbox{}\small\leftmark \hfil \thepage} + \fi + \ifintern@l + \def\theeventphe@d{\footnotesize\thepage \hfil \rightmark\hbox{}} + \def\theoddtphe@d{\hbox{}\footnotesize\rightmark \hfil \thepage} + \def\rightmark{\vbox to 0pt{\vss\hbox{\internalmsg} \hbox{\sh@rttitle}}} + \def\leftmark{\vbox to 0pt{\vss\hbox{\internalmsg} + \hbox{\phantom{\internalmsg}\llap{\sh@rttitle}}}} + \fi + \ifprepr@nt + \def\leftmark{\submittedmsg\ \@journal\@titletext, \TODAY} + \fi + \ifinpr@ss + \def\leftmark{\acceptedmsg\ \@journal\@titletext, \inpressmsg} + \fi + \ifrepr@nt + % reset page size on second and following pages b/c no copyright info + \let\oldshipout\shipout + \gdef\shipout{\global\textheight 243.5mm\oldshipout} + \def\theeventpf@@t{\footnotesize\hfil\@ieeecopyright\hfil} + \def\theoddtpf@@t{\footnotesize\hfil\@ieeecopyright\hfil} + \def\leftmark{\reprintmsg\ \@journal\@titletext} + \fi +\fi + +%% Defines the command for putting the header. footernote{TEXT} is the same +%% as markboth{TEXT}{TEXT}. Here for compatibility with other style files. +\def\markboth#1#2{\def\leftmark{#1}\def\rightmark{#2}} +\def\footernote#1{\markboth{#1}{#1}} + +% ************************************************************************** +% ***** Citation/Bibliography Definitions ****************************** +% ************************************************************************** +%% separate citations with "], [" +\def\@citex[#1]#2{\if@filesw\immediate\write\@auxout{\string\citation{#2}}\fi +\def\@citea{}\@cite{\@for\@citeb:=#2\do {\@citea\def\@citea{], +[}\@ifundefined {b@\@citeb}{{\bf ?}\@warning {Citation `\@citeb' on +page \thepage \space undefined}}% +{\csname b@\@citeb\endcsname}}}{#1}} + +\def\@cite#1#2{[{#1\if@tempswa, #2\fi}]} + +%% Allow short (name-less) citations, when used in conjunction with a +%% bibliography style that creates labels like \citename{, } +\let\@internalcite\cite +\def\cite{\def\citename##1{##1}\@internalcite} +\def\shortcite{\def\citename##1{}\@internalcite} +\def\@biblabel#1{\def\citename##1{##1}[#1]\hfill} + +\def\thebibliography#1{\section*{\refname}\footnotesize\list + {\hss[\arabic{enumi}]}{\settowidth\labelwidth{[#1]}\leftmargin\labelwidth + \advance\leftmargin\labelsep \itemsep 0pt plus .5pt + \usecounter{enumi}} + \def\newblock{\hskip .11em plus .33em minus .07em} + \sloppy\clubpenalty4000\widowpenalty4000 + \sfcode`\.=1000\relax + \ifev@l\else\normalsize\fi %added by GLP +} +\let\endthebibliography=\endlist + +% ************************************************************************** +% ***** Appendix/Appendices Definitions ******************************** +% ************************************************************************** +\newcounter{numappendices}\setcounter{numappendices}{0} +\newif\ifappendix \appendixfalse +%% appendix command for one single appendix +\def\appendix{\par + \appendixtrue + \typeout{appendices: \arabic{numappendices}} + \setcounter{section}{0}\setcounter{subsection}{0} + \gdef\thesection{\Alph{section}} + \ifnum \value{numappendices}>1 + \section*{\appendicesname} + \else + \section*{\appendixname} + \fi + \setcounter{numappendices}{0} +} +%% appendices command for multiple appendicies +\def\appendices{\par + \appendixtrue + \typeout{appendices: \arabic{numappendices}} + \setcounter{section}{0}\setcounter{subsection}{0} + \gdef\thesection{\Alph{section}} \section*{\appendicesname} + \setcounter{numappendices}{0} +} +\AtEndDocument{\if@filesw\immediate\write\@auxout{\string\setcounter{numappendices}{\arabic{numappendices}}}\fi} + +% ************************************************************************** +% ***** Title Definitions ********************************************** +% ************************************************************************** +\def\titl@line{\sh@rttitle} %for the header at the top of the page. + +\def\@title{\typeout{ieee: Warning! No \noexpand\title given!}} +\def\title{\@ifnextchar [{\titlea}{\titleb}}%] + +\def\set@title#1{\gdef\@title{#1}\global\def\set@title##1{}} +\def\setsh@rttitle#1{\gdef\sh@rttitle{#1}\global\def\setsh@rttitle##1{}} +\def\titlea[#1]#2{\set@title{#2}\setsh@rttitle{\uppercase{#1}}} +\def\titleb#1{\set@title{#1}\setsh@rttitle{\uppercase{#1}}} + +\def\authorinfo#1{\let\\\relax\thanks{#1}} + +\ifev@l + \if@technote + \def\member#1{} + \else + \def\member#1{, \emph{#1, IEEE}} + \fi +\else + \def\member#1{} +\fi + +\def\and{\unskip% % \begin{tabular} +\end{tabular}% +\hskip 0pt plus 0.1pt% +\begin{tabular}[t]{@{}c@{}}\ }% + +\def\@author{\typeout{ieee: Warning! No \noexpand\author given!}} +\def\author{\@ifnextchar [{\authora}{\authorb}}%] +\def\set@author#1{\gdef\@author{#1}\global\def\set@author##1{}} +\def\settitl@line#1{\gdef\titl@line{#1}\global\def\settitl@line##1{}} +\def\authora[#1]#2{\set@author{#2}\if@non\else\settitl@line{#1: \sh@rttitle}\fi} +\def\authorb#1{\set@author{#1}} + +\def\date#1{\def\today{#1}\edef\TODAY{\uppercase{\today}}} + +\long\def\maketitle{% + \begingroup + \let\@thanks\@empty + \renewcommand\thefootnote{} % the \thanks{} mark type is empty + \iftitlep@ge\begin{titlepage}\@maketitlepage\@thanks\end{titlepage}% + \let\@thanks\@empty\fi + \thispagestyle{titlepagestyle} + \if@twocolumn + \if@technote + %\if@twoside\newpage\cleardoublepage\else\newpage\fi% + \newpage\global\@topnum\z@ + \ifrepr@nt + \ifx\@loginfo\undefined\typeout{ieee: Warning! No \noexpand\loginfo + given!}\else\let\\\relax\thanks{\@loginfo}\fi% + \fi + \@maketitle + \else + \ifnum \col@number=\@ne + \ifrepr@nt + \ifx\@loginfo\undefined\typeout{ieee: Warning! No \noexpand\loginfo + given!}\else\let\\\relax\thanks{\@loginfo}\fi% + \fi + \@maketitle + \else \twocolumn[% + \ifrepr@nt% + \ifx\@loginfo\undefined\typeout{ieee: Warning! No \noexpand\loginfo% + given!}\else\let\\\relax\thanks{\@loginfo}\fi% + \fi% + \@maketitle]% + \fi + \fi + \else + \newpage + \global\@topnum\z@ % Prevents figures from going at top of page. + \ifrepr@nt + \ifx\@loginfo\undefined\typeout{ieee: Warning! No \noexpand\loginfo + given!}\else\let\\\relax\thanks{\@loginfo}\fi + \fi + \@maketitle + \fi + \thispagestyle{titlepagestyle}% + \@thanks + \endgroup + \setcounter{footnote}{0}% + \global\let\thanks\relax \global\let\maketitle\relax + \global\let\@maketitle\relax \global\let\@thanks\@empty + \global\let\@author\@empty \global\let\@date\@empty + \global\let\@title\@empty \global\let\title\relax + \global\let\author\relax \global\let\date\relax + \global\let\and\relax +} + +\long\def\@maketitle{\unskip\newpage% + \begin{center}\blsone + \let \footnote \thanks + \if@technote + {\bfseries\@title\par}\if@non\else\vskip 1.3em{\lineskip .5em + \noindent\begin{tabular}[t]{@{}c@{}}\@author\end{tabular}}\fi\par + \else\unskip + \noindent{\Huge\@title\par}% + \if@non\else\vskip1.0em% + \noindent{\large\lineskip .5em% + \begin{tabular}[t]{@{}c@{}}\@author\end{tabular}}% + \fi\par% + \if@nvited\vskip1.0em\noindent\emph{\large(Invited Paper)}\par\fi + \fi + \ifrepr@nt + \ifx\@lognumber\undefined\typeout{ieee: Warning! No + \noexpand\pubitemident or \noexpand\lognumber + given!}\else\thanks{\@lognumber}\fi% + \fi + \end{center}\par\vskip 0.5em}% + +\long\def\@maketitlepage{\newpage% + \mbox{}\vfil + \begin{center}\blsone + \let \footnote \thanks + \if@technote + {\bfseries\@title\par}\vskip 1.3em{\lineskip .5em + \noindent\begin{tabular}[t]{@{}c@{}}\@author\end{tabular}\par} + \else + \vskip0.2em{\Huge\@title\par}\vskip1.0em% + \iftitlep@ge\vfil\fi + \noindent{\large\lineskip .5em% + \begin{tabular}[t]{@{}c@{}}\@author\end{tabular}\par}% + \fi + \end{center}\par\vfil\mbox{}} + +\def\@journal{\typeout{ieee: Warning! No \noexpand\journal given!}} +\def\journal#1{\def\@journal{\uppercase{#1}}} + +\def\@ieeecopyright{\typeout{ieee: Warning! No \noexpand\ieeecopyright given!}} +\def\ieeecopyright#1{\def\@ieeecopyright{#1}} + +\def\lognumber#1{\def\@lognumber{IEEE Log Number #1.}} +\def\pubitemident#1{\def\@lognumber{Publisher Item Identifier #1.}} +\long\def\loginfo#1{\long\def\@loginfo{\hbox{\vrule height 3ex width \z@}#1}} + +\def\sh@rttitle{} +\def\@titletext{} +\def\titletext#1{\def\@titletext{#1}} + +\def\firstpage#1{\setcounter{page}{#1}} + +% ************************************************************************** +% ***** Abstract Definition ******************************************** +% ************************************************************************** +\def\abstract{% + \if@twocolumn + \small\bfseries{\itshape\abstractname\/---}% + \else + \begin{center}\vspace{-0.8em}\small\bf\abstractname\end{center} + \quotation\small + \fi\ignorespaces} +\def\endabstract{\vspace{0.6em}\par\if@twocolumn\else\endquotation\fi + \normalsize\normalstyle} + +% ************************************************************************** +% ***** Keywords Definition ******************************************** +% ************************************************************************** +\def\keywords{\vspace{-.3em} + \if@twocolumn + \small\bfseries{\itshape\keywordsname\/---}% + \else + \begin{center}\small\bf\keywordsname\end{center}\quotation\small + \fi\ignorespaces} +\def\endkeywords{\vspace{0.6em}\par\if@twocolumn\else\endquotation\fi + \normalsize\normalstyle} + +% ************************************************************************** +% ***** Fix Section Numbering ****************************************** +% ************************************************************************** +\gdef\@punct{.\ \ } % Punctuation after run-in section heading +\def\@sect#1#2#3#4#5#6[#7]#8{% + \ifnum #2>\c@secnumdepth + \def\@svsec\@empty + \else + \refstepcounter{#1}% + \protected@edef\@svsec{% + %\ifnum #2=1\Roman{#1}.\fi\ifnum #2=2\Alph{#1}.\fi + \ifnum #2=1\thesection.\fi + \ifnum #2=2\thesubsection.\fi + \ifnum #2>2{\csname the#1dis\endcsname}\if@technote.\fi\fi \hskip .5em} + \ifnum #2=1\ifappendix\stepcounter{numappendices}\fi\fi + \fi + \@tempskipa #5\relax + \ifdim \@tempskipa>\z@ + \begingroup #6\relax + \@hangfrom{\hskip #3\relax\@svsec}{\interlinepenalty \@M #8\par} + \endgroup + \csname #1mark\endcsname{#7} + \addcontentsline{toc}{#1}{\ifnum #2>\c@secnumdepth\else + \protect\numberline{\csname the#1\endcsname}\fi#7} + \else + \def\@svsechd{#6\hskip #3\@svsec #8\@punct\csname #1mark\endcsname{#7} + \addcontentsline{toc}{#1}{\ifnum #2>\c@secnumdepth \else + \protect\numberline{\csname the#1\endcsname}\fi#7}} + \fi + \@xsect{#5}} + +\def\@ssect#1#2#3#4#5{\@tempskipa #3\relax + \ifdim \@tempskipa>\z@ + \begingroup #4\@hangfrom{\hskip #1}{\interlinepenalty \@M #5\par}\endgroup + \else \def\@svsechd{#4\hskip #1\relax #5\@punct}\fi + \@xsect{#3}} + +% ************************************************************************** +% ***** Section Definitions ******************************************** +% ************************************************************************** +\def\section{\@startsection{section}{1}{\z@}{2.0ex plus .5ex + minus .2ex}{1.0ex plus .2ex}{\centering\scshape}} +\def\subsection{\@startsection{subsection}{2}{\z@}{2.0ex plus .5ex + minus .2ex}{1.0ex plus .2ex}{\itshape}} +\if@technote + \def\subsubsection{\@startsection{subsubsection}{3}{\z@}{2.0ex plus .5ex + minus .1ex}{0pt}{\itshape}} +\else + \def\subsubsection{\@startsection{subsubsection}{3}{\z@}{2.0ex plus .5ex + minus .2ex}{1.0ex plus .2ex}{\normalstyle}} + \def\paragraph{\@startsection{paragraph}{4}{\z@}{1.0ex plus .5ex + minus .2ex}{0ex}{\normalstyle}} +\fi + +% ************************************************************************** +% ***** Special Environment Definitions ******************************** +% ************************************************************************** +\def\QED{\mbox{\rule[0pt]{1.5ex}{1.5ex}}} +\def\proof{\noindent\hspace{1em}{\it Proof: }} +\def\endproof{\hspace*{\fill}~\QED\par\endtrivlist\unskip} +\def\@begintheorem#1#2{\tmpitemindent\itemindent\topsep 0pt\normalstyle\trivlist + \item[\hskip \labelsep{\indent\it #1\ #2:}]\itemindent\tmpitemindent} +\def\@opargbegintheorem#1#2#3{\tmpitemindent\itemindent\topsep 0pt\normalstyle \trivlist + \item[\hskip\labelsep{\indent\it #1\ #2\ \normalstyle(#3)}]\itemindent\tmpitemindent} +\def\@endtheorem{\endtrivlist\unskip} + +% ************************************************************************** +% ***** Special Environment Definitions ******************************** +% ************************************************************************** +\if@twoside\else\raggedbottom\fi + +%% Definition for Big letter at the beginning of a paragraph +%% +\def\PARstart#1#2 {\begingroup\def\par{\endgraf\endgroup\lineskiplimit=0pt} + \setbox2=\hbox{\uppercase{#2} }\newdimen\tmpht \tmpht \ht2 + \advance\tmpht by \baselineskip\font\hhuge=cmr10 at \tmpht + \setbox1=\hbox{{\hhuge #1}} + \count7=\tmpht \count8=\ht1\divide\count8 by 1000 \divide\count7 by\count8 + \tmpht=.001\tmpht\multiply\tmpht by \count7\font\hhuge=cmr10 at \tmpht + \setbox1=\hbox{{\hhuge #1}} \noindent \hangindent1.05\wd1 + \hangafter=-2 {\hskip-\hangindent \lower1\ht1\hbox{\raise1.0\ht2\copy1}% + \kern-0\wd1}\copy2\lineskiplimit=-1000pt} + +\def\PARstartCal#1#2 {\begingroup\def\par{\endgraf\endgroup\lineskiplimit=0pt} + \setbox2=\hbox{\uppercase{#2} }\newdimen\tmpht \tmpht \ht2 + \advance\tmpht by \baselineskip\font\hhuge=cmsy10 at \tmpht + \setbox1=\hbox{{\hhuge #1\/}} + \count7=\tmpht \count8=\ht1\divide\count8 by 1000 \divide\count7 by\count8 + \tmpht=.001\tmpht\multiply\tmpht by \count7\font\hhuge=cmsy10 at \tmpht + \setbox1=\hbox{{\hhuge #1\/}} \noindent \hangindent1.05\wd1 + \hangafter=-2 {\hskip-\hangindent \lower1\ht1\hbox{\raise1.0\ht2\copy1}% + \kern-0\wd1}\copy2\lineskiplimit=-1000pt} + +\def\PARstartLyX#1{\PARstart #1} +\def\PARstartCalLyX#1{\PARstartCal #1} + +\if@technote\def\PARstart#1#2{#1#2}\fi % if technical note, disable it +\if@technote\def\PARstartCal#1#2{#1#2}\fi % if technical note, disable it +\if@technote\def\PARstartLyX#1{#1}\fi % if technical note, disable it +\if@technote\def\PARstartCalLyx#1{#1}\fi % if technical note, disable it + +% ************************************************************************** +% ***** Misc. Definitions ********************************************** +% ************************************************************************** +%Restore single spacing +\newcommand{\blsone}{\renewcommand\baselinestretch{1}% + \renewcommand\arraystretch{1.2}\setlength{\parindent}{\parindentsave}% + \normalsize} +\newcommand{\capitem}[1]{{\hspace{0.2ex}(#1)}~} +\newcommand{\insdate}{} + +% ************************************************************************** +% ***** MATH Definitions *********************************************** +% ************************************************************************** +\def\eqnarray{% + \stepcounter{equation}% + \def\@currentlabel{\p@equation\theequation}% + \global\@eqnswtrue + \m@th + \global\@eqcnt\z@ + \tabskip\@centering + \let\\\@eqncr + $$\everycr{}\halign to\displaywidth\bgroup + \hskip\@centering$\displaystyle\tabskip\z@skip{##}$\@eqnsel + &\global\@eqcnt\@ne\hskip \eqnarr@ysep\hfil${##}$\hfil + &\global\@eqcnt\tw@ \hskip \eqnarr@ysep + $\displaystyle{##}$\hfil\tabskip\@centering + &\global\@eqcnt\thr@@ \hb@xt@\z@\bgroup\hss##\egroup + \tabskip\z@skip + \cr +} +\def\endeqnarray{% + \@@eqncr + \egroup + \global\advance\c@equation\m@ne + $$\@ignoretrue +} + +% ************************************************************************** +% ***** Biography Definitions ****************************************** +% ************************************************************************** +% This is the main code for the biography environment of the IEEE +% transactions class. The previous biography code had some known +% problems which were difficult to fix. The crux of the issue was that +% the photo frame was overlaid by text when \baselinestretch>1 or when +% the biography consisted of multiple short paragraphs. +% +% The fix was done by extracting code from the excellent package: +% 'picinpar.sty' version 1.2a as of july 13, 1993 +% by Friedhelm Sowa +% +% (At least most of) The bugs you find in this code were introduced +% unwittingly by myself. +% +%---------------- +% Known problems: +% +% - Don't use multiple blank lines to separate paragraphs. A single +% blank line works well, but multiple blank lines will confuse +% the code. This has something to do with the \def\par{\\\indent} +% line, but I can't think of an appropriate fix. Similarly, make +% sure the environment doesn't end with an extra blank line. +% - Don't use \samepage +% - Use \footnotemark within and \footnotetext outside the +% window-environment instead of \footnote +% - When using the epic-package load picinpar before epic +% like \documentstyle[...,picinpar,epic]{...} +% +% Counts +\newcount\br \newcount\nb \newcount\tcdsav \newcount\tcl \newcount\tcd +\newcount\tcn \newcount\cumtcl +% Dimens +\newdimen\rtside \newdimen\hpic \newdimen\vpic \newdimen\strutilg +\newdimen\picwd \newdimen\topheight \newdimen\ilg \newdimen\lpic +\newdimen\lwindowsep \newdimen\rwindowsep % VK 10 Feb 93 +\lwindowsep0.5\baselineskip % " +\rwindowsep0.5\baselineskip % " +\newdimen\cumpar +% Tokens +\newtoks\twa \newtoks\la \newtoks\ra \newtoks\ha \newtoks\pictoc +% Boxes +\newbox\rawtext \newbox\holder \newbox\windowbox \newbox\wartext +\newbox\finaltext \newbox\aslice \newbox\bslice \newbox\wbox +\newbox\wstrutbox \newbox\picbox \newbox\waslice \newbox\wbslice +\newbox\fslice + % Another strut +\def\wstrut{\relax\ifmmode\copy\wstrutbox\else\unhcopy\wstrutbox\fi} +% + +\def\getpic#1{\sbox{\@tempboxa}{\includegraphics{#1}}% +\newcount\tmpcta \tmpcta=\ht\@tempboxa% +\newcount\tmpctb \tmpctb=\wd\@tempboxa% +\divide\tmpctb by 100% +\divide\tmpcta by\tmpctb% +\ifnum\tmpcta>133% +\typeout{ieee: Biography picture `#1' too tall.}% +\frame{\hbox to 25mm{\hfil\resizebox{!}{32mm}{\usebox{\@tempboxa}}\hfil}}% +\else \ifnum\tmpcta<123% +\typeout{ieee: Biography picture `#1' too wide.}% +\frame{\vbox to 32mm{\vss\hbox{\resizebox{25mm}{!}{\usebox{\@tempboxa}}}\vss}}% +\else% +\resizebox{25mm}{32mm}{\usebox{\@tempboxa}} +\fi\fi} + +\long\def\biographyLyX#1{\if@non\else\begin{biography} #1\end{biography}\fi} + +\if@non + \long\def\biography{} +\else + \long\def\biography{\@ifnextchar [{\@biographyb}{\@biographya[{\unitlength + 1mm\hbox{\framebox(25,32){}}}]}} +\fi + +\long\def\@biographyb[#1]{\@biographya[\getpic{#1}]} + +\long\def\@biographya[#1]#2{\bgroup +\footnotesize\bigskip\bigskip\bigskip\parskip=0pt\par% +\rule{0pt}{35mm}\vspace*{-35mm}\par% garantees correct page breaking +\begin{main@bio}[{#1}]% +\noindent{\bf #2}% +} +\def\endbiography{\if@non\else\end{main@bio}\egroup\fi} + +\long\def\main@bio[#1]{% #1 is the material for setting a graphic box +\vskip\parskip\everypar{} +\global\cumpar=0pt +\global\cumtcl=0 + \tcd=0 + \rtside=0pt +% \hpic=\linewidth + \twa={} \la={} \ra={} \ha={} +\setbox\wbox=\hbox{(} +\computeilg +\pictoc={#1} +\setbox\windowbox=\vbox{\hbox{#1}} +\picwd=\wd\windowbox +\hpic=\picwd +\vpic=\ht\windowbox\advance\vpic\dp\windowbox +\rtside=\linewidth\advance\rtside-\picwd +\setbox\picbox=\vbox{\hsize=\hpic\vbox to\vpic{\box\windowbox}}% \vfill}}% + +\vpic=\ht\picbox\advance\vpic\dp\picbox +\ifdim\rtside>0pt\advance\rtside-\rwindowsep\fi % " +\global\br=\rtside +\ifnum\picwd=0 +\ifdim\vpic>0pt\picwd=\hpic +\else\vpic=\ht\picbox\advance\vpic\dp\picbox +\fi +\fi + \global\tcl=0 \lpic=0pt + \loop\global\advance\tcl by 1 \lpic=\tcl\baselineskip + \ifdim\lpic<\vpic\repeat + \vpic=\lpic + \global\cumtcl=\tcl +% +% Here we know exactly the number of indented lines and +% are able to generate the tokens for the \parshape list +% + \ifnum\br>0\ra={ 0pt \rtside}\fi + \ifnum\tcd>0\ha={ 0pt \linewidth}\fi + \ifnum\tcl<1\global\tcl=1\fi + \createparshapespec + \tcd=0 % restore the lintel + \global\tcdsav=0 +% +% This is a very tricky part of the package. Some day there +% will exist a detailed documentation. +% +\def\par{\\\indent} +% +% This is where we start to pick up the paragraph(s) +% + \setbox\rawtext=\vbox\bgroup\unvbox\rawtext\unskip + \clubpenalty=0\widowpenalty=0 + \ifnum\brokenpenalty<\maxdimen\else\brokenpenalty=9999\fi + \tolerance=1000 + \parshape=\tcn \the\twa } +% +\def\endmain@bio{% + %\par + \global\tcd=\tcdsav + \egroup\vskip\parskip\parshape=0 % reset parshape; end \box\rawtext + \vbadness=10000 + \splittopskip=0pt +% +% Now we build the boxes beside the window +% +\global\topheight=\tcl\baselineskip +\ifnum\br>0\setbox\holder=\vsplit\rawtext to\topheight\fi +\tcn=\tcl \nb=0 +\ifnum\br>0\nb=\tcn\fi +% +% text on the right side +% +\ifnum\nb>0 + \loop\advance\nb -1 + \setbox\bslice=\vsplit\holder to\baselineskip + \prune\bslice\rtside + \setbox\wbslice=\vbox{\unvbox\wbslice\hbox + to\rtside{\box\bslice\hfil}} + \ifdim\ht\holder>0pt\repeat +\fi +%GLP add fix to make sure bio starts at top of picture +\setbox\wbslice=\vbox to\topheight{\unvbox\wbslice\vfill\vss} +% +% fixing the dimensions of the window part +% +\topheight=\ht\wbslice +% +% ship out the window material to the main vertical list +% +\setbox\windowbox=\vbox{\hbox to\linewidth{% +\vbox to\topheight{\hrule width\picwd height0pt depth0pt\vskip0pt% +\vfill\unvbox\picbox% +\ifnum\picwd>0\vfill\fi% +\vss}\ifnum\br>0\hfill\vbox{\box\wbslice}\fi}}% +% +\unvbox\windowbox% +\loop% lines below picture.... + \setbox\bslice=\vsplit\rawtext to\baselineskip + \prune\bslice\linewidth + \setbox\wbslice=\vbox{\hbox to\linewidth{\box\bslice\hfil}} + \unvbox\wbslice + \ifdim\ht\rawtext>0pt +\repeat +%GLP +%\ifnum\nb>0\topheight=\nb\baselineskip %\advance\topheight by\ilg +%\vspace*{\topheight} +%\fi +}% FINITO +% +% What else do we need? +% +\def\prune#1#2{ +% take a \vbox containing a single \hbox, +% \unvbox it, and cancel the \lastskip +% put in a \hbox of width #2 + \unvbox#1 \setbox#1=\lastbox % \box#1 now is an \hbox + \ifdim\ht#1=\parskip + \setbox#1=\hbox to#2{\vrule height\parskip depth0pt width0pt\hfill} + \else\ifdim\ht#1=0pt\relax + \else\setbox#1=\hbox to#2{\wstrut\unhbox#1\unskip}\fi\fi} +% +% Here the token \twa is generated. +% It's not so difficult as it looks like. +% +\def\createparshapespec{% +\global\tcn=0 +\ifnum\br>0\global\tcn=\tcl\fi +\nb=0 +\ifnum\br>0\nb=\tcn\fi +\global\advance\tcn by\tcd \global\advance\tcn by1 +\ifnum\tcd>0 +\loop\twa=\expandafter{\the\twa\the\ha}\advance\tcd -1 +\ifnum\tcd>0\repeat +\fi +\ifnum\nb>0 +\loop\twa=\expandafter{\the\twa\the\ra}\advance\nb -1 +\ifnum\nb>0\repeat +\fi +\global\twa=\expandafter{\the\twa 0pt \the\linewidth}} +% +\def\computeilg{% compute the interline glue + \tcl=0\ilg=0pt\strutilg=0pt + \loop\setbox\wbox=\hbox{\char\tcl} + \ifdim\ht\wbox>\ilg\ilg=\ht\wbox\fi + \ifdim\dp\wbox>\strutilg\strutilg=\dp\wbox\fi + \advance\tcl by 1 + \ifnum\tcl<128\repeat + \ht\wbox=\ilg + \dp\wbox=\strutilg + \strutilg=\ht\wbox %\advance\strutilg by\ilg + \ifdim\strutilg>\baselineskip + \typeout{character with height greater baselineskip found in font} + \typeout{baselineskip changed to 1.5 of that height!} + \baselineskip=1.5\strutilg + \fi + \global\ilg=\baselineskip + \global\advance\ilg-\ht\wbox \global\advance\ilg-\dp\wbox + \strutilg=\ht\wbox \advance\strutilg by\ilg + \setbox\wstrutbox=\hbox{\vrule height\strutilg depth\dp\wbox width0pt}} + + +% the following code from version.sty by Stephen Bellantoni 1990, loosely +% based on "annotation.sty" by Tom Hofmann. Used to exclude "biography" from +% anonymous mode. +\begingroup +\catcode`@=11\relax% +\catcode`{=12\relax\catcode`}=12\relax% +\catcode`(=1\relax \catcode`)=2\relax% +\gdef\glpinclude#1(% + \expandafter\gdef\csname #1\endcsname% + ()% + \expandafter\gdef\csname end#1\endcsname% + ()% +)% +\gdef\glpexclude#1(% + \expandafter\gdef\csname #1\endcsname% + (\@bsphack\catcode`{=12\relax\catcode`}=12\relax\csname #1@NOTE\endcsname)% + \long\expandafter\gdef\csname #1@NOTE\endcsname ##1\end{#1}% + (\csname #1END@NOTE\endcsname)% + \expandafter\gdef\csname #1END@NOTE\endcsname% + (\@esphack\end(#1))% +)% +\endgroup + +%------- +\def\@confplacedate{\typeout{ieee: Warning! No \noexpand\confplacedate set!} +\bfseries `confplacedate' needs to be set. For example, to: Stanford, CA, USA, +September 29--30, 1991} +\def\confplacedate#1{\def\@confplacedate{#1}} + +%%%%%%%%%%%%%%%%%%%%%%%%% End of ieee.cls %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% diff --git a/cryptominisat/cppsrc/docs/satcomp20-pdf/ccanr/sigproc.bib b/cryptominisat/cppsrc/docs/satcomp20-pdf/ccanr/sigproc.bib new file mode 100644 index 00000000..01d15513 --- /dev/null +++ b/cryptominisat/cppsrc/docs/satcomp20-pdf/ccanr/sigproc.bib @@ -0,0 +1,468 @@ +@InProceedings{stamping, +author="Heule, Marijn J. H. +and J{\"a}rvisalo, Matti +and Biere, Armin", +editor="Sakallah, Karem A. +and Simon, Laurent", +title="Efficient {CNF} Simplification Based on Binary Implication Graphs", +booktitle="Theory and Applications of Satisfiability Testing - SAT 2011", +year="2011", +publisher="Springer Berlin Heidelberg", +address="Berlin, Heidelberg", +pages="201--215", +abstract="This paper develops techniques for efficiently detecting redundancies in CNF formulas. We introduce the concept of hidden literals, resulting in the novel technique of hidden literal elimination. We develop a practical simplification algorithm that enables ``Unhiding'' various redundancies in a unified framework. Based on time stamping literals in the binary implication graph, the algorithm applies various binary clause based simplifications, including techniques that, when run repeatedly until fixpoint, can be too costly. Unhiding can also be applied during search, taking learnt clauses into account. We show that Unhiding gives performance improvements on real-world SAT competition benchmarks.", +isbn="978-3-642-21581-0" +} + +@inproceedings{TACAS-2010-JarvisaloBH, + author = "Matti Järvisalo and Armin Biere and Marijn Heule", + booktitle = "{Proceedings of the 16th International Conference on Tools and Algorithms for the Construction and Analysis of Systems}", + doi = "10.1007/978-3-642-12002-2_10", + pages = "129--144", + publisher = "{Springer International Publishing}", + series = "{Lecture Notes in Computer Science}", + title = "{Blocked Clause Elimination}", + volume = 6015, + year = 2010, +} + +@InProceedings{probsat, +author="Balint, Adrian +and Sch{\"o}ning, Uwe", +editor="Cimatti, Alessandro +and Sebastiani, Roberto", +title="Choosing Probability Distributions for Stochastic Local Search and the Role of Make versus Break", +booktitle="Theory and Applications of Satisfiability Testing -- SAT 2012", +year="2012", +publisher="Springer Berlin Heidelberg", +address="Berlin, Heidelberg", +pages="16--29", +abstract="Stochastic local search solvers for SAT made a large progress with the introduction of probability distributions like the ones used by the SAT Competition 2011 winners Sparrow2010 and EagleUp. These solvers though used a relatively complex decision heuristic, where probability distributions played a marginal role.", +isbn="978-3-642-31612-8" +} + +@InProceedings{balint-improving-sls, +author="Balint, Adrian +and Biere, Armin +and Fr{\"o}hlich, Andreas +and Sch{\"o}ning, Uwe", +editor="Sinz, Carsten +and Egly, Uwe", +title="Improving Implementation of {SLS} Solvers for {SAT} and New Heuristics for {k-SAT} with Long Clauses", +booktitle="Theory and Applications of Satisfiability Testing -- SAT 2014", +year="2014", +publisher="Springer International Publishing", +address="Cham", +pages="302--316", +abstract="Stochastic Local Search (SLS) solvers are considered one of the best solving technique for randomly generated problems and more recently also have shown great promise for several types of hard combinatorial problems. Within this work, we provide a thorough analysis of different implementation variants of SLS solvers on random and on hard combinatorial problems. By analyzing existing SLS implementations, we are able to discover new improvements inspired by CDCL solvers, which can speed up the search of all types of SLS solvers. Further, our analysis reveals that the multilevel break values of variables can be easily computed and used within the decision heuristic. By augmenting the probSAT solver with the new heuristic, we are able to reach new state-of-the-art performance on several types of SAT problems, especially on those with long clauses. We further provide a detailed analysis of the clause selection policy used in focused search SLS solvers.", +isbn="978-3-319-09284-3" +} + + + +@inproceedings{DBLP:conf/ictai/LynceS03, + author = {In{\^{e}}s Lynce and + Jo{\~{a}}o P. Marques Silva}, + title = {Probing-Based Preprocessing Techniques for Propositional Satisfiability}, + booktitle = {15th {IEEE} International Conference on Tools with Artificial Intelligence + {(ICTAI} 2003), 3-5 November 2003, Sacramento, California, {USA}}, + pages = {105}, + year = {2003}, + crossref = {DBLP:conf/ictai/2003}, + url = {https://doi.org/10.1109/TAI.2003.1250177}, + doi = {10.1109/TAI.2003.1250177}, + timestamp = {Fri, 02 Nov 2018 09:48:27 +0100}, + biburl = {https://dblp.org/rec/bib/conf/ictai/LynceS03}, + bibsource = {dblp computer science bibliography, https://dblp.org} +} + +@proceedings{DBLP:conf/ictai/2003, + title = {15th {IEEE} International Conference on Tools with Artificial Intelligence + {(ICTAI} 2003), 3-5 November 2003, Sacramento, California, {USA}}, + publisher = {{IEEE} Computer Society}, + year = {2003}, + url = {http://ieeexplore.ieee.org/xpl/mostRecentIssue.jsp?punumber=8840}, + isbn = {0-7695-2038-3}, + timestamp = {Thu, 18 Dec 2014 16:57:40 +0100}, + biburl = {https://dblp.org/rec/bib/conf/ictai/2003}, + bibsource = {dblp computer science bibliography, https://dblp.org} +} + +@InProceedings{chronobt, +author="Nadel, Alexander +and Ryvchin, Vadim", +editor="Beyersdorff, Olaf +and Wintersteiger, Christoph M.", +title="Chronological Backtracking", +booktitle="Theory and Applications of Satisfiability Testing -- {SAT} 2018", +year="2018", +publisher="Springer International Publishing", +address="Cham", +pages="111--121", +abstract="Non-Chronological Backtracking (NCB) has been implemented in every modern CDCL SAT solver since the original CDCL solver GRASP. NCB's importance has never been questioned. This paper argues that NCB is not always helpful. We show how one can implement the alternative to NCB--Chronological Backtracking (CB)--in a modern SAT solver. We demonstrate that CB improves the performance of the winner of the latest SAT Competition, Maple{\_}LCM{\_}Dist, and the winner of the latest MaxSAT Evaluation Open-WBO.", +isbn="978-3-319-94144-8" +} + +@inproceedings{smith94phase, + author = "Barbara Smith", + title = "The Phase Transition in Constraint Satisfaction Problems: {A} {CL}oser Look at the Mushy Region", + booktitle = {{ECAI}'94}, + year = "1994" +} + +@inproceedings{swdia, + author = "Chanseok Oh", + title = "{MiniSat HACK 999ED, MiniSat HACK 1430ED and SWDiA5BY}", + booktitle = "SAT Competition 2014 Booklet", + year = "201", +} + +@inproceedings{lingeling, + author = "Armin Biere", + title = "Yet another Local Search Solver and Lingeling and Friends Entering the SAT Competition 2014", + booktitle = "SAT Competition 2014 Booklet", + year = "2014", +} + +@inproceedings{maple, + author="Tomas Balyo and Marijn J. H. Heule and Matti Jarvisalo", + title="{MapleLRB\_LCM, Maple\_LCM, Maple\_LCM\_Dist, MapleLRB\_LCMoccRestart and Glucose-3.0+width in SAT Competition 2017}", + booktitle = "Proceedings of SAT Competition 2017", + year="2018" +} + +@inproceedings{sat-comp-2014-armin, + author="Belov Anton and Diepold Daniel and Marijn J. H. Heule and Matti Jarvisalo", + title="{Yet another Local Search Solver and Lingeling and Friends Entering the SAT Competition 2014}", + booktitle = "Proceedings of SAT Competition 2014", + year="2014" +} + +@misc {nscc, + author="ASTAR and NTU and NUS and SUTD", + title="{National Supercomputing Centre (NSCC)} {S}ingapore", + url="https://www.nscc.sg/about-nscc/overview/", + year="2018" +} + +@misc {CMS, + author="Mate Soos", + title="{CryptoMiniSat SAT solver GitHub page}", + url="https://github.com/msoos/cryptominisat", + year="2018" +} + +@misc {cadical, + author="Armin Biere", + title="{CaDiCaL SAT solver GitHub page}", + url="https://github.com/arminbiere/cadical", + year="2020" +} + +@inproceedings{DBLP:conf/sat/CaiLS15, + + author = {Shaowei Cai and +Chuan Luo and +Kaile Su}, + + title = {CCAnr: {A} Configuration Checking Based Local Search Solver for Non-random + Satisfiability}, + + booktitle = {{SAT} 2015}, + + year = {2015}, + + crossref = {DBLP:conf/sat/2015}, + + doi = {10.1007/978-3-319-24318-4\_1}, + +} + + +@proceedings{DBLP:conf/sat/2015, + + editor = {Marijn Heule and +Sean A. Weaver}, + + title = {{SAT} 2015}, + + series = {LNCS}, + + volume = {9340}, + + publisher = {Springer}, + + year = {2015}, + + doi = {10.1007/978-3-319-24318-4}, + + isbn = {978-3-319-24317-7}, + +} + + +@inproceedings{cheeseman91where, + author = "Peter Cheeseman and Bob Kanefsky and William M. Taylor", + title = "Where the Really Hard Problems Are", + booktitle = "IJCAI-91", + pages = "331--337", + year = "1991", +} + +@InProceedings{BVA, +author="Manthey, Norbert +and Heule, Marijn J. H. +and Biere, Armin", +editor="Biere, Armin +and Nahir, Amir +and Vos, Tanja", +title="Automated Reencoding of Boolean Formulas", +booktitle="Hardware and Software: Verification and Testing", +year="2013", +publisher="Springer Berlin Heidelberg", +address="Berlin, Heidelberg", +pages="102--117", +abstract="We present a novel preprocessing technique to automatically reduce the size of Boolean formulas. This technique, called Bounded Variable Addition (BVA), exchanges clauses for variables. Similar to other preprocessing techniques, BVA greedily lowers the sum of variables and clauses, a rough measure for the hardness to solve a formula. We show that cardinality constraints (CCs) can efficiently be reencoded: from a naive CC encoding, BVA automatically generates a compact encoding, which is smaller than sophisticated encodings. Experimental results show that applying BVA can improve SAT solving performance.", +isbn="978-3-642-39611-3" +} + +@InProceedings{BVE, +author="E{\'e}n, Niklas +and Biere, Armin", +editor="Bacchus, Fahiem +and Walsh, Toby", +title="Effective Preprocessing in {SAT} Through Variable and Clause Elimination", +booktitle="Theory and Applications of Satisfiability Testing", +year="2005", +publisher="Springer Berlin Heidelberg", +address="Berlin, Heidelberg", +pages="61--75", +abstract="Preprocessing SAT instances can reduce their size considerably. We combine variable elimination with subsumption and self-subsuming resolution, and show that these techniques not only shrink the formula further than previous preprocessing efforts based on variable elimination, but also decrease runtime of SAT solvers substantially for typical industrial SAT problems. We discuss critical implementation details that make the reduction procedure fast enough to be practical.", +isbn="978-3-540-31679-4" +} + +@INPROCEEDINGS{Selman95localsearch, + author = {Bart Selman and Henry Kautz and Bram Cohen}, + title = {Local Search Strategies for Satisfiability Testing}, + booktitle = {{DIMACS} Series in Discrete Mathematics and Theoretical Computer Science}, + year = {1995}, + pages = {521--532}, + publisher = {} +} + +@INPROCEEDINGS{birdtwo, + author = {Mate Soos and Stephan Gocht and Kuldeep S Meel}, + title = {Accelerating Approximate Techniques for Counting and Sampling Models Through Refined {CNF-XOR} Solving}, + booktitle = {CAV 2020}, + year = {2020}, + publisher = {} +} + + + + +@inproceedings{DBLP:conf/sat/Devriendt0B17, + + author = {Jo Devriendt and + + Bart Bogaerts and + + Maurice Bruynooghe}, + + title = {Symmetric Explanation Learning: Effective Dynamic Symmetry Handling + + for {SAT}}, + + booktitle = {{SAT} 2017}, + + pages = {83--100}, + + year = {2017}, + + crossref = {DBLP:conf/sat/2017}, + +} + + +@proceedings{DBLP:conf/sat/2017, + + editor = {Serge Gaspers and + + Toby Walsh}, + + title = {{SAT} 2017}, + + series = {LNCS}, + + volume = {10491}, + + publisher = {Springer}, + + year = {2017}, +} + + + + + + +@inproceedings{DBLP:conf/alenex/JunttilaK07, + + author = {Tommi A. Junttila and + + Petteri Kaski}, + + title = {Engineering an Efficient Canonical Labeling Tool for Large and Sparse + + Graphs}, + + booktitle = {{ALENEX} 2007}, + + year = {2007}, + + crossref = {DBLP:conf/alenex/2007}, + +} + + +@proceedings{DBLP:conf/alenex/2007, + + title = { +{ALENEX} 2007}, + + publisher = {{SIAM}}, + + year = {2007}, + + isbn = {978-1-61197-287-0}, + +} + + + + + + + +@inproceedings{DBLP:conf/aaai/KautzS96, + author = {Henry A. Kautz and + Bart Selman}, + title = {Pushing the Envelope: Planning, Propositional Logic and Stochastic + Search}, + booktitle = {Proceedings of the Thirteenth National Conference on Artificial Intelligence + and Eighth Innovative Applications of Artificial Intelligence Conference, + {AAAI} 96, {IAAI} 96, Portland, Oregon, USA, August 4-8, 1996, Volume + 2.}, + pages = {1194--1201}, + year = {1996}, + crossref = {DBLP:conf/aaai/1996-2}, + url = {http://www.aaai.org/Library/AAAI/1996/aaai96-177.php}, + timestamp = {Tue, 19 Jun 2018 18:21:36 +0200}, + biburl = {https://dblp.org/rec/bib/conf/aaai/KautzS96}, + bibsource = {dblp computer science bibliography, https://dblp.org} +} + +@proceedings{DBLP:conf/aaai/1996-2, + editor = {William J. Clancey and + Daniel S. Weld}, + title = {Proceedings of the Thirteenth National Conference on Artificial Intelligence + and Eighth Innovative Applications of Artificial Intelligence Conference, + {AAAI} 96, {IAAI} 96, Portland, Oregon, USA, August 4-8, 1996, Volume + 2}, + publisher = {{AAAI} Press / The {MIT} Press}, + year = {1996}, + url = {http://www.aaai.org/Conferences/AAAI/aaai96.php}, + timestamp = {Tue, 19 Jun 2018 18:21:36 +0200}, + biburl = {https://dblp.org/rec/bib/conf/aaai/1996-2}, + bibsource = {dblp computer science bibliography, https://dblp.org} +} + + + +@inproceedings{DBLP:conf/aaai/Hoos02, + author = {Holger H. Hoos}, + title = {An Adaptive Noise Mechanism for {WalkSAT}}, + booktitle = {Proceedings of the Eighteenth National Conference on Artificial Intelligence + and Fourteenth Conference on Innovative Applications of Artificial + Intelligence, July 28 - August 1, 2002, Edmonton, Alberta, Canada.}, + pages = {655--660}, + year = {2002}, + crossref = {DBLP:conf/aaai/2002}, + url = {http://www.aaai.org/Library/AAAI/2002/aaai02-098.php}, + timestamp = {Mon, 26 Feb 2018 07:08:45 +0100}, + biburl = {https://dblp.org/rec/bib/conf/aaai/Hoos02}, + bibsource = {dblp computer science bibliography, https://dblp.org} +} + +@proceedings{DBLP:conf/aaai/2002, + editor = {Rina Dechter and + Michael J. Kearns and + Richard S. Sutton}, + title = {Proceedings of the Eighteenth National Conference on Artificial Intelligence + and Fourteenth Conference on Innovative Applications of Artificial + Intelligence, July 28 - August 1, 2002, Edmonton, Alberta, Canada}, + publisher = {{AAAI} Press / The {MIT} Press}, + year = {2002}, + url = {http://www.aaai.org/Conferences/AAAI/aaai02.php}, + timestamp = {Mon, 26 Feb 2018 07:08:45 +0100}, + biburl = {https://dblp.org/rec/bib/conf/aaai/2002}, + bibsource = {dblp computer science bibliography, https://dblp.org} +} + +@InProceedings{breakid2016, +author="Devriendt, Jo +and Bogaerts, Bart +and Bruynooghe, Maurice +and Denecker, Marc", +editor="Creignou, Nadia +and Le Berre, Daniel", +title="Improved Static Symmetry Breaking for {SAT}", +booktitle="Theory and Applications of Satisfiability Testing -- SAT 2016", +year="2016", +publisher="Springer International Publishing", +address="Cham", +pages="104--122", +abstract="An effective SAT preprocessing technique is the construction of symmetry breaking formulas: auxiliary clauses that guide a SAT solver away from needless exploration of symmetric subproblems. However, during the past decade, state-of-the-art SAT solvers rarely incorporated symmetry breaking. This suggests that the reduction of the search space does not outweigh the overhead incurred by detecting symmetry and constructing symmetry breaking formulas. We investigate three methods to construct more effective symmetry breaking formulas. The first method simply improves the encoding of symmetry breaking formulas. The second detects special symmetry subgroups, for which complete symmetry breaking formulas exist. The third infers binary symmetry breaking clauses for a symmetry group as a whole rather than longer clauses for individual symmetries. We implement these methods in a symmetry breaking preprocessor, and verify their effectiveness on both hand-picked problems as well as the 2014 SAT competition benchmark set. Our experiments indicate that our symmetry breaking preprocessor improves the current state-of-the-art in static symmetry breaking for SAT and has a sufficiently low overhead to improve the performance of modern SAT solvers on hard combinatorial instances.", +isbn="978-3-319-40970-2", +doi="10.1007/978-3-319-40970-2\_8", +url="https://bitbucket.org/krr/breakid" +} + +@article{shatter2006, +author = {Aloul, Fadi A. and Sakallah, Karem A. and Markov, Igor L.}, +title = {Efficient Symmetry Breaking for {B}oolean Satisfiability}, +year = {2006}, +issue_date = {May 2006}, +publisher = {IEEE Computer Society}, +address = {USA}, +volume = {55}, +number = {5}, +issn = {0018-9340}, +url = {https://doi.org/10.1109/TC.2006.75}, +doi = {10.1109/TC.2006.75}, +journal = {IEEE Trans. Comput.}, +month = may, +pages = {549–558}, +numpages = {10}, +keywords = {graph automorphism, clause learning, conjunctive normal form (CNF), satisfiability (SAT), symmetries., Backtrack Search} +} + +@article{DBLP:journals/ai/LiXLMLL20, + author = {Chu{-}Min Li and + Fan Xiao and + Mao Luo and + Felip Many{\`{a}} and + Zhipeng L{\"{u}} and + Yu Li}, + title = {Clause vivification by unit propagation in {CDCL} {SAT} solvers}, + journal = {Artif. Intell.}, + volume = {279}, + year = {2020}, +} + +@inproceedings{shaw2020designing, + title={Designing new Phase Selection Heuristics}, + author={Shaw, Arijit and Meel, Kuldeep S}, + booktitle={SAT 2020}, + year={2020} +} diff --git a/cryptominisat/cppsrc/docs/satcomp20-pdf/ccanr/splncs03.bst b/cryptominisat/cppsrc/docs/satcomp20-pdf/ccanr/splncs03.bst new file mode 100644 index 00000000..32791691 --- /dev/null +++ b/cryptominisat/cppsrc/docs/satcomp20-pdf/ccanr/splncs03.bst @@ -0,0 +1,1519 @@ +%% BibTeX bibliography style `splncs03' +%% +%% BibTeX bibliography style for use with numbered references in +%% Springer Verlag's "Lecture Notes in Computer Science" series. +%% (See Springer's documentation for llncs.cls for +%% more details of the suggested reference format.) Note that this +%% file will not work for author-year style citations. +%% +%% Use \documentclass{llncs} and \bibliographystyle{splncs03}, and cite +%% a reference with (e.g.) \cite{smith77} to get a "[1]" in the text. +%% +%% This file comes to you courtesy of Maurizio "Titto" Patrignani of +%% Dipartimento di Informatica e Automazione Universita' Roma Tre +%% +%% ================================================================================================ +%% This was file `titto-lncs-02.bst' produced on Wed Apr 1, 2009 +%% Edited by hand by titto based on `titto-lncs-01.bst' (see below) +%% +%% CHANGES (with respect to titto-lncs-01.bst): +%% - Removed the call to \urlprefix (thus no "URL" string is added to the output) +%% ================================================================================================ +%% This was file `titto-lncs-01.bst' produced on Fri Aug 22, 2008 +%% Edited by hand by titto based on `titto.bst' (see below) +%% +%% CHANGES (with respect to titto.bst): +%% - Removed the "capitalize" command for editors string "(eds.)" and "(ed.)" +%% - Introduced the functions titto.bbl.pages and titto.bbl.page for journal pages (without "pp.") +%% - Added a new.sentence command to separate with a dot booktitle and series in the inproceedings +%% - Commented all new.block commands before urls and notes (to separate them with a comma) +%% - Introduced the functions titto.bbl.volume for handling journal volumes (without "vol." label) +%% - Used for editors the same name conventions used for authors (see function format.in.ed.booktitle) +%% - Removed a \newblock to avoid long spaces between title and "In: ..." +%% - Added function titto.space.prefix to add a space instead of "~" after the (removed) "vol." label +%% ================================================================================================ +%% This was file `titto.bst', +%% generated with the docstrip utility. +%% +%% The original source files were: +%% +%% merlin.mbs (with options: `vonx,nm-rvvc,yr-par,jttl-rm,volp-com,jwdpg,jwdvol,numser,ser-vol,jnm-x,btit-rm,bt-rm,edparxc,bkedcap,au-col,in-col,fin-bare,pp,ed,abr,mth-bare,xedn,jabr,and-com,and-com-ed,xand,url,url-blk,em-x,nfss,') +%% ---------------------------------------- +%% *** Tentative .bst file for Springer LNCS *** +%% +%% Copyright 1994-2007 Patrick W Daly + % =============================================================== + % IMPORTANT NOTICE: + % This bibliographic style (bst) file has been generated from one or + % more master bibliographic style (mbs) files, listed above. + % + % This generated file can be redistributed and/or modified under the terms + % of the LaTeX Project Public License Distributed from CTAN + % archives in directory macros/latex/base/lppl.txt; either + % version 1 of the License, or any later version. + % =============================================================== + % Name and version information of the main mbs file: + % \ProvidesFile{merlin.mbs}[2007/04/24 4.20 (PWD, AO, DPC)] + % For use with BibTeX version 0.99a or later + %------------------------------------------------------------------- + % This bibliography style file is intended for texts in ENGLISH + % This is a numerical citation style, and as such is standard LaTeX. + % It requires no extra package to interface to the main text. + % The form of the \bibitem entries is + % \bibitem{key}... + % Usage of \cite is as follows: + % \cite{key} ==>> [#] + % \cite[chap. 2]{key} ==>> [#, chap. 2] + % where # is a number determined by the ordering in the reference list. + % The order in the reference list is alphabetical by authors. + %--------------------------------------------------------------------- + +ENTRY + { address + author + booktitle + chapter + edition + editor + eid + howpublished + institution + journal + key + month + note + number + organization + pages + publisher + school + series + title + type + url + volume + year + } + {} + { label } +INTEGERS { output.state before.all mid.sentence after.sentence after.block } +FUNCTION {init.state.consts} +{ #0 'before.all := + #1 'mid.sentence := + #2 'after.sentence := + #3 'after.block := +} +STRINGS { s t} +FUNCTION {output.nonnull} +{ 's := + output.state mid.sentence = + { ", " * write$ } + { output.state after.block = + { add.period$ write$ +% newline$ +% "\newblock " write$ % removed for titto-lncs-01 + " " write$ % to avoid long spaces between title and "In: ..." + } + { output.state before.all = + 'write$ + { add.period$ " " * write$ } + if$ + } + if$ + mid.sentence 'output.state := + } + if$ + s +} +FUNCTION {output} +{ duplicate$ empty$ + 'pop$ + 'output.nonnull + if$ +} +FUNCTION {output.check} +{ 't := + duplicate$ empty$ + { pop$ "empty " t * " in " * cite$ * warning$ } + 'output.nonnull + if$ +} +FUNCTION {fin.entry} +{ duplicate$ empty$ + 'pop$ + 'write$ + if$ + newline$ +} + +FUNCTION {new.block} +{ output.state before.all = + 'skip$ + { after.block 'output.state := } + if$ +} +FUNCTION {new.sentence} +{ output.state after.block = + 'skip$ + { output.state before.all = + 'skip$ + { after.sentence 'output.state := } + if$ + } + if$ +} +FUNCTION {add.blank} +{ " " * before.all 'output.state := +} + + +FUNCTION {add.colon} +{ duplicate$ empty$ + 'skip$ + { ":" * add.blank } + if$ +} + +FUNCTION {date.block} +{ + new.block +} + +FUNCTION {not} +{ { #0 } + { #1 } + if$ +} +FUNCTION {and} +{ 'skip$ + { pop$ #0 } + if$ +} +FUNCTION {or} +{ { pop$ #1 } + 'skip$ + if$ +} +STRINGS {z} +FUNCTION {remove.dots} +{ 'z := + "" + { z empty$ not } + { z #1 #1 substring$ + z #2 global.max$ substring$ 'z := + duplicate$ "." = 'pop$ + { * } + if$ + } + while$ +} +FUNCTION {new.block.checka} +{ empty$ + 'skip$ + 'new.block + if$ +} +FUNCTION {new.block.checkb} +{ empty$ + swap$ empty$ + and + 'skip$ + 'new.block + if$ +} +FUNCTION {new.sentence.checka} +{ empty$ + 'skip$ + 'new.sentence + if$ +} +FUNCTION {new.sentence.checkb} +{ empty$ + swap$ empty$ + and + 'skip$ + 'new.sentence + if$ +} +FUNCTION {field.or.null} +{ duplicate$ empty$ + { pop$ "" } + 'skip$ + if$ +} +FUNCTION {emphasize} +{ skip$ } +FUNCTION {tie.or.space.prefix} +{ duplicate$ text.length$ #3 < + { "~" } + { " " } + if$ + swap$ +} +FUNCTION {titto.space.prefix} % always introduce a space +{ duplicate$ text.length$ #3 < + { " " } + { " " } + if$ + swap$ +} + + +FUNCTION {capitalize} +{ "u" change.case$ "t" change.case$ } + +FUNCTION {space.word} +{ " " swap$ * " " * } + % Here are the language-specific definitions for explicit words. + % Each function has a name bbl.xxx where xxx is the English word. + % The language selected here is ENGLISH +FUNCTION {bbl.and} +{ "and"} + +FUNCTION {bbl.etal} +{ "et~al." } + +FUNCTION {bbl.editors} +{ "eds." } + +FUNCTION {bbl.editor} +{ "ed." } + +FUNCTION {bbl.edby} +{ "edited by" } + +FUNCTION {bbl.edition} +{ "edn." } + +FUNCTION {bbl.volume} +{ "vol." } + +FUNCTION {titto.bbl.volume} % for handling journals +{ "" } + +FUNCTION {bbl.of} +{ "of" } + +FUNCTION {bbl.number} +{ "no." } + +FUNCTION {bbl.nr} +{ "no." } + +FUNCTION {bbl.in} +{ "in" } + +FUNCTION {bbl.pages} +{ "pp." } + +FUNCTION {bbl.page} +{ "p." } + +FUNCTION {titto.bbl.pages} % for journals +{ "" } + +FUNCTION {titto.bbl.page} % for journals +{ "" } + +FUNCTION {bbl.chapter} +{ "chap." } + +FUNCTION {bbl.techrep} +{ "Tech. Rep." } + +FUNCTION {bbl.mthesis} +{ "Master's thesis" } + +FUNCTION {bbl.phdthesis} +{ "Ph.D. thesis" } + +MACRO {jan} {"Jan."} + +MACRO {feb} {"Feb."} + +MACRO {mar} {"Mar."} + +MACRO {apr} {"Apr."} + +MACRO {may} {"May"} + +MACRO {jun} {"Jun."} + +MACRO {jul} {"Jul."} + +MACRO {aug} {"Aug."} + +MACRO {sep} {"Sep."} + +MACRO {oct} {"Oct."} + +MACRO {nov} {"Nov."} + +MACRO {dec} {"Dec."} + +MACRO {acmcs} {"ACM Comput. Surv."} + +MACRO {acta} {"Acta Inf."} + +MACRO {cacm} {"Commun. ACM"} + +MACRO {ibmjrd} {"IBM J. Res. Dev."} + +MACRO {ibmsj} {"IBM Syst.~J."} + +MACRO {ieeese} {"IEEE Trans. Software Eng."} + +MACRO {ieeetc} {"IEEE Trans. Comput."} + +MACRO {ieeetcad} + {"IEEE Trans. Comput. Aid. Des."} + +MACRO {ipl} {"Inf. Process. Lett."} + +MACRO {jacm} {"J.~ACM"} + +MACRO {jcss} {"J.~Comput. Syst. Sci."} + +MACRO {scp} {"Sci. Comput. Program."} + +MACRO {sicomp} {"SIAM J. Comput."} + +MACRO {tocs} {"ACM Trans. Comput. Syst."} + +MACRO {tods} {"ACM Trans. Database Syst."} + +MACRO {tog} {"ACM Trans. Graphic."} + +MACRO {toms} {"ACM Trans. Math. Software"} + +MACRO {toois} {"ACM Trans. Office Inf. Syst."} + +MACRO {toplas} {"ACM Trans. Progr. Lang. Syst."} + +MACRO {tcs} {"Theor. Comput. Sci."} + +FUNCTION {bibinfo.check} +{ swap$ + duplicate$ missing$ + { + pop$ pop$ + "" + } + { duplicate$ empty$ + { + swap$ pop$ + } + { swap$ + pop$ + } + if$ + } + if$ +} +FUNCTION {bibinfo.warn} +{ swap$ + duplicate$ missing$ + { + swap$ "missing " swap$ * " in " * cite$ * warning$ pop$ + "" + } + { duplicate$ empty$ + { + swap$ "empty " swap$ * " in " * cite$ * warning$ + } + { swap$ + pop$ + } + if$ + } + if$ +} +FUNCTION {format.url} +{ url empty$ + { "" } +% { "\urlprefix\url{" url * "}" * } + { "\url{" url * "}" * } % changed in titto-lncs-02.bst + if$ +} + +INTEGERS { nameptr namesleft numnames } + + +STRINGS { bibinfo} + +FUNCTION {format.names} +{ 'bibinfo := + duplicate$ empty$ 'skip$ { + 's := + "" 't := + #1 'nameptr := + s num.names$ 'numnames := + numnames 'namesleft := + { namesleft #0 > } + { s nameptr + "{vv~}{ll}{, jj}{, f{.}.}" + format.name$ + bibinfo bibinfo.check + 't := + nameptr #1 > + { + namesleft #1 > + { ", " * t * } + { + s nameptr "{ll}" format.name$ duplicate$ "others" = + { 't := } + { pop$ } + if$ + "," * + t "others" = + { + " " * bbl.etal * + } + { " " * t * } + if$ + } + if$ + } + 't + if$ + nameptr #1 + 'nameptr := + namesleft #1 - 'namesleft := + } + while$ + } if$ +} +FUNCTION {format.names.ed} +{ + 'bibinfo := + duplicate$ empty$ 'skip$ { + 's := + "" 't := + #1 'nameptr := + s num.names$ 'numnames := + numnames 'namesleft := + { namesleft #0 > } + { s nameptr + "{f{.}.~}{vv~}{ll}{ jj}" + format.name$ + bibinfo bibinfo.check + 't := + nameptr #1 > + { + namesleft #1 > + { ", " * t * } + { + s nameptr "{ll}" format.name$ duplicate$ "others" = + { 't := } + { pop$ } + if$ + "," * + t "others" = + { + + " " * bbl.etal * + } + { " " * t * } + if$ + } + if$ + } + 't + if$ + nameptr #1 + 'nameptr := + namesleft #1 - 'namesleft := + } + while$ + } if$ +} +FUNCTION {format.authors} +{ author "author" format.names +} +FUNCTION {get.bbl.editor} +{ editor num.names$ #1 > 'bbl.editors 'bbl.editor if$ } + +FUNCTION {format.editors} +{ editor "editor" format.names duplicate$ empty$ 'skip$ + { + " " * + get.bbl.editor +% capitalize + "(" swap$ * ")" * + * + } + if$ +} +FUNCTION {format.note} +{ + note empty$ + { "" } + { note #1 #1 substring$ + duplicate$ "{" = + 'skip$ + { output.state mid.sentence = + { "l" } + { "u" } + if$ + change.case$ + } + if$ + note #2 global.max$ substring$ * "note" bibinfo.check + } + if$ +} + +FUNCTION {format.title} +{ title + duplicate$ empty$ 'skip$ + { "t" change.case$ } + if$ + "title" bibinfo.check +} +FUNCTION {output.bibitem} +{ newline$ + "\bibitem{" write$ + cite$ write$ + "}" write$ + newline$ + "" + before.all 'output.state := +} + +FUNCTION {n.dashify} +{ + 't := + "" + { t empty$ not } + { t #1 #1 substring$ "-" = + { t #1 #2 substring$ "--" = not + { "--" * + t #2 global.max$ substring$ 't := + } + { { t #1 #1 substring$ "-" = } + { "-" * + t #2 global.max$ substring$ 't := + } + while$ + } + if$ + } + { t #1 #1 substring$ * + t #2 global.max$ substring$ 't := + } + if$ + } + while$ +} + +FUNCTION {word.in} +{ bbl.in capitalize + ":" * + " " * } + +FUNCTION {format.date} +{ + month "month" bibinfo.check + duplicate$ empty$ + year "year" bibinfo.check duplicate$ empty$ + { swap$ 'skip$ + { "there's a month but no year in " cite$ * warning$ } + if$ + * + } + { swap$ 'skip$ + { + swap$ + " " * swap$ + } + if$ + * + remove.dots + } + if$ + duplicate$ empty$ + 'skip$ + { + before.all 'output.state := + " (" swap$ * ")" * + } + if$ +} +FUNCTION {format.btitle} +{ title "title" bibinfo.check + duplicate$ empty$ 'skip$ + { + } + if$ +} +FUNCTION {either.or.check} +{ empty$ + 'pop$ + { "can't use both " swap$ * " fields in " * cite$ * warning$ } + if$ +} +FUNCTION {format.bvolume} +{ volume empty$ + { "" } + { bbl.volume volume tie.or.space.prefix + "volume" bibinfo.check * * + series "series" bibinfo.check + duplicate$ empty$ 'pop$ + { emphasize ", " * swap$ * } + if$ + "volume and number" number either.or.check + } + if$ +} +FUNCTION {format.number.series} +{ volume empty$ + { number empty$ + { series field.or.null } + { output.state mid.sentence = + { bbl.number } + { bbl.number capitalize } + if$ + number tie.or.space.prefix "number" bibinfo.check * * + series empty$ + { "there's a number but no series in " cite$ * warning$ } + { bbl.in space.word * + series "series" bibinfo.check * + } + if$ + } + if$ + } + { "" } + if$ +} + +FUNCTION {format.edition} +{ edition duplicate$ empty$ 'skip$ + { + output.state mid.sentence = + { "l" } + { "t" } + if$ change.case$ + "edition" bibinfo.check + " " * bbl.edition * + } + if$ +} +INTEGERS { multiresult } +FUNCTION {multi.page.check} +{ 't := + #0 'multiresult := + { multiresult not + t empty$ not + and + } + { t #1 #1 substring$ + duplicate$ "-" = + swap$ duplicate$ "," = + swap$ "+" = + or or + { #1 'multiresult := } + { t #2 global.max$ substring$ 't := } + if$ + } + while$ + multiresult +} +FUNCTION {format.pages} +{ pages duplicate$ empty$ 'skip$ + { duplicate$ multi.page.check + { + bbl.pages swap$ + n.dashify + } + { + bbl.page swap$ + } + if$ + tie.or.space.prefix + "pages" bibinfo.check + * * + } + if$ +} +FUNCTION {format.journal.pages} +{ pages duplicate$ empty$ 'pop$ + { swap$ duplicate$ empty$ + { pop$ pop$ format.pages } + { + ", " * + swap$ + n.dashify + pages multi.page.check + 'titto.bbl.pages + 'titto.bbl.page + if$ + swap$ tie.or.space.prefix + "pages" bibinfo.check + * * + * + } + if$ + } + if$ +} +FUNCTION {format.journal.eid} +{ eid "eid" bibinfo.check + duplicate$ empty$ 'pop$ + { swap$ duplicate$ empty$ 'skip$ + { + ", " * + } + if$ + swap$ * + } + if$ +} +FUNCTION {format.vol.num.pages} % this function is used only for journal entries +{ volume field.or.null + duplicate$ empty$ 'skip$ + { +% bbl.volume swap$ tie.or.space.prefix + titto.bbl.volume swap$ titto.space.prefix +% rationale for the change above: for journals you don't want "vol." label +% hence it does not make sense to attach the journal number to the label when +% it is short + "volume" bibinfo.check + * * + } + if$ + number "number" bibinfo.check duplicate$ empty$ 'skip$ + { + swap$ duplicate$ empty$ + { "there's a number but no volume in " cite$ * warning$ } + 'skip$ + if$ + swap$ + "(" swap$ * ")" * + } + if$ * + eid empty$ + { format.journal.pages } + { format.journal.eid } + if$ +} + +FUNCTION {format.chapter.pages} +{ chapter empty$ + 'format.pages + { type empty$ + { bbl.chapter } + { type "l" change.case$ + "type" bibinfo.check + } + if$ + chapter tie.or.space.prefix + "chapter" bibinfo.check + * * + pages empty$ + 'skip$ + { ", " * format.pages * } + if$ + } + if$ +} + +FUNCTION {format.booktitle} +{ + booktitle "booktitle" bibinfo.check +} +FUNCTION {format.in.ed.booktitle} +{ format.booktitle duplicate$ empty$ 'skip$ + { +% editor "editor" format.names.ed duplicate$ empty$ 'pop$ % changed by titto + editor "editor" format.names duplicate$ empty$ 'pop$ + { + " " * + get.bbl.editor +% capitalize + "(" swap$ * ") " * + * swap$ + * } + if$ + word.in swap$ * + } + if$ +} +FUNCTION {empty.misc.check} +{ author empty$ title empty$ howpublished empty$ + month empty$ year empty$ note empty$ + and and and and and + key empty$ not and + { "all relevant fields are empty in " cite$ * warning$ } + 'skip$ + if$ +} +FUNCTION {format.thesis.type} +{ type duplicate$ empty$ + 'pop$ + { swap$ pop$ + "t" change.case$ "type" bibinfo.check + } + if$ +} +FUNCTION {format.tr.number} +{ number "number" bibinfo.check + type duplicate$ empty$ + { pop$ bbl.techrep } + 'skip$ + if$ + "type" bibinfo.check + swap$ duplicate$ empty$ + { pop$ "t" change.case$ } + { tie.or.space.prefix * * } + if$ +} +FUNCTION {format.article.crossref} +{ + key duplicate$ empty$ + { pop$ + journal duplicate$ empty$ + { "need key or journal for " cite$ * " to crossref " * crossref * warning$ } + { "journal" bibinfo.check emphasize word.in swap$ * } + if$ + } + { word.in swap$ * " " *} + if$ + " \cite{" * crossref * "}" * +} +FUNCTION {format.crossref.editor} +{ editor #1 "{vv~}{ll}" format.name$ + "editor" bibinfo.check + editor num.names$ duplicate$ + #2 > + { pop$ + "editor" bibinfo.check + " " * bbl.etal + * + } + { #2 < + 'skip$ + { editor #2 "{ff }{vv }{ll}{ jj}" format.name$ "others" = + { + "editor" bibinfo.check + " " * bbl.etal + * + } + { + bbl.and space.word + * editor #2 "{vv~}{ll}" format.name$ + "editor" bibinfo.check + * + } + if$ + } + if$ + } + if$ +} +FUNCTION {format.book.crossref} +{ volume duplicate$ empty$ + { "empty volume in " cite$ * "'s crossref of " * crossref * warning$ + pop$ word.in + } + { bbl.volume + capitalize + swap$ tie.or.space.prefix "volume" bibinfo.check * * bbl.of space.word * + } + if$ + editor empty$ + editor field.or.null author field.or.null = + or + { key empty$ + { series empty$ + { "need editor, key, or series for " cite$ * " to crossref " * + crossref * warning$ + "" * + } + { series emphasize * } + if$ + } + { key * } + if$ + } + { format.crossref.editor * } + if$ + " \cite{" * crossref * "}" * +} +FUNCTION {format.incoll.inproc.crossref} +{ + editor empty$ + editor field.or.null author field.or.null = + or + { key empty$ + { format.booktitle duplicate$ empty$ + { "need editor, key, or booktitle for " cite$ * " to crossref " * + crossref * warning$ + } + { word.in swap$ * } + if$ + } + { word.in key * " " *} + if$ + } + { word.in format.crossref.editor * " " *} + if$ + " \cite{" * crossref * "}" * +} +FUNCTION {format.org.or.pub} +{ 't := + "" + address empty$ t empty$ and + 'skip$ + { + t empty$ + { address "address" bibinfo.check * + } + { t * + address empty$ + 'skip$ + { ", " * address "address" bibinfo.check * } + if$ + } + if$ + } + if$ +} +FUNCTION {format.publisher.address} +{ publisher "publisher" bibinfo.warn format.org.or.pub +} + +FUNCTION {format.organization.address} +{ organization "organization" bibinfo.check format.org.or.pub +} + +FUNCTION {article} +{ output.bibitem + format.authors "author" output.check + add.colon + new.block + format.title "title" output.check + new.block + crossref missing$ + { + journal + "journal" bibinfo.check + "journal" output.check + add.blank + format.vol.num.pages output + format.date "year" output.check + } + { format.article.crossref output.nonnull + format.pages output + } + if$ +% new.block + format.url output +% new.block + format.note output + fin.entry +} +FUNCTION {book} +{ output.bibitem + author empty$ + { format.editors "author and editor" output.check + add.colon + } + { format.authors output.nonnull + add.colon + crossref missing$ + { "author and editor" editor either.or.check } + 'skip$ + if$ + } + if$ + new.block + format.btitle "title" output.check + crossref missing$ + { format.bvolume output + new.block + new.sentence + format.number.series output + format.publisher.address output + } + { + new.block + format.book.crossref output.nonnull + } + if$ + format.edition output + format.date "year" output.check +% new.block + format.url output +% new.block + format.note output + fin.entry +} +FUNCTION {booklet} +{ output.bibitem + format.authors output + add.colon + new.block + format.title "title" output.check + new.block + howpublished "howpublished" bibinfo.check output + address "address" bibinfo.check output + format.date output +% new.block + format.url output +% new.block + format.note output + fin.entry +} + +FUNCTION {inbook} +{ output.bibitem + author empty$ + { format.editors "author and editor" output.check + add.colon + } + { format.authors output.nonnull + add.colon + crossref missing$ + { "author and editor" editor either.or.check } + 'skip$ + if$ + } + if$ + new.block + format.btitle "title" output.check + crossref missing$ + { + format.bvolume output + format.chapter.pages "chapter and pages" output.check + new.block + new.sentence + format.number.series output + format.publisher.address output + } + { + format.chapter.pages "chapter and pages" output.check + new.block + format.book.crossref output.nonnull + } + if$ + format.edition output + format.date "year" output.check +% new.block + format.url output +% new.block + format.note output + fin.entry +} + +FUNCTION {incollection} +{ output.bibitem + format.authors "author" output.check + add.colon + new.block + format.title "title" output.check + new.block + crossref missing$ + { format.in.ed.booktitle "booktitle" output.check + format.bvolume output + format.chapter.pages output + new.sentence + format.number.series output + format.publisher.address output + format.edition output + format.date "year" output.check + } + { format.incoll.inproc.crossref output.nonnull + format.chapter.pages output + } + if$ +% new.block + format.url output +% new.block + format.note output + fin.entry +} +FUNCTION {inproceedings} +{ output.bibitem + format.authors "author" output.check + add.colon + new.block + format.title "title" output.check + new.block + crossref missing$ + { format.in.ed.booktitle "booktitle" output.check + new.sentence % added by titto + format.bvolume output + format.pages output + new.sentence + format.number.series output + publisher empty$ + { format.organization.address output } + { organization "organization" bibinfo.check output + format.publisher.address output + } + if$ + format.date "year" output.check + } + { format.incoll.inproc.crossref output.nonnull + format.pages output + } + if$ +% new.block + format.url output +% new.block + format.note output + fin.entry +} +FUNCTION {conference} { inproceedings } +FUNCTION {manual} +{ output.bibitem + author empty$ + { organization "organization" bibinfo.check + duplicate$ empty$ 'pop$ + { output + address "address" bibinfo.check output + } + if$ + } + { format.authors output.nonnull } + if$ + add.colon + new.block + format.btitle "title" output.check + author empty$ + { organization empty$ + { + address new.block.checka + address "address" bibinfo.check output + } + 'skip$ + if$ + } + { + organization address new.block.checkb + organization "organization" bibinfo.check output + address "address" bibinfo.check output + } + if$ + format.edition output + format.date output +% new.block + format.url output +% new.block + format.note output + fin.entry +} + +FUNCTION {mastersthesis} +{ output.bibitem + format.authors "author" output.check + add.colon + new.block + format.btitle + "title" output.check + new.block + bbl.mthesis format.thesis.type output.nonnull + school "school" bibinfo.warn output + address "address" bibinfo.check output + format.date "year" output.check +% new.block + format.url output +% new.block + format.note output + fin.entry +} + +FUNCTION {misc} +{ output.bibitem + format.authors output + add.colon + title howpublished new.block.checkb + format.title output + howpublished new.block.checka + howpublished "howpublished" bibinfo.check output + format.date output +% new.block + format.url output +% new.block + format.note output + fin.entry + empty.misc.check +} +FUNCTION {phdthesis} +{ output.bibitem + format.authors "author" output.check + add.colon + new.block + format.btitle + "title" output.check + new.block + bbl.phdthesis format.thesis.type output.nonnull + school "school" bibinfo.warn output + address "address" bibinfo.check output + format.date "year" output.check +% new.block + format.url output +% new.block + format.note output + fin.entry +} + +FUNCTION {proceedings} +{ output.bibitem + editor empty$ + { organization "organization" bibinfo.check output + } + { format.editors output.nonnull } + if$ + add.colon + new.block + format.btitle "title" output.check + format.bvolume output + editor empty$ + { publisher empty$ + { format.number.series output } + { + new.sentence + format.number.series output + format.publisher.address output + } + if$ + } + { publisher empty$ + { + new.sentence + format.number.series output + format.organization.address output } + { + new.sentence + format.number.series output + organization "organization" bibinfo.check output + format.publisher.address output + } + if$ + } + if$ + format.date "year" output.check +% new.block + format.url output +% new.block + format.note output + fin.entry +} + +FUNCTION {techreport} +{ output.bibitem + format.authors "author" output.check + add.colon + new.block + format.title + "title" output.check + new.block + format.tr.number output.nonnull + institution "institution" bibinfo.warn output + address "address" bibinfo.check output + format.date "year" output.check +% new.block + format.url output +% new.block + format.note output + fin.entry +} + +FUNCTION {unpublished} +{ output.bibitem + format.authors "author" output.check + add.colon + new.block + format.title "title" output.check + format.date output +% new.block + format.url output +% new.block + format.note "note" output.check + fin.entry +} + +FUNCTION {default.type} { misc } +READ +FUNCTION {sortify} +{ purify$ + "l" change.case$ +} +INTEGERS { len } +FUNCTION {chop.word} +{ 's := + 'len := + s #1 len substring$ = + { s len #1 + global.max$ substring$ } + 's + if$ +} +FUNCTION {sort.format.names} +{ 's := + #1 'nameptr := + "" + s num.names$ 'numnames := + numnames 'namesleft := + { namesleft #0 > } + { s nameptr + "{ll{ }}{ ff{ }}{ jj{ }}" + format.name$ 't := + nameptr #1 > + { + " " * + namesleft #1 = t "others" = and + { "zzzzz" * } + { t sortify * } + if$ + } + { t sortify * } + if$ + nameptr #1 + 'nameptr := + namesleft #1 - 'namesleft := + } + while$ +} + +FUNCTION {sort.format.title} +{ 't := + "A " #2 + "An " #3 + "The " #4 t chop.word + chop.word + chop.word + sortify + #1 global.max$ substring$ +} +FUNCTION {author.sort} +{ author empty$ + { key empty$ + { "to sort, need author or key in " cite$ * warning$ + "" + } + { key sortify } + if$ + } + { author sort.format.names } + if$ +} +FUNCTION {author.editor.sort} +{ author empty$ + { editor empty$ + { key empty$ + { "to sort, need author, editor, or key in " cite$ * warning$ + "" + } + { key sortify } + if$ + } + { editor sort.format.names } + if$ + } + { author sort.format.names } + if$ +} +FUNCTION {author.organization.sort} +{ author empty$ + { organization empty$ + { key empty$ + { "to sort, need author, organization, or key in " cite$ * warning$ + "" + } + { key sortify } + if$ + } + { "The " #4 organization chop.word sortify } + if$ + } + { author sort.format.names } + if$ +} +FUNCTION {editor.organization.sort} +{ editor empty$ + { organization empty$ + { key empty$ + { "to sort, need editor, organization, or key in " cite$ * warning$ + "" + } + { key sortify } + if$ + } + { "The " #4 organization chop.word sortify } + if$ + } + { editor sort.format.names } + if$ +} +FUNCTION {presort} +{ type$ "book" = + type$ "inbook" = + or + 'author.editor.sort + { type$ "proceedings" = + 'editor.organization.sort + { type$ "manual" = + 'author.organization.sort + 'author.sort + if$ + } + if$ + } + if$ + " " + * + year field.or.null sortify + * + " " + * + title field.or.null + sort.format.title + * + #1 entry.max$ substring$ + 'sort.key$ := +} +ITERATE {presort} +SORT +STRINGS { longest.label } +INTEGERS { number.label longest.label.width } +FUNCTION {initialize.longest.label} +{ "" 'longest.label := + #1 'number.label := + #0 'longest.label.width := +} +FUNCTION {longest.label.pass} +{ number.label int.to.str$ 'label := + number.label #1 + 'number.label := + label width$ longest.label.width > + { label 'longest.label := + label width$ 'longest.label.width := + } + 'skip$ + if$ +} +EXECUTE {initialize.longest.label} +ITERATE {longest.label.pass} +FUNCTION {begin.bib} +{ preamble$ empty$ + 'skip$ + { preamble$ write$ newline$ } + if$ + "\begin{thebibliography}{" longest.label * "}" * + write$ newline$ + "\providecommand{\url}[1]{\texttt{#1}}" + write$ newline$ + "\providecommand{\urlprefix}{URL }" + write$ newline$ +} +EXECUTE {begin.bib} +EXECUTE {init.state.consts} +ITERATE {call.type$} +FUNCTION {end.bib} +{ newline$ + "\end{thebibliography}" write$ newline$ +} +EXECUTE {end.bib} +%% End of customized bst file +%% +%% End of file `titto.bst'. + + diff --git a/cryptominisat/cppsrc/docs/satcomp20-pdf/walksat/Makefile b/cryptominisat/cppsrc/docs/satcomp20-pdf/walksat/Makefile new file mode 100644 index 00000000..f58cd0a1 --- /dev/null +++ b/cryptominisat/cppsrc/docs/satcomp20-pdf/walksat/Makefile @@ -0,0 +1,24 @@ +TEX = pdflatex -shell-escape -interaction=nonstopmode -file-line-error +PRE = $(TEX) -ini -job-name="preamble" "&pdflatex preamble.tex\dump" +BIB = bibtex + +all: cms-walksat.pdf + +view : + okular cms-walksat.pdf + +cms-walksat.pdf : clean cms-walksat.tex cms-walksat.bbl cms-walksat.blg + $(TEX) cms-walksat.tex + $(TEX) cms-walksat.tex + +cms-walksat.bbl cmsv5.blg : cms-walksat.bib cms-walksat.aux + $(BIB) cms-walksat + +cms-walksat.aux : cms-walksat.tex + $(TEX) cms-walksat.tex + +cms-walksat.bib : cms-walksat.tex + $(TEX) cms-walksat.tex + +clean: + rm -f *.log *.pdf *.blg *.bbl *.aux *.out *.backup diff --git a/cryptominisat/cppsrc/docs/satcomp20-pdf/walksat/cms-walksat.tex b/cryptominisat/cppsrc/docs/satcomp20-pdf/walksat/cms-walksat.tex new file mode 100644 index 00000000..e09cc973 --- /dev/null +++ b/cryptominisat/cppsrc/docs/satcomp20-pdf/walksat/cms-walksat.tex @@ -0,0 +1,87 @@ +%\documentclass[runningheads]{llncs} +\documentclass[final]{ieee} + +\usepackage{microtype} %This gives MUCH better PDF results! +%\usepackage[active]{srcltx} %DVI search +\usepackage[cmex10]{amsmath} +\usepackage{amssymb} +\usepackage{fnbreak} %warn for split footnotes +\usepackage{url} +%\usepackage{qtree} %for drawing trees +%\usepackage{fancybox} % if we need rounded corners +%\usepackage{pict2e} % large circles can be drawn +%\usepackage{courier} %for using courier in texttt{} +%\usepackage{nth} %allows to \nth{4} to make 1st 2nd, etc. +%\usepackage{subfigure} %allows to have side-by-side figures +%\usepackage{booktabs} %nice tables +%\usepackage{multirow} %allow multiple cells with rows in tabular +\usepackage[utf8]{inputenc} % allows to write Faugere correctly +\usepackage[bookmarks=true, citecolor=black, linkcolor=black, colorlinks=true]{hyperref} +\hypersetup{ +pdfauthor = {Mate Soos, Bart Selman, Henry Kautz}, +pdftitle = {CryptoMiniSat v5.6 + walksat}, +pdfsubject = {SAT Competition 2020}, +pdfkeywords = {SAT Solver, DPLL, SLS}, +pdfcreator = {PdfLaTeX with hyperref package}, +pdfproducer = {PdfLaTex}} +%\usepackage{butterma} + +%\usepackage{pstricks} +\usepackage{graphicx,epsfig,xcolor} + +\begin{document} +\title{CryptoMiniSat with WalkSAT at the SAT Competition 2020} +\author{Mate Soos (National University of Singapore)\\ +Bart Selman (Cornell University), Henry Kautz (University of Rochester)\\ +Jo Devriendt, Stephan Gocht (Lund University \& University of Copenhagen)} + +\maketitle +\thispagestyle{empty} +\pagestyle{empty} + +\section{Introduction} +This paper presents the conflict-driven clause-learning (CLDL) SAT solver CryptoMiniSat (\emph{CMS}) augmented with the Stochastic Local Search (SLS)~\cite{Selman95localsearch} solver WalkSAT v56 as submitted to SAT Competition 2020. + +CryptoMiniSat aims to be a modern, open source SAT solver using inprocessing techniques, optimized data structures and finely-tuned timeouts to have good control over both memory and time usage of inprocessing steps. CryptoMiniSat is authored by Mate Soos. + +WalkSAT~\cite{DBLP:conf/aaai/KautzS96} is a standard system to solve satisfiability problems using Stochastic Local Search. The version inside CryptoMiniSat is functionally equivalent to the ``rnovelity'' heuristic of WalkSAT v56 using an adaptive noise heuristic~\cite{DBLP:conf/aaai/Hoos02}. It behaves exactly as WalkSAT with the minor modification of performing early-abort in case the ``lowbad'' statistic (i.e. the quality indicator of the current best solution) indicates the solution is far. In these cases, we early abort, let the CDCL solver work longer to simplify the problem, and come back to WalkSAT later. The only major modification to WalkSAT has been to allow it to import variables and clauses directly from the main solver taking into account assumptions given by the user. + +\section{Composing the Two Solvers} +The two solvers are composed together in a way that does \emph{not} resemble portfolio solvers. The system runs the CDCL solver CryptoMiniSat, along with its periodic inprocessing, by default. However, at every 2nd inprocessing step, CryptoMiniSat's irredundant clauses are pushed into the SLS solver (in case the predicted memory use is not too high). The SLS solver is then allowed to run for a predefined number of steps. In case the SLS solver finds a solution, this is given back to the CDCL solver, which then performs all the necessary extension to the solution (e.g. for Bounded Variable Elimination, BVE~\cite{BVE}) and then outputs the solution. + +Note that the inclusion of the SLS solver is full in the sense that assumptions-based solving, library-based solver use, and all other uses of the SAT solver is fully supported with SLS solving enabled. Hence, this is not some form of portfolio where a simple shell script determines which solver to run and then runs that solver. Instead, the SLS solver is a full member of the CDCL solver, much like any other inprocessing system, and works in tandem with it. For example, in case an inprocessing step has reduced the number of variables through BVE or increased it through BVA~\cite{BVA}, the SLS solver will then try to solve the problem thus modified. In case the SLS solver finds a solution, the main solver will then correctly manipulate it to fit the needs of the ``outside world'', i.e. the caller. + +As the two solvers are well-coupled, the combination of the two solvers can solve problems that neither system can solve on its own. Hence, \emph{the system is more than just a union of its parts} which is not the case for traditional portfolio solvers. + +\section{Gauss-Jordan Elimination} +As per the upcoming paper~\cite{birdtwo}, the Gauss-Jordan elimination of CryptoMiniSat has been significantly improved. The average speed increase for moderately sized matrices is approx 3-6x, allowing the system to be ran at all times even when the matrix is not contributing as much to the overall solving. Hence, for the first time in CryptoMiniSat's 10 year history, Gauss-Jordan elimination is turned on by default for the NoLimits track. + + +\section{Symmetry Breaking using BreakID and Bliss} +The BreakID~\cite{breakid2016} system is a cost-effective symmetry breaking preprocessor for SAT. +Classic SAT symmetry preprocessing~\cite{shatter2006} detects symmetry by converting the input formula to a graph and computing generators for this graph's automorphism group, and adds symmetry breaking clauses on a generator-by-generator basis. +On top of this, BreakID heuristically searches for structure in the automorphism group, detecting \emph{row interchangeability symmetry} (such as in the pigeonhole problem) and computing binary symmetry breaking clauses from orbits arising from the symmetry group. +The resulting symmetry breaking clauses are more effective at reducing symmetrical assignments from the search space, both from a theory point of view as well as in practical experiments. + +BreakID has been modified to work as a library. It can receive the clauses on-the-fly from the SAT solver, and produce the breaking clauses as a function return value. Various small bugs have also be fixed, such as memory leaks, which were not an issue when ran as a single executable, but created isses when ran as a library. Furthermore, the underlying highly sophisticated graph automorphism detection system, Bliss~\cite{DBLP:conf/alenex/JunttilaK07}, has been slightly improved to allow for time-outs and it, too, has been fixed not to leak memory. BreakID is fully integrated into CryptoMiniSat by calling it on every 5th inprocessing iteration, and asked to contribute breaking clauses. These are always added with an assumption literal, so they can be removed when the solving finishes. Hence, symmetry breaking also works when CryptoMiniSat is used as a library. + + +\section{Further Improvements Relative to SAT Race 2019} +Many of the inprocessing parameters have been tuned. A few bugs related to clause activities have been fixed. Clause distillation (or clause vivification)~\cite{DBLP:journals/ai/LiXLMLL20} is now used a lot more, similarly to the previous years' winning solvers. The VSIDS and Maple decay factors are now iteratively changed between 0.70 and 0.90 for Maple and 0.92 and 0.99 for VSIDS. Between each iteration there is an inprocessing step, as before. This seems to add heterogeneity and avoids having to tune these parameters to a ``single best'' value. Polarity caching is still used, but once in a while, so-called ``stable'' polarities are used, as per CaDiCaL~\cite{cadical} in the SAT Race of 2019. Ternary resolution is also used at every inprocessing step, thanks to the suggestion by Armin Biere. + + +\section{Thanks} +Mate Soos was supported in part by the National Research Foundation Singapore under its NRF Fellowship Programme[NRF-NRFFAI1-2019-0004 ] and AI Singapore Programme [AISG-RP-2018-005], and NUS ODPRT Grant [R-252-000-685-13]. + +Stephan Gocht was funded by the Swedish Research Council (VR) grant \mbox{2016-00782}. + +The computational work for this article was performed on resources of the National Supercomputing Center, Singapore\cite{nscc}. Mate Soos would also like to thank all the users of CryptoMiniSat who have submitted over 600 issues and pull requests to the GitHub CMS repository\cite{CMS}. + +\bibliographystyle{splncs03} +\bibliography{sigproc} + +\vfill +\pagebreak + +\end{document} + diff --git a/cryptominisat/cppsrc/docs/satcomp20-pdf/walksat/ieee.cls b/cryptominisat/cppsrc/docs/satcomp20-pdf/walksat/ieee.cls new file mode 100644 index 00000000..3c57bba5 --- /dev/null +++ b/cryptominisat/cppsrc/docs/satcomp20-pdf/walksat/ieee.cls @@ -0,0 +1,1497 @@ +% Copyright 2014 IEEEE +% for terms of use see https://www.ieee.org/publications_standards/publications/rights/copyrightpolicy.html + +% ========================================================================= +% ------------------------------------------------------------------------- +% XX X +% X +% XX XXX XXX XXX XXX X XXXX +% X X X X X X X X X X X +% X XXXXX XXXXX XXXXX X X XXX +% X X X X XX X X X X +% XXX XXX XXX XXX XX XXX X XXXX +% ------------------------------------------------------------------------- +% ========================================================================= +% ieee.cls --- For formatting IEEE conference & journal papers +% --- Compiled by Gregory Plett, Sept 1997 +% +% This class was inspired by one first compiled by Gerry Murray and +% Silvano Balemi for LaTeX209. It was later updated for use with +% LaTeX2e, and some bugs were fixed, all by Istvan Kollar. Lastly, +% I have tried to make the class easier to use by paper authors. +% Significant new functionality has been added. Many routines are +% "borrowed" from other people's packages and modified extensively. +% When I rembered where I got the routines from, I gave the author +% credit. +% +% After I made many changes on my own, I found a version by Peter +% N"uchter, and tried to retain some amount of compatibility with his +% version. To be completely compatible with him, you may need to +% manually: +% \usepackage{rawfonts}\usepackage{oldlfont} +% \AtBeginDocument{\parindent1.0em} (?) +% +%=========================================================================== +% +% Usage: +% \documentclass[main-mode,sub-mode,misc-options]{ieee} +% \usepackage{your own packages} +% \begin{document} +% \bibliographystyle{IEEEbib} +% \title[short]{regular} +% \author[short]{full} +% \maketitle +% \begin{abstract}...\end{abstract} +% \begin{keywords}...\end{keywords} +% \section{...} +% \PARstart ... or \PARstartCal ... +% ... +% \begin{biography}[picname.ps]{Author's name}...\end{biography} +% \end{document} +% +% The document class options are: +% +% main-mode: One of the following is required. (draft is the default) +% draft: Double-spaced, single column with date/time stamp. +% submission: Double-spaced, suitable for submission for review. +% compressed: Same as "submission", only single spaced. +% final: Double-column, for assessing page-length and +% format of final version. +% +% sub-mode: +% techreport: This can modify "final" to produce a two-col +% technical report. +% internal: This can modify "submission", "compressed" or "final". +% It changes the header to notify the reader that +% this is a version of the manuscript to be used for +% internal review processes only, and not to be +% distributed. +% submitted: This can modify "compressed" or "final". It changes +% the header to notify the reader that this +% is a preprint and not to be distributed. +% inpress: This can modify "compressed" or "final". It changes the +% header to notify the reader that this paper has +% been accepted for publishing, but it is not yet to be +% distributed. +% reprint: This can modify "final". It changes the header +% to notify the reader where the paper is reprinted from. +% +% misc-options: +% narroweqnarray: Changes the spacing around the "=" sign in +% equation arrays to make it the same as in displayed math. +% inline: Compresses the horizontal spacing of inline math equations. +% notitlepage: No separate title page. (default) +% titlepage: Separate title page. +% anonymous: Omit all author information from main part of paper. +% Author info only prints on titlepage. +% 9pt,10pt,11pt,12pt: Choose the appropriate type size. You should +% not need to do this as the "correct" size is automatically +% chosen. However, if you want, you may use these to change +% the type size of the main text. "9pt" is a bit of a hack +% to retain backward-compatibility. +% invited: If the paper is an "invited" paper, then this option +% prints "(Invited Paper)" under the authors' names. +% +% For regular IEEE submissions, define the journal name as: +% \journal{IEEE Trans. Inst. Meas.} +% +% To specify the conference place and date: +% \confplacedate{Ottawa, Canada, May 19--21, 1997} +% +% Before \maketitle, define: +% \title{Title of paper} +% \author{Author1\member{Fellow}\authorinfo{Department of +% Electrical Engineering\\ Some University, Somewhere, CA 94305 +% USA} \and Author2\member{Senior Member}\authorinfo{Deptartment of +% Measurement and Instrument Eng., Another University, ...}} +% +% Note, the contents of \authorinfo tends to vary depending on if it is +% a conference or journal paper. The amount of manual changes are +% small, and must be done by a human anyway. The example given is for an +% IMTC conference. +% +% See also IEEEbib.bst and ieeefig.sty +% Also very useful for document preparation is the style file "endfloat", +% available on all CTAN TeX archives. +% +%=========================================================================== +% modified 14 October 2002: +% - fixed bibliography listing of [#] when # < 10 and number of +% references is greater than 9. Thanks for Janos Markus for finding +% this bug and suggesting a solution. +% modified 15 January 2000: +% - "fixed" narroweqnarray. Never implemented! Now it is... +% modified 12 January 2000: +% - modified so only first \title and \author commands are recognized. +% This allows LyX to have \title and \author with full syntax in +% header, but dummy \title and \author show up in GUI. +% - added "\date" so the \date command can change "submitted" and +% "draft" date headers. +% modified 11 January 2000: +% - added PARstartLyX and PARstartCalLyX for LyX compatibility +% - added biographyLyX +% modified 1 Dec 1997: +% - fixed first page in reprint mode to be same length as other pages +% - added "invited" misc-option +% modified 5 Sept 1997: +% - added the inpress, reprint and internal sub-modes +% - removed IMTC-conf and CDC-conf to separate files +% modified 1 Sept 1997: +% - included Babel package compatibility +% - removed paper title from header on first page of draft +% manuscript +% - removed the fixed option "letterpaper" to allow a4paper (etc) +% modified 1 Aug 1997: +% - included the CDC-conf option +%=========================================================================== +% ************************************************************************** +% ****** ****************************************** +% ***** LaTeX2e INITIALIZATION ***************************************** +% ****** ****************************************** +% ************************************************************************** +\typeout{Document Class `ieee' .} +\NeedsTeXFormat{LaTeX2e}[1993/11/11] % Oldest acceptable version of LaTeX2e +\ProvidesClass{ieee}[2000/01/11] % Name of package provided, date +\def\i@@@cls{exists} + +% Initial Code & Declaration of Options +% ------------------------------------- +\newif\ifev@l \ev@lfalse % true if "final" mode. +\newif\ifsubm@t \subm@tfalse % true if "submission" mode. +\newif\ifdr@ft \dr@fttrue % true if "draft" mode. +\newif\ifc@mpress \c@mpressfalse % true if "compressed" mode. + +\newif\if@technote \@technotefalse % true if "technote" sub-mode. +\newif\ifintern@l \intern@lfalse % true if "internal" sub-mode. +\newif\ifprepr@nt \prepr@ntfalse % true if "preprint" sub-mode. +\newif\ifinpr@ss \inpr@ssfalse % true if "inpress" sub-mode. +\newif\ifrepr@nt \repr@ntfalse % true if "reprint" sub-mode. + +\newif\iftitlep@ge \titlep@gefalse % true if has own titlepage +\newif\if@non \@nonfalse % true if anonymous +\newif\ifixpt \ixptfalse % true if trying to do 9 pt +\newif\if@nvited \@nvitedfalse % true if an invited paper + +% Main options +% ------------ +\DeclareOption{draft}{\ev@lfalse\subm@tfalse\dr@fttrue% + \typeout{ieee: `Draft' mode selected.}} +\DeclareOption{submission}{\ev@lfalse\dr@ftfalse\subm@ttrue% + \typeout{ieee: `Submission' mode selected.}} +\DeclareOption{compressed}{\ev@lfalse\dr@ftfalse\subm@tfalse\c@mpresstrue% + \typeout{ieee: `Compressed' mode selected.}} +\DeclareOption{final}{\ev@ltrue\dr@ftfalse\subm@tfalse% + \typeout{ieee: `Final' mode selected.}} +\DeclareOption{evaluation}{\ev@ltrue\dr@ftfalse\subm@tfalse% + \typeout{ieee: `Final' mode selected.}} % synonym for final + +% Sub options +% ----------- +\DeclareOption{technote}{\@technotetrue% + \typeout{ieee: `Technote' sub-mode selected.}} +\DeclareOption{internal}{\intern@ltrue\prepr@ntfalse\inpr@ssfalse\repr@ntfalse% + \typeout{ieee: `Internal-Review' sub-mode selected.}} +\DeclareOption{submitted}{\intern@lfalse\prepr@nttrue\inpr@ssfalse\repr@ntfalse% + \typeout{ieee: `Submitted' sub-mode selected.}} +\DeclareOption{preprint}{\intern@lfalse\prepr@nttrue\inpr@ssfalse\repr@ntfalse% + \typeout{ieee: `Submitted' sub-mode selected.}} % synonym for submitted +\DeclareOption{inpress}{\intern@lfalse\prepr@ntfalse\inpr@sstrue\repr@ntfalse% + \typeout{ieee: `Inpress' sub-mode selected.}} +\DeclareOption{reprint}{\intern@lfalse\prepr@ntfalse\inpr@ssfalse\repr@nttrue% + \typeout{ieee: `Reprint' sub-mode selected.}} + +% Misc options +% ------------ + % regular or compressed "=" spacing in +\def\eqnarr@ysep{\arraycolsep} % eqnarray (this is the default) + % NOTE: we must use "def" and not "=" + % as arraycolsep not yet defined. +\DeclareOption{narroweqnarray}{\gdef\eqnarr@ysep{0.28em\relax}% + \typeout{ieee: Narrow equation arrays selected.}} +\DeclareOption{inline}{\everymath{\thinmuskip=2mu plus 1mu + \medmuskip=3mu plus 1mu minus 2mu + \thickmuskip=4mu plus 2mu\relax}% + \typeout{ieee: Narrower inline equations selected.}} +\DeclareOption{notitlepage}{\titlep@gefalse% + \typeout{ieee: No separate title page.}} +\DeclareOption{titlepage}{\titlep@getrue% + \typeout{ieee: Use separate title page.}} +\DeclareOption{anonymous}{\@nontrue\AtBeginDocument{\glpexclude{biography}} + \typeout{ieee: Omit author information from paper.}} +\DeclareOption{invited}{\@nvitedtrue% + \typeout{ieee: (Invited Paper).}} + +\DeclareOption{9pt}{\ixpttrue% + \typeout{ieee: Trying to emulate old `9pt' document class.}} + +\DeclareOption*{\PassOptionsToClass{\CurrentOption}{article}} + +% Execution of Options/Package Loading +% ------------------------------------ +\newlength\narrowcol +\newlength\parindentsave % recover parindent in blsone text + +\ProcessOptions +\ifev@l % if "final" mode... + \if@technote\ixpttrue\typeout{ieee: Trying to emulate old `9pt' + document class.}\fi% + \LoadClass[twoside,final,twocolumn,10pt]{article} +\else % if "draft"/"submission"/(compressed) mode... + \ifixpt + \LoadClass[oneside,final,onecolumn,10pt]{article} + \else + \LoadClass[oneside,final,onecolumn,12pt]{article} + \fi +\fi +\RequirePackage[final]{graphicx} +\RequirePackage{ifthen} + +% Re-Definitions of English words which must be done before +% the Babel package (optional) is loaded. +% --------------------------------------------------------- +\def\keywordsname{Index Terms} +\def\indexterms#1{\def\keywordsname{#1}} +\def\appendicesname{Appendices} +\def\figurename{Fig.} + +% ************************************************************************** +% ***** Check Sub-Options for Compatibility w/ Main-Options ************ +% ************************************************************************** +\if@technote\ifev@l\else\ClassError{ieee}{`technote' sub-mode may be + used only with the `final' ^^Jmain-mode. It may not be used + with either the `draft,' `submission,' or ^^J`compressed' + main-modes}{}\endinput\fi\fi +\ifintern@l\ifdr@ft\ClassError{ieee}{`internal' sub-mode may be + used only with the ^^J`submission,' `compressed,' or `final' main-modes. + It may not be used ^^Jwith the `draft' main-mode}{}\endinput\fi\fi +\ifprepr@nt\ifc@mpress\else\ifev@l\else\ClassError{ieee}{`submitted' + sub-mode may be used only with the ^^J`compressed' or `final' + main-modes. It may not be used with either the ^^J`draft' or + `submission' main-modes}{}\endinput\fi\fi\fi +\ifinpr@ss\ifc@mpress\else\ifev@l\else\ClassError{ieee}{`inpress' + sub-mode may be used only with the `compressed' ^^Jor `final' + main-modes. It may not be used with either the `draft' or + ^^J`submission' main-modes}{}\endinput\fi\fi\fi +\ifrepr@nt\ifev@l\else\ClassError{ieee}{`reprint' + sub-mode may be used only with the `final' ^^Jmain-mode. It may not be + used with either the `draft,' `submission,' or ^^J`compressed' + main-modes}{}\endinput\fi\fi + +% ************************************************************************** +% ***** Page Layout Definition ***************************************** +% ************************************************************************** +%% Layout definitions (mostly) common to all options. + +\hoffset 0in \voffset 0in +\headheight 12pt \headsep 7mm +\marginparsep 10pt \marginparwidth 20pt +\marginparpush 25pt +\columnsep 4mm +\parindent 1.0em +\lineskip 1pt +\normallineskip 1pt +\def\baselinestretch{1} + +\partopsep \z@ +\topsep 1.3ex +\parsep \z@ +\itemsep \z@ + +\setlength{\parindentsave}{\parindent} + +\ifev@l % if "evaluation" mode + % if camera-ready or A4paper ... + \ifdim\paperwidth<211mm + \oddsidemargin -11.4mm \evensidemargin -11.4mm + % for regular US Letter, not camera-ready + \else + \oddsidemargin -8.45mm \evensidemargin -8.45mm + \fi + \ifrepr@nt + \textheight 237.5mm % leave 6mm for cpyright on first page + \else + \textheight 243.5mm + \fi + \voffset -0.5in + \textwidth 182.0mm + \topmargin -12pt + \setlength{\narrowcol}{89mm} +\else % if "draft"/"submission" mode... + \ifc@mpress % and "compressed" + \oddsidemargin -0.25in \evensidemargin -0.25in + \textheight 9in \textwidth 7in + \topmargin -0.25in + \setlength{\narrowcol}{7in} + \else % and NOT "compressed" + \renewcommand\baselinestretch{1.8}\renewcommand{\arraystretch}{0.8} + \parindent=1.8\parindent + \oddsidemargin 0pt \evensidemargin 0pt + \headheight 12pt \headsep 0.375in + \topmargin 0pt + \textheight 8.5in \textwidth 6.5in + \marginparsep 0in \marginparwidth 0pt + \marginparpush 5pt + \setlength{\narrowcol}{6.5in} + \fi +\fi + +\def\normalstyle{\rmfamily} + +% ************************************************************************** +% ***** Font Definition ************************************************ +% ************************************************************************** +%% The 9-point option is being faked since it is not supported by the +%% article base class. + +%% Check if we have selected 9 points +\ifixpt +\typeout{-- This is a 9 point document} +\gdef\@ptsize{9} +\def\@normalsize{\@setsize\normalsize{10.7pt}\ixpt\@ixpt +\abovedisplayskip 1em plus2pt minus5pt\belowdisplayskip \abovedisplayskip +\abovedisplayshortskip \z@ plus3pt\belowdisplayshortskip .6em plus3pt minus3pt +\topsep \belowdisplayshortskip%!PN +} +\def\small{\@setsize\small{9.12pt}\viiipt\@viipt} +\def\footnotesize{\@setsize\footnotesize{8.15pt}\viipt\@vipt} +\def\scriptsize{\@setsize\scriptsize{8pt}\vipt\@vpt} +\def\tiny{\@setsize\tiny{5pt}\vpt\@vpt} +\def\large{\@setsize\large{12pt}\xpt\@xpt} +\def\Large{\@setsize\Large{14pt}\xiipt\@xiipt} +\def\LARGE{\@setsize\LARGE{18pt}\xivpt\@xivpt} +\def\huge{\@setsize\huge{22pt}\xviipt\@xviipt} +\def\Huge{\@setsize\Huge{25pt}\xxpt\@xxpt} +\fi +%% +%% Check if we have selected 10 points +\def\@tempa{0}\if\@ptsize\@tempa +\typeout{-- This is a 10 point document} +\def\@normalsize{\@setsize\normalsize{11.9pt}\xpt\@xpt +\abovedisplayskip 1em plus2pt minus5pt\belowdisplayskip \abovedisplayskip +\abovedisplayshortskip \z@ plus3pt\belowdisplayshortskip .6em plus3pt minus3pt +\topsep \belowdisplayshortskip%!PN +} +\def\small{\@setsize\small{9.2pt}\viiipt\@viiipt} +\def\footnotesize{\@setsize\footnotesize{8.8pt}\viiipt\@viiipt} +\def\scriptsize{\@setsize\scriptsize{8pt}\viipt\@viipt} +\def\tiny{\@setsize\tiny{6pt}\vpt\@vpt} +\def\normalsize{\@setsize\normalsize{11.9pt}\xpt\@xpt} +\def\large{\@setsize\large{14pt}\xiipt\@xiipt} +\def\Large{\@setsize\Large{18pt}\xivpt\@xivpt} +\def\LARGE{\@setsize\LARGE{22pt}\xviipt\@xviipt} +\def\huge{\@setsize\huge{22pt}\xxpt\@xxpt} +\def\Huge{\@setsize\Huge{28pt}\xxvpt\@xxvpt} +\fi +%% +%% Check if we have selected 11 points +\def\@tempa{1}\if\@ptsize\@tempa +\typeout{-- This is an 11 point document} +\def\@normalsize{\@setsize\normalsize{13.6pt}\xipt\@xipt +\abovedisplayskip 1em plus2pt minus5pt\belowdisplayskip \abovedisplayskip +\abovedisplayshortskip \z@ plus3pt\belowdisplayshortskip .6em plus3pt minus3pt +\topsep \belowdisplayshortskip%!PN +} +\def\small{\@setsize\small{12pt}\xpt\@xpt} +\def\footnotesize{\@setsize\footnotesize{11pt}\ixpt\@ixpt} +\def\scriptsize{\@setsize\scriptsize{9.5pt}\viiipt\@viiipt} +\def\tiny{\@setsize\tiny{7pt}\vipt\@vipt} +\def\normalsize{\@setsize\normalsize{13.6pt}\xipt\@xipt} +\def\large{\@setsize\large{14pt}\xiipt\@xiipt} +\def\Large{\@setsize\Large{18pt}\xivpt\@xivpt} +\def\LARGE{\@setsize\LARGE{22pt}\xviipt\@xviipt} +\def\huge{\@setsize\huge{25pt}\xxpt\@xxpt} +\def\Huge{\@setsize\Huge{30pt}\xxvpt\@xxvpt} +\fi +%% +%% Check if we have selected 12 points +\def\@tempa{2}\if\@ptsize\@tempa +\typeout{-- This is a 12 point document} +\def\@normalsize{\@setsize\normalsize{14pt}\xiipt\@xiipt +\abovedisplayskip 1em plus3pt minus6pt\belowdisplayskip \abovedisplayskip +\abovedisplayshortskip \z@ plus3pt\belowdisplayshortskip .6em plus4pt minus4pt +\topsep \belowdisplayshortskip%!PN +} +\def\small{\@setsize\small{11.4pt}\xpt\@xpt} +\def\footnotesize{\@setsize\footnotesize{10pt}\ixpt\@ixpt} +\def\scriptsize{\@setsize\scriptsize{9pt}\viiipt\@viiipt} +\def\tiny{\@setsize\tiny{8pt}\vipt\@vipt} +\def\normalsize{\@setsize\normalsize{14pt}\xiipt\@xiipt} +\def\large{\@setsize\large{18pt}\xivpt\@xivpt} +\def\Large{\@setsize\Large{22pt}\xviipt\@xviipt} +\def\LARGE{\@setsize\LARGE{25pt}\xxpt\@xxpt} +\def\huge{\@setsize\huge{30pt}\xxvpt\@xxvpt} +\let\Huge=\huge +\fi + +\AtBeginDocument{\normalsize\normalstyle\ps@headings\pagenumbering{arabic}} + +% ************************************************************************** +% ***** List Definition ************************************************ +% ************************************************************************** +%% Change aspect of lists with +%% 1) \itemindent, label indentation wrt to left list margin +%% 2) \leftmargini, the indentation of the whole list (on left, first level) +\ifev@l + \itemindent -1em + \leftmargini 2em + \leftmarginii 1em + \leftmarginiii 1.5em + \leftmarginiv 1.5em + \leftmarginv 1.0em + \leftmarginvi 1.0em +\else + \itemindent -1em + \leftmargini 3em + \leftmarginii 3em + \leftmarginiii 3em + \leftmarginiv 3em + \leftmarginv 3em + \leftmarginvi 3em +\fi +%\itemindent 2em % Alternative values: sometimes used.. +%\leftmargini 0em +\labelsep 5pt +\leftmargin\leftmargini +\labelwidth \z@ + +\def\@listI{\leftmargin\leftmargini} \@listI +\def\@listi{\leftmargin\leftmargini \topsep \z@ plus 1pt minus 1pt} +\def\@listii{\leftmargin\leftmarginii\labelwidth\leftmarginii + \advance\labelwidth-\labelsep \topsep \z@} +\def\@listiii{\leftmargin\leftmarginiii\labelwidth\leftmarginiii + \advance\labelwidth-\labelsep \topsep \z@} +\def\@listiv{\leftmargin\leftmarginiv\labelwidth\leftmarginiv + \advance\labelwidth-\labelsep \topsep \z@} +\def\@listv{\leftmargin\leftmarginv\labelwidth\leftmarginv + \advance\labelwidth-\labelsep \topsep \z@} +\def\@listvi{\leftmargin\leftmarginvi\labelwidth\leftmarginvi + \advance\labelwidth-\labelsep \topsep \z@} + +\def\labelenumi{\theenumi.} \def\theenumi{\arabic{enumi}} +\def\labelenumii{(\theenumii)} \def\theenumii{\alph{enumii}} +\def\labelenumiii{\theenumiii.} \def\theenumiii{\roman{enumiii}} +\def\labelenumiv{\theenumiv.} \def\theenumiv{\Alph{enumiv}} +\def\p@enumii{\theenumi} +\def\p@enumiii{\theenumi(\theenumii)} +\def\p@enumiv{\p@enumiii\theenumiii} + +\def\labelitemi{$\scriptstyle\bullet$} +\def\labelitemii{\bf --} +\def\labelitemiii{$\ast$} +\def\labelitemiv{$\cdot$} + +%% \itemindent is set to \z@ by list, so define new temporary variable +\newdimen\tmpitemindent +\def\verse{\let\\=\@centercr + \list{}{\itemsep\z@ \itemindent -1.5em \listparindent \itemindent + \rightmargin\leftmargin\advance\leftmargin 1.5em}\item[]} +\let\endverse\endlist +\def\quotation{\list{}{\listparindent 1.5em \itemindent\listparindent + \rightmargin\leftmargin \parsep 0pt plus 1pt}\item[]} +\let\endquotation=\endlist +\def\quote{\list{}{\rightmargin\leftmargin}\item[]} +\let\endquote=\endlist +\def\@mklab#1{#1} +\def\description{\tmpitemindent\itemindent\list{}{\itemindent\tmpitemindent + \labelwidth\z@\def\makelabel##1{\hspace\labelsep\emph{##1}}}} +\def\enddescription{\endlist\par} +\def\enumerate{\tmpitemindent\itemindent\ifnum \@enumdepth >3 \@toodeep\else + \advance\@enumdepth \@ne \edef\@enumctr{enum\romannumeral\the\@enumdepth}% + \list{\csname label\@enumctr\endcsname}{\itemindent\tmpitemindent + \usecounter{\@enumctr}\def\makelabel##1{\hspace\labelsep\hfil{##1}}}\fi} +\def\endenumerate{\endlist\par} +\def\itemize{\tmpitemindent\itemindent\ifnum \@itemdepth >3 \@toodeep\else + \advance\@itemdepth\@ne + \edef\@itemitem{labelitem\romannumeral\the\@itemdepth}% + \list{\csname\@itemitem\endcsname}{\itemindent\tmpitemindent + \def\makelabel##1{\hspace\labelsep\hfil\emph{##1}}}\fi} +\def\enditemize{\endlist\par} + +\newif\if@restonecol +\def\titlepage{\@restonecolfalse\if@twocolumn\@restonecoltrue\onecolumn + \else \newpage \fi \thispagestyle{coverpagestyle}\c@page\z@} +\def\endtitlepage{\if@restonecol\twocolumn \else \newpage \fi% +\if@twoside\mbox{}\thispagestyle{coverpagestyle}\c@page\z@\cleardoublepage\fi} + +\arraycolsep 5pt +\tabcolsep 6pt +\arrayrulewidth .4pt +\doublerulesep 2pt +\tabbingsep\labelsep + +% ************************************************************************** +% ***** Footnote Definition ******************************************** +% ************************************************************************** +\skip\footins 10pt plus 5pt minus 2pt +\footnotesep 7pt +\footskip 6mm +\skip\@mpfootins = \skip\footins +\fboxsep = 3pt \fboxrule = .4pt +\long\def\@makefntext#1{\parindent .8em\indent$^{\@thefnmark}$#1} +\def\footnoterule{} + +% Reset baselinestretch within footnotes. +% Originally stolen from Stanford University thesis style. +% -------------------------------------------------------- +\long\def\@footnotetext#1{\insert\footins{\blsone% + \footnotesize\interlinepenalty\interfootnotelinepenalty + \splittopskip\footnotesep + \splitmaxdepth \dp\strutbox \floatingpenalty \@MM + \hsize\columnwidth \@parboxrestore + \edef\@currentlabel{\csname p@footnote\endcsname\@thefnmark}\@makefntext + \let\par\\ + {\rule{\z@}{\footnotesep}\ignorespaces + #1\strut}}} + +% ************************************************************************** +% ***** Keep track of Sections ***************************************** +% ************************************************************************** +\if@technote + \setcounter{secnumdepth}{3} +\else + \setcounter{secnumdepth}{4} +\fi + +\def\thesection{\@Roman\c@section} +\def\thesubsection{\Alph{subsection}} +\def\thesubsubsection{\thesubsection.\arabic{subsubsection}} +\def\thesubsubsectiondis{\Alph{subsection}.\arabic{subsubsection}} +\def\theparagraph{\thesubsubsection.\alph{paragraph}} +\def\theparagraphdis{\thesubsubsectiondis.\alph{paragraph}} + +\def\theequation{\arabic{equation}} + +% ************************************************************************** +% ***** Table of Contents, List of Figures/Tables Definitions ********** +% ************************************************************************** +\def\@pnumwidth{1.55em} +\def\@tocrmarg {2.55em} +\def\@dotsep{4.5} +\setcounter{tocdepth}{3} + +\def\tableofcontents{\section*{\contentsname}\@starttoc{toc}} +\def\l@section#1#2{\addpenalty{\@secpenalty} \addvspace{1.0em plus 1pt} + \@tempdima 1.8em \begingroup \parindent \z@ \rightskip \@pnumwidth + \parfillskip-\@pnumwidth \bf\leavevmode #1\hfil\hbox to\@pnumwidth{\hss #2} + \par \endgroup} +\def\l@subsection{\@dottedtocline{2}{1.5em}{2.3em}} +\def\l@subsubsection{\@dottedtocline{3}{3.8em}{3.2em}} +\def\listoffigures{\section*{\listfigurename}\@starttoc{lof}} +\def\l@figure{\@dottedtocline{1}{1em}{1.8em}} +\def\listoftables{\section*{\listtablename}\@starttoc{lot}} +\let\l@table\l@figure + +% ************************************************************************** +% ***** Float Definitions ********************************************** +% ************************************************************************** +%% Normal Floats %% Double Column Floats +\floatsep 12pt plus 2pt minus 2pt \dblfloatsep 12pt plus 2pt minus 2pt +\textfloatsep 20pt plus 2pt minus 4pt \dbltextfloatsep 20pt plus 2pt minus 4pt +%\@maxsep 20pt \@dblmaxsep 20pt %!PN +\@fptop 0pt plus 1fil \@dblfptop 0pt plus 1fil +\@fpsep 8pt plus 2fil \@dblfpsep 8pt plus 2fil +\@fpbot 0pt plus 1fil \@dblfpbot 0pt plus 1fil +\def\topfraction{1.0} \def\dbltopfraction{1.0} +\def\floatpagefraction{0.8} \def\dblfloatpagefraction{0.8} +\setcounter{topnumber}{2} \setcounter{dbltopnumber}{4} +% +\intextsep 12pt plus 2pt minus 2pt +\setcounter{bottomnumber}{2} +\def\bottomfraction{.4} +\setcounter{totalnumber}{4} +\def\textfraction{.2} + +% Reset baselinestretch within floats. +% Originally stolen from Stanford University thesis style. +% -------------------------------------------------------- +\def\@xfloat#1[#2]{\ifhmode \@bsphack\@floatpenalty -\@Mii\else + \@floatpenalty-\@Miii\fi\def\@captype{#1}\ifinner + \@parmoderr\@floatpenalty\z@ + \else\@next\@currbox\@freelist{\@tempcnta\csname ftype@#1\endcsname + \multiply\@tempcnta\@xxxii\advance\@tempcnta\sixt@@n + \@tfor \@tempa :=#2\do + {\if\@tempa h\advance\@tempcnta \@ne\fi + \if\@tempa t\advance\@tempcnta \tw@\fi + \if\@tempa b\advance\@tempcnta 4\relax\fi + \if\@tempa p\advance\@tempcnta 8\relax\fi + }\global\count\@currbox\@tempcnta}\@fltovf\fi + \global\setbox\@currbox\vbox\bgroup + \def\baselinestretch{1}\small\normalsize + \hsize\columnwidth \@parboxrestore} + +% ************************************************************************** +% ***** Caption Definition ********************************************* +% ************************************************************************** +% some journals do not have centered captions for figures. +\newif\ifc@ptionleft \c@ptionlefttrue +\def\leftfigcaptions{\c@ptionlefttrue} +\def\centerfigcaptions{\c@ptionleftfalse} + +\long\def\caption{\refstepcounter\@captype \@dblarg{\@caption\@captype}} + +\long\def\@caption#1[#2]#3{\par\addcontentsline{\csname ext@#1\endcsname}{#1}{% + \protect\numberline{\csname the#1\endcsname}{\ignorespaces #2}} + \begingroup \@parboxrestore \normalsize + \@makecaption{\csname fnum@#1\endcsname}{\ignorespaces #3}{#1}\par + \endgroup} + +\def\tablestring{table} +\def\figurestring{figure} + +% changed by GLP to allow table captions to be set to a specific maximum +% width "\captionwidth", if defined. +\newlength{\captionindent} +\long\def\@makecaption#1#2#3{ +\ifx\figurestring#3 + \vskip 5pt + \setbox\@tempboxa\hbox{\small #1.~ #2} + \ifdim \wd\@tempboxa >\hsize + \setbox\@tempboxa\hbox{\small #1.~ } + %\setlength\captionindent{\wd\@tempboxa} \divide\captionindent by 2 + %\parbox[t]{\hsize}{\small \hangindent \captionindent \hangafter=1% + \parbox[t]{\hsize}{\small + \unhbox\@tempboxa#2} + \else \hbox + to\hsize{\small\ifc@ptionleft\else\hfil\fi\box\@tempboxa\hfil} + \fi +\else + \begin{center} + \ifx\captionwidth\undefined {\small #1}\\{\small\scshape #2} + \else + \begin{minipage}{\captionwidth} + \begin{center}{\small #1}\\{\small\scshape #2}\end{center} + \end{minipage} + \fi + \end{center}\vskip 4pt +\fi} + +\def\thefigure{\@arabic\c@figure} +\def\fps@figure{tbp} +\def\ftype@figure{1} +\def\ext@figure{lof} +\def\fnum@figure{\figurename\ \thefigure} +%\def\figure{\@float{figure}} % GLP +%\let\endfigure\end@float +\@namedef{figure*}{\@dblfloat{figure}} +\@namedef{endfigure*}{\end@dblfloat} + +\def\thetable{\@Roman\c@table} +\def\fps@table{tbp} +\def\ftype@table{2} +\def\ext@table{lot} +\def\fnum@table{TABLE~\thetable} +\def\table{\@float{table}} +\let\endtable\end@float +\@namedef{table*}{\@dblfloat{table}} +\@namedef{endtable*}{\end@dblfloat} + +% ************************************************************************** +% ***** Header/Footer Definition *************************************** +% ************************************************************************** +% compute the time in hours and minutes; make new vars \timehh and \timemm +\newcount\timehh\newcount\timemm\timehh=\time\divide\timehh by 60 +\timemm=\time\count255=\timehh\multiply\count255 by-60 +\advance\timemm by \count255 +\ifnum\timehh=12\def\apm{pm}\else +\ifnum\timehh>12\def\apm{pm}\advance\timehh by-12\else +\def\apm{am}\fi\fi +\def\t@me{\number\timehh\,:\,\ifnum\timemm<10 0\fi\number\timemm\,\apm} + +% default definitions +% ------------------- +\def\theevenhe@d{\footnotesize\thepage \hfil \leftmark\hbox{}} +\def\theoddhe@d{\hbox{}\footnotesize\rightmark \hfil \thepage} +\def\theevenf@@t{} +\def\theoddf@@t{} + +\def\theeventphe@d{\footnotesize\thepage \hfil \hbox{}} +\def\theoddtphe@d{\hbox{}\footnotesize \hfil \thepage} +\def\theeventpf@@t{} +\def\theoddtpf@@t{} + +\def\theevencphe@d{} +\def\theoddcphe@d{} +\def\theevencpf@@t{} +\def\theoddcpf@@t{} + +\def\internalmsg{Preliminary version for evaluation: Please do not + circulate without the permission of the author(s)} +\def\submittedmsg{SUBMITTED FOR PUBLICATION TO:} +\def\acceptedmsg{ACCEPTED FOR PUBLICATION:} +\def\inpressmsg{(IN PRESS)} +\def\reprintmsg{REPRINTED FROM:} + +% default cover page style (optional cover page) +% ---------------------------------------------- +\def\ps@coverpagestyle{ + \def\@oddhead{\theoddcphe@d} \def\@evenhead{\theevencphe@d} + \def\@oddfoot{\theoddcpf@@t} \def\@evenfoot{\theevencpf@@t} +} + +% default title page style (first page of paper) +% ---------------------------------------------- +\def\ps@titlepagestyle{ + \def\@oddhead{\theoddtphe@d} \def\@evenhead{\theeventphe@d} + \def\@oddfoot{\theoddtpf@@t} \def\@evenfoot{\theeventpf@@t} +} + +% default regular page style +% -------------------------- +\if@twoside + \def\ps@headings{ + \def\@oddhead{\theoddhe@d} + \def\@evenhead{\theevenhe@d} + \def\@oddfoot{\theoddf@@t} \def\@evenfoot{\theevenf@@t} + } +\else + \def\ps@headings{ + \def\@oddhead{\theoddhe@d} + \def\@oddfoot{\theoddf@@t} + \def\@evenhead{} \def\@evenfoot{} + } +\fi + +% For draft mode (no sub-modes allowed) +% ------------------------------------- +\ifdr@ft + \def\leftmark{\sh@rttitle}\let\rightmark\leftmark + \def\theoddf@@t{\footnotesize\today---\t@me\hfil DRAFT} + \def\theevenf@@t{\footnotesize DRAFT\hfil\today---\t@me} + \def\theoddtpf@@t{\footnotesize\today---\t@me\hfil DRAFT} + \def\theeventpf@@t{\footnotesize DRAFT\hfil\today---\t@me} +\fi + +% For submission mode (default plus internal sub-modes allowed) +% ------------------------------------------------------------- +\ifsubm@t + \def\leftmark{\sh@rttitle}\def\rightmark{\titl@line} + \ifintern@l + \def\theeventphe@d{\footnotesize\thepage \hfil \rightmark\hbox{}} + \def\theoddtphe@d{\hbox{}\footnotesize\rightmark \hfil \thepage} + \def\rightmark{\vbox to 0pt{\vss\hbox{\internalmsg} \hbox{\sh@rttitle}}} + \def\leftmark{\vbox to 0pt{\vss\hbox{\internalmsg} + \hbox{\phantom{\internalmsg}\llap{\sh@rttitle}}}} + \else % put date on first page. + \edef\TODAY{\uppercase{\today}} + \def\theeventphe@d{\footnotesize\thepage \hfil \submittedmsg\ + \@journal\@titletext, \TODAY} + \def\theoddtphe@d{\footnotesize\submittedmsg\ + \@journal\@titletext, \TODAY\hfil \thepage} + \def\theevencphe@d{\footnotesize\hbox{} \hfil \submittedmsg\ + \@journal\@titletext, \TODAY} + \def\theoddcphe@d{\footnotesize\submittedmsg\ + \@journal\@titletext, \TODAY\hfil \hbox{}} + \fi +\fi + +% For compressed mode (default, internal, submitted and +% inpress sub-modes allowed) +% ----------------------------------------------------- +\ifc@mpress + \def\leftmark{\sh@rttitle}\def\rightmark{\titl@line} + \ifintern@l + \def\theeventphe@d{\footnotesize\thepage \hfil \rightmark\hbox{}} + \def\theoddtphe@d{\hbox{}\footnotesize\rightmark \hfil \thepage} + \def\rightmark{\vbox to 0pt{\vss\hbox{\internalmsg} \hbox{\sh@rttitle}}} + \def\leftmark{\vbox to 0pt{\vss\hbox{\internalmsg} + \hbox{\phantom{\internalmsg}\llap{\sh@rttitle}}}} + \fi + \ifprepr@nt + \edef\TODAY{\uppercase{\today}} + \def\theeventphe@d{\footnotesize\thepage \hfil \submittedmsg\ + \@journal\@titletext, \TODAY} + \def\theoddtphe@d{\footnotesize\submittedmsg\ + \@journal\@titletext, \TODAY\hfil \thepage} + \def\theevencphe@d{\footnotesize\hbox{} \hfil \submittedmsg\ + \@journal\@titletext, \TODAY} + \def\theoddcphe@d{\footnotesize\submittedmsg\ + \@journal\@titletext, \TODAY\hfil \hbox{}} + \fi + \ifinpr@ss + \def\leftmark{\acceptedmsg\ \@journal\@titletext, \inpressmsg} + \def\theeventphe@d{\footnotesize\thepage \hfil \leftmark\hbox{}} + \def\theoddtphe@d{\hbox{}\footnotesize\leftmark \hfil \thepage} + \fi +\fi + +% For final (evaluate) mode (default, techreport, internal, +% submitted, inpress and reprint sub-modes allowed) +% --------------------------------------------------------- +\ifev@l + \edef\TODAY{\uppercase{\today}} + \def\leftmark{\@journal\@titletext}\def\rightmark{\titl@line} + \def\theeventphe@d{\footnotesize\thepage \hfil \leftmark\hbox{}} + \def\theoddtphe@d{\hbox{}\footnotesize\leftmark \hfil \thepage} + \if@technote % make header a little bigger + \def\theevenhe@d{\small\thepage \hfil \leftmark\hbox{}} + \def\theoddhe@d{\hbox{}\small\rightmark \hfil \thepage} + \def\theeventphe@d{\small\thepage \hfil \leftmark\hbox{}} + \def\theoddtphe@d{\hbox{}\small\leftmark \hfil \thepage} + \fi + \ifintern@l + \def\theeventphe@d{\footnotesize\thepage \hfil \rightmark\hbox{}} + \def\theoddtphe@d{\hbox{}\footnotesize\rightmark \hfil \thepage} + \def\rightmark{\vbox to 0pt{\vss\hbox{\internalmsg} \hbox{\sh@rttitle}}} + \def\leftmark{\vbox to 0pt{\vss\hbox{\internalmsg} + \hbox{\phantom{\internalmsg}\llap{\sh@rttitle}}}} + \fi + \ifprepr@nt + \def\leftmark{\submittedmsg\ \@journal\@titletext, \TODAY} + \fi + \ifinpr@ss + \def\leftmark{\acceptedmsg\ \@journal\@titletext, \inpressmsg} + \fi + \ifrepr@nt + % reset page size on second and following pages b/c no copyright info + \let\oldshipout\shipout + \gdef\shipout{\global\textheight 243.5mm\oldshipout} + \def\theeventpf@@t{\footnotesize\hfil\@ieeecopyright\hfil} + \def\theoddtpf@@t{\footnotesize\hfil\@ieeecopyright\hfil} + \def\leftmark{\reprintmsg\ \@journal\@titletext} + \fi +\fi + +%% Defines the command for putting the header. footernote{TEXT} is the same +%% as markboth{TEXT}{TEXT}. Here for compatibility with other style files. +\def\markboth#1#2{\def\leftmark{#1}\def\rightmark{#2}} +\def\footernote#1{\markboth{#1}{#1}} + +% ************************************************************************** +% ***** Citation/Bibliography Definitions ****************************** +% ************************************************************************** +%% separate citations with "], [" +\def\@citex[#1]#2{\if@filesw\immediate\write\@auxout{\string\citation{#2}}\fi +\def\@citea{}\@cite{\@for\@citeb:=#2\do {\@citea\def\@citea{], +[}\@ifundefined {b@\@citeb}{{\bf ?}\@warning {Citation `\@citeb' on +page \thepage \space undefined}}% +{\csname b@\@citeb\endcsname}}}{#1}} + +\def\@cite#1#2{[{#1\if@tempswa, #2\fi}]} + +%% Allow short (name-less) citations, when used in conjunction with a +%% bibliography style that creates labels like \citename{, } +\let\@internalcite\cite +\def\cite{\def\citename##1{##1}\@internalcite} +\def\shortcite{\def\citename##1{}\@internalcite} +\def\@biblabel#1{\def\citename##1{##1}[#1]\hfill} + +\def\thebibliography#1{\section*{\refname}\footnotesize\list + {\hss[\arabic{enumi}]}{\settowidth\labelwidth{[#1]}\leftmargin\labelwidth + \advance\leftmargin\labelsep \itemsep 0pt plus .5pt + \usecounter{enumi}} + \def\newblock{\hskip .11em plus .33em minus .07em} + \sloppy\clubpenalty4000\widowpenalty4000 + \sfcode`\.=1000\relax + \ifev@l\else\normalsize\fi %added by GLP +} +\let\endthebibliography=\endlist + +% ************************************************************************** +% ***** Appendix/Appendices Definitions ******************************** +% ************************************************************************** +\newcounter{numappendices}\setcounter{numappendices}{0} +\newif\ifappendix \appendixfalse +%% appendix command for one single appendix +\def\appendix{\par + \appendixtrue + \typeout{appendices: \arabic{numappendices}} + \setcounter{section}{0}\setcounter{subsection}{0} + \gdef\thesection{\Alph{section}} + \ifnum \value{numappendices}>1 + \section*{\appendicesname} + \else + \section*{\appendixname} + \fi + \setcounter{numappendices}{0} +} +%% appendices command for multiple appendicies +\def\appendices{\par + \appendixtrue + \typeout{appendices: \arabic{numappendices}} + \setcounter{section}{0}\setcounter{subsection}{0} + \gdef\thesection{\Alph{section}} \section*{\appendicesname} + \setcounter{numappendices}{0} +} +\AtEndDocument{\if@filesw\immediate\write\@auxout{\string\setcounter{numappendices}{\arabic{numappendices}}}\fi} + +% ************************************************************************** +% ***** Title Definitions ********************************************** +% ************************************************************************** +\def\titl@line{\sh@rttitle} %for the header at the top of the page. + +\def\@title{\typeout{ieee: Warning! No \noexpand\title given!}} +\def\title{\@ifnextchar [{\titlea}{\titleb}}%] + +\def\set@title#1{\gdef\@title{#1}\global\def\set@title##1{}} +\def\setsh@rttitle#1{\gdef\sh@rttitle{#1}\global\def\setsh@rttitle##1{}} +\def\titlea[#1]#2{\set@title{#2}\setsh@rttitle{\uppercase{#1}}} +\def\titleb#1{\set@title{#1}\setsh@rttitle{\uppercase{#1}}} + +\def\authorinfo#1{\let\\\relax\thanks{#1}} + +\ifev@l + \if@technote + \def\member#1{} + \else + \def\member#1{, \emph{#1, IEEE}} + \fi +\else + \def\member#1{} +\fi + +\def\and{\unskip% % \begin{tabular} +\end{tabular}% +\hskip 0pt plus 0.1pt% +\begin{tabular}[t]{@{}c@{}}\ }% + +\def\@author{\typeout{ieee: Warning! No \noexpand\author given!}} +\def\author{\@ifnextchar [{\authora}{\authorb}}%] +\def\set@author#1{\gdef\@author{#1}\global\def\set@author##1{}} +\def\settitl@line#1{\gdef\titl@line{#1}\global\def\settitl@line##1{}} +\def\authora[#1]#2{\set@author{#2}\if@non\else\settitl@line{#1: \sh@rttitle}\fi} +\def\authorb#1{\set@author{#1}} + +\def\date#1{\def\today{#1}\edef\TODAY{\uppercase{\today}}} + +\long\def\maketitle{% + \begingroup + \let\@thanks\@empty + \renewcommand\thefootnote{} % the \thanks{} mark type is empty + \iftitlep@ge\begin{titlepage}\@maketitlepage\@thanks\end{titlepage}% + \let\@thanks\@empty\fi + \thispagestyle{titlepagestyle} + \if@twocolumn + \if@technote + %\if@twoside\newpage\cleardoublepage\else\newpage\fi% + \newpage\global\@topnum\z@ + \ifrepr@nt + \ifx\@loginfo\undefined\typeout{ieee: Warning! No \noexpand\loginfo + given!}\else\let\\\relax\thanks{\@loginfo}\fi% + \fi + \@maketitle + \else + \ifnum \col@number=\@ne + \ifrepr@nt + \ifx\@loginfo\undefined\typeout{ieee: Warning! No \noexpand\loginfo + given!}\else\let\\\relax\thanks{\@loginfo}\fi% + \fi + \@maketitle + \else \twocolumn[% + \ifrepr@nt% + \ifx\@loginfo\undefined\typeout{ieee: Warning! No \noexpand\loginfo% + given!}\else\let\\\relax\thanks{\@loginfo}\fi% + \fi% + \@maketitle]% + \fi + \fi + \else + \newpage + \global\@topnum\z@ % Prevents figures from going at top of page. + \ifrepr@nt + \ifx\@loginfo\undefined\typeout{ieee: Warning! No \noexpand\loginfo + given!}\else\let\\\relax\thanks{\@loginfo}\fi + \fi + \@maketitle + \fi + \thispagestyle{titlepagestyle}% + \@thanks + \endgroup + \setcounter{footnote}{0}% + \global\let\thanks\relax \global\let\maketitle\relax + \global\let\@maketitle\relax \global\let\@thanks\@empty + \global\let\@author\@empty \global\let\@date\@empty + \global\let\@title\@empty \global\let\title\relax + \global\let\author\relax \global\let\date\relax + \global\let\and\relax +} + +\long\def\@maketitle{\unskip\newpage% + \begin{center}\blsone + \let \footnote \thanks + \if@technote + {\bfseries\@title\par}\if@non\else\vskip 1.3em{\lineskip .5em + \noindent\begin{tabular}[t]{@{}c@{}}\@author\end{tabular}}\fi\par + \else\unskip + \noindent{\Huge\@title\par}% + \if@non\else\vskip1.0em% + \noindent{\large\lineskip .5em% + \begin{tabular}[t]{@{}c@{}}\@author\end{tabular}}% + \fi\par% + \if@nvited\vskip1.0em\noindent\emph{\large(Invited Paper)}\par\fi + \fi + \ifrepr@nt + \ifx\@lognumber\undefined\typeout{ieee: Warning! No + \noexpand\pubitemident or \noexpand\lognumber + given!}\else\thanks{\@lognumber}\fi% + \fi + \end{center}\par\vskip 0.5em}% + +\long\def\@maketitlepage{\newpage% + \mbox{}\vfil + \begin{center}\blsone + \let \footnote \thanks + \if@technote + {\bfseries\@title\par}\vskip 1.3em{\lineskip .5em + \noindent\begin{tabular}[t]{@{}c@{}}\@author\end{tabular}\par} + \else + \vskip0.2em{\Huge\@title\par}\vskip1.0em% + \iftitlep@ge\vfil\fi + \noindent{\large\lineskip .5em% + \begin{tabular}[t]{@{}c@{}}\@author\end{tabular}\par}% + \fi + \end{center}\par\vfil\mbox{}} + +\def\@journal{\typeout{ieee: Warning! No \noexpand\journal given!}} +\def\journal#1{\def\@journal{\uppercase{#1}}} + +\def\@ieeecopyright{\typeout{ieee: Warning! No \noexpand\ieeecopyright given!}} +\def\ieeecopyright#1{\def\@ieeecopyright{#1}} + +\def\lognumber#1{\def\@lognumber{IEEE Log Number #1.}} +\def\pubitemident#1{\def\@lognumber{Publisher Item Identifier #1.}} +\long\def\loginfo#1{\long\def\@loginfo{\hbox{\vrule height 3ex width \z@}#1}} + +\def\sh@rttitle{} +\def\@titletext{} +\def\titletext#1{\def\@titletext{#1}} + +\def\firstpage#1{\setcounter{page}{#1}} + +% ************************************************************************** +% ***** Abstract Definition ******************************************** +% ************************************************************************** +\def\abstract{% + \if@twocolumn + \small\bfseries{\itshape\abstractname\/---}% + \else + \begin{center}\vspace{-0.8em}\small\bf\abstractname\end{center} + \quotation\small + \fi\ignorespaces} +\def\endabstract{\vspace{0.6em}\par\if@twocolumn\else\endquotation\fi + \normalsize\normalstyle} + +% ************************************************************************** +% ***** Keywords Definition ******************************************** +% ************************************************************************** +\def\keywords{\vspace{-.3em} + \if@twocolumn + \small\bfseries{\itshape\keywordsname\/---}% + \else + \begin{center}\small\bf\keywordsname\end{center}\quotation\small + \fi\ignorespaces} +\def\endkeywords{\vspace{0.6em}\par\if@twocolumn\else\endquotation\fi + \normalsize\normalstyle} + +% ************************************************************************** +% ***** Fix Section Numbering ****************************************** +% ************************************************************************** +\gdef\@punct{.\ \ } % Punctuation after run-in section heading +\def\@sect#1#2#3#4#5#6[#7]#8{% + \ifnum #2>\c@secnumdepth + \def\@svsec\@empty + \else + \refstepcounter{#1}% + \protected@edef\@svsec{% + %\ifnum #2=1\Roman{#1}.\fi\ifnum #2=2\Alph{#1}.\fi + \ifnum #2=1\thesection.\fi + \ifnum #2=2\thesubsection.\fi + \ifnum #2>2{\csname the#1dis\endcsname}\if@technote.\fi\fi \hskip .5em} + \ifnum #2=1\ifappendix\stepcounter{numappendices}\fi\fi + \fi + \@tempskipa #5\relax + \ifdim \@tempskipa>\z@ + \begingroup #6\relax + \@hangfrom{\hskip #3\relax\@svsec}{\interlinepenalty \@M #8\par} + \endgroup + \csname #1mark\endcsname{#7} + \addcontentsline{toc}{#1}{\ifnum #2>\c@secnumdepth\else + \protect\numberline{\csname the#1\endcsname}\fi#7} + \else + \def\@svsechd{#6\hskip #3\@svsec #8\@punct\csname #1mark\endcsname{#7} + \addcontentsline{toc}{#1}{\ifnum #2>\c@secnumdepth \else + \protect\numberline{\csname the#1\endcsname}\fi#7}} + \fi + \@xsect{#5}} + +\def\@ssect#1#2#3#4#5{\@tempskipa #3\relax + \ifdim \@tempskipa>\z@ + \begingroup #4\@hangfrom{\hskip #1}{\interlinepenalty \@M #5\par}\endgroup + \else \def\@svsechd{#4\hskip #1\relax #5\@punct}\fi + \@xsect{#3}} + +% ************************************************************************** +% ***** Section Definitions ******************************************** +% ************************************************************************** +\def\section{\@startsection{section}{1}{\z@}{2.0ex plus .5ex + minus .2ex}{1.0ex plus .2ex}{\centering\scshape}} +\def\subsection{\@startsection{subsection}{2}{\z@}{2.0ex plus .5ex + minus .2ex}{1.0ex plus .2ex}{\itshape}} +\if@technote + \def\subsubsection{\@startsection{subsubsection}{3}{\z@}{2.0ex plus .5ex + minus .1ex}{0pt}{\itshape}} +\else + \def\subsubsection{\@startsection{subsubsection}{3}{\z@}{2.0ex plus .5ex + minus .2ex}{1.0ex plus .2ex}{\normalstyle}} + \def\paragraph{\@startsection{paragraph}{4}{\z@}{1.0ex plus .5ex + minus .2ex}{0ex}{\normalstyle}} +\fi + +% ************************************************************************** +% ***** Special Environment Definitions ******************************** +% ************************************************************************** +\def\QED{\mbox{\rule[0pt]{1.5ex}{1.5ex}}} +\def\proof{\noindent\hspace{1em}{\it Proof: }} +\def\endproof{\hspace*{\fill}~\QED\par\endtrivlist\unskip} +\def\@begintheorem#1#2{\tmpitemindent\itemindent\topsep 0pt\normalstyle\trivlist + \item[\hskip \labelsep{\indent\it #1\ #2:}]\itemindent\tmpitemindent} +\def\@opargbegintheorem#1#2#3{\tmpitemindent\itemindent\topsep 0pt\normalstyle \trivlist + \item[\hskip\labelsep{\indent\it #1\ #2\ \normalstyle(#3)}]\itemindent\tmpitemindent} +\def\@endtheorem{\endtrivlist\unskip} + +% ************************************************************************** +% ***** Special Environment Definitions ******************************** +% ************************************************************************** +\if@twoside\else\raggedbottom\fi + +%% Definition for Big letter at the beginning of a paragraph +%% +\def\PARstart#1#2 {\begingroup\def\par{\endgraf\endgroup\lineskiplimit=0pt} + \setbox2=\hbox{\uppercase{#2} }\newdimen\tmpht \tmpht \ht2 + \advance\tmpht by \baselineskip\font\hhuge=cmr10 at \tmpht + \setbox1=\hbox{{\hhuge #1}} + \count7=\tmpht \count8=\ht1\divide\count8 by 1000 \divide\count7 by\count8 + \tmpht=.001\tmpht\multiply\tmpht by \count7\font\hhuge=cmr10 at \tmpht + \setbox1=\hbox{{\hhuge #1}} \noindent \hangindent1.05\wd1 + \hangafter=-2 {\hskip-\hangindent \lower1\ht1\hbox{\raise1.0\ht2\copy1}% + \kern-0\wd1}\copy2\lineskiplimit=-1000pt} + +\def\PARstartCal#1#2 {\begingroup\def\par{\endgraf\endgroup\lineskiplimit=0pt} + \setbox2=\hbox{\uppercase{#2} }\newdimen\tmpht \tmpht \ht2 + \advance\tmpht by \baselineskip\font\hhuge=cmsy10 at \tmpht + \setbox1=\hbox{{\hhuge #1\/}} + \count7=\tmpht \count8=\ht1\divide\count8 by 1000 \divide\count7 by\count8 + \tmpht=.001\tmpht\multiply\tmpht by \count7\font\hhuge=cmsy10 at \tmpht + \setbox1=\hbox{{\hhuge #1\/}} \noindent \hangindent1.05\wd1 + \hangafter=-2 {\hskip-\hangindent \lower1\ht1\hbox{\raise1.0\ht2\copy1}% + \kern-0\wd1}\copy2\lineskiplimit=-1000pt} + +\def\PARstartLyX#1{\PARstart #1} +\def\PARstartCalLyX#1{\PARstartCal #1} + +\if@technote\def\PARstart#1#2{#1#2}\fi % if technical note, disable it +\if@technote\def\PARstartCal#1#2{#1#2}\fi % if technical note, disable it +\if@technote\def\PARstartLyX#1{#1}\fi % if technical note, disable it +\if@technote\def\PARstartCalLyx#1{#1}\fi % if technical note, disable it + +% ************************************************************************** +% ***** Misc. Definitions ********************************************** +% ************************************************************************** +%Restore single spacing +\newcommand{\blsone}{\renewcommand\baselinestretch{1}% + \renewcommand\arraystretch{1.2}\setlength{\parindent}{\parindentsave}% + \normalsize} +\newcommand{\capitem}[1]{{\hspace{0.2ex}(#1)}~} +\newcommand{\insdate}{} + +% ************************************************************************** +% ***** MATH Definitions *********************************************** +% ************************************************************************** +\def\eqnarray{% + \stepcounter{equation}% + \def\@currentlabel{\p@equation\theequation}% + \global\@eqnswtrue + \m@th + \global\@eqcnt\z@ + \tabskip\@centering + \let\\\@eqncr + $$\everycr{}\halign to\displaywidth\bgroup + \hskip\@centering$\displaystyle\tabskip\z@skip{##}$\@eqnsel + &\global\@eqcnt\@ne\hskip \eqnarr@ysep\hfil${##}$\hfil + &\global\@eqcnt\tw@ \hskip \eqnarr@ysep + $\displaystyle{##}$\hfil\tabskip\@centering + &\global\@eqcnt\thr@@ \hb@xt@\z@\bgroup\hss##\egroup + \tabskip\z@skip + \cr +} +\def\endeqnarray{% + \@@eqncr + \egroup + \global\advance\c@equation\m@ne + $$\@ignoretrue +} + +% ************************************************************************** +% ***** Biography Definitions ****************************************** +% ************************************************************************** +% This is the main code for the biography environment of the IEEE +% transactions class. The previous biography code had some known +% problems which were difficult to fix. The crux of the issue was that +% the photo frame was overlaid by text when \baselinestretch>1 or when +% the biography consisted of multiple short paragraphs. +% +% The fix was done by extracting code from the excellent package: +% 'picinpar.sty' version 1.2a as of july 13, 1993 +% by Friedhelm Sowa +% +% (At least most of) The bugs you find in this code were introduced +% unwittingly by myself. +% +%---------------- +% Known problems: +% +% - Don't use multiple blank lines to separate paragraphs. A single +% blank line works well, but multiple blank lines will confuse +% the code. This has something to do with the \def\par{\\\indent} +% line, but I can't think of an appropriate fix. Similarly, make +% sure the environment doesn't end with an extra blank line. +% - Don't use \samepage +% - Use \footnotemark within and \footnotetext outside the +% window-environment instead of \footnote +% - When using the epic-package load picinpar before epic +% like \documentstyle[...,picinpar,epic]{...} +% +% Counts +\newcount\br \newcount\nb \newcount\tcdsav \newcount\tcl \newcount\tcd +\newcount\tcn \newcount\cumtcl +% Dimens +\newdimen\rtside \newdimen\hpic \newdimen\vpic \newdimen\strutilg +\newdimen\picwd \newdimen\topheight \newdimen\ilg \newdimen\lpic +\newdimen\lwindowsep \newdimen\rwindowsep % VK 10 Feb 93 +\lwindowsep0.5\baselineskip % " +\rwindowsep0.5\baselineskip % " +\newdimen\cumpar +% Tokens +\newtoks\twa \newtoks\la \newtoks\ra \newtoks\ha \newtoks\pictoc +% Boxes +\newbox\rawtext \newbox\holder \newbox\windowbox \newbox\wartext +\newbox\finaltext \newbox\aslice \newbox\bslice \newbox\wbox +\newbox\wstrutbox \newbox\picbox \newbox\waslice \newbox\wbslice +\newbox\fslice + % Another strut +\def\wstrut{\relax\ifmmode\copy\wstrutbox\else\unhcopy\wstrutbox\fi} +% + +\def\getpic#1{\sbox{\@tempboxa}{\includegraphics{#1}}% +\newcount\tmpcta \tmpcta=\ht\@tempboxa% +\newcount\tmpctb \tmpctb=\wd\@tempboxa% +\divide\tmpctb by 100% +\divide\tmpcta by\tmpctb% +\ifnum\tmpcta>133% +\typeout{ieee: Biography picture `#1' too tall.}% +\frame{\hbox to 25mm{\hfil\resizebox{!}{32mm}{\usebox{\@tempboxa}}\hfil}}% +\else \ifnum\tmpcta<123% +\typeout{ieee: Biography picture `#1' too wide.}% +\frame{\vbox to 32mm{\vss\hbox{\resizebox{25mm}{!}{\usebox{\@tempboxa}}}\vss}}% +\else% +\resizebox{25mm}{32mm}{\usebox{\@tempboxa}} +\fi\fi} + +\long\def\biographyLyX#1{\if@non\else\begin{biography} #1\end{biography}\fi} + +\if@non + \long\def\biography{} +\else + \long\def\biography{\@ifnextchar [{\@biographyb}{\@biographya[{\unitlength + 1mm\hbox{\framebox(25,32){}}}]}} +\fi + +\long\def\@biographyb[#1]{\@biographya[\getpic{#1}]} + +\long\def\@biographya[#1]#2{\bgroup +\footnotesize\bigskip\bigskip\bigskip\parskip=0pt\par% +\rule{0pt}{35mm}\vspace*{-35mm}\par% garantees correct page breaking +\begin{main@bio}[{#1}]% +\noindent{\bf #2}% +} +\def\endbiography{\if@non\else\end{main@bio}\egroup\fi} + +\long\def\main@bio[#1]{% #1 is the material for setting a graphic box +\vskip\parskip\everypar{} +\global\cumpar=0pt +\global\cumtcl=0 + \tcd=0 + \rtside=0pt +% \hpic=\linewidth + \twa={} \la={} \ra={} \ha={} +\setbox\wbox=\hbox{(} +\computeilg +\pictoc={#1} +\setbox\windowbox=\vbox{\hbox{#1}} +\picwd=\wd\windowbox +\hpic=\picwd +\vpic=\ht\windowbox\advance\vpic\dp\windowbox +\rtside=\linewidth\advance\rtside-\picwd +\setbox\picbox=\vbox{\hsize=\hpic\vbox to\vpic{\box\windowbox}}% \vfill}}% + +\vpic=\ht\picbox\advance\vpic\dp\picbox +\ifdim\rtside>0pt\advance\rtside-\rwindowsep\fi % " +\global\br=\rtside +\ifnum\picwd=0 +\ifdim\vpic>0pt\picwd=\hpic +\else\vpic=\ht\picbox\advance\vpic\dp\picbox +\fi +\fi + \global\tcl=0 \lpic=0pt + \loop\global\advance\tcl by 1 \lpic=\tcl\baselineskip + \ifdim\lpic<\vpic\repeat + \vpic=\lpic + \global\cumtcl=\tcl +% +% Here we know exactly the number of indented lines and +% are able to generate the tokens for the \parshape list +% + \ifnum\br>0\ra={ 0pt \rtside}\fi + \ifnum\tcd>0\ha={ 0pt \linewidth}\fi + \ifnum\tcl<1\global\tcl=1\fi + \createparshapespec + \tcd=0 % restore the lintel + \global\tcdsav=0 +% +% This is a very tricky part of the package. Some day there +% will exist a detailed documentation. +% +\def\par{\\\indent} +% +% This is where we start to pick up the paragraph(s) +% + \setbox\rawtext=\vbox\bgroup\unvbox\rawtext\unskip + \clubpenalty=0\widowpenalty=0 + \ifnum\brokenpenalty<\maxdimen\else\brokenpenalty=9999\fi + \tolerance=1000 + \parshape=\tcn \the\twa } +% +\def\endmain@bio{% + %\par + \global\tcd=\tcdsav + \egroup\vskip\parskip\parshape=0 % reset parshape; end \box\rawtext + \vbadness=10000 + \splittopskip=0pt +% +% Now we build the boxes beside the window +% +\global\topheight=\tcl\baselineskip +\ifnum\br>0\setbox\holder=\vsplit\rawtext to\topheight\fi +\tcn=\tcl \nb=0 +\ifnum\br>0\nb=\tcn\fi +% +% text on the right side +% +\ifnum\nb>0 + \loop\advance\nb -1 + \setbox\bslice=\vsplit\holder to\baselineskip + \prune\bslice\rtside + \setbox\wbslice=\vbox{\unvbox\wbslice\hbox + to\rtside{\box\bslice\hfil}} + \ifdim\ht\holder>0pt\repeat +\fi +%GLP add fix to make sure bio starts at top of picture +\setbox\wbslice=\vbox to\topheight{\unvbox\wbslice\vfill\vss} +% +% fixing the dimensions of the window part +% +\topheight=\ht\wbslice +% +% ship out the window material to the main vertical list +% +\setbox\windowbox=\vbox{\hbox to\linewidth{% +\vbox to\topheight{\hrule width\picwd height0pt depth0pt\vskip0pt% +\vfill\unvbox\picbox% +\ifnum\picwd>0\vfill\fi% +\vss}\ifnum\br>0\hfill\vbox{\box\wbslice}\fi}}% +% +\unvbox\windowbox% +\loop% lines below picture.... + \setbox\bslice=\vsplit\rawtext to\baselineskip + \prune\bslice\linewidth + \setbox\wbslice=\vbox{\hbox to\linewidth{\box\bslice\hfil}} + \unvbox\wbslice + \ifdim\ht\rawtext>0pt +\repeat +%GLP +%\ifnum\nb>0\topheight=\nb\baselineskip %\advance\topheight by\ilg +%\vspace*{\topheight} +%\fi +}% FINITO +% +% What else do we need? +% +\def\prune#1#2{ +% take a \vbox containing a single \hbox, +% \unvbox it, and cancel the \lastskip +% put in a \hbox of width #2 + \unvbox#1 \setbox#1=\lastbox % \box#1 now is an \hbox + \ifdim\ht#1=\parskip + \setbox#1=\hbox to#2{\vrule height\parskip depth0pt width0pt\hfill} + \else\ifdim\ht#1=0pt\relax + \else\setbox#1=\hbox to#2{\wstrut\unhbox#1\unskip}\fi\fi} +% +% Here the token \twa is generated. +% It's not so difficult as it looks like. +% +\def\createparshapespec{% +\global\tcn=0 +\ifnum\br>0\global\tcn=\tcl\fi +\nb=0 +\ifnum\br>0\nb=\tcn\fi +\global\advance\tcn by\tcd \global\advance\tcn by1 +\ifnum\tcd>0 +\loop\twa=\expandafter{\the\twa\the\ha}\advance\tcd -1 +\ifnum\tcd>0\repeat +\fi +\ifnum\nb>0 +\loop\twa=\expandafter{\the\twa\the\ra}\advance\nb -1 +\ifnum\nb>0\repeat +\fi +\global\twa=\expandafter{\the\twa 0pt \the\linewidth}} +% +\def\computeilg{% compute the interline glue + \tcl=0\ilg=0pt\strutilg=0pt + \loop\setbox\wbox=\hbox{\char\tcl} + \ifdim\ht\wbox>\ilg\ilg=\ht\wbox\fi + \ifdim\dp\wbox>\strutilg\strutilg=\dp\wbox\fi + \advance\tcl by 1 + \ifnum\tcl<128\repeat + \ht\wbox=\ilg + \dp\wbox=\strutilg + \strutilg=\ht\wbox %\advance\strutilg by\ilg + \ifdim\strutilg>\baselineskip + \typeout{character with height greater baselineskip found in font} + \typeout{baselineskip changed to 1.5 of that height!} + \baselineskip=1.5\strutilg + \fi + \global\ilg=\baselineskip + \global\advance\ilg-\ht\wbox \global\advance\ilg-\dp\wbox + \strutilg=\ht\wbox \advance\strutilg by\ilg + \setbox\wstrutbox=\hbox{\vrule height\strutilg depth\dp\wbox width0pt}} + + +% the following code from version.sty by Stephen Bellantoni 1990, loosely +% based on "annotation.sty" by Tom Hofmann. Used to exclude "biography" from +% anonymous mode. +\begingroup +\catcode`@=11\relax% +\catcode`{=12\relax\catcode`}=12\relax% +\catcode`(=1\relax \catcode`)=2\relax% +\gdef\glpinclude#1(% + \expandafter\gdef\csname #1\endcsname% + ()% + \expandafter\gdef\csname end#1\endcsname% + ()% +)% +\gdef\glpexclude#1(% + \expandafter\gdef\csname #1\endcsname% + (\@bsphack\catcode`{=12\relax\catcode`}=12\relax\csname #1@NOTE\endcsname)% + \long\expandafter\gdef\csname #1@NOTE\endcsname ##1\end{#1}% + (\csname #1END@NOTE\endcsname)% + \expandafter\gdef\csname #1END@NOTE\endcsname% + (\@esphack\end(#1))% +)% +\endgroup + +%------- +\def\@confplacedate{\typeout{ieee: Warning! No \noexpand\confplacedate set!} +\bfseries `confplacedate' needs to be set. For example, to: Stanford, CA, USA, +September 29--30, 1991} +\def\confplacedate#1{\def\@confplacedate{#1}} + +%%%%%%%%%%%%%%%%%%%%%%%%% End of ieee.cls %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% diff --git a/cryptominisat/cppsrc/docs/satcomp20-pdf/walksat/sigproc.bib b/cryptominisat/cppsrc/docs/satcomp20-pdf/walksat/sigproc.bib new file mode 100644 index 00000000..01d15513 --- /dev/null +++ b/cryptominisat/cppsrc/docs/satcomp20-pdf/walksat/sigproc.bib @@ -0,0 +1,468 @@ +@InProceedings{stamping, +author="Heule, Marijn J. H. +and J{\"a}rvisalo, Matti +and Biere, Armin", +editor="Sakallah, Karem A. +and Simon, Laurent", +title="Efficient {CNF} Simplification Based on Binary Implication Graphs", +booktitle="Theory and Applications of Satisfiability Testing - SAT 2011", +year="2011", +publisher="Springer Berlin Heidelberg", +address="Berlin, Heidelberg", +pages="201--215", +abstract="This paper develops techniques for efficiently detecting redundancies in CNF formulas. We introduce the concept of hidden literals, resulting in the novel technique of hidden literal elimination. We develop a practical simplification algorithm that enables ``Unhiding'' various redundancies in a unified framework. Based on time stamping literals in the binary implication graph, the algorithm applies various binary clause based simplifications, including techniques that, when run repeatedly until fixpoint, can be too costly. Unhiding can also be applied during search, taking learnt clauses into account. We show that Unhiding gives performance improvements on real-world SAT competition benchmarks.", +isbn="978-3-642-21581-0" +} + +@inproceedings{TACAS-2010-JarvisaloBH, + author = "Matti Järvisalo and Armin Biere and Marijn Heule", + booktitle = "{Proceedings of the 16th International Conference on Tools and Algorithms for the Construction and Analysis of Systems}", + doi = "10.1007/978-3-642-12002-2_10", + pages = "129--144", + publisher = "{Springer International Publishing}", + series = "{Lecture Notes in Computer Science}", + title = "{Blocked Clause Elimination}", + volume = 6015, + year = 2010, +} + +@InProceedings{probsat, +author="Balint, Adrian +and Sch{\"o}ning, Uwe", +editor="Cimatti, Alessandro +and Sebastiani, Roberto", +title="Choosing Probability Distributions for Stochastic Local Search and the Role of Make versus Break", +booktitle="Theory and Applications of Satisfiability Testing -- SAT 2012", +year="2012", +publisher="Springer Berlin Heidelberg", +address="Berlin, Heidelberg", +pages="16--29", +abstract="Stochastic local search solvers for SAT made a large progress with the introduction of probability distributions like the ones used by the SAT Competition 2011 winners Sparrow2010 and EagleUp. These solvers though used a relatively complex decision heuristic, where probability distributions played a marginal role.", +isbn="978-3-642-31612-8" +} + +@InProceedings{balint-improving-sls, +author="Balint, Adrian +and Biere, Armin +and Fr{\"o}hlich, Andreas +and Sch{\"o}ning, Uwe", +editor="Sinz, Carsten +and Egly, Uwe", +title="Improving Implementation of {SLS} Solvers for {SAT} and New Heuristics for {k-SAT} with Long Clauses", +booktitle="Theory and Applications of Satisfiability Testing -- SAT 2014", +year="2014", +publisher="Springer International Publishing", +address="Cham", +pages="302--316", +abstract="Stochastic Local Search (SLS) solvers are considered one of the best solving technique for randomly generated problems and more recently also have shown great promise for several types of hard combinatorial problems. Within this work, we provide a thorough analysis of different implementation variants of SLS solvers on random and on hard combinatorial problems. By analyzing existing SLS implementations, we are able to discover new improvements inspired by CDCL solvers, which can speed up the search of all types of SLS solvers. Further, our analysis reveals that the multilevel break values of variables can be easily computed and used within the decision heuristic. By augmenting the probSAT solver with the new heuristic, we are able to reach new state-of-the-art performance on several types of SAT problems, especially on those with long clauses. We further provide a detailed analysis of the clause selection policy used in focused search SLS solvers.", +isbn="978-3-319-09284-3" +} + + + +@inproceedings{DBLP:conf/ictai/LynceS03, + author = {In{\^{e}}s Lynce and + Jo{\~{a}}o P. Marques Silva}, + title = {Probing-Based Preprocessing Techniques for Propositional Satisfiability}, + booktitle = {15th {IEEE} International Conference on Tools with Artificial Intelligence + {(ICTAI} 2003), 3-5 November 2003, Sacramento, California, {USA}}, + pages = {105}, + year = {2003}, + crossref = {DBLP:conf/ictai/2003}, + url = {https://doi.org/10.1109/TAI.2003.1250177}, + doi = {10.1109/TAI.2003.1250177}, + timestamp = {Fri, 02 Nov 2018 09:48:27 +0100}, + biburl = {https://dblp.org/rec/bib/conf/ictai/LynceS03}, + bibsource = {dblp computer science bibliography, https://dblp.org} +} + +@proceedings{DBLP:conf/ictai/2003, + title = {15th {IEEE} International Conference on Tools with Artificial Intelligence + {(ICTAI} 2003), 3-5 November 2003, Sacramento, California, {USA}}, + publisher = {{IEEE} Computer Society}, + year = {2003}, + url = {http://ieeexplore.ieee.org/xpl/mostRecentIssue.jsp?punumber=8840}, + isbn = {0-7695-2038-3}, + timestamp = {Thu, 18 Dec 2014 16:57:40 +0100}, + biburl = {https://dblp.org/rec/bib/conf/ictai/2003}, + bibsource = {dblp computer science bibliography, https://dblp.org} +} + +@InProceedings{chronobt, +author="Nadel, Alexander +and Ryvchin, Vadim", +editor="Beyersdorff, Olaf +and Wintersteiger, Christoph M.", +title="Chronological Backtracking", +booktitle="Theory and Applications of Satisfiability Testing -- {SAT} 2018", +year="2018", +publisher="Springer International Publishing", +address="Cham", +pages="111--121", +abstract="Non-Chronological Backtracking (NCB) has been implemented in every modern CDCL SAT solver since the original CDCL solver GRASP. NCB's importance has never been questioned. This paper argues that NCB is not always helpful. We show how one can implement the alternative to NCB--Chronological Backtracking (CB)--in a modern SAT solver. We demonstrate that CB improves the performance of the winner of the latest SAT Competition, Maple{\_}LCM{\_}Dist, and the winner of the latest MaxSAT Evaluation Open-WBO.", +isbn="978-3-319-94144-8" +} + +@inproceedings{smith94phase, + author = "Barbara Smith", + title = "The Phase Transition in Constraint Satisfaction Problems: {A} {CL}oser Look at the Mushy Region", + booktitle = {{ECAI}'94}, + year = "1994" +} + +@inproceedings{swdia, + author = "Chanseok Oh", + title = "{MiniSat HACK 999ED, MiniSat HACK 1430ED and SWDiA5BY}", + booktitle = "SAT Competition 2014 Booklet", + year = "201", +} + +@inproceedings{lingeling, + author = "Armin Biere", + title = "Yet another Local Search Solver and Lingeling and Friends Entering the SAT Competition 2014", + booktitle = "SAT Competition 2014 Booklet", + year = "2014", +} + +@inproceedings{maple, + author="Tomas Balyo and Marijn J. H. Heule and Matti Jarvisalo", + title="{MapleLRB\_LCM, Maple\_LCM, Maple\_LCM\_Dist, MapleLRB\_LCMoccRestart and Glucose-3.0+width in SAT Competition 2017}", + booktitle = "Proceedings of SAT Competition 2017", + year="2018" +} + +@inproceedings{sat-comp-2014-armin, + author="Belov Anton and Diepold Daniel and Marijn J. H. Heule and Matti Jarvisalo", + title="{Yet another Local Search Solver and Lingeling and Friends Entering the SAT Competition 2014}", + booktitle = "Proceedings of SAT Competition 2014", + year="2014" +} + +@misc {nscc, + author="ASTAR and NTU and NUS and SUTD", + title="{National Supercomputing Centre (NSCC)} {S}ingapore", + url="https://www.nscc.sg/about-nscc/overview/", + year="2018" +} + +@misc {CMS, + author="Mate Soos", + title="{CryptoMiniSat SAT solver GitHub page}", + url="https://github.com/msoos/cryptominisat", + year="2018" +} + +@misc {cadical, + author="Armin Biere", + title="{CaDiCaL SAT solver GitHub page}", + url="https://github.com/arminbiere/cadical", + year="2020" +} + +@inproceedings{DBLP:conf/sat/CaiLS15, + + author = {Shaowei Cai and +Chuan Luo and +Kaile Su}, + + title = {CCAnr: {A} Configuration Checking Based Local Search Solver for Non-random + Satisfiability}, + + booktitle = {{SAT} 2015}, + + year = {2015}, + + crossref = {DBLP:conf/sat/2015}, + + doi = {10.1007/978-3-319-24318-4\_1}, + +} + + +@proceedings{DBLP:conf/sat/2015, + + editor = {Marijn Heule and +Sean A. Weaver}, + + title = {{SAT} 2015}, + + series = {LNCS}, + + volume = {9340}, + + publisher = {Springer}, + + year = {2015}, + + doi = {10.1007/978-3-319-24318-4}, + + isbn = {978-3-319-24317-7}, + +} + + +@inproceedings{cheeseman91where, + author = "Peter Cheeseman and Bob Kanefsky and William M. Taylor", + title = "Where the Really Hard Problems Are", + booktitle = "IJCAI-91", + pages = "331--337", + year = "1991", +} + +@InProceedings{BVA, +author="Manthey, Norbert +and Heule, Marijn J. H. +and Biere, Armin", +editor="Biere, Armin +and Nahir, Amir +and Vos, Tanja", +title="Automated Reencoding of Boolean Formulas", +booktitle="Hardware and Software: Verification and Testing", +year="2013", +publisher="Springer Berlin Heidelberg", +address="Berlin, Heidelberg", +pages="102--117", +abstract="We present a novel preprocessing technique to automatically reduce the size of Boolean formulas. This technique, called Bounded Variable Addition (BVA), exchanges clauses for variables. Similar to other preprocessing techniques, BVA greedily lowers the sum of variables and clauses, a rough measure for the hardness to solve a formula. We show that cardinality constraints (CCs) can efficiently be reencoded: from a naive CC encoding, BVA automatically generates a compact encoding, which is smaller than sophisticated encodings. Experimental results show that applying BVA can improve SAT solving performance.", +isbn="978-3-642-39611-3" +} + +@InProceedings{BVE, +author="E{\'e}n, Niklas +and Biere, Armin", +editor="Bacchus, Fahiem +and Walsh, Toby", +title="Effective Preprocessing in {SAT} Through Variable and Clause Elimination", +booktitle="Theory and Applications of Satisfiability Testing", +year="2005", +publisher="Springer Berlin Heidelberg", +address="Berlin, Heidelberg", +pages="61--75", +abstract="Preprocessing SAT instances can reduce their size considerably. We combine variable elimination with subsumption and self-subsuming resolution, and show that these techniques not only shrink the formula further than previous preprocessing efforts based on variable elimination, but also decrease runtime of SAT solvers substantially for typical industrial SAT problems. We discuss critical implementation details that make the reduction procedure fast enough to be practical.", +isbn="978-3-540-31679-4" +} + +@INPROCEEDINGS{Selman95localsearch, + author = {Bart Selman and Henry Kautz and Bram Cohen}, + title = {Local Search Strategies for Satisfiability Testing}, + booktitle = {{DIMACS} Series in Discrete Mathematics and Theoretical Computer Science}, + year = {1995}, + pages = {521--532}, + publisher = {} +} + +@INPROCEEDINGS{birdtwo, + author = {Mate Soos and Stephan Gocht and Kuldeep S Meel}, + title = {Accelerating Approximate Techniques for Counting and Sampling Models Through Refined {CNF-XOR} Solving}, + booktitle = {CAV 2020}, + year = {2020}, + publisher = {} +} + + + + +@inproceedings{DBLP:conf/sat/Devriendt0B17, + + author = {Jo Devriendt and + + Bart Bogaerts and + + Maurice Bruynooghe}, + + title = {Symmetric Explanation Learning: Effective Dynamic Symmetry Handling + + for {SAT}}, + + booktitle = {{SAT} 2017}, + + pages = {83--100}, + + year = {2017}, + + crossref = {DBLP:conf/sat/2017}, + +} + + +@proceedings{DBLP:conf/sat/2017, + + editor = {Serge Gaspers and + + Toby Walsh}, + + title = {{SAT} 2017}, + + series = {LNCS}, + + volume = {10491}, + + publisher = {Springer}, + + year = {2017}, +} + + + + + + +@inproceedings{DBLP:conf/alenex/JunttilaK07, + + author = {Tommi A. Junttila and + + Petteri Kaski}, + + title = {Engineering an Efficient Canonical Labeling Tool for Large and Sparse + + Graphs}, + + booktitle = {{ALENEX} 2007}, + + year = {2007}, + + crossref = {DBLP:conf/alenex/2007}, + +} + + +@proceedings{DBLP:conf/alenex/2007, + + title = { +{ALENEX} 2007}, + + publisher = {{SIAM}}, + + year = {2007}, + + isbn = {978-1-61197-287-0}, + +} + + + + + + + +@inproceedings{DBLP:conf/aaai/KautzS96, + author = {Henry A. Kautz and + Bart Selman}, + title = {Pushing the Envelope: Planning, Propositional Logic and Stochastic + Search}, + booktitle = {Proceedings of the Thirteenth National Conference on Artificial Intelligence + and Eighth Innovative Applications of Artificial Intelligence Conference, + {AAAI} 96, {IAAI} 96, Portland, Oregon, USA, August 4-8, 1996, Volume + 2.}, + pages = {1194--1201}, + year = {1996}, + crossref = {DBLP:conf/aaai/1996-2}, + url = {http://www.aaai.org/Library/AAAI/1996/aaai96-177.php}, + timestamp = {Tue, 19 Jun 2018 18:21:36 +0200}, + biburl = {https://dblp.org/rec/bib/conf/aaai/KautzS96}, + bibsource = {dblp computer science bibliography, https://dblp.org} +} + +@proceedings{DBLP:conf/aaai/1996-2, + editor = {William J. Clancey and + Daniel S. Weld}, + title = {Proceedings of the Thirteenth National Conference on Artificial Intelligence + and Eighth Innovative Applications of Artificial Intelligence Conference, + {AAAI} 96, {IAAI} 96, Portland, Oregon, USA, August 4-8, 1996, Volume + 2}, + publisher = {{AAAI} Press / The {MIT} Press}, + year = {1996}, + url = {http://www.aaai.org/Conferences/AAAI/aaai96.php}, + timestamp = {Tue, 19 Jun 2018 18:21:36 +0200}, + biburl = {https://dblp.org/rec/bib/conf/aaai/1996-2}, + bibsource = {dblp computer science bibliography, https://dblp.org} +} + + + +@inproceedings{DBLP:conf/aaai/Hoos02, + author = {Holger H. Hoos}, + title = {An Adaptive Noise Mechanism for {WalkSAT}}, + booktitle = {Proceedings of the Eighteenth National Conference on Artificial Intelligence + and Fourteenth Conference on Innovative Applications of Artificial + Intelligence, July 28 - August 1, 2002, Edmonton, Alberta, Canada.}, + pages = {655--660}, + year = {2002}, + crossref = {DBLP:conf/aaai/2002}, + url = {http://www.aaai.org/Library/AAAI/2002/aaai02-098.php}, + timestamp = {Mon, 26 Feb 2018 07:08:45 +0100}, + biburl = {https://dblp.org/rec/bib/conf/aaai/Hoos02}, + bibsource = {dblp computer science bibliography, https://dblp.org} +} + +@proceedings{DBLP:conf/aaai/2002, + editor = {Rina Dechter and + Michael J. Kearns and + Richard S. Sutton}, + title = {Proceedings of the Eighteenth National Conference on Artificial Intelligence + and Fourteenth Conference on Innovative Applications of Artificial + Intelligence, July 28 - August 1, 2002, Edmonton, Alberta, Canada}, + publisher = {{AAAI} Press / The {MIT} Press}, + year = {2002}, + url = {http://www.aaai.org/Conferences/AAAI/aaai02.php}, + timestamp = {Mon, 26 Feb 2018 07:08:45 +0100}, + biburl = {https://dblp.org/rec/bib/conf/aaai/2002}, + bibsource = {dblp computer science bibliography, https://dblp.org} +} + +@InProceedings{breakid2016, +author="Devriendt, Jo +and Bogaerts, Bart +and Bruynooghe, Maurice +and Denecker, Marc", +editor="Creignou, Nadia +and Le Berre, Daniel", +title="Improved Static Symmetry Breaking for {SAT}", +booktitle="Theory and Applications of Satisfiability Testing -- SAT 2016", +year="2016", +publisher="Springer International Publishing", +address="Cham", +pages="104--122", +abstract="An effective SAT preprocessing technique is the construction of symmetry breaking formulas: auxiliary clauses that guide a SAT solver away from needless exploration of symmetric subproblems. However, during the past decade, state-of-the-art SAT solvers rarely incorporated symmetry breaking. This suggests that the reduction of the search space does not outweigh the overhead incurred by detecting symmetry and constructing symmetry breaking formulas. We investigate three methods to construct more effective symmetry breaking formulas. The first method simply improves the encoding of symmetry breaking formulas. The second detects special symmetry subgroups, for which complete symmetry breaking formulas exist. The third infers binary symmetry breaking clauses for a symmetry group as a whole rather than longer clauses for individual symmetries. We implement these methods in a symmetry breaking preprocessor, and verify their effectiveness on both hand-picked problems as well as the 2014 SAT competition benchmark set. Our experiments indicate that our symmetry breaking preprocessor improves the current state-of-the-art in static symmetry breaking for SAT and has a sufficiently low overhead to improve the performance of modern SAT solvers on hard combinatorial instances.", +isbn="978-3-319-40970-2", +doi="10.1007/978-3-319-40970-2\_8", +url="https://bitbucket.org/krr/breakid" +} + +@article{shatter2006, +author = {Aloul, Fadi A. and Sakallah, Karem A. and Markov, Igor L.}, +title = {Efficient Symmetry Breaking for {B}oolean Satisfiability}, +year = {2006}, +issue_date = {May 2006}, +publisher = {IEEE Computer Society}, +address = {USA}, +volume = {55}, +number = {5}, +issn = {0018-9340}, +url = {https://doi.org/10.1109/TC.2006.75}, +doi = {10.1109/TC.2006.75}, +journal = {IEEE Trans. Comput.}, +month = may, +pages = {549–558}, +numpages = {10}, +keywords = {graph automorphism, clause learning, conjunctive normal form (CNF), satisfiability (SAT), symmetries., Backtrack Search} +} + +@article{DBLP:journals/ai/LiXLMLL20, + author = {Chu{-}Min Li and + Fan Xiao and + Mao Luo and + Felip Many{\`{a}} and + Zhipeng L{\"{u}} and + Yu Li}, + title = {Clause vivification by unit propagation in {CDCL} {SAT} solvers}, + journal = {Artif. Intell.}, + volume = {279}, + year = {2020}, +} + +@inproceedings{shaw2020designing, + title={Designing new Phase Selection Heuristics}, + author={Shaw, Arijit and Meel, Kuldeep S}, + booktitle={SAT 2020}, + year={2020} +} diff --git a/cryptominisat/cppsrc/docs/satcomp20-pdf/walksat/splncs03.bst b/cryptominisat/cppsrc/docs/satcomp20-pdf/walksat/splncs03.bst new file mode 100644 index 00000000..32791691 --- /dev/null +++ b/cryptominisat/cppsrc/docs/satcomp20-pdf/walksat/splncs03.bst @@ -0,0 +1,1519 @@ +%% BibTeX bibliography style `splncs03' +%% +%% BibTeX bibliography style for use with numbered references in +%% Springer Verlag's "Lecture Notes in Computer Science" series. +%% (See Springer's documentation for llncs.cls for +%% more details of the suggested reference format.) Note that this +%% file will not work for author-year style citations. +%% +%% Use \documentclass{llncs} and \bibliographystyle{splncs03}, and cite +%% a reference with (e.g.) \cite{smith77} to get a "[1]" in the text. +%% +%% This file comes to you courtesy of Maurizio "Titto" Patrignani of +%% Dipartimento di Informatica e Automazione Universita' Roma Tre +%% +%% ================================================================================================ +%% This was file `titto-lncs-02.bst' produced on Wed Apr 1, 2009 +%% Edited by hand by titto based on `titto-lncs-01.bst' (see below) +%% +%% CHANGES (with respect to titto-lncs-01.bst): +%% - Removed the call to \urlprefix (thus no "URL" string is added to the output) +%% ================================================================================================ +%% This was file `titto-lncs-01.bst' produced on Fri Aug 22, 2008 +%% Edited by hand by titto based on `titto.bst' (see below) +%% +%% CHANGES (with respect to titto.bst): +%% - Removed the "capitalize" command for editors string "(eds.)" and "(ed.)" +%% - Introduced the functions titto.bbl.pages and titto.bbl.page for journal pages (without "pp.") +%% - Added a new.sentence command to separate with a dot booktitle and series in the inproceedings +%% - Commented all new.block commands before urls and notes (to separate them with a comma) +%% - Introduced the functions titto.bbl.volume for handling journal volumes (without "vol." label) +%% - Used for editors the same name conventions used for authors (see function format.in.ed.booktitle) +%% - Removed a \newblock to avoid long spaces between title and "In: ..." +%% - Added function titto.space.prefix to add a space instead of "~" after the (removed) "vol." label +%% ================================================================================================ +%% This was file `titto.bst', +%% generated with the docstrip utility. +%% +%% The original source files were: +%% +%% merlin.mbs (with options: `vonx,nm-rvvc,yr-par,jttl-rm,volp-com,jwdpg,jwdvol,numser,ser-vol,jnm-x,btit-rm,bt-rm,edparxc,bkedcap,au-col,in-col,fin-bare,pp,ed,abr,mth-bare,xedn,jabr,and-com,and-com-ed,xand,url,url-blk,em-x,nfss,') +%% ---------------------------------------- +%% *** Tentative .bst file for Springer LNCS *** +%% +%% Copyright 1994-2007 Patrick W Daly + % =============================================================== + % IMPORTANT NOTICE: + % This bibliographic style (bst) file has been generated from one or + % more master bibliographic style (mbs) files, listed above. + % + % This generated file can be redistributed and/or modified under the terms + % of the LaTeX Project Public License Distributed from CTAN + % archives in directory macros/latex/base/lppl.txt; either + % version 1 of the License, or any later version. + % =============================================================== + % Name and version information of the main mbs file: + % \ProvidesFile{merlin.mbs}[2007/04/24 4.20 (PWD, AO, DPC)] + % For use with BibTeX version 0.99a or later + %------------------------------------------------------------------- + % This bibliography style file is intended for texts in ENGLISH + % This is a numerical citation style, and as such is standard LaTeX. + % It requires no extra package to interface to the main text. + % The form of the \bibitem entries is + % \bibitem{key}... + % Usage of \cite is as follows: + % \cite{key} ==>> [#] + % \cite[chap. 2]{key} ==>> [#, chap. 2] + % where # is a number determined by the ordering in the reference list. + % The order in the reference list is alphabetical by authors. + %--------------------------------------------------------------------- + +ENTRY + { address + author + booktitle + chapter + edition + editor + eid + howpublished + institution + journal + key + month + note + number + organization + pages + publisher + school + series + title + type + url + volume + year + } + {} + { label } +INTEGERS { output.state before.all mid.sentence after.sentence after.block } +FUNCTION {init.state.consts} +{ #0 'before.all := + #1 'mid.sentence := + #2 'after.sentence := + #3 'after.block := +} +STRINGS { s t} +FUNCTION {output.nonnull} +{ 's := + output.state mid.sentence = + { ", " * write$ } + { output.state after.block = + { add.period$ write$ +% newline$ +% "\newblock " write$ % removed for titto-lncs-01 + " " write$ % to avoid long spaces between title and "In: ..." + } + { output.state before.all = + 'write$ + { add.period$ " " * write$ } + if$ + } + if$ + mid.sentence 'output.state := + } + if$ + s +} +FUNCTION {output} +{ duplicate$ empty$ + 'pop$ + 'output.nonnull + if$ +} +FUNCTION {output.check} +{ 't := + duplicate$ empty$ + { pop$ "empty " t * " in " * cite$ * warning$ } + 'output.nonnull + if$ +} +FUNCTION {fin.entry} +{ duplicate$ empty$ + 'pop$ + 'write$ + if$ + newline$ +} + +FUNCTION {new.block} +{ output.state before.all = + 'skip$ + { after.block 'output.state := } + if$ +} +FUNCTION {new.sentence} +{ output.state after.block = + 'skip$ + { output.state before.all = + 'skip$ + { after.sentence 'output.state := } + if$ + } + if$ +} +FUNCTION {add.blank} +{ " " * before.all 'output.state := +} + + +FUNCTION {add.colon} +{ duplicate$ empty$ + 'skip$ + { ":" * add.blank } + if$ +} + +FUNCTION {date.block} +{ + new.block +} + +FUNCTION {not} +{ { #0 } + { #1 } + if$ +} +FUNCTION {and} +{ 'skip$ + { pop$ #0 } + if$ +} +FUNCTION {or} +{ { pop$ #1 } + 'skip$ + if$ +} +STRINGS {z} +FUNCTION {remove.dots} +{ 'z := + "" + { z empty$ not } + { z #1 #1 substring$ + z #2 global.max$ substring$ 'z := + duplicate$ "." = 'pop$ + { * } + if$ + } + while$ +} +FUNCTION {new.block.checka} +{ empty$ + 'skip$ + 'new.block + if$ +} +FUNCTION {new.block.checkb} +{ empty$ + swap$ empty$ + and + 'skip$ + 'new.block + if$ +} +FUNCTION {new.sentence.checka} +{ empty$ + 'skip$ + 'new.sentence + if$ +} +FUNCTION {new.sentence.checkb} +{ empty$ + swap$ empty$ + and + 'skip$ + 'new.sentence + if$ +} +FUNCTION {field.or.null} +{ duplicate$ empty$ + { pop$ "" } + 'skip$ + if$ +} +FUNCTION {emphasize} +{ skip$ } +FUNCTION {tie.or.space.prefix} +{ duplicate$ text.length$ #3 < + { "~" } + { " " } + if$ + swap$ +} +FUNCTION {titto.space.prefix} % always introduce a space +{ duplicate$ text.length$ #3 < + { " " } + { " " } + if$ + swap$ +} + + +FUNCTION {capitalize} +{ "u" change.case$ "t" change.case$ } + +FUNCTION {space.word} +{ " " swap$ * " " * } + % Here are the language-specific definitions for explicit words. + % Each function has a name bbl.xxx where xxx is the English word. + % The language selected here is ENGLISH +FUNCTION {bbl.and} +{ "and"} + +FUNCTION {bbl.etal} +{ "et~al." } + +FUNCTION {bbl.editors} +{ "eds." } + +FUNCTION {bbl.editor} +{ "ed." } + +FUNCTION {bbl.edby} +{ "edited by" } + +FUNCTION {bbl.edition} +{ "edn." } + +FUNCTION {bbl.volume} +{ "vol." } + +FUNCTION {titto.bbl.volume} % for handling journals +{ "" } + +FUNCTION {bbl.of} +{ "of" } + +FUNCTION {bbl.number} +{ "no." } + +FUNCTION {bbl.nr} +{ "no." } + +FUNCTION {bbl.in} +{ "in" } + +FUNCTION {bbl.pages} +{ "pp." } + +FUNCTION {bbl.page} +{ "p." } + +FUNCTION {titto.bbl.pages} % for journals +{ "" } + +FUNCTION {titto.bbl.page} % for journals +{ "" } + +FUNCTION {bbl.chapter} +{ "chap." } + +FUNCTION {bbl.techrep} +{ "Tech. Rep." } + +FUNCTION {bbl.mthesis} +{ "Master's thesis" } + +FUNCTION {bbl.phdthesis} +{ "Ph.D. thesis" } + +MACRO {jan} {"Jan."} + +MACRO {feb} {"Feb."} + +MACRO {mar} {"Mar."} + +MACRO {apr} {"Apr."} + +MACRO {may} {"May"} + +MACRO {jun} {"Jun."} + +MACRO {jul} {"Jul."} + +MACRO {aug} {"Aug."} + +MACRO {sep} {"Sep."} + +MACRO {oct} {"Oct."} + +MACRO {nov} {"Nov."} + +MACRO {dec} {"Dec."} + +MACRO {acmcs} {"ACM Comput. Surv."} + +MACRO {acta} {"Acta Inf."} + +MACRO {cacm} {"Commun. ACM"} + +MACRO {ibmjrd} {"IBM J. Res. Dev."} + +MACRO {ibmsj} {"IBM Syst.~J."} + +MACRO {ieeese} {"IEEE Trans. Software Eng."} + +MACRO {ieeetc} {"IEEE Trans. Comput."} + +MACRO {ieeetcad} + {"IEEE Trans. Comput. Aid. Des."} + +MACRO {ipl} {"Inf. Process. Lett."} + +MACRO {jacm} {"J.~ACM"} + +MACRO {jcss} {"J.~Comput. Syst. Sci."} + +MACRO {scp} {"Sci. Comput. Program."} + +MACRO {sicomp} {"SIAM J. Comput."} + +MACRO {tocs} {"ACM Trans. Comput. Syst."} + +MACRO {tods} {"ACM Trans. Database Syst."} + +MACRO {tog} {"ACM Trans. Graphic."} + +MACRO {toms} {"ACM Trans. Math. Software"} + +MACRO {toois} {"ACM Trans. Office Inf. Syst."} + +MACRO {toplas} {"ACM Trans. Progr. Lang. Syst."} + +MACRO {tcs} {"Theor. Comput. Sci."} + +FUNCTION {bibinfo.check} +{ swap$ + duplicate$ missing$ + { + pop$ pop$ + "" + } + { duplicate$ empty$ + { + swap$ pop$ + } + { swap$ + pop$ + } + if$ + } + if$ +} +FUNCTION {bibinfo.warn} +{ swap$ + duplicate$ missing$ + { + swap$ "missing " swap$ * " in " * cite$ * warning$ pop$ + "" + } + { duplicate$ empty$ + { + swap$ "empty " swap$ * " in " * cite$ * warning$ + } + { swap$ + pop$ + } + if$ + } + if$ +} +FUNCTION {format.url} +{ url empty$ + { "" } +% { "\urlprefix\url{" url * "}" * } + { "\url{" url * "}" * } % changed in titto-lncs-02.bst + if$ +} + +INTEGERS { nameptr namesleft numnames } + + +STRINGS { bibinfo} + +FUNCTION {format.names} +{ 'bibinfo := + duplicate$ empty$ 'skip$ { + 's := + "" 't := + #1 'nameptr := + s num.names$ 'numnames := + numnames 'namesleft := + { namesleft #0 > } + { s nameptr + "{vv~}{ll}{, jj}{, f{.}.}" + format.name$ + bibinfo bibinfo.check + 't := + nameptr #1 > + { + namesleft #1 > + { ", " * t * } + { + s nameptr "{ll}" format.name$ duplicate$ "others" = + { 't := } + { pop$ } + if$ + "," * + t "others" = + { + " " * bbl.etal * + } + { " " * t * } + if$ + } + if$ + } + 't + if$ + nameptr #1 + 'nameptr := + namesleft #1 - 'namesleft := + } + while$ + } if$ +} +FUNCTION {format.names.ed} +{ + 'bibinfo := + duplicate$ empty$ 'skip$ { + 's := + "" 't := + #1 'nameptr := + s num.names$ 'numnames := + numnames 'namesleft := + { namesleft #0 > } + { s nameptr + "{f{.}.~}{vv~}{ll}{ jj}" + format.name$ + bibinfo bibinfo.check + 't := + nameptr #1 > + { + namesleft #1 > + { ", " * t * } + { + s nameptr "{ll}" format.name$ duplicate$ "others" = + { 't := } + { pop$ } + if$ + "," * + t "others" = + { + + " " * bbl.etal * + } + { " " * t * } + if$ + } + if$ + } + 't + if$ + nameptr #1 + 'nameptr := + namesleft #1 - 'namesleft := + } + while$ + } if$ +} +FUNCTION {format.authors} +{ author "author" format.names +} +FUNCTION {get.bbl.editor} +{ editor num.names$ #1 > 'bbl.editors 'bbl.editor if$ } + +FUNCTION {format.editors} +{ editor "editor" format.names duplicate$ empty$ 'skip$ + { + " " * + get.bbl.editor +% capitalize + "(" swap$ * ")" * + * + } + if$ +} +FUNCTION {format.note} +{ + note empty$ + { "" } + { note #1 #1 substring$ + duplicate$ "{" = + 'skip$ + { output.state mid.sentence = + { "l" } + { "u" } + if$ + change.case$ + } + if$ + note #2 global.max$ substring$ * "note" bibinfo.check + } + if$ +} + +FUNCTION {format.title} +{ title + duplicate$ empty$ 'skip$ + { "t" change.case$ } + if$ + "title" bibinfo.check +} +FUNCTION {output.bibitem} +{ newline$ + "\bibitem{" write$ + cite$ write$ + "}" write$ + newline$ + "" + before.all 'output.state := +} + +FUNCTION {n.dashify} +{ + 't := + "" + { t empty$ not } + { t #1 #1 substring$ "-" = + { t #1 #2 substring$ "--" = not + { "--" * + t #2 global.max$ substring$ 't := + } + { { t #1 #1 substring$ "-" = } + { "-" * + t #2 global.max$ substring$ 't := + } + while$ + } + if$ + } + { t #1 #1 substring$ * + t #2 global.max$ substring$ 't := + } + if$ + } + while$ +} + +FUNCTION {word.in} +{ bbl.in capitalize + ":" * + " " * } + +FUNCTION {format.date} +{ + month "month" bibinfo.check + duplicate$ empty$ + year "year" bibinfo.check duplicate$ empty$ + { swap$ 'skip$ + { "there's a month but no year in " cite$ * warning$ } + if$ + * + } + { swap$ 'skip$ + { + swap$ + " " * swap$ + } + if$ + * + remove.dots + } + if$ + duplicate$ empty$ + 'skip$ + { + before.all 'output.state := + " (" swap$ * ")" * + } + if$ +} +FUNCTION {format.btitle} +{ title "title" bibinfo.check + duplicate$ empty$ 'skip$ + { + } + if$ +} +FUNCTION {either.or.check} +{ empty$ + 'pop$ + { "can't use both " swap$ * " fields in " * cite$ * warning$ } + if$ +} +FUNCTION {format.bvolume} +{ volume empty$ + { "" } + { bbl.volume volume tie.or.space.prefix + "volume" bibinfo.check * * + series "series" bibinfo.check + duplicate$ empty$ 'pop$ + { emphasize ", " * swap$ * } + if$ + "volume and number" number either.or.check + } + if$ +} +FUNCTION {format.number.series} +{ volume empty$ + { number empty$ + { series field.or.null } + { output.state mid.sentence = + { bbl.number } + { bbl.number capitalize } + if$ + number tie.or.space.prefix "number" bibinfo.check * * + series empty$ + { "there's a number but no series in " cite$ * warning$ } + { bbl.in space.word * + series "series" bibinfo.check * + } + if$ + } + if$ + } + { "" } + if$ +} + +FUNCTION {format.edition} +{ edition duplicate$ empty$ 'skip$ + { + output.state mid.sentence = + { "l" } + { "t" } + if$ change.case$ + "edition" bibinfo.check + " " * bbl.edition * + } + if$ +} +INTEGERS { multiresult } +FUNCTION {multi.page.check} +{ 't := + #0 'multiresult := + { multiresult not + t empty$ not + and + } + { t #1 #1 substring$ + duplicate$ "-" = + swap$ duplicate$ "," = + swap$ "+" = + or or + { #1 'multiresult := } + { t #2 global.max$ substring$ 't := } + if$ + } + while$ + multiresult +} +FUNCTION {format.pages} +{ pages duplicate$ empty$ 'skip$ + { duplicate$ multi.page.check + { + bbl.pages swap$ + n.dashify + } + { + bbl.page swap$ + } + if$ + tie.or.space.prefix + "pages" bibinfo.check + * * + } + if$ +} +FUNCTION {format.journal.pages} +{ pages duplicate$ empty$ 'pop$ + { swap$ duplicate$ empty$ + { pop$ pop$ format.pages } + { + ", " * + swap$ + n.dashify + pages multi.page.check + 'titto.bbl.pages + 'titto.bbl.page + if$ + swap$ tie.or.space.prefix + "pages" bibinfo.check + * * + * + } + if$ + } + if$ +} +FUNCTION {format.journal.eid} +{ eid "eid" bibinfo.check + duplicate$ empty$ 'pop$ + { swap$ duplicate$ empty$ 'skip$ + { + ", " * + } + if$ + swap$ * + } + if$ +} +FUNCTION {format.vol.num.pages} % this function is used only for journal entries +{ volume field.or.null + duplicate$ empty$ 'skip$ + { +% bbl.volume swap$ tie.or.space.prefix + titto.bbl.volume swap$ titto.space.prefix +% rationale for the change above: for journals you don't want "vol." label +% hence it does not make sense to attach the journal number to the label when +% it is short + "volume" bibinfo.check + * * + } + if$ + number "number" bibinfo.check duplicate$ empty$ 'skip$ + { + swap$ duplicate$ empty$ + { "there's a number but no volume in " cite$ * warning$ } + 'skip$ + if$ + swap$ + "(" swap$ * ")" * + } + if$ * + eid empty$ + { format.journal.pages } + { format.journal.eid } + if$ +} + +FUNCTION {format.chapter.pages} +{ chapter empty$ + 'format.pages + { type empty$ + { bbl.chapter } + { type "l" change.case$ + "type" bibinfo.check + } + if$ + chapter tie.or.space.prefix + "chapter" bibinfo.check + * * + pages empty$ + 'skip$ + { ", " * format.pages * } + if$ + } + if$ +} + +FUNCTION {format.booktitle} +{ + booktitle "booktitle" bibinfo.check +} +FUNCTION {format.in.ed.booktitle} +{ format.booktitle duplicate$ empty$ 'skip$ + { +% editor "editor" format.names.ed duplicate$ empty$ 'pop$ % changed by titto + editor "editor" format.names duplicate$ empty$ 'pop$ + { + " " * + get.bbl.editor +% capitalize + "(" swap$ * ") " * + * swap$ + * } + if$ + word.in swap$ * + } + if$ +} +FUNCTION {empty.misc.check} +{ author empty$ title empty$ howpublished empty$ + month empty$ year empty$ note empty$ + and and and and and + key empty$ not and + { "all relevant fields are empty in " cite$ * warning$ } + 'skip$ + if$ +} +FUNCTION {format.thesis.type} +{ type duplicate$ empty$ + 'pop$ + { swap$ pop$ + "t" change.case$ "type" bibinfo.check + } + if$ +} +FUNCTION {format.tr.number} +{ number "number" bibinfo.check + type duplicate$ empty$ + { pop$ bbl.techrep } + 'skip$ + if$ + "type" bibinfo.check + swap$ duplicate$ empty$ + { pop$ "t" change.case$ } + { tie.or.space.prefix * * } + if$ +} +FUNCTION {format.article.crossref} +{ + key duplicate$ empty$ + { pop$ + journal duplicate$ empty$ + { "need key or journal for " cite$ * " to crossref " * crossref * warning$ } + { "journal" bibinfo.check emphasize word.in swap$ * } + if$ + } + { word.in swap$ * " " *} + if$ + " \cite{" * crossref * "}" * +} +FUNCTION {format.crossref.editor} +{ editor #1 "{vv~}{ll}" format.name$ + "editor" bibinfo.check + editor num.names$ duplicate$ + #2 > + { pop$ + "editor" bibinfo.check + " " * bbl.etal + * + } + { #2 < + 'skip$ + { editor #2 "{ff }{vv }{ll}{ jj}" format.name$ "others" = + { + "editor" bibinfo.check + " " * bbl.etal + * + } + { + bbl.and space.word + * editor #2 "{vv~}{ll}" format.name$ + "editor" bibinfo.check + * + } + if$ + } + if$ + } + if$ +} +FUNCTION {format.book.crossref} +{ volume duplicate$ empty$ + { "empty volume in " cite$ * "'s crossref of " * crossref * warning$ + pop$ word.in + } + { bbl.volume + capitalize + swap$ tie.or.space.prefix "volume" bibinfo.check * * bbl.of space.word * + } + if$ + editor empty$ + editor field.or.null author field.or.null = + or + { key empty$ + { series empty$ + { "need editor, key, or series for " cite$ * " to crossref " * + crossref * warning$ + "" * + } + { series emphasize * } + if$ + } + { key * } + if$ + } + { format.crossref.editor * } + if$ + " \cite{" * crossref * "}" * +} +FUNCTION {format.incoll.inproc.crossref} +{ + editor empty$ + editor field.or.null author field.or.null = + or + { key empty$ + { format.booktitle duplicate$ empty$ + { "need editor, key, or booktitle for " cite$ * " to crossref " * + crossref * warning$ + } + { word.in swap$ * } + if$ + } + { word.in key * " " *} + if$ + } + { word.in format.crossref.editor * " " *} + if$ + " \cite{" * crossref * "}" * +} +FUNCTION {format.org.or.pub} +{ 't := + "" + address empty$ t empty$ and + 'skip$ + { + t empty$ + { address "address" bibinfo.check * + } + { t * + address empty$ + 'skip$ + { ", " * address "address" bibinfo.check * } + if$ + } + if$ + } + if$ +} +FUNCTION {format.publisher.address} +{ publisher "publisher" bibinfo.warn format.org.or.pub +} + +FUNCTION {format.organization.address} +{ organization "organization" bibinfo.check format.org.or.pub +} + +FUNCTION {article} +{ output.bibitem + format.authors "author" output.check + add.colon + new.block + format.title "title" output.check + new.block + crossref missing$ + { + journal + "journal" bibinfo.check + "journal" output.check + add.blank + format.vol.num.pages output + format.date "year" output.check + } + { format.article.crossref output.nonnull + format.pages output + } + if$ +% new.block + format.url output +% new.block + format.note output + fin.entry +} +FUNCTION {book} +{ output.bibitem + author empty$ + { format.editors "author and editor" output.check + add.colon + } + { format.authors output.nonnull + add.colon + crossref missing$ + { "author and editor" editor either.or.check } + 'skip$ + if$ + } + if$ + new.block + format.btitle "title" output.check + crossref missing$ + { format.bvolume output + new.block + new.sentence + format.number.series output + format.publisher.address output + } + { + new.block + format.book.crossref output.nonnull + } + if$ + format.edition output + format.date "year" output.check +% new.block + format.url output +% new.block + format.note output + fin.entry +} +FUNCTION {booklet} +{ output.bibitem + format.authors output + add.colon + new.block + format.title "title" output.check + new.block + howpublished "howpublished" bibinfo.check output + address "address" bibinfo.check output + format.date output +% new.block + format.url output +% new.block + format.note output + fin.entry +} + +FUNCTION {inbook} +{ output.bibitem + author empty$ + { format.editors "author and editor" output.check + add.colon + } + { format.authors output.nonnull + add.colon + crossref missing$ + { "author and editor" editor either.or.check } + 'skip$ + if$ + } + if$ + new.block + format.btitle "title" output.check + crossref missing$ + { + format.bvolume output + format.chapter.pages "chapter and pages" output.check + new.block + new.sentence + format.number.series output + format.publisher.address output + } + { + format.chapter.pages "chapter and pages" output.check + new.block + format.book.crossref output.nonnull + } + if$ + format.edition output + format.date "year" output.check +% new.block + format.url output +% new.block + format.note output + fin.entry +} + +FUNCTION {incollection} +{ output.bibitem + format.authors "author" output.check + add.colon + new.block + format.title "title" output.check + new.block + crossref missing$ + { format.in.ed.booktitle "booktitle" output.check + format.bvolume output + format.chapter.pages output + new.sentence + format.number.series output + format.publisher.address output + format.edition output + format.date "year" output.check + } + { format.incoll.inproc.crossref output.nonnull + format.chapter.pages output + } + if$ +% new.block + format.url output +% new.block + format.note output + fin.entry +} +FUNCTION {inproceedings} +{ output.bibitem + format.authors "author" output.check + add.colon + new.block + format.title "title" output.check + new.block + crossref missing$ + { format.in.ed.booktitle "booktitle" output.check + new.sentence % added by titto + format.bvolume output + format.pages output + new.sentence + format.number.series output + publisher empty$ + { format.organization.address output } + { organization "organization" bibinfo.check output + format.publisher.address output + } + if$ + format.date "year" output.check + } + { format.incoll.inproc.crossref output.nonnull + format.pages output + } + if$ +% new.block + format.url output +% new.block + format.note output + fin.entry +} +FUNCTION {conference} { inproceedings } +FUNCTION {manual} +{ output.bibitem + author empty$ + { organization "organization" bibinfo.check + duplicate$ empty$ 'pop$ + { output + address "address" bibinfo.check output + } + if$ + } + { format.authors output.nonnull } + if$ + add.colon + new.block + format.btitle "title" output.check + author empty$ + { organization empty$ + { + address new.block.checka + address "address" bibinfo.check output + } + 'skip$ + if$ + } + { + organization address new.block.checkb + organization "organization" bibinfo.check output + address "address" bibinfo.check output + } + if$ + format.edition output + format.date output +% new.block + format.url output +% new.block + format.note output + fin.entry +} + +FUNCTION {mastersthesis} +{ output.bibitem + format.authors "author" output.check + add.colon + new.block + format.btitle + "title" output.check + new.block + bbl.mthesis format.thesis.type output.nonnull + school "school" bibinfo.warn output + address "address" bibinfo.check output + format.date "year" output.check +% new.block + format.url output +% new.block + format.note output + fin.entry +} + +FUNCTION {misc} +{ output.bibitem + format.authors output + add.colon + title howpublished new.block.checkb + format.title output + howpublished new.block.checka + howpublished "howpublished" bibinfo.check output + format.date output +% new.block + format.url output +% new.block + format.note output + fin.entry + empty.misc.check +} +FUNCTION {phdthesis} +{ output.bibitem + format.authors "author" output.check + add.colon + new.block + format.btitle + "title" output.check + new.block + bbl.phdthesis format.thesis.type output.nonnull + school "school" bibinfo.warn output + address "address" bibinfo.check output + format.date "year" output.check +% new.block + format.url output +% new.block + format.note output + fin.entry +} + +FUNCTION {proceedings} +{ output.bibitem + editor empty$ + { organization "organization" bibinfo.check output + } + { format.editors output.nonnull } + if$ + add.colon + new.block + format.btitle "title" output.check + format.bvolume output + editor empty$ + { publisher empty$ + { format.number.series output } + { + new.sentence + format.number.series output + format.publisher.address output + } + if$ + } + { publisher empty$ + { + new.sentence + format.number.series output + format.organization.address output } + { + new.sentence + format.number.series output + organization "organization" bibinfo.check output + format.publisher.address output + } + if$ + } + if$ + format.date "year" output.check +% new.block + format.url output +% new.block + format.note output + fin.entry +} + +FUNCTION {techreport} +{ output.bibitem + format.authors "author" output.check + add.colon + new.block + format.title + "title" output.check + new.block + format.tr.number output.nonnull + institution "institution" bibinfo.warn output + address "address" bibinfo.check output + format.date "year" output.check +% new.block + format.url output +% new.block + format.note output + fin.entry +} + +FUNCTION {unpublished} +{ output.bibitem + format.authors "author" output.check + add.colon + new.block + format.title "title" output.check + format.date output +% new.block + format.url output +% new.block + format.note "note" output.check + fin.entry +} + +FUNCTION {default.type} { misc } +READ +FUNCTION {sortify} +{ purify$ + "l" change.case$ +} +INTEGERS { len } +FUNCTION {chop.word} +{ 's := + 'len := + s #1 len substring$ = + { s len #1 + global.max$ substring$ } + 's + if$ +} +FUNCTION {sort.format.names} +{ 's := + #1 'nameptr := + "" + s num.names$ 'numnames := + numnames 'namesleft := + { namesleft #0 > } + { s nameptr + "{ll{ }}{ ff{ }}{ jj{ }}" + format.name$ 't := + nameptr #1 > + { + " " * + namesleft #1 = t "others" = and + { "zzzzz" * } + { t sortify * } + if$ + } + { t sortify * } + if$ + nameptr #1 + 'nameptr := + namesleft #1 - 'namesleft := + } + while$ +} + +FUNCTION {sort.format.title} +{ 't := + "A " #2 + "An " #3 + "The " #4 t chop.word + chop.word + chop.word + sortify + #1 global.max$ substring$ +} +FUNCTION {author.sort} +{ author empty$ + { key empty$ + { "to sort, need author or key in " cite$ * warning$ + "" + } + { key sortify } + if$ + } + { author sort.format.names } + if$ +} +FUNCTION {author.editor.sort} +{ author empty$ + { editor empty$ + { key empty$ + { "to sort, need author, editor, or key in " cite$ * warning$ + "" + } + { key sortify } + if$ + } + { editor sort.format.names } + if$ + } + { author sort.format.names } + if$ +} +FUNCTION {author.organization.sort} +{ author empty$ + { organization empty$ + { key empty$ + { "to sort, need author, organization, or key in " cite$ * warning$ + "" + } + { key sortify } + if$ + } + { "The " #4 organization chop.word sortify } + if$ + } + { author sort.format.names } + if$ +} +FUNCTION {editor.organization.sort} +{ editor empty$ + { organization empty$ + { key empty$ + { "to sort, need editor, organization, or key in " cite$ * warning$ + "" + } + { key sortify } + if$ + } + { "The " #4 organization chop.word sortify } + if$ + } + { editor sort.format.names } + if$ +} +FUNCTION {presort} +{ type$ "book" = + type$ "inbook" = + or + 'author.editor.sort + { type$ "proceedings" = + 'editor.organization.sort + { type$ "manual" = + 'author.organization.sort + 'author.sort + if$ + } + if$ + } + if$ + " " + * + year field.or.null sortify + * + " " + * + title field.or.null + sort.format.title + * + #1 entry.max$ substring$ + 'sort.key$ := +} +ITERATE {presort} +SORT +STRINGS { longest.label } +INTEGERS { number.label longest.label.width } +FUNCTION {initialize.longest.label} +{ "" 'longest.label := + #1 'number.label := + #0 'longest.label.width := +} +FUNCTION {longest.label.pass} +{ number.label int.to.str$ 'label := + number.label #1 + 'number.label := + label width$ longest.label.width > + { label 'longest.label := + label width$ 'longest.label.width := + } + 'skip$ + if$ +} +EXECUTE {initialize.longest.label} +ITERATE {longest.label.pass} +FUNCTION {begin.bib} +{ preamble$ empty$ + 'skip$ + { preamble$ write$ newline$ } + if$ + "\begin{thebibliography}{" longest.label * "}" * + write$ newline$ + "\providecommand{\url}[1]{\texttt{#1}}" + write$ newline$ + "\providecommand{\urlprefix}{URL }" + write$ newline$ +} +EXECUTE {begin.bib} +EXECUTE {init.state.consts} +ITERATE {call.type$} +FUNCTION {end.bib} +{ newline$ + "\end{thebibliography}" write$ newline$ +} +EXECUTE {end.bib} +%% End of customized bst file +%% +%% End of file `titto.bst'. + + diff --git a/cryptominisat/cppsrc/docs/satrace19-pdf/walksat/Makefile b/cryptominisat/cppsrc/docs/satrace19-pdf/walksat/Makefile new file mode 100644 index 00000000..2423564d --- /dev/null +++ b/cryptominisat/cppsrc/docs/satrace19-pdf/walksat/Makefile @@ -0,0 +1,24 @@ +TEX = pdflatex -shell-escape -interaction=nonstopmode -file-line-error +PRE = $(TEX) -ini -job-name="preamble" "&pdflatex preamble.tex\dump" +BIB = bibtex + +all: cmsv56-walksat.pdf + +view : + okular cmsv56-walksat.pdf + +cmsv56-walksat.pdf : clean cmsv56-walksat.tex cmsv56-walksat.bbl cmsv56-walksat.blg + $(TEX) cmsv56-walksat.tex + $(TEX) cmsv56-walksat.tex + +cmsv56-walksat.bbl cmsv5.blg : cmsv56-walksat.bib cmsv56-walksat.aux + $(BIB) cmsv56-walksat + +cmsv56-walksat.aux : cmsv56-walksat.tex + $(TEX) cmsv56-walksat.tex + +cmsv56-walksat.bib : cmsv56-walksat.tex + $(TEX) cmsv56-walksat.tex + +clean: + rm -f *.log *.pdf *.blg *.bbl *.aux *.out *.backup diff --git a/cryptominisat/cppsrc/docs/satrace19-pdf/walksat/cmsv56-walksat.tex b/cryptominisat/cppsrc/docs/satrace19-pdf/walksat/cmsv56-walksat.tex new file mode 100644 index 00000000..89e380e8 --- /dev/null +++ b/cryptominisat/cppsrc/docs/satrace19-pdf/walksat/cmsv56-walksat.tex @@ -0,0 +1,83 @@ +%\documentclass[runningheads]{llncs} +\documentclass[final]{ieee} + +\usepackage{microtype} %This gives MUCH better PDF results! +%\usepackage[active]{srcltx} %DVI search +\usepackage[cmex10]{amsmath} +\usepackage{amssymb} +\usepackage{fnbreak} %warn for split footnotes +\usepackage{url} +%\usepackage{qtree} %for drawing trees +%\usepackage{fancybox} % if we need rounded corners +%\usepackage{pict2e} % large circles can be drawn +%\usepackage{courier} %for using courier in texttt{} +%\usepackage{nth} %allows to \nth{4} to make 1st 2nd, etc. +%\usepackage{subfigure} %allows to have side-by-side figures +%\usepackage{booktabs} %nice tables +%\usepackage{multirow} %allow multiple cells with rows in tabular +\usepackage[utf8]{inputenc} % allows to write Faugere correctly +\usepackage[bookmarks=true, citecolor=black, linkcolor=black, colorlinks=true]{hyperref} +\hypersetup{ +pdfauthor = {Mate Soos, Bart Selman, Henry Kautz}, +pdftitle = {CryptoMiniSat v5.6 + walksat}, +pdfsubject = {SAT Race 2019}, +pdfkeywords = {SAT Solver, DPLL, SLS}, +pdfcreator = {PdfLaTeX with hyperref package}, +pdfproducer = {PdfLaTex}} +%\usepackage{butterma} + +%\usepackage{pstricks} +\usepackage{graphicx,epsfig,xcolor} + +\begin{document} +\title{CryptoMiniSat 5.6 with WalkSAT at the SAT Race 2019} +\author{Mate Soos (National University of Singapore)\\ +Bart Selman (Cornell University), Henry Kautz (University of Rochester)} + +\maketitle +\thispagestyle{empty} +\pagestyle{empty} + +\section{Introduction} +This paper presents the conflict-driven clause-learning (CLDL) SAT solver CryptoMiniSat v5.6 (\emph{CMS}) augmented with the Stochastic Local Search (SLS)~\cite{Selman95localsearch} solver WalkSAT v56 as submitted to SAT Race 2019. + +CryptoMiniSat aims to be a modern, open source SAT solver using inprocessing techniques, optimized data structures and finely-tuned timeouts to have good control over both memory and time usage of inprocessing steps. It also supports, when compiled as such, to recover XOR constraints and perform Gauss-Jordan elimination on them at every decision level. For the competition, this option was disabled. CryptoMiniSat is authored by Mate Soos. + +WalkSAT~\cite{DBLP:conf/aaai/KautzS96} is a standard system to solve satisfiability problems using Stochastic Local Search. The version inside CryptoMiniSat is functionally equivalent to the ``rnovelity'' heuristic of WalkSAT v56 using an adaptive noise heuristic~\cite{DBLP:conf/aaai/Hoos02}. It behaves exactly as WalkSAT with the minor modification of performing early-abort in case the ``lowbad'' statistic (i.e. the quality indicator of the current best solution) indicates the solution is far. In these cases, we early abort, let the CDCL solver work longer to simplify the problem, and come back to WalkSAT later. The only major modification to WalkSAT has been to allow it to import variables and clauses directly from the main solver taking into account assumptions given by the user. + +\subsection{Composing the Two Solvers} +The two solvers are composed together in a way that does \emph{not} resemble portfolio solvers. The system runs the CDCL solver CryptoMiniSat, along with its periodic inprocessing, by default. However, at every N inprocessing step, CryptoMiniSat's irredundant clauses are pushed into the SLS solver (in case the predicted memory use is not too high). The SLS solver is then allowed to run for a predefined number of steps. In case the SLS solver finds a solution, this is given back to the CDCL solver, which then performs all the necessary extension to the solution (e.g. for Bounded Variable Elimination, BVE~\cite{BVE}) and then outputs the solution. + +Note that the inclusion of the SLS solver is full in the sense that assumptions-based solving, library-based solver use, and all other uses of the SAT solver is fully supported with SLS solving enabled. Hence, this is not some form of portfolio where a simple shell script determines which solver to run and then runs that solver. Instead, the SLS solver is a full member of the CDCL solver, much like any other inprocessing system, and works in tandem with it. For example, in case an inprocessing step has reduced the number of variables through BVE or increased it through BVA~\cite{BVA}, the SLS solver will then try to solve the problem thus modified. In case the SLS solver finds a solution, the main solver will then correctly manipulate is to fit the needs of the ``outside world'', i.e. the caller. + +As the two solvers are well-coupled, the combination of the two solvers can solve problems that neither system can solve on its own. Hence, \emph{the system is more than just a union of its parts} which is not the case for traditional portfolio solvers. + +\section{Major Improvements} +\subsection{Via Negativa} +The system has been subjected to a thorough investigation whether all the different systems that have been implemented into it actually make the solver faster. In this spirit, failed literal probing~\cite{DBLP:conf/ictai/LynceS03}, stamping~\cite{stamping}, burst searching (random variable picking), and blocked clause elimination~\cite{TACAS-2010-JarvisaloBH} have all been disabled. + +\subsection{Chronological Backtracking} +Chronological backtracking~\cite{chronobt} has been implemented into a branch of the solver. However, chronological backtracking (CBT) is a double-edged sword. Firstly, it slows down the solver's normal functionality as it adds a number of expensive checks to both the propagation and the backtracking code. Secondly, it changes the trail of the solver in ways that make it hard to reason about the current state of the solver. Finally, it seems only to help with satisfiable instances which are theoretically less interesting for the author of CryptoMiniSat. These issues make CBT a difficult addition. + +Currently, CryptoMiniSat by default does not implement CBT. The SAT Race has two versions submitted, clearly marked, one with, an one without CBT. + +\subsection{Cluster Tuning} +The author has been generously given time on the ASPIRE-1 cluster of the National Supercomputing Center Singapore\cite{nscc}. This allowed experimentation and tuning that would have been impossible otherwise. Without this opportunity, CryptoMiniSat would not stand a chance at the SAT Race. + +\section{General Notes} +\subsection{On-the-fly Gaussian Elimination} +On-the-fly Gaussian elimination is again part of CryptoMiniSat. This is explicitly disabled for the competition, but the code is available and well-tested. This allows for special uses of the solver that other solvers, without on-the-fly Gaussian elimination, are not capable of. + +\subsection{Robustness} +CMS aims to be usable in both industry and academia. CMS has over 150 test cases and over 2000 lines of Python just for fuzzing orchestration, and runs without fault under both the ASAN and UBSAN sanitisers of clang. It also compiles and runs under Windows, Linux and MacOS X. This is in contrast many academic winning SAT solvers that produce results that are non-reproducible, cannot be compiled on anything but a few select systems, and/or produce segmentation faults if used as a library. CryptoMiniSat has extensive fuzzing setup for library usage and is very robust under strange/unexpected use cases. + +\section{Thanks} +This work was supported in part by NUS ODPRT Grant R-252-000-685-133 and AI Singapore Grant R-252- 000-A16-490. The computational work for this article was performed on resources of the National Supercomputing Center, Singapore\cite{nscc}. The author would also like to thank all the users of CryptoMiniSat who have submitted over 500 issues and many pull requests to the GitHub CMS repository\cite{CMS}. + +\bibliographystyle{splncs03} +\bibliography{sigproc} + +\vfill +\pagebreak + +\end{document} diff --git a/cryptominisat/cppsrc/docs/satrace19-pdf/walksat/ieee.cls b/cryptominisat/cppsrc/docs/satrace19-pdf/walksat/ieee.cls new file mode 100644 index 00000000..3c57bba5 --- /dev/null +++ b/cryptominisat/cppsrc/docs/satrace19-pdf/walksat/ieee.cls @@ -0,0 +1,1497 @@ +% Copyright 2014 IEEEE +% for terms of use see https://www.ieee.org/publications_standards/publications/rights/copyrightpolicy.html + +% ========================================================================= +% ------------------------------------------------------------------------- +% XX X +% X +% XX XXX XXX XXX XXX X XXXX +% X X X X X X X X X X X +% X XXXXX XXXXX XXXXX X X XXX +% X X X X XX X X X X +% XXX XXX XXX XXX XX XXX X XXXX +% ------------------------------------------------------------------------- +% ========================================================================= +% ieee.cls --- For formatting IEEE conference & journal papers +% --- Compiled by Gregory Plett, Sept 1997 +% +% This class was inspired by one first compiled by Gerry Murray and +% Silvano Balemi for LaTeX209. It was later updated for use with +% LaTeX2e, and some bugs were fixed, all by Istvan Kollar. Lastly, +% I have tried to make the class easier to use by paper authors. +% Significant new functionality has been added. Many routines are +% "borrowed" from other people's packages and modified extensively. +% When I rembered where I got the routines from, I gave the author +% credit. +% +% After I made many changes on my own, I found a version by Peter +% N"uchter, and tried to retain some amount of compatibility with his +% version. To be completely compatible with him, you may need to +% manually: +% \usepackage{rawfonts}\usepackage{oldlfont} +% \AtBeginDocument{\parindent1.0em} (?) +% +%=========================================================================== +% +% Usage: +% \documentclass[main-mode,sub-mode,misc-options]{ieee} +% \usepackage{your own packages} +% \begin{document} +% \bibliographystyle{IEEEbib} +% \title[short]{regular} +% \author[short]{full} +% \maketitle +% \begin{abstract}...\end{abstract} +% \begin{keywords}...\end{keywords} +% \section{...} +% \PARstart ... or \PARstartCal ... +% ... +% \begin{biography}[picname.ps]{Author's name}...\end{biography} +% \end{document} +% +% The document class options are: +% +% main-mode: One of the following is required. (draft is the default) +% draft: Double-spaced, single column with date/time stamp. +% submission: Double-spaced, suitable for submission for review. +% compressed: Same as "submission", only single spaced. +% final: Double-column, for assessing page-length and +% format of final version. +% +% sub-mode: +% techreport: This can modify "final" to produce a two-col +% technical report. +% internal: This can modify "submission", "compressed" or "final". +% It changes the header to notify the reader that +% this is a version of the manuscript to be used for +% internal review processes only, and not to be +% distributed. +% submitted: This can modify "compressed" or "final". It changes +% the header to notify the reader that this +% is a preprint and not to be distributed. +% inpress: This can modify "compressed" or "final". It changes the +% header to notify the reader that this paper has +% been accepted for publishing, but it is not yet to be +% distributed. +% reprint: This can modify "final". It changes the header +% to notify the reader where the paper is reprinted from. +% +% misc-options: +% narroweqnarray: Changes the spacing around the "=" sign in +% equation arrays to make it the same as in displayed math. +% inline: Compresses the horizontal spacing of inline math equations. +% notitlepage: No separate title page. (default) +% titlepage: Separate title page. +% anonymous: Omit all author information from main part of paper. +% Author info only prints on titlepage. +% 9pt,10pt,11pt,12pt: Choose the appropriate type size. You should +% not need to do this as the "correct" size is automatically +% chosen. However, if you want, you may use these to change +% the type size of the main text. "9pt" is a bit of a hack +% to retain backward-compatibility. +% invited: If the paper is an "invited" paper, then this option +% prints "(Invited Paper)" under the authors' names. +% +% For regular IEEE submissions, define the journal name as: +% \journal{IEEE Trans. Inst. Meas.} +% +% To specify the conference place and date: +% \confplacedate{Ottawa, Canada, May 19--21, 1997} +% +% Before \maketitle, define: +% \title{Title of paper} +% \author{Author1\member{Fellow}\authorinfo{Department of +% Electrical Engineering\\ Some University, Somewhere, CA 94305 +% USA} \and Author2\member{Senior Member}\authorinfo{Deptartment of +% Measurement and Instrument Eng., Another University, ...}} +% +% Note, the contents of \authorinfo tends to vary depending on if it is +% a conference or journal paper. The amount of manual changes are +% small, and must be done by a human anyway. The example given is for an +% IMTC conference. +% +% See also IEEEbib.bst and ieeefig.sty +% Also very useful for document preparation is the style file "endfloat", +% available on all CTAN TeX archives. +% +%=========================================================================== +% modified 14 October 2002: +% - fixed bibliography listing of [#] when # < 10 and number of +% references is greater than 9. Thanks for Janos Markus for finding +% this bug and suggesting a solution. +% modified 15 January 2000: +% - "fixed" narroweqnarray. Never implemented! Now it is... +% modified 12 January 2000: +% - modified so only first \title and \author commands are recognized. +% This allows LyX to have \title and \author with full syntax in +% header, but dummy \title and \author show up in GUI. +% - added "\date" so the \date command can change "submitted" and +% "draft" date headers. +% modified 11 January 2000: +% - added PARstartLyX and PARstartCalLyX for LyX compatibility +% - added biographyLyX +% modified 1 Dec 1997: +% - fixed first page in reprint mode to be same length as other pages +% - added "invited" misc-option +% modified 5 Sept 1997: +% - added the inpress, reprint and internal sub-modes +% - removed IMTC-conf and CDC-conf to separate files +% modified 1 Sept 1997: +% - included Babel package compatibility +% - removed paper title from header on first page of draft +% manuscript +% - removed the fixed option "letterpaper" to allow a4paper (etc) +% modified 1 Aug 1997: +% - included the CDC-conf option +%=========================================================================== +% ************************************************************************** +% ****** ****************************************** +% ***** LaTeX2e INITIALIZATION ***************************************** +% ****** ****************************************** +% ************************************************************************** +\typeout{Document Class `ieee' .} +\NeedsTeXFormat{LaTeX2e}[1993/11/11] % Oldest acceptable version of LaTeX2e +\ProvidesClass{ieee}[2000/01/11] % Name of package provided, date +\def\i@@@cls{exists} + +% Initial Code & Declaration of Options +% ------------------------------------- +\newif\ifev@l \ev@lfalse % true if "final" mode. +\newif\ifsubm@t \subm@tfalse % true if "submission" mode. +\newif\ifdr@ft \dr@fttrue % true if "draft" mode. +\newif\ifc@mpress \c@mpressfalse % true if "compressed" mode. + +\newif\if@technote \@technotefalse % true if "technote" sub-mode. +\newif\ifintern@l \intern@lfalse % true if "internal" sub-mode. +\newif\ifprepr@nt \prepr@ntfalse % true if "preprint" sub-mode. +\newif\ifinpr@ss \inpr@ssfalse % true if "inpress" sub-mode. +\newif\ifrepr@nt \repr@ntfalse % true if "reprint" sub-mode. + +\newif\iftitlep@ge \titlep@gefalse % true if has own titlepage +\newif\if@non \@nonfalse % true if anonymous +\newif\ifixpt \ixptfalse % true if trying to do 9 pt +\newif\if@nvited \@nvitedfalse % true if an invited paper + +% Main options +% ------------ +\DeclareOption{draft}{\ev@lfalse\subm@tfalse\dr@fttrue% + \typeout{ieee: `Draft' mode selected.}} +\DeclareOption{submission}{\ev@lfalse\dr@ftfalse\subm@ttrue% + \typeout{ieee: `Submission' mode selected.}} +\DeclareOption{compressed}{\ev@lfalse\dr@ftfalse\subm@tfalse\c@mpresstrue% + \typeout{ieee: `Compressed' mode selected.}} +\DeclareOption{final}{\ev@ltrue\dr@ftfalse\subm@tfalse% + \typeout{ieee: `Final' mode selected.}} +\DeclareOption{evaluation}{\ev@ltrue\dr@ftfalse\subm@tfalse% + \typeout{ieee: `Final' mode selected.}} % synonym for final + +% Sub options +% ----------- +\DeclareOption{technote}{\@technotetrue% + \typeout{ieee: `Technote' sub-mode selected.}} +\DeclareOption{internal}{\intern@ltrue\prepr@ntfalse\inpr@ssfalse\repr@ntfalse% + \typeout{ieee: `Internal-Review' sub-mode selected.}} +\DeclareOption{submitted}{\intern@lfalse\prepr@nttrue\inpr@ssfalse\repr@ntfalse% + \typeout{ieee: `Submitted' sub-mode selected.}} +\DeclareOption{preprint}{\intern@lfalse\prepr@nttrue\inpr@ssfalse\repr@ntfalse% + \typeout{ieee: `Submitted' sub-mode selected.}} % synonym for submitted +\DeclareOption{inpress}{\intern@lfalse\prepr@ntfalse\inpr@sstrue\repr@ntfalse% + \typeout{ieee: `Inpress' sub-mode selected.}} +\DeclareOption{reprint}{\intern@lfalse\prepr@ntfalse\inpr@ssfalse\repr@nttrue% + \typeout{ieee: `Reprint' sub-mode selected.}} + +% Misc options +% ------------ + % regular or compressed "=" spacing in +\def\eqnarr@ysep{\arraycolsep} % eqnarray (this is the default) + % NOTE: we must use "def" and not "=" + % as arraycolsep not yet defined. +\DeclareOption{narroweqnarray}{\gdef\eqnarr@ysep{0.28em\relax}% + \typeout{ieee: Narrow equation arrays selected.}} +\DeclareOption{inline}{\everymath{\thinmuskip=2mu plus 1mu + \medmuskip=3mu plus 1mu minus 2mu + \thickmuskip=4mu plus 2mu\relax}% + \typeout{ieee: Narrower inline equations selected.}} +\DeclareOption{notitlepage}{\titlep@gefalse% + \typeout{ieee: No separate title page.}} +\DeclareOption{titlepage}{\titlep@getrue% + \typeout{ieee: Use separate title page.}} +\DeclareOption{anonymous}{\@nontrue\AtBeginDocument{\glpexclude{biography}} + \typeout{ieee: Omit author information from paper.}} +\DeclareOption{invited}{\@nvitedtrue% + \typeout{ieee: (Invited Paper).}} + +\DeclareOption{9pt}{\ixpttrue% + \typeout{ieee: Trying to emulate old `9pt' document class.}} + +\DeclareOption*{\PassOptionsToClass{\CurrentOption}{article}} + +% Execution of Options/Package Loading +% ------------------------------------ +\newlength\narrowcol +\newlength\parindentsave % recover parindent in blsone text + +\ProcessOptions +\ifev@l % if "final" mode... + \if@technote\ixpttrue\typeout{ieee: Trying to emulate old `9pt' + document class.}\fi% + \LoadClass[twoside,final,twocolumn,10pt]{article} +\else % if "draft"/"submission"/(compressed) mode... + \ifixpt + \LoadClass[oneside,final,onecolumn,10pt]{article} + \else + \LoadClass[oneside,final,onecolumn,12pt]{article} + \fi +\fi +\RequirePackage[final]{graphicx} +\RequirePackage{ifthen} + +% Re-Definitions of English words which must be done before +% the Babel package (optional) is loaded. +% --------------------------------------------------------- +\def\keywordsname{Index Terms} +\def\indexterms#1{\def\keywordsname{#1}} +\def\appendicesname{Appendices} +\def\figurename{Fig.} + +% ************************************************************************** +% ***** Check Sub-Options for Compatibility w/ Main-Options ************ +% ************************************************************************** +\if@technote\ifev@l\else\ClassError{ieee}{`technote' sub-mode may be + used only with the `final' ^^Jmain-mode. It may not be used + with either the `draft,' `submission,' or ^^J`compressed' + main-modes}{}\endinput\fi\fi +\ifintern@l\ifdr@ft\ClassError{ieee}{`internal' sub-mode may be + used only with the ^^J`submission,' `compressed,' or `final' main-modes. + It may not be used ^^Jwith the `draft' main-mode}{}\endinput\fi\fi +\ifprepr@nt\ifc@mpress\else\ifev@l\else\ClassError{ieee}{`submitted' + sub-mode may be used only with the ^^J`compressed' or `final' + main-modes. It may not be used with either the ^^J`draft' or + `submission' main-modes}{}\endinput\fi\fi\fi +\ifinpr@ss\ifc@mpress\else\ifev@l\else\ClassError{ieee}{`inpress' + sub-mode may be used only with the `compressed' ^^Jor `final' + main-modes. It may not be used with either the `draft' or + ^^J`submission' main-modes}{}\endinput\fi\fi\fi +\ifrepr@nt\ifev@l\else\ClassError{ieee}{`reprint' + sub-mode may be used only with the `final' ^^Jmain-mode. It may not be + used with either the `draft,' `submission,' or ^^J`compressed' + main-modes}{}\endinput\fi\fi + +% ************************************************************************** +% ***** Page Layout Definition ***************************************** +% ************************************************************************** +%% Layout definitions (mostly) common to all options. + +\hoffset 0in \voffset 0in +\headheight 12pt \headsep 7mm +\marginparsep 10pt \marginparwidth 20pt +\marginparpush 25pt +\columnsep 4mm +\parindent 1.0em +\lineskip 1pt +\normallineskip 1pt +\def\baselinestretch{1} + +\partopsep \z@ +\topsep 1.3ex +\parsep \z@ +\itemsep \z@ + +\setlength{\parindentsave}{\parindent} + +\ifev@l % if "evaluation" mode + % if camera-ready or A4paper ... + \ifdim\paperwidth<211mm + \oddsidemargin -11.4mm \evensidemargin -11.4mm + % for regular US Letter, not camera-ready + \else + \oddsidemargin -8.45mm \evensidemargin -8.45mm + \fi + \ifrepr@nt + \textheight 237.5mm % leave 6mm for cpyright on first page + \else + \textheight 243.5mm + \fi + \voffset -0.5in + \textwidth 182.0mm + \topmargin -12pt + \setlength{\narrowcol}{89mm} +\else % if "draft"/"submission" mode... + \ifc@mpress % and "compressed" + \oddsidemargin -0.25in \evensidemargin -0.25in + \textheight 9in \textwidth 7in + \topmargin -0.25in + \setlength{\narrowcol}{7in} + \else % and NOT "compressed" + \renewcommand\baselinestretch{1.8}\renewcommand{\arraystretch}{0.8} + \parindent=1.8\parindent + \oddsidemargin 0pt \evensidemargin 0pt + \headheight 12pt \headsep 0.375in + \topmargin 0pt + \textheight 8.5in \textwidth 6.5in + \marginparsep 0in \marginparwidth 0pt + \marginparpush 5pt + \setlength{\narrowcol}{6.5in} + \fi +\fi + +\def\normalstyle{\rmfamily} + +% ************************************************************************** +% ***** Font Definition ************************************************ +% ************************************************************************** +%% The 9-point option is being faked since it is not supported by the +%% article base class. + +%% Check if we have selected 9 points +\ifixpt +\typeout{-- This is a 9 point document} +\gdef\@ptsize{9} +\def\@normalsize{\@setsize\normalsize{10.7pt}\ixpt\@ixpt +\abovedisplayskip 1em plus2pt minus5pt\belowdisplayskip \abovedisplayskip +\abovedisplayshortskip \z@ plus3pt\belowdisplayshortskip .6em plus3pt minus3pt +\topsep \belowdisplayshortskip%!PN +} +\def\small{\@setsize\small{9.12pt}\viiipt\@viipt} +\def\footnotesize{\@setsize\footnotesize{8.15pt}\viipt\@vipt} +\def\scriptsize{\@setsize\scriptsize{8pt}\vipt\@vpt} +\def\tiny{\@setsize\tiny{5pt}\vpt\@vpt} +\def\large{\@setsize\large{12pt}\xpt\@xpt} +\def\Large{\@setsize\Large{14pt}\xiipt\@xiipt} +\def\LARGE{\@setsize\LARGE{18pt}\xivpt\@xivpt} +\def\huge{\@setsize\huge{22pt}\xviipt\@xviipt} +\def\Huge{\@setsize\Huge{25pt}\xxpt\@xxpt} +\fi +%% +%% Check if we have selected 10 points +\def\@tempa{0}\if\@ptsize\@tempa +\typeout{-- This is a 10 point document} +\def\@normalsize{\@setsize\normalsize{11.9pt}\xpt\@xpt +\abovedisplayskip 1em plus2pt minus5pt\belowdisplayskip \abovedisplayskip +\abovedisplayshortskip \z@ plus3pt\belowdisplayshortskip .6em plus3pt minus3pt +\topsep \belowdisplayshortskip%!PN +} +\def\small{\@setsize\small{9.2pt}\viiipt\@viiipt} +\def\footnotesize{\@setsize\footnotesize{8.8pt}\viiipt\@viiipt} +\def\scriptsize{\@setsize\scriptsize{8pt}\viipt\@viipt} +\def\tiny{\@setsize\tiny{6pt}\vpt\@vpt} +\def\normalsize{\@setsize\normalsize{11.9pt}\xpt\@xpt} +\def\large{\@setsize\large{14pt}\xiipt\@xiipt} +\def\Large{\@setsize\Large{18pt}\xivpt\@xivpt} +\def\LARGE{\@setsize\LARGE{22pt}\xviipt\@xviipt} +\def\huge{\@setsize\huge{22pt}\xxpt\@xxpt} +\def\Huge{\@setsize\Huge{28pt}\xxvpt\@xxvpt} +\fi +%% +%% Check if we have selected 11 points +\def\@tempa{1}\if\@ptsize\@tempa +\typeout{-- This is an 11 point document} +\def\@normalsize{\@setsize\normalsize{13.6pt}\xipt\@xipt +\abovedisplayskip 1em plus2pt minus5pt\belowdisplayskip \abovedisplayskip +\abovedisplayshortskip \z@ plus3pt\belowdisplayshortskip .6em plus3pt minus3pt +\topsep \belowdisplayshortskip%!PN +} +\def\small{\@setsize\small{12pt}\xpt\@xpt} +\def\footnotesize{\@setsize\footnotesize{11pt}\ixpt\@ixpt} +\def\scriptsize{\@setsize\scriptsize{9.5pt}\viiipt\@viiipt} +\def\tiny{\@setsize\tiny{7pt}\vipt\@vipt} +\def\normalsize{\@setsize\normalsize{13.6pt}\xipt\@xipt} +\def\large{\@setsize\large{14pt}\xiipt\@xiipt} +\def\Large{\@setsize\Large{18pt}\xivpt\@xivpt} +\def\LARGE{\@setsize\LARGE{22pt}\xviipt\@xviipt} +\def\huge{\@setsize\huge{25pt}\xxpt\@xxpt} +\def\Huge{\@setsize\Huge{30pt}\xxvpt\@xxvpt} +\fi +%% +%% Check if we have selected 12 points +\def\@tempa{2}\if\@ptsize\@tempa +\typeout{-- This is a 12 point document} +\def\@normalsize{\@setsize\normalsize{14pt}\xiipt\@xiipt +\abovedisplayskip 1em plus3pt minus6pt\belowdisplayskip \abovedisplayskip +\abovedisplayshortskip \z@ plus3pt\belowdisplayshortskip .6em plus4pt minus4pt +\topsep \belowdisplayshortskip%!PN +} +\def\small{\@setsize\small{11.4pt}\xpt\@xpt} +\def\footnotesize{\@setsize\footnotesize{10pt}\ixpt\@ixpt} +\def\scriptsize{\@setsize\scriptsize{9pt}\viiipt\@viiipt} +\def\tiny{\@setsize\tiny{8pt}\vipt\@vipt} +\def\normalsize{\@setsize\normalsize{14pt}\xiipt\@xiipt} +\def\large{\@setsize\large{18pt}\xivpt\@xivpt} +\def\Large{\@setsize\Large{22pt}\xviipt\@xviipt} +\def\LARGE{\@setsize\LARGE{25pt}\xxpt\@xxpt} +\def\huge{\@setsize\huge{30pt}\xxvpt\@xxvpt} +\let\Huge=\huge +\fi + +\AtBeginDocument{\normalsize\normalstyle\ps@headings\pagenumbering{arabic}} + +% ************************************************************************** +% ***** List Definition ************************************************ +% ************************************************************************** +%% Change aspect of lists with +%% 1) \itemindent, label indentation wrt to left list margin +%% 2) \leftmargini, the indentation of the whole list (on left, first level) +\ifev@l + \itemindent -1em + \leftmargini 2em + \leftmarginii 1em + \leftmarginiii 1.5em + \leftmarginiv 1.5em + \leftmarginv 1.0em + \leftmarginvi 1.0em +\else + \itemindent -1em + \leftmargini 3em + \leftmarginii 3em + \leftmarginiii 3em + \leftmarginiv 3em + \leftmarginv 3em + \leftmarginvi 3em +\fi +%\itemindent 2em % Alternative values: sometimes used.. +%\leftmargini 0em +\labelsep 5pt +\leftmargin\leftmargini +\labelwidth \z@ + +\def\@listI{\leftmargin\leftmargini} \@listI +\def\@listi{\leftmargin\leftmargini \topsep \z@ plus 1pt minus 1pt} +\def\@listii{\leftmargin\leftmarginii\labelwidth\leftmarginii + \advance\labelwidth-\labelsep \topsep \z@} +\def\@listiii{\leftmargin\leftmarginiii\labelwidth\leftmarginiii + \advance\labelwidth-\labelsep \topsep \z@} +\def\@listiv{\leftmargin\leftmarginiv\labelwidth\leftmarginiv + \advance\labelwidth-\labelsep \topsep \z@} +\def\@listv{\leftmargin\leftmarginv\labelwidth\leftmarginv + \advance\labelwidth-\labelsep \topsep \z@} +\def\@listvi{\leftmargin\leftmarginvi\labelwidth\leftmarginvi + \advance\labelwidth-\labelsep \topsep \z@} + +\def\labelenumi{\theenumi.} \def\theenumi{\arabic{enumi}} +\def\labelenumii{(\theenumii)} \def\theenumii{\alph{enumii}} +\def\labelenumiii{\theenumiii.} \def\theenumiii{\roman{enumiii}} +\def\labelenumiv{\theenumiv.} \def\theenumiv{\Alph{enumiv}} +\def\p@enumii{\theenumi} +\def\p@enumiii{\theenumi(\theenumii)} +\def\p@enumiv{\p@enumiii\theenumiii} + +\def\labelitemi{$\scriptstyle\bullet$} +\def\labelitemii{\bf --} +\def\labelitemiii{$\ast$} +\def\labelitemiv{$\cdot$} + +%% \itemindent is set to \z@ by list, so define new temporary variable +\newdimen\tmpitemindent +\def\verse{\let\\=\@centercr + \list{}{\itemsep\z@ \itemindent -1.5em \listparindent \itemindent + \rightmargin\leftmargin\advance\leftmargin 1.5em}\item[]} +\let\endverse\endlist +\def\quotation{\list{}{\listparindent 1.5em \itemindent\listparindent + \rightmargin\leftmargin \parsep 0pt plus 1pt}\item[]} +\let\endquotation=\endlist +\def\quote{\list{}{\rightmargin\leftmargin}\item[]} +\let\endquote=\endlist +\def\@mklab#1{#1} +\def\description{\tmpitemindent\itemindent\list{}{\itemindent\tmpitemindent + \labelwidth\z@\def\makelabel##1{\hspace\labelsep\emph{##1}}}} +\def\enddescription{\endlist\par} +\def\enumerate{\tmpitemindent\itemindent\ifnum \@enumdepth >3 \@toodeep\else + \advance\@enumdepth \@ne \edef\@enumctr{enum\romannumeral\the\@enumdepth}% + \list{\csname label\@enumctr\endcsname}{\itemindent\tmpitemindent + \usecounter{\@enumctr}\def\makelabel##1{\hspace\labelsep\hfil{##1}}}\fi} +\def\endenumerate{\endlist\par} +\def\itemize{\tmpitemindent\itemindent\ifnum \@itemdepth >3 \@toodeep\else + \advance\@itemdepth\@ne + \edef\@itemitem{labelitem\romannumeral\the\@itemdepth}% + \list{\csname\@itemitem\endcsname}{\itemindent\tmpitemindent + \def\makelabel##1{\hspace\labelsep\hfil\emph{##1}}}\fi} +\def\enditemize{\endlist\par} + +\newif\if@restonecol +\def\titlepage{\@restonecolfalse\if@twocolumn\@restonecoltrue\onecolumn + \else \newpage \fi \thispagestyle{coverpagestyle}\c@page\z@} +\def\endtitlepage{\if@restonecol\twocolumn \else \newpage \fi% +\if@twoside\mbox{}\thispagestyle{coverpagestyle}\c@page\z@\cleardoublepage\fi} + +\arraycolsep 5pt +\tabcolsep 6pt +\arrayrulewidth .4pt +\doublerulesep 2pt +\tabbingsep\labelsep + +% ************************************************************************** +% ***** Footnote Definition ******************************************** +% ************************************************************************** +\skip\footins 10pt plus 5pt minus 2pt +\footnotesep 7pt +\footskip 6mm +\skip\@mpfootins = \skip\footins +\fboxsep = 3pt \fboxrule = .4pt +\long\def\@makefntext#1{\parindent .8em\indent$^{\@thefnmark}$#1} +\def\footnoterule{} + +% Reset baselinestretch within footnotes. +% Originally stolen from Stanford University thesis style. +% -------------------------------------------------------- +\long\def\@footnotetext#1{\insert\footins{\blsone% + \footnotesize\interlinepenalty\interfootnotelinepenalty + \splittopskip\footnotesep + \splitmaxdepth \dp\strutbox \floatingpenalty \@MM + \hsize\columnwidth \@parboxrestore + \edef\@currentlabel{\csname p@footnote\endcsname\@thefnmark}\@makefntext + \let\par\\ + {\rule{\z@}{\footnotesep}\ignorespaces + #1\strut}}} + +% ************************************************************************** +% ***** Keep track of Sections ***************************************** +% ************************************************************************** +\if@technote + \setcounter{secnumdepth}{3} +\else + \setcounter{secnumdepth}{4} +\fi + +\def\thesection{\@Roman\c@section} +\def\thesubsection{\Alph{subsection}} +\def\thesubsubsection{\thesubsection.\arabic{subsubsection}} +\def\thesubsubsectiondis{\Alph{subsection}.\arabic{subsubsection}} +\def\theparagraph{\thesubsubsection.\alph{paragraph}} +\def\theparagraphdis{\thesubsubsectiondis.\alph{paragraph}} + +\def\theequation{\arabic{equation}} + +% ************************************************************************** +% ***** Table of Contents, List of Figures/Tables Definitions ********** +% ************************************************************************** +\def\@pnumwidth{1.55em} +\def\@tocrmarg {2.55em} +\def\@dotsep{4.5} +\setcounter{tocdepth}{3} + +\def\tableofcontents{\section*{\contentsname}\@starttoc{toc}} +\def\l@section#1#2{\addpenalty{\@secpenalty} \addvspace{1.0em plus 1pt} + \@tempdima 1.8em \begingroup \parindent \z@ \rightskip \@pnumwidth + \parfillskip-\@pnumwidth \bf\leavevmode #1\hfil\hbox to\@pnumwidth{\hss #2} + \par \endgroup} +\def\l@subsection{\@dottedtocline{2}{1.5em}{2.3em}} +\def\l@subsubsection{\@dottedtocline{3}{3.8em}{3.2em}} +\def\listoffigures{\section*{\listfigurename}\@starttoc{lof}} +\def\l@figure{\@dottedtocline{1}{1em}{1.8em}} +\def\listoftables{\section*{\listtablename}\@starttoc{lot}} +\let\l@table\l@figure + +% ************************************************************************** +% ***** Float Definitions ********************************************** +% ************************************************************************** +%% Normal Floats %% Double Column Floats +\floatsep 12pt plus 2pt minus 2pt \dblfloatsep 12pt plus 2pt minus 2pt +\textfloatsep 20pt plus 2pt minus 4pt \dbltextfloatsep 20pt plus 2pt minus 4pt +%\@maxsep 20pt \@dblmaxsep 20pt %!PN +\@fptop 0pt plus 1fil \@dblfptop 0pt plus 1fil +\@fpsep 8pt plus 2fil \@dblfpsep 8pt plus 2fil +\@fpbot 0pt plus 1fil \@dblfpbot 0pt plus 1fil +\def\topfraction{1.0} \def\dbltopfraction{1.0} +\def\floatpagefraction{0.8} \def\dblfloatpagefraction{0.8} +\setcounter{topnumber}{2} \setcounter{dbltopnumber}{4} +% +\intextsep 12pt plus 2pt minus 2pt +\setcounter{bottomnumber}{2} +\def\bottomfraction{.4} +\setcounter{totalnumber}{4} +\def\textfraction{.2} + +% Reset baselinestretch within floats. +% Originally stolen from Stanford University thesis style. +% -------------------------------------------------------- +\def\@xfloat#1[#2]{\ifhmode \@bsphack\@floatpenalty -\@Mii\else + \@floatpenalty-\@Miii\fi\def\@captype{#1}\ifinner + \@parmoderr\@floatpenalty\z@ + \else\@next\@currbox\@freelist{\@tempcnta\csname ftype@#1\endcsname + \multiply\@tempcnta\@xxxii\advance\@tempcnta\sixt@@n + \@tfor \@tempa :=#2\do + {\if\@tempa h\advance\@tempcnta \@ne\fi + \if\@tempa t\advance\@tempcnta \tw@\fi + \if\@tempa b\advance\@tempcnta 4\relax\fi + \if\@tempa p\advance\@tempcnta 8\relax\fi + }\global\count\@currbox\@tempcnta}\@fltovf\fi + \global\setbox\@currbox\vbox\bgroup + \def\baselinestretch{1}\small\normalsize + \hsize\columnwidth \@parboxrestore} + +% ************************************************************************** +% ***** Caption Definition ********************************************* +% ************************************************************************** +% some journals do not have centered captions for figures. +\newif\ifc@ptionleft \c@ptionlefttrue +\def\leftfigcaptions{\c@ptionlefttrue} +\def\centerfigcaptions{\c@ptionleftfalse} + +\long\def\caption{\refstepcounter\@captype \@dblarg{\@caption\@captype}} + +\long\def\@caption#1[#2]#3{\par\addcontentsline{\csname ext@#1\endcsname}{#1}{% + \protect\numberline{\csname the#1\endcsname}{\ignorespaces #2}} + \begingroup \@parboxrestore \normalsize + \@makecaption{\csname fnum@#1\endcsname}{\ignorespaces #3}{#1}\par + \endgroup} + +\def\tablestring{table} +\def\figurestring{figure} + +% changed by GLP to allow table captions to be set to a specific maximum +% width "\captionwidth", if defined. +\newlength{\captionindent} +\long\def\@makecaption#1#2#3{ +\ifx\figurestring#3 + \vskip 5pt + \setbox\@tempboxa\hbox{\small #1.~ #2} + \ifdim \wd\@tempboxa >\hsize + \setbox\@tempboxa\hbox{\small #1.~ } + %\setlength\captionindent{\wd\@tempboxa} \divide\captionindent by 2 + %\parbox[t]{\hsize}{\small \hangindent \captionindent \hangafter=1% + \parbox[t]{\hsize}{\small + \unhbox\@tempboxa#2} + \else \hbox + to\hsize{\small\ifc@ptionleft\else\hfil\fi\box\@tempboxa\hfil} + \fi +\else + \begin{center} + \ifx\captionwidth\undefined {\small #1}\\{\small\scshape #2} + \else + \begin{minipage}{\captionwidth} + \begin{center}{\small #1}\\{\small\scshape #2}\end{center} + \end{minipage} + \fi + \end{center}\vskip 4pt +\fi} + +\def\thefigure{\@arabic\c@figure} +\def\fps@figure{tbp} +\def\ftype@figure{1} +\def\ext@figure{lof} +\def\fnum@figure{\figurename\ \thefigure} +%\def\figure{\@float{figure}} % GLP +%\let\endfigure\end@float +\@namedef{figure*}{\@dblfloat{figure}} +\@namedef{endfigure*}{\end@dblfloat} + +\def\thetable{\@Roman\c@table} +\def\fps@table{tbp} +\def\ftype@table{2} +\def\ext@table{lot} +\def\fnum@table{TABLE~\thetable} +\def\table{\@float{table}} +\let\endtable\end@float +\@namedef{table*}{\@dblfloat{table}} +\@namedef{endtable*}{\end@dblfloat} + +% ************************************************************************** +% ***** Header/Footer Definition *************************************** +% ************************************************************************** +% compute the time in hours and minutes; make new vars \timehh and \timemm +\newcount\timehh\newcount\timemm\timehh=\time\divide\timehh by 60 +\timemm=\time\count255=\timehh\multiply\count255 by-60 +\advance\timemm by \count255 +\ifnum\timehh=12\def\apm{pm}\else +\ifnum\timehh>12\def\apm{pm}\advance\timehh by-12\else +\def\apm{am}\fi\fi +\def\t@me{\number\timehh\,:\,\ifnum\timemm<10 0\fi\number\timemm\,\apm} + +% default definitions +% ------------------- +\def\theevenhe@d{\footnotesize\thepage \hfil \leftmark\hbox{}} +\def\theoddhe@d{\hbox{}\footnotesize\rightmark \hfil \thepage} +\def\theevenf@@t{} +\def\theoddf@@t{} + +\def\theeventphe@d{\footnotesize\thepage \hfil \hbox{}} +\def\theoddtphe@d{\hbox{}\footnotesize \hfil \thepage} +\def\theeventpf@@t{} +\def\theoddtpf@@t{} + +\def\theevencphe@d{} +\def\theoddcphe@d{} +\def\theevencpf@@t{} +\def\theoddcpf@@t{} + +\def\internalmsg{Preliminary version for evaluation: Please do not + circulate without the permission of the author(s)} +\def\submittedmsg{SUBMITTED FOR PUBLICATION TO:} +\def\acceptedmsg{ACCEPTED FOR PUBLICATION:} +\def\inpressmsg{(IN PRESS)} +\def\reprintmsg{REPRINTED FROM:} + +% default cover page style (optional cover page) +% ---------------------------------------------- +\def\ps@coverpagestyle{ + \def\@oddhead{\theoddcphe@d} \def\@evenhead{\theevencphe@d} + \def\@oddfoot{\theoddcpf@@t} \def\@evenfoot{\theevencpf@@t} +} + +% default title page style (first page of paper) +% ---------------------------------------------- +\def\ps@titlepagestyle{ + \def\@oddhead{\theoddtphe@d} \def\@evenhead{\theeventphe@d} + \def\@oddfoot{\theoddtpf@@t} \def\@evenfoot{\theeventpf@@t} +} + +% default regular page style +% -------------------------- +\if@twoside + \def\ps@headings{ + \def\@oddhead{\theoddhe@d} + \def\@evenhead{\theevenhe@d} + \def\@oddfoot{\theoddf@@t} \def\@evenfoot{\theevenf@@t} + } +\else + \def\ps@headings{ + \def\@oddhead{\theoddhe@d} + \def\@oddfoot{\theoddf@@t} + \def\@evenhead{} \def\@evenfoot{} + } +\fi + +% For draft mode (no sub-modes allowed) +% ------------------------------------- +\ifdr@ft + \def\leftmark{\sh@rttitle}\let\rightmark\leftmark + \def\theoddf@@t{\footnotesize\today---\t@me\hfil DRAFT} + \def\theevenf@@t{\footnotesize DRAFT\hfil\today---\t@me} + \def\theoddtpf@@t{\footnotesize\today---\t@me\hfil DRAFT} + \def\theeventpf@@t{\footnotesize DRAFT\hfil\today---\t@me} +\fi + +% For submission mode (default plus internal sub-modes allowed) +% ------------------------------------------------------------- +\ifsubm@t + \def\leftmark{\sh@rttitle}\def\rightmark{\titl@line} + \ifintern@l + \def\theeventphe@d{\footnotesize\thepage \hfil \rightmark\hbox{}} + \def\theoddtphe@d{\hbox{}\footnotesize\rightmark \hfil \thepage} + \def\rightmark{\vbox to 0pt{\vss\hbox{\internalmsg} \hbox{\sh@rttitle}}} + \def\leftmark{\vbox to 0pt{\vss\hbox{\internalmsg} + \hbox{\phantom{\internalmsg}\llap{\sh@rttitle}}}} + \else % put date on first page. + \edef\TODAY{\uppercase{\today}} + \def\theeventphe@d{\footnotesize\thepage \hfil \submittedmsg\ + \@journal\@titletext, \TODAY} + \def\theoddtphe@d{\footnotesize\submittedmsg\ + \@journal\@titletext, \TODAY\hfil \thepage} + \def\theevencphe@d{\footnotesize\hbox{} \hfil \submittedmsg\ + \@journal\@titletext, \TODAY} + \def\theoddcphe@d{\footnotesize\submittedmsg\ + \@journal\@titletext, \TODAY\hfil \hbox{}} + \fi +\fi + +% For compressed mode (default, internal, submitted and +% inpress sub-modes allowed) +% ----------------------------------------------------- +\ifc@mpress + \def\leftmark{\sh@rttitle}\def\rightmark{\titl@line} + \ifintern@l + \def\theeventphe@d{\footnotesize\thepage \hfil \rightmark\hbox{}} + \def\theoddtphe@d{\hbox{}\footnotesize\rightmark \hfil \thepage} + \def\rightmark{\vbox to 0pt{\vss\hbox{\internalmsg} \hbox{\sh@rttitle}}} + \def\leftmark{\vbox to 0pt{\vss\hbox{\internalmsg} + \hbox{\phantom{\internalmsg}\llap{\sh@rttitle}}}} + \fi + \ifprepr@nt + \edef\TODAY{\uppercase{\today}} + \def\theeventphe@d{\footnotesize\thepage \hfil \submittedmsg\ + \@journal\@titletext, \TODAY} + \def\theoddtphe@d{\footnotesize\submittedmsg\ + \@journal\@titletext, \TODAY\hfil \thepage} + \def\theevencphe@d{\footnotesize\hbox{} \hfil \submittedmsg\ + \@journal\@titletext, \TODAY} + \def\theoddcphe@d{\footnotesize\submittedmsg\ + \@journal\@titletext, \TODAY\hfil \hbox{}} + \fi + \ifinpr@ss + \def\leftmark{\acceptedmsg\ \@journal\@titletext, \inpressmsg} + \def\theeventphe@d{\footnotesize\thepage \hfil \leftmark\hbox{}} + \def\theoddtphe@d{\hbox{}\footnotesize\leftmark \hfil \thepage} + \fi +\fi + +% For final (evaluate) mode (default, techreport, internal, +% submitted, inpress and reprint sub-modes allowed) +% --------------------------------------------------------- +\ifev@l + \edef\TODAY{\uppercase{\today}} + \def\leftmark{\@journal\@titletext}\def\rightmark{\titl@line} + \def\theeventphe@d{\footnotesize\thepage \hfil \leftmark\hbox{}} + \def\theoddtphe@d{\hbox{}\footnotesize\leftmark \hfil \thepage} + \if@technote % make header a little bigger + \def\theevenhe@d{\small\thepage \hfil \leftmark\hbox{}} + \def\theoddhe@d{\hbox{}\small\rightmark \hfil \thepage} + \def\theeventphe@d{\small\thepage \hfil \leftmark\hbox{}} + \def\theoddtphe@d{\hbox{}\small\leftmark \hfil \thepage} + \fi + \ifintern@l + \def\theeventphe@d{\footnotesize\thepage \hfil \rightmark\hbox{}} + \def\theoddtphe@d{\hbox{}\footnotesize\rightmark \hfil \thepage} + \def\rightmark{\vbox to 0pt{\vss\hbox{\internalmsg} \hbox{\sh@rttitle}}} + \def\leftmark{\vbox to 0pt{\vss\hbox{\internalmsg} + \hbox{\phantom{\internalmsg}\llap{\sh@rttitle}}}} + \fi + \ifprepr@nt + \def\leftmark{\submittedmsg\ \@journal\@titletext, \TODAY} + \fi + \ifinpr@ss + \def\leftmark{\acceptedmsg\ \@journal\@titletext, \inpressmsg} + \fi + \ifrepr@nt + % reset page size on second and following pages b/c no copyright info + \let\oldshipout\shipout + \gdef\shipout{\global\textheight 243.5mm\oldshipout} + \def\theeventpf@@t{\footnotesize\hfil\@ieeecopyright\hfil} + \def\theoddtpf@@t{\footnotesize\hfil\@ieeecopyright\hfil} + \def\leftmark{\reprintmsg\ \@journal\@titletext} + \fi +\fi + +%% Defines the command for putting the header. footernote{TEXT} is the same +%% as markboth{TEXT}{TEXT}. Here for compatibility with other style files. +\def\markboth#1#2{\def\leftmark{#1}\def\rightmark{#2}} +\def\footernote#1{\markboth{#1}{#1}} + +% ************************************************************************** +% ***** Citation/Bibliography Definitions ****************************** +% ************************************************************************** +%% separate citations with "], [" +\def\@citex[#1]#2{\if@filesw\immediate\write\@auxout{\string\citation{#2}}\fi +\def\@citea{}\@cite{\@for\@citeb:=#2\do {\@citea\def\@citea{], +[}\@ifundefined {b@\@citeb}{{\bf ?}\@warning {Citation `\@citeb' on +page \thepage \space undefined}}% +{\csname b@\@citeb\endcsname}}}{#1}} + +\def\@cite#1#2{[{#1\if@tempswa, #2\fi}]} + +%% Allow short (name-less) citations, when used in conjunction with a +%% bibliography style that creates labels like \citename{, } +\let\@internalcite\cite +\def\cite{\def\citename##1{##1}\@internalcite} +\def\shortcite{\def\citename##1{}\@internalcite} +\def\@biblabel#1{\def\citename##1{##1}[#1]\hfill} + +\def\thebibliography#1{\section*{\refname}\footnotesize\list + {\hss[\arabic{enumi}]}{\settowidth\labelwidth{[#1]}\leftmargin\labelwidth + \advance\leftmargin\labelsep \itemsep 0pt plus .5pt + \usecounter{enumi}} + \def\newblock{\hskip .11em plus .33em minus .07em} + \sloppy\clubpenalty4000\widowpenalty4000 + \sfcode`\.=1000\relax + \ifev@l\else\normalsize\fi %added by GLP +} +\let\endthebibliography=\endlist + +% ************************************************************************** +% ***** Appendix/Appendices Definitions ******************************** +% ************************************************************************** +\newcounter{numappendices}\setcounter{numappendices}{0} +\newif\ifappendix \appendixfalse +%% appendix command for one single appendix +\def\appendix{\par + \appendixtrue + \typeout{appendices: \arabic{numappendices}} + \setcounter{section}{0}\setcounter{subsection}{0} + \gdef\thesection{\Alph{section}} + \ifnum \value{numappendices}>1 + \section*{\appendicesname} + \else + \section*{\appendixname} + \fi + \setcounter{numappendices}{0} +} +%% appendices command for multiple appendicies +\def\appendices{\par + \appendixtrue + \typeout{appendices: \arabic{numappendices}} + \setcounter{section}{0}\setcounter{subsection}{0} + \gdef\thesection{\Alph{section}} \section*{\appendicesname} + \setcounter{numappendices}{0} +} +\AtEndDocument{\if@filesw\immediate\write\@auxout{\string\setcounter{numappendices}{\arabic{numappendices}}}\fi} + +% ************************************************************************** +% ***** Title Definitions ********************************************** +% ************************************************************************** +\def\titl@line{\sh@rttitle} %for the header at the top of the page. + +\def\@title{\typeout{ieee: Warning! No \noexpand\title given!}} +\def\title{\@ifnextchar [{\titlea}{\titleb}}%] + +\def\set@title#1{\gdef\@title{#1}\global\def\set@title##1{}} +\def\setsh@rttitle#1{\gdef\sh@rttitle{#1}\global\def\setsh@rttitle##1{}} +\def\titlea[#1]#2{\set@title{#2}\setsh@rttitle{\uppercase{#1}}} +\def\titleb#1{\set@title{#1}\setsh@rttitle{\uppercase{#1}}} + +\def\authorinfo#1{\let\\\relax\thanks{#1}} + +\ifev@l + \if@technote + \def\member#1{} + \else + \def\member#1{, \emph{#1, IEEE}} + \fi +\else + \def\member#1{} +\fi + +\def\and{\unskip% % \begin{tabular} +\end{tabular}% +\hskip 0pt plus 0.1pt% +\begin{tabular}[t]{@{}c@{}}\ }% + +\def\@author{\typeout{ieee: Warning! No \noexpand\author given!}} +\def\author{\@ifnextchar [{\authora}{\authorb}}%] +\def\set@author#1{\gdef\@author{#1}\global\def\set@author##1{}} +\def\settitl@line#1{\gdef\titl@line{#1}\global\def\settitl@line##1{}} +\def\authora[#1]#2{\set@author{#2}\if@non\else\settitl@line{#1: \sh@rttitle}\fi} +\def\authorb#1{\set@author{#1}} + +\def\date#1{\def\today{#1}\edef\TODAY{\uppercase{\today}}} + +\long\def\maketitle{% + \begingroup + \let\@thanks\@empty + \renewcommand\thefootnote{} % the \thanks{} mark type is empty + \iftitlep@ge\begin{titlepage}\@maketitlepage\@thanks\end{titlepage}% + \let\@thanks\@empty\fi + \thispagestyle{titlepagestyle} + \if@twocolumn + \if@technote + %\if@twoside\newpage\cleardoublepage\else\newpage\fi% + \newpage\global\@topnum\z@ + \ifrepr@nt + \ifx\@loginfo\undefined\typeout{ieee: Warning! No \noexpand\loginfo + given!}\else\let\\\relax\thanks{\@loginfo}\fi% + \fi + \@maketitle + \else + \ifnum \col@number=\@ne + \ifrepr@nt + \ifx\@loginfo\undefined\typeout{ieee: Warning! No \noexpand\loginfo + given!}\else\let\\\relax\thanks{\@loginfo}\fi% + \fi + \@maketitle + \else \twocolumn[% + \ifrepr@nt% + \ifx\@loginfo\undefined\typeout{ieee: Warning! No \noexpand\loginfo% + given!}\else\let\\\relax\thanks{\@loginfo}\fi% + \fi% + \@maketitle]% + \fi + \fi + \else + \newpage + \global\@topnum\z@ % Prevents figures from going at top of page. + \ifrepr@nt + \ifx\@loginfo\undefined\typeout{ieee: Warning! No \noexpand\loginfo + given!}\else\let\\\relax\thanks{\@loginfo}\fi + \fi + \@maketitle + \fi + \thispagestyle{titlepagestyle}% + \@thanks + \endgroup + \setcounter{footnote}{0}% + \global\let\thanks\relax \global\let\maketitle\relax + \global\let\@maketitle\relax \global\let\@thanks\@empty + \global\let\@author\@empty \global\let\@date\@empty + \global\let\@title\@empty \global\let\title\relax + \global\let\author\relax \global\let\date\relax + \global\let\and\relax +} + +\long\def\@maketitle{\unskip\newpage% + \begin{center}\blsone + \let \footnote \thanks + \if@technote + {\bfseries\@title\par}\if@non\else\vskip 1.3em{\lineskip .5em + \noindent\begin{tabular}[t]{@{}c@{}}\@author\end{tabular}}\fi\par + \else\unskip + \noindent{\Huge\@title\par}% + \if@non\else\vskip1.0em% + \noindent{\large\lineskip .5em% + \begin{tabular}[t]{@{}c@{}}\@author\end{tabular}}% + \fi\par% + \if@nvited\vskip1.0em\noindent\emph{\large(Invited Paper)}\par\fi + \fi + \ifrepr@nt + \ifx\@lognumber\undefined\typeout{ieee: Warning! No + \noexpand\pubitemident or \noexpand\lognumber + given!}\else\thanks{\@lognumber}\fi% + \fi + \end{center}\par\vskip 0.5em}% + +\long\def\@maketitlepage{\newpage% + \mbox{}\vfil + \begin{center}\blsone + \let \footnote \thanks + \if@technote + {\bfseries\@title\par}\vskip 1.3em{\lineskip .5em + \noindent\begin{tabular}[t]{@{}c@{}}\@author\end{tabular}\par} + \else + \vskip0.2em{\Huge\@title\par}\vskip1.0em% + \iftitlep@ge\vfil\fi + \noindent{\large\lineskip .5em% + \begin{tabular}[t]{@{}c@{}}\@author\end{tabular}\par}% + \fi + \end{center}\par\vfil\mbox{}} + +\def\@journal{\typeout{ieee: Warning! No \noexpand\journal given!}} +\def\journal#1{\def\@journal{\uppercase{#1}}} + +\def\@ieeecopyright{\typeout{ieee: Warning! No \noexpand\ieeecopyright given!}} +\def\ieeecopyright#1{\def\@ieeecopyright{#1}} + +\def\lognumber#1{\def\@lognumber{IEEE Log Number #1.}} +\def\pubitemident#1{\def\@lognumber{Publisher Item Identifier #1.}} +\long\def\loginfo#1{\long\def\@loginfo{\hbox{\vrule height 3ex width \z@}#1}} + +\def\sh@rttitle{} +\def\@titletext{} +\def\titletext#1{\def\@titletext{#1}} + +\def\firstpage#1{\setcounter{page}{#1}} + +% ************************************************************************** +% ***** Abstract Definition ******************************************** +% ************************************************************************** +\def\abstract{% + \if@twocolumn + \small\bfseries{\itshape\abstractname\/---}% + \else + \begin{center}\vspace{-0.8em}\small\bf\abstractname\end{center} + \quotation\small + \fi\ignorespaces} +\def\endabstract{\vspace{0.6em}\par\if@twocolumn\else\endquotation\fi + \normalsize\normalstyle} + +% ************************************************************************** +% ***** Keywords Definition ******************************************** +% ************************************************************************** +\def\keywords{\vspace{-.3em} + \if@twocolumn + \small\bfseries{\itshape\keywordsname\/---}% + \else + \begin{center}\small\bf\keywordsname\end{center}\quotation\small + \fi\ignorespaces} +\def\endkeywords{\vspace{0.6em}\par\if@twocolumn\else\endquotation\fi + \normalsize\normalstyle} + +% ************************************************************************** +% ***** Fix Section Numbering ****************************************** +% ************************************************************************** +\gdef\@punct{.\ \ } % Punctuation after run-in section heading +\def\@sect#1#2#3#4#5#6[#7]#8{% + \ifnum #2>\c@secnumdepth + \def\@svsec\@empty + \else + \refstepcounter{#1}% + \protected@edef\@svsec{% + %\ifnum #2=1\Roman{#1}.\fi\ifnum #2=2\Alph{#1}.\fi + \ifnum #2=1\thesection.\fi + \ifnum #2=2\thesubsection.\fi + \ifnum #2>2{\csname the#1dis\endcsname}\if@technote.\fi\fi \hskip .5em} + \ifnum #2=1\ifappendix\stepcounter{numappendices}\fi\fi + \fi + \@tempskipa #5\relax + \ifdim \@tempskipa>\z@ + \begingroup #6\relax + \@hangfrom{\hskip #3\relax\@svsec}{\interlinepenalty \@M #8\par} + \endgroup + \csname #1mark\endcsname{#7} + \addcontentsline{toc}{#1}{\ifnum #2>\c@secnumdepth\else + \protect\numberline{\csname the#1\endcsname}\fi#7} + \else + \def\@svsechd{#6\hskip #3\@svsec #8\@punct\csname #1mark\endcsname{#7} + \addcontentsline{toc}{#1}{\ifnum #2>\c@secnumdepth \else + \protect\numberline{\csname the#1\endcsname}\fi#7}} + \fi + \@xsect{#5}} + +\def\@ssect#1#2#3#4#5{\@tempskipa #3\relax + \ifdim \@tempskipa>\z@ + \begingroup #4\@hangfrom{\hskip #1}{\interlinepenalty \@M #5\par}\endgroup + \else \def\@svsechd{#4\hskip #1\relax #5\@punct}\fi + \@xsect{#3}} + +% ************************************************************************** +% ***** Section Definitions ******************************************** +% ************************************************************************** +\def\section{\@startsection{section}{1}{\z@}{2.0ex plus .5ex + minus .2ex}{1.0ex plus .2ex}{\centering\scshape}} +\def\subsection{\@startsection{subsection}{2}{\z@}{2.0ex plus .5ex + minus .2ex}{1.0ex plus .2ex}{\itshape}} +\if@technote + \def\subsubsection{\@startsection{subsubsection}{3}{\z@}{2.0ex plus .5ex + minus .1ex}{0pt}{\itshape}} +\else + \def\subsubsection{\@startsection{subsubsection}{3}{\z@}{2.0ex plus .5ex + minus .2ex}{1.0ex plus .2ex}{\normalstyle}} + \def\paragraph{\@startsection{paragraph}{4}{\z@}{1.0ex plus .5ex + minus .2ex}{0ex}{\normalstyle}} +\fi + +% ************************************************************************** +% ***** Special Environment Definitions ******************************** +% ************************************************************************** +\def\QED{\mbox{\rule[0pt]{1.5ex}{1.5ex}}} +\def\proof{\noindent\hspace{1em}{\it Proof: }} +\def\endproof{\hspace*{\fill}~\QED\par\endtrivlist\unskip} +\def\@begintheorem#1#2{\tmpitemindent\itemindent\topsep 0pt\normalstyle\trivlist + \item[\hskip \labelsep{\indent\it #1\ #2:}]\itemindent\tmpitemindent} +\def\@opargbegintheorem#1#2#3{\tmpitemindent\itemindent\topsep 0pt\normalstyle \trivlist + \item[\hskip\labelsep{\indent\it #1\ #2\ \normalstyle(#3)}]\itemindent\tmpitemindent} +\def\@endtheorem{\endtrivlist\unskip} + +% ************************************************************************** +% ***** Special Environment Definitions ******************************** +% ************************************************************************** +\if@twoside\else\raggedbottom\fi + +%% Definition for Big letter at the beginning of a paragraph +%% +\def\PARstart#1#2 {\begingroup\def\par{\endgraf\endgroup\lineskiplimit=0pt} + \setbox2=\hbox{\uppercase{#2} }\newdimen\tmpht \tmpht \ht2 + \advance\tmpht by \baselineskip\font\hhuge=cmr10 at \tmpht + \setbox1=\hbox{{\hhuge #1}} + \count7=\tmpht \count8=\ht1\divide\count8 by 1000 \divide\count7 by\count8 + \tmpht=.001\tmpht\multiply\tmpht by \count7\font\hhuge=cmr10 at \tmpht + \setbox1=\hbox{{\hhuge #1}} \noindent \hangindent1.05\wd1 + \hangafter=-2 {\hskip-\hangindent \lower1\ht1\hbox{\raise1.0\ht2\copy1}% + \kern-0\wd1}\copy2\lineskiplimit=-1000pt} + +\def\PARstartCal#1#2 {\begingroup\def\par{\endgraf\endgroup\lineskiplimit=0pt} + \setbox2=\hbox{\uppercase{#2} }\newdimen\tmpht \tmpht \ht2 + \advance\tmpht by \baselineskip\font\hhuge=cmsy10 at \tmpht + \setbox1=\hbox{{\hhuge #1\/}} + \count7=\tmpht \count8=\ht1\divide\count8 by 1000 \divide\count7 by\count8 + \tmpht=.001\tmpht\multiply\tmpht by \count7\font\hhuge=cmsy10 at \tmpht + \setbox1=\hbox{{\hhuge #1\/}} \noindent \hangindent1.05\wd1 + \hangafter=-2 {\hskip-\hangindent \lower1\ht1\hbox{\raise1.0\ht2\copy1}% + \kern-0\wd1}\copy2\lineskiplimit=-1000pt} + +\def\PARstartLyX#1{\PARstart #1} +\def\PARstartCalLyX#1{\PARstartCal #1} + +\if@technote\def\PARstart#1#2{#1#2}\fi % if technical note, disable it +\if@technote\def\PARstartCal#1#2{#1#2}\fi % if technical note, disable it +\if@technote\def\PARstartLyX#1{#1}\fi % if technical note, disable it +\if@technote\def\PARstartCalLyx#1{#1}\fi % if technical note, disable it + +% ************************************************************************** +% ***** Misc. Definitions ********************************************** +% ************************************************************************** +%Restore single spacing +\newcommand{\blsone}{\renewcommand\baselinestretch{1}% + \renewcommand\arraystretch{1.2}\setlength{\parindent}{\parindentsave}% + \normalsize} +\newcommand{\capitem}[1]{{\hspace{0.2ex}(#1)}~} +\newcommand{\insdate}{} + +% ************************************************************************** +% ***** MATH Definitions *********************************************** +% ************************************************************************** +\def\eqnarray{% + \stepcounter{equation}% + \def\@currentlabel{\p@equation\theequation}% + \global\@eqnswtrue + \m@th + \global\@eqcnt\z@ + \tabskip\@centering + \let\\\@eqncr + $$\everycr{}\halign to\displaywidth\bgroup + \hskip\@centering$\displaystyle\tabskip\z@skip{##}$\@eqnsel + &\global\@eqcnt\@ne\hskip \eqnarr@ysep\hfil${##}$\hfil + &\global\@eqcnt\tw@ \hskip \eqnarr@ysep + $\displaystyle{##}$\hfil\tabskip\@centering + &\global\@eqcnt\thr@@ \hb@xt@\z@\bgroup\hss##\egroup + \tabskip\z@skip + \cr +} +\def\endeqnarray{% + \@@eqncr + \egroup + \global\advance\c@equation\m@ne + $$\@ignoretrue +} + +% ************************************************************************** +% ***** Biography Definitions ****************************************** +% ************************************************************************** +% This is the main code for the biography environment of the IEEE +% transactions class. The previous biography code had some known +% problems which were difficult to fix. The crux of the issue was that +% the photo frame was overlaid by text when \baselinestretch>1 or when +% the biography consisted of multiple short paragraphs. +% +% The fix was done by extracting code from the excellent package: +% 'picinpar.sty' version 1.2a as of july 13, 1993 +% by Friedhelm Sowa +% +% (At least most of) The bugs you find in this code were introduced +% unwittingly by myself. +% +%---------------- +% Known problems: +% +% - Don't use multiple blank lines to separate paragraphs. A single +% blank line works well, but multiple blank lines will confuse +% the code. This has something to do with the \def\par{\\\indent} +% line, but I can't think of an appropriate fix. Similarly, make +% sure the environment doesn't end with an extra blank line. +% - Don't use \samepage +% - Use \footnotemark within and \footnotetext outside the +% window-environment instead of \footnote +% - When using the epic-package load picinpar before epic +% like \documentstyle[...,picinpar,epic]{...} +% +% Counts +\newcount\br \newcount\nb \newcount\tcdsav \newcount\tcl \newcount\tcd +\newcount\tcn \newcount\cumtcl +% Dimens +\newdimen\rtside \newdimen\hpic \newdimen\vpic \newdimen\strutilg +\newdimen\picwd \newdimen\topheight \newdimen\ilg \newdimen\lpic +\newdimen\lwindowsep \newdimen\rwindowsep % VK 10 Feb 93 +\lwindowsep0.5\baselineskip % " +\rwindowsep0.5\baselineskip % " +\newdimen\cumpar +% Tokens +\newtoks\twa \newtoks\la \newtoks\ra \newtoks\ha \newtoks\pictoc +% Boxes +\newbox\rawtext \newbox\holder \newbox\windowbox \newbox\wartext +\newbox\finaltext \newbox\aslice \newbox\bslice \newbox\wbox +\newbox\wstrutbox \newbox\picbox \newbox\waslice \newbox\wbslice +\newbox\fslice + % Another strut +\def\wstrut{\relax\ifmmode\copy\wstrutbox\else\unhcopy\wstrutbox\fi} +% + +\def\getpic#1{\sbox{\@tempboxa}{\includegraphics{#1}}% +\newcount\tmpcta \tmpcta=\ht\@tempboxa% +\newcount\tmpctb \tmpctb=\wd\@tempboxa% +\divide\tmpctb by 100% +\divide\tmpcta by\tmpctb% +\ifnum\tmpcta>133% +\typeout{ieee: Biography picture `#1' too tall.}% +\frame{\hbox to 25mm{\hfil\resizebox{!}{32mm}{\usebox{\@tempboxa}}\hfil}}% +\else \ifnum\tmpcta<123% +\typeout{ieee: Biography picture `#1' too wide.}% +\frame{\vbox to 32mm{\vss\hbox{\resizebox{25mm}{!}{\usebox{\@tempboxa}}}\vss}}% +\else% +\resizebox{25mm}{32mm}{\usebox{\@tempboxa}} +\fi\fi} + +\long\def\biographyLyX#1{\if@non\else\begin{biography} #1\end{biography}\fi} + +\if@non + \long\def\biography{} +\else + \long\def\biography{\@ifnextchar [{\@biographyb}{\@biographya[{\unitlength + 1mm\hbox{\framebox(25,32){}}}]}} +\fi + +\long\def\@biographyb[#1]{\@biographya[\getpic{#1}]} + +\long\def\@biographya[#1]#2{\bgroup +\footnotesize\bigskip\bigskip\bigskip\parskip=0pt\par% +\rule{0pt}{35mm}\vspace*{-35mm}\par% garantees correct page breaking +\begin{main@bio}[{#1}]% +\noindent{\bf #2}% +} +\def\endbiography{\if@non\else\end{main@bio}\egroup\fi} + +\long\def\main@bio[#1]{% #1 is the material for setting a graphic box +\vskip\parskip\everypar{} +\global\cumpar=0pt +\global\cumtcl=0 + \tcd=0 + \rtside=0pt +% \hpic=\linewidth + \twa={} \la={} \ra={} \ha={} +\setbox\wbox=\hbox{(} +\computeilg +\pictoc={#1} +\setbox\windowbox=\vbox{\hbox{#1}} +\picwd=\wd\windowbox +\hpic=\picwd +\vpic=\ht\windowbox\advance\vpic\dp\windowbox +\rtside=\linewidth\advance\rtside-\picwd +\setbox\picbox=\vbox{\hsize=\hpic\vbox to\vpic{\box\windowbox}}% \vfill}}% + +\vpic=\ht\picbox\advance\vpic\dp\picbox +\ifdim\rtside>0pt\advance\rtside-\rwindowsep\fi % " +\global\br=\rtside +\ifnum\picwd=0 +\ifdim\vpic>0pt\picwd=\hpic +\else\vpic=\ht\picbox\advance\vpic\dp\picbox +\fi +\fi + \global\tcl=0 \lpic=0pt + \loop\global\advance\tcl by 1 \lpic=\tcl\baselineskip + \ifdim\lpic<\vpic\repeat + \vpic=\lpic + \global\cumtcl=\tcl +% +% Here we know exactly the number of indented lines and +% are able to generate the tokens for the \parshape list +% + \ifnum\br>0\ra={ 0pt \rtside}\fi + \ifnum\tcd>0\ha={ 0pt \linewidth}\fi + \ifnum\tcl<1\global\tcl=1\fi + \createparshapespec + \tcd=0 % restore the lintel + \global\tcdsav=0 +% +% This is a very tricky part of the package. Some day there +% will exist a detailed documentation. +% +\def\par{\\\indent} +% +% This is where we start to pick up the paragraph(s) +% + \setbox\rawtext=\vbox\bgroup\unvbox\rawtext\unskip + \clubpenalty=0\widowpenalty=0 + \ifnum\brokenpenalty<\maxdimen\else\brokenpenalty=9999\fi + \tolerance=1000 + \parshape=\tcn \the\twa } +% +\def\endmain@bio{% + %\par + \global\tcd=\tcdsav + \egroup\vskip\parskip\parshape=0 % reset parshape; end \box\rawtext + \vbadness=10000 + \splittopskip=0pt +% +% Now we build the boxes beside the window +% +\global\topheight=\tcl\baselineskip +\ifnum\br>0\setbox\holder=\vsplit\rawtext to\topheight\fi +\tcn=\tcl \nb=0 +\ifnum\br>0\nb=\tcn\fi +% +% text on the right side +% +\ifnum\nb>0 + \loop\advance\nb -1 + \setbox\bslice=\vsplit\holder to\baselineskip + \prune\bslice\rtside + \setbox\wbslice=\vbox{\unvbox\wbslice\hbox + to\rtside{\box\bslice\hfil}} + \ifdim\ht\holder>0pt\repeat +\fi +%GLP add fix to make sure bio starts at top of picture +\setbox\wbslice=\vbox to\topheight{\unvbox\wbslice\vfill\vss} +% +% fixing the dimensions of the window part +% +\topheight=\ht\wbslice +% +% ship out the window material to the main vertical list +% +\setbox\windowbox=\vbox{\hbox to\linewidth{% +\vbox to\topheight{\hrule width\picwd height0pt depth0pt\vskip0pt% +\vfill\unvbox\picbox% +\ifnum\picwd>0\vfill\fi% +\vss}\ifnum\br>0\hfill\vbox{\box\wbslice}\fi}}% +% +\unvbox\windowbox% +\loop% lines below picture.... + \setbox\bslice=\vsplit\rawtext to\baselineskip + \prune\bslice\linewidth + \setbox\wbslice=\vbox{\hbox to\linewidth{\box\bslice\hfil}} + \unvbox\wbslice + \ifdim\ht\rawtext>0pt +\repeat +%GLP +%\ifnum\nb>0\topheight=\nb\baselineskip %\advance\topheight by\ilg +%\vspace*{\topheight} +%\fi +}% FINITO +% +% What else do we need? +% +\def\prune#1#2{ +% take a \vbox containing a single \hbox, +% \unvbox it, and cancel the \lastskip +% put in a \hbox of width #2 + \unvbox#1 \setbox#1=\lastbox % \box#1 now is an \hbox + \ifdim\ht#1=\parskip + \setbox#1=\hbox to#2{\vrule height\parskip depth0pt width0pt\hfill} + \else\ifdim\ht#1=0pt\relax + \else\setbox#1=\hbox to#2{\wstrut\unhbox#1\unskip}\fi\fi} +% +% Here the token \twa is generated. +% It's not so difficult as it looks like. +% +\def\createparshapespec{% +\global\tcn=0 +\ifnum\br>0\global\tcn=\tcl\fi +\nb=0 +\ifnum\br>0\nb=\tcn\fi +\global\advance\tcn by\tcd \global\advance\tcn by1 +\ifnum\tcd>0 +\loop\twa=\expandafter{\the\twa\the\ha}\advance\tcd -1 +\ifnum\tcd>0\repeat +\fi +\ifnum\nb>0 +\loop\twa=\expandafter{\the\twa\the\ra}\advance\nb -1 +\ifnum\nb>0\repeat +\fi +\global\twa=\expandafter{\the\twa 0pt \the\linewidth}} +% +\def\computeilg{% compute the interline glue + \tcl=0\ilg=0pt\strutilg=0pt + \loop\setbox\wbox=\hbox{\char\tcl} + \ifdim\ht\wbox>\ilg\ilg=\ht\wbox\fi + \ifdim\dp\wbox>\strutilg\strutilg=\dp\wbox\fi + \advance\tcl by 1 + \ifnum\tcl<128\repeat + \ht\wbox=\ilg + \dp\wbox=\strutilg + \strutilg=\ht\wbox %\advance\strutilg by\ilg + \ifdim\strutilg>\baselineskip + \typeout{character with height greater baselineskip found in font} + \typeout{baselineskip changed to 1.5 of that height!} + \baselineskip=1.5\strutilg + \fi + \global\ilg=\baselineskip + \global\advance\ilg-\ht\wbox \global\advance\ilg-\dp\wbox + \strutilg=\ht\wbox \advance\strutilg by\ilg + \setbox\wstrutbox=\hbox{\vrule height\strutilg depth\dp\wbox width0pt}} + + +% the following code from version.sty by Stephen Bellantoni 1990, loosely +% based on "annotation.sty" by Tom Hofmann. Used to exclude "biography" from +% anonymous mode. +\begingroup +\catcode`@=11\relax% +\catcode`{=12\relax\catcode`}=12\relax% +\catcode`(=1\relax \catcode`)=2\relax% +\gdef\glpinclude#1(% + \expandafter\gdef\csname #1\endcsname% + ()% + \expandafter\gdef\csname end#1\endcsname% + ()% +)% +\gdef\glpexclude#1(% + \expandafter\gdef\csname #1\endcsname% + (\@bsphack\catcode`{=12\relax\catcode`}=12\relax\csname #1@NOTE\endcsname)% + \long\expandafter\gdef\csname #1@NOTE\endcsname ##1\end{#1}% + (\csname #1END@NOTE\endcsname)% + \expandafter\gdef\csname #1END@NOTE\endcsname% + (\@esphack\end(#1))% +)% +\endgroup + +%------- +\def\@confplacedate{\typeout{ieee: Warning! No \noexpand\confplacedate set!} +\bfseries `confplacedate' needs to be set. For example, to: Stanford, CA, USA, +September 29--30, 1991} +\def\confplacedate#1{\def\@confplacedate{#1}} + +%%%%%%%%%%%%%%%%%%%%%%%%% End of ieee.cls %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% diff --git a/cryptominisat/cppsrc/docs/satrace19-pdf/walksat/sigproc.bib b/cryptominisat/cppsrc/docs/satrace19-pdf/walksat/sigproc.bib new file mode 100644 index 00000000..0eefb01b --- /dev/null +++ b/cryptominisat/cppsrc/docs/satrace19-pdf/walksat/sigproc.bib @@ -0,0 +1,271 @@ +@InProceedings{stamping, +author="Heule, Marijn J. H. +and J{\"a}rvisalo, Matti +and Biere, Armin", +editor="Sakallah, Karem A. +and Simon, Laurent", +title="Efficient {CNF} Simplification Based on Binary Implication Graphs", +booktitle="Theory and Applications of Satisfiability Testing - SAT 2011", +year="2011", +publisher="Springer Berlin Heidelberg", +address="Berlin, Heidelberg", +pages="201--215", +abstract="This paper develops techniques for efficiently detecting redundancies in CNF formulas. We introduce the concept of hidden literals, resulting in the novel technique of hidden literal elimination. We develop a practical simplification algorithm that enables ``Unhiding'' various redundancies in a unified framework. Based on time stamping literals in the binary implication graph, the algorithm applies various binary clause based simplifications, including techniques that, when run repeatedly until fixpoint, can be too costly. Unhiding can also be applied during search, taking learnt clauses into account. We show that Unhiding gives performance improvements on real-world SAT competition benchmarks.", +isbn="978-3-642-21581-0" +} + +@inproceedings{TACAS-2010-JarvisaloBH, + author = "Matti Järvisalo and Armin Biere and Marijn Heule", + booktitle = "{Proceedings of the 16th International Conference on Tools and Algorithms for the Construction and Analysis of Systems}", + doi = "10.1007/978-3-642-12002-2_10", + pages = "129--144", + publisher = "{Springer International Publishing}", + series = "{Lecture Notes in Computer Science}", + title = "{Blocked Clause Elimination}", + volume = 6015, + year = 2010, +} + +@InProceedings{probsat, +author="Balint, Adrian +and Sch{\"o}ning, Uwe", +editor="Cimatti, Alessandro +and Sebastiani, Roberto", +title="Choosing Probability Distributions for Stochastic Local Search and the Role of Make versus Break", +booktitle="Theory and Applications of Satisfiability Testing -- SAT 2012", +year="2012", +publisher="Springer Berlin Heidelberg", +address="Berlin, Heidelberg", +pages="16--29", +abstract="Stochastic local search solvers for SAT made a large progress with the introduction of probability distributions like the ones used by the SAT Competition 2011 winners Sparrow2010 and EagleUp. These solvers though used a relatively complex decision heuristic, where probability distributions played a marginal role.", +isbn="978-3-642-31612-8" +} + +@InProceedings{balint-improving-sls, +author="Balint, Adrian +and Biere, Armin +and Fr{\"o}hlich, Andreas +and Sch{\"o}ning, Uwe", +editor="Sinz, Carsten +and Egly, Uwe", +title="Improving Implementation of {SLS} Solvers for {SAT} and New Heuristics for {k-SAT} with Long Clauses", +booktitle="Theory and Applications of Satisfiability Testing -- SAT 2014", +year="2014", +publisher="Springer International Publishing", +address="Cham", +pages="302--316", +abstract="Stochastic Local Search (SLS) solvers are considered one of the best solving technique for randomly generated problems and more recently also have shown great promise for several types of hard combinatorial problems. Within this work, we provide a thorough analysis of different implementation variants of SLS solvers on random and on hard combinatorial problems. By analyzing existing SLS implementations, we are able to discover new improvements inspired by CDCL solvers, which can speed up the search of all types of SLS solvers. Further, our analysis reveals that the multilevel break values of variables can be easily computed and used within the decision heuristic. By augmenting the probSAT solver with the new heuristic, we are able to reach new state-of-the-art performance on several types of SAT problems, especially on those with long clauses. We further provide a detailed analysis of the clause selection policy used in focused search SLS solvers.", +isbn="978-3-319-09284-3" +} + + + +@inproceedings{DBLP:conf/ictai/LynceS03, + author = {In{\^{e}}s Lynce and + Jo{\~{a}}o P. Marques Silva}, + title = {Probing-Based Preprocessing Techniques for Propositional Satisfiability}, + booktitle = {15th {IEEE} International Conference on Tools with Artificial Intelligence + {(ICTAI} 2003), 3-5 November 2003, Sacramento, California, {USA}}, + pages = {105}, + year = {2003}, + crossref = {DBLP:conf/ictai/2003}, + url = {https://doi.org/10.1109/TAI.2003.1250177}, + doi = {10.1109/TAI.2003.1250177}, + timestamp = {Fri, 02 Nov 2018 09:48:27 +0100}, + biburl = {https://dblp.org/rec/bib/conf/ictai/LynceS03}, + bibsource = {dblp computer science bibliography, https://dblp.org} +} + +@proceedings{DBLP:conf/ictai/2003, + title = {15th {IEEE} International Conference on Tools with Artificial Intelligence + {(ICTAI} 2003), 3-5 November 2003, Sacramento, California, {USA}}, + publisher = {{IEEE} Computer Society}, + year = {2003}, + url = {http://ieeexplore.ieee.org/xpl/mostRecentIssue.jsp?punumber=8840}, + isbn = {0-7695-2038-3}, + timestamp = {Thu, 18 Dec 2014 16:57:40 +0100}, + biburl = {https://dblp.org/rec/bib/conf/ictai/2003}, + bibsource = {dblp computer science bibliography, https://dblp.org} +} + +@InProceedings{chronobt, +author="Nadel, Alexander +and Ryvchin, Vadim", +editor="Beyersdorff, Olaf +and Wintersteiger, Christoph M.", +title="Chronological Backtracking", +booktitle="Theory and Applications of Satisfiability Testing -- {SAT} 2018", +year="2018", +publisher="Springer International Publishing", +address="Cham", +pages="111--121", +abstract="Non-Chronological Backtracking (NCB) has been implemented in every modern CDCL SAT solver since the original CDCL solver GRASP. NCB's importance has never been questioned. This paper argues that NCB is not always helpful. We show how one can implement the alternative to NCB--Chronological Backtracking (CB)--in a modern SAT solver. We demonstrate that CB improves the performance of the winner of the latest SAT Competition, Maple{\_}LCM{\_}Dist, and the winner of the latest MaxSAT Evaluation Open-WBO.", +isbn="978-3-319-94144-8" +} + +@inproceedings{smith94phase, + author = "Barbara Smith", + title = "The Phase Transition in Constraint Satisfaction Problems: {A} {CL}oser Look at the Mushy Region", + booktitle = {{ECAI}'94}, + year = "1994" +} + +@inproceedings{swdia, + author = "Chanseok Oh", + title = "{MiniSat HACK 999ED, MiniSat HACK 1430ED and SWDiA5BY}", + booktitle = "SAT Competition 2014 Booklet", + year = "201", +} + +@inproceedings{lingeling, + author = "Armin Biere", + title = "Yet another Local Search Solver and Lingeling and Friends Entering the SAT Competition 2014", + booktitle = "SAT Competition 2014 Booklet", + year = "2014", +} + +@inproceedings{maple, + author="Tomas Balyo and Marijn J. H. Heule and Matti Jarvisalo", + title="{MapleLRB\_LCM, Maple\_LCM, Maple\_LCM\_Dist, MapleLRB\_LCMoccRestart and Glucose-3.0+width in SAT Competition 2017}", + booktitle = "Proceedings of SAT Competition 2017", + year="2018" +} + +@inproceedings{sat-comp-2014-armin, + author="Belov Anton and Diepold Daniel and Marijn J. H. Heule and Matti Jarvisalo", + title="{Yet another Local Search Solver and Lingeling and Friends Entering the SAT Competition 2014}", + booktitle = "Proceedings of SAT Competition 2014", + year="2014" +} + +@misc {nscc, + author="ASTAR and NTU and NUS and SUTD", + title="{National Supercomputing Centre (NSCC)} {S}ingapore", + url="https://www.nscc.sg/about-nscc/overview/", + year="2018" +} + +@misc {CMS, + author="Mate Soos", + title="{CryptoMiniSat SAT solver GitHub page}", + url="https://github.com/msoos/cryptominisat", + year="2018" +} + +@inproceedings{cheeseman91where, + author = "Peter Cheeseman and Bob Kanefsky and William M. Taylor", + title = "Where the Really Hard Problems Are", + booktitle = "IJCAI-91", + pages = "331--337", + year = "1991", +} + +@InProceedings{BVA, +author="Manthey, Norbert +and Heule, Marijn J. H. +and Biere, Armin", +editor="Biere, Armin +and Nahir, Amir +and Vos, Tanja", +title="Automated Reencoding of Boolean Formulas", +booktitle="Hardware and Software: Verification and Testing", +year="2013", +publisher="Springer Berlin Heidelberg", +address="Berlin, Heidelberg", +pages="102--117", +abstract="We present a novel preprocessing technique to automatically reduce the size of Boolean formulas. This technique, called Bounded Variable Addition (BVA), exchanges clauses for variables. Similar to other preprocessing techniques, BVA greedily lowers the sum of variables and clauses, a rough measure for the hardness to solve a formula. We show that cardinality constraints (CCs) can efficiently be reencoded: from a naive CC encoding, BVA automatically generates a compact encoding, which is smaller than sophisticated encodings. Experimental results show that applying BVA can improve SAT solving performance.", +isbn="978-3-642-39611-3" +} + +@InProceedings{BVE, +author="E{\'e}n, Niklas +and Biere, Armin", +editor="Bacchus, Fahiem +and Walsh, Toby", +title="Effective Preprocessing in {SAT} Through Variable and Clause Elimination", +booktitle="Theory and Applications of Satisfiability Testing", +year="2005", +publisher="Springer Berlin Heidelberg", +address="Berlin, Heidelberg", +pages="61--75", +abstract="Preprocessing SAT instances can reduce their size considerably. We combine variable elimination with subsumption and self-subsuming resolution, and show that these techniques not only shrink the formula further than previous preprocessing efforts based on variable elimination, but also decrease runtime of SAT solvers substantially for typical industrial SAT problems. We discuss critical implementation details that make the reduction procedure fast enough to be practical.", +isbn="978-3-540-31679-4" +} + +@INPROCEEDINGS{Selman95localsearch, + author = {Bart Selman and Henry Kautz and Bram Cohen}, + title = {Local Search Strategies for Satisfiability Testing}, + booktitle = {{DIMACS} Series in Discrete Mathematics and Theoretical Computer Science}, + year = {1995}, + pages = {521--532}, + publisher = {} +} + + + + +@inproceedings{DBLP:conf/aaai/KautzS96, + author = {Henry A. Kautz and + Bart Selman}, + title = {Pushing the Envelope: Planning, Propositional Logic and Stochastic + Search}, + booktitle = {Proceedings of the Thirteenth National Conference on Artificial Intelligence + and Eighth Innovative Applications of Artificial Intelligence Conference, + {AAAI} 96, {IAAI} 96, Portland, Oregon, USA, August 4-8, 1996, Volume + 2.}, + pages = {1194--1201}, + year = {1996}, + crossref = {DBLP:conf/aaai/1996-2}, + url = {http://www.aaai.org/Library/AAAI/1996/aaai96-177.php}, + timestamp = {Tue, 19 Jun 2018 18:21:36 +0200}, + biburl = {https://dblp.org/rec/bib/conf/aaai/KautzS96}, + bibsource = {dblp computer science bibliography, https://dblp.org} +} + +@proceedings{DBLP:conf/aaai/1996-2, + editor = {William J. Clancey and + Daniel S. Weld}, + title = {Proceedings of the Thirteenth National Conference on Artificial Intelligence + and Eighth Innovative Applications of Artificial Intelligence Conference, + {AAAI} 96, {IAAI} 96, Portland, Oregon, USA, August 4-8, 1996, Volume + 2}, + publisher = {{AAAI} Press / The {MIT} Press}, + year = {1996}, + url = {http://www.aaai.org/Conferences/AAAI/aaai96.php}, + timestamp = {Tue, 19 Jun 2018 18:21:36 +0200}, + biburl = {https://dblp.org/rec/bib/conf/aaai/1996-2}, + bibsource = {dblp computer science bibliography, https://dblp.org} +} + + + +@inproceedings{DBLP:conf/aaai/Hoos02, + author = {Holger H. Hoos}, + title = {An Adaptive Noise Mechanism for {WalkSAT}}, + booktitle = {Proceedings of the Eighteenth National Conference on Artificial Intelligence + and Fourteenth Conference on Innovative Applications of Artificial + Intelligence, July 28 - August 1, 2002, Edmonton, Alberta, Canada.}, + pages = {655--660}, + year = {2002}, + crossref = {DBLP:conf/aaai/2002}, + url = {http://www.aaai.org/Library/AAAI/2002/aaai02-098.php}, + timestamp = {Mon, 26 Feb 2018 07:08:45 +0100}, + biburl = {https://dblp.org/rec/bib/conf/aaai/Hoos02}, + bibsource = {dblp computer science bibliography, https://dblp.org} +} + +@proceedings{DBLP:conf/aaai/2002, + editor = {Rina Dechter and + Michael J. Kearns and + Richard S. Sutton}, + title = {Proceedings of the Eighteenth National Conference on Artificial Intelligence + and Fourteenth Conference on Innovative Applications of Artificial + Intelligence, July 28 - August 1, 2002, Edmonton, Alberta, Canada}, + publisher = {{AAAI} Press / The {MIT} Press}, + year = {2002}, + url = {http://www.aaai.org/Conferences/AAAI/aaai02.php}, + timestamp = {Mon, 26 Feb 2018 07:08:45 +0100}, + biburl = {https://dblp.org/rec/bib/conf/aaai/2002}, + bibsource = {dblp computer science bibliography, https://dblp.org} +} + diff --git a/cryptominisat/cppsrc/docs/satrace19-pdf/walksat/splncs03.bst b/cryptominisat/cppsrc/docs/satrace19-pdf/walksat/splncs03.bst new file mode 100644 index 00000000..32791691 --- /dev/null +++ b/cryptominisat/cppsrc/docs/satrace19-pdf/walksat/splncs03.bst @@ -0,0 +1,1519 @@ +%% BibTeX bibliography style `splncs03' +%% +%% BibTeX bibliography style for use with numbered references in +%% Springer Verlag's "Lecture Notes in Computer Science" series. +%% (See Springer's documentation for llncs.cls for +%% more details of the suggested reference format.) Note that this +%% file will not work for author-year style citations. +%% +%% Use \documentclass{llncs} and \bibliographystyle{splncs03}, and cite +%% a reference with (e.g.) \cite{smith77} to get a "[1]" in the text. +%% +%% This file comes to you courtesy of Maurizio "Titto" Patrignani of +%% Dipartimento di Informatica e Automazione Universita' Roma Tre +%% +%% ================================================================================================ +%% This was file `titto-lncs-02.bst' produced on Wed Apr 1, 2009 +%% Edited by hand by titto based on `titto-lncs-01.bst' (see below) +%% +%% CHANGES (with respect to titto-lncs-01.bst): +%% - Removed the call to \urlprefix (thus no "URL" string is added to the output) +%% ================================================================================================ +%% This was file `titto-lncs-01.bst' produced on Fri Aug 22, 2008 +%% Edited by hand by titto based on `titto.bst' (see below) +%% +%% CHANGES (with respect to titto.bst): +%% - Removed the "capitalize" command for editors string "(eds.)" and "(ed.)" +%% - Introduced the functions titto.bbl.pages and titto.bbl.page for journal pages (without "pp.") +%% - Added a new.sentence command to separate with a dot booktitle and series in the inproceedings +%% - Commented all new.block commands before urls and notes (to separate them with a comma) +%% - Introduced the functions titto.bbl.volume for handling journal volumes (without "vol." label) +%% - Used for editors the same name conventions used for authors (see function format.in.ed.booktitle) +%% - Removed a \newblock to avoid long spaces between title and "In: ..." +%% - Added function titto.space.prefix to add a space instead of "~" after the (removed) "vol." label +%% ================================================================================================ +%% This was file `titto.bst', +%% generated with the docstrip utility. +%% +%% The original source files were: +%% +%% merlin.mbs (with options: `vonx,nm-rvvc,yr-par,jttl-rm,volp-com,jwdpg,jwdvol,numser,ser-vol,jnm-x,btit-rm,bt-rm,edparxc,bkedcap,au-col,in-col,fin-bare,pp,ed,abr,mth-bare,xedn,jabr,and-com,and-com-ed,xand,url,url-blk,em-x,nfss,') +%% ---------------------------------------- +%% *** Tentative .bst file for Springer LNCS *** +%% +%% Copyright 1994-2007 Patrick W Daly + % =============================================================== + % IMPORTANT NOTICE: + % This bibliographic style (bst) file has been generated from one or + % more master bibliographic style (mbs) files, listed above. + % + % This generated file can be redistributed and/or modified under the terms + % of the LaTeX Project Public License Distributed from CTAN + % archives in directory macros/latex/base/lppl.txt; either + % version 1 of the License, or any later version. + % =============================================================== + % Name and version information of the main mbs file: + % \ProvidesFile{merlin.mbs}[2007/04/24 4.20 (PWD, AO, DPC)] + % For use with BibTeX version 0.99a or later + %------------------------------------------------------------------- + % This bibliography style file is intended for texts in ENGLISH + % This is a numerical citation style, and as such is standard LaTeX. + % It requires no extra package to interface to the main text. + % The form of the \bibitem entries is + % \bibitem{key}... + % Usage of \cite is as follows: + % \cite{key} ==>> [#] + % \cite[chap. 2]{key} ==>> [#, chap. 2] + % where # is a number determined by the ordering in the reference list. + % The order in the reference list is alphabetical by authors. + %--------------------------------------------------------------------- + +ENTRY + { address + author + booktitle + chapter + edition + editor + eid + howpublished + institution + journal + key + month + note + number + organization + pages + publisher + school + series + title + type + url + volume + year + } + {} + { label } +INTEGERS { output.state before.all mid.sentence after.sentence after.block } +FUNCTION {init.state.consts} +{ #0 'before.all := + #1 'mid.sentence := + #2 'after.sentence := + #3 'after.block := +} +STRINGS { s t} +FUNCTION {output.nonnull} +{ 's := + output.state mid.sentence = + { ", " * write$ } + { output.state after.block = + { add.period$ write$ +% newline$ +% "\newblock " write$ % removed for titto-lncs-01 + " " write$ % to avoid long spaces between title and "In: ..." + } + { output.state before.all = + 'write$ + { add.period$ " " * write$ } + if$ + } + if$ + mid.sentence 'output.state := + } + if$ + s +} +FUNCTION {output} +{ duplicate$ empty$ + 'pop$ + 'output.nonnull + if$ +} +FUNCTION {output.check} +{ 't := + duplicate$ empty$ + { pop$ "empty " t * " in " * cite$ * warning$ } + 'output.nonnull + if$ +} +FUNCTION {fin.entry} +{ duplicate$ empty$ + 'pop$ + 'write$ + if$ + newline$ +} + +FUNCTION {new.block} +{ output.state before.all = + 'skip$ + { after.block 'output.state := } + if$ +} +FUNCTION {new.sentence} +{ output.state after.block = + 'skip$ + { output.state before.all = + 'skip$ + { after.sentence 'output.state := } + if$ + } + if$ +} +FUNCTION {add.blank} +{ " " * before.all 'output.state := +} + + +FUNCTION {add.colon} +{ duplicate$ empty$ + 'skip$ + { ":" * add.blank } + if$ +} + +FUNCTION {date.block} +{ + new.block +} + +FUNCTION {not} +{ { #0 } + { #1 } + if$ +} +FUNCTION {and} +{ 'skip$ + { pop$ #0 } + if$ +} +FUNCTION {or} +{ { pop$ #1 } + 'skip$ + if$ +} +STRINGS {z} +FUNCTION {remove.dots} +{ 'z := + "" + { z empty$ not } + { z #1 #1 substring$ + z #2 global.max$ substring$ 'z := + duplicate$ "." = 'pop$ + { * } + if$ + } + while$ +} +FUNCTION {new.block.checka} +{ empty$ + 'skip$ + 'new.block + if$ +} +FUNCTION {new.block.checkb} +{ empty$ + swap$ empty$ + and + 'skip$ + 'new.block + if$ +} +FUNCTION {new.sentence.checka} +{ empty$ + 'skip$ + 'new.sentence + if$ +} +FUNCTION {new.sentence.checkb} +{ empty$ + swap$ empty$ + and + 'skip$ + 'new.sentence + if$ +} +FUNCTION {field.or.null} +{ duplicate$ empty$ + { pop$ "" } + 'skip$ + if$ +} +FUNCTION {emphasize} +{ skip$ } +FUNCTION {tie.or.space.prefix} +{ duplicate$ text.length$ #3 < + { "~" } + { " " } + if$ + swap$ +} +FUNCTION {titto.space.prefix} % always introduce a space +{ duplicate$ text.length$ #3 < + { " " } + { " " } + if$ + swap$ +} + + +FUNCTION {capitalize} +{ "u" change.case$ "t" change.case$ } + +FUNCTION {space.word} +{ " " swap$ * " " * } + % Here are the language-specific definitions for explicit words. + % Each function has a name bbl.xxx where xxx is the English word. + % The language selected here is ENGLISH +FUNCTION {bbl.and} +{ "and"} + +FUNCTION {bbl.etal} +{ "et~al." } + +FUNCTION {bbl.editors} +{ "eds." } + +FUNCTION {bbl.editor} +{ "ed." } + +FUNCTION {bbl.edby} +{ "edited by" } + +FUNCTION {bbl.edition} +{ "edn." } + +FUNCTION {bbl.volume} +{ "vol." } + +FUNCTION {titto.bbl.volume} % for handling journals +{ "" } + +FUNCTION {bbl.of} +{ "of" } + +FUNCTION {bbl.number} +{ "no." } + +FUNCTION {bbl.nr} +{ "no." } + +FUNCTION {bbl.in} +{ "in" } + +FUNCTION {bbl.pages} +{ "pp." } + +FUNCTION {bbl.page} +{ "p." } + +FUNCTION {titto.bbl.pages} % for journals +{ "" } + +FUNCTION {titto.bbl.page} % for journals +{ "" } + +FUNCTION {bbl.chapter} +{ "chap." } + +FUNCTION {bbl.techrep} +{ "Tech. Rep." } + +FUNCTION {bbl.mthesis} +{ "Master's thesis" } + +FUNCTION {bbl.phdthesis} +{ "Ph.D. thesis" } + +MACRO {jan} {"Jan."} + +MACRO {feb} {"Feb."} + +MACRO {mar} {"Mar."} + +MACRO {apr} {"Apr."} + +MACRO {may} {"May"} + +MACRO {jun} {"Jun."} + +MACRO {jul} {"Jul."} + +MACRO {aug} {"Aug."} + +MACRO {sep} {"Sep."} + +MACRO {oct} {"Oct."} + +MACRO {nov} {"Nov."} + +MACRO {dec} {"Dec."} + +MACRO {acmcs} {"ACM Comput. Surv."} + +MACRO {acta} {"Acta Inf."} + +MACRO {cacm} {"Commun. ACM"} + +MACRO {ibmjrd} {"IBM J. Res. Dev."} + +MACRO {ibmsj} {"IBM Syst.~J."} + +MACRO {ieeese} {"IEEE Trans. Software Eng."} + +MACRO {ieeetc} {"IEEE Trans. Comput."} + +MACRO {ieeetcad} + {"IEEE Trans. Comput. Aid. Des."} + +MACRO {ipl} {"Inf. Process. Lett."} + +MACRO {jacm} {"J.~ACM"} + +MACRO {jcss} {"J.~Comput. Syst. Sci."} + +MACRO {scp} {"Sci. Comput. Program."} + +MACRO {sicomp} {"SIAM J. Comput."} + +MACRO {tocs} {"ACM Trans. Comput. Syst."} + +MACRO {tods} {"ACM Trans. Database Syst."} + +MACRO {tog} {"ACM Trans. Graphic."} + +MACRO {toms} {"ACM Trans. Math. Software"} + +MACRO {toois} {"ACM Trans. Office Inf. Syst."} + +MACRO {toplas} {"ACM Trans. Progr. Lang. Syst."} + +MACRO {tcs} {"Theor. Comput. Sci."} + +FUNCTION {bibinfo.check} +{ swap$ + duplicate$ missing$ + { + pop$ pop$ + "" + } + { duplicate$ empty$ + { + swap$ pop$ + } + { swap$ + pop$ + } + if$ + } + if$ +} +FUNCTION {bibinfo.warn} +{ swap$ + duplicate$ missing$ + { + swap$ "missing " swap$ * " in " * cite$ * warning$ pop$ + "" + } + { duplicate$ empty$ + { + swap$ "empty " swap$ * " in " * cite$ * warning$ + } + { swap$ + pop$ + } + if$ + } + if$ +} +FUNCTION {format.url} +{ url empty$ + { "" } +% { "\urlprefix\url{" url * "}" * } + { "\url{" url * "}" * } % changed in titto-lncs-02.bst + if$ +} + +INTEGERS { nameptr namesleft numnames } + + +STRINGS { bibinfo} + +FUNCTION {format.names} +{ 'bibinfo := + duplicate$ empty$ 'skip$ { + 's := + "" 't := + #1 'nameptr := + s num.names$ 'numnames := + numnames 'namesleft := + { namesleft #0 > } + { s nameptr + "{vv~}{ll}{, jj}{, f{.}.}" + format.name$ + bibinfo bibinfo.check + 't := + nameptr #1 > + { + namesleft #1 > + { ", " * t * } + { + s nameptr "{ll}" format.name$ duplicate$ "others" = + { 't := } + { pop$ } + if$ + "," * + t "others" = + { + " " * bbl.etal * + } + { " " * t * } + if$ + } + if$ + } + 't + if$ + nameptr #1 + 'nameptr := + namesleft #1 - 'namesleft := + } + while$ + } if$ +} +FUNCTION {format.names.ed} +{ + 'bibinfo := + duplicate$ empty$ 'skip$ { + 's := + "" 't := + #1 'nameptr := + s num.names$ 'numnames := + numnames 'namesleft := + { namesleft #0 > } + { s nameptr + "{f{.}.~}{vv~}{ll}{ jj}" + format.name$ + bibinfo bibinfo.check + 't := + nameptr #1 > + { + namesleft #1 > + { ", " * t * } + { + s nameptr "{ll}" format.name$ duplicate$ "others" = + { 't := } + { pop$ } + if$ + "," * + t "others" = + { + + " " * bbl.etal * + } + { " " * t * } + if$ + } + if$ + } + 't + if$ + nameptr #1 + 'nameptr := + namesleft #1 - 'namesleft := + } + while$ + } if$ +} +FUNCTION {format.authors} +{ author "author" format.names +} +FUNCTION {get.bbl.editor} +{ editor num.names$ #1 > 'bbl.editors 'bbl.editor if$ } + +FUNCTION {format.editors} +{ editor "editor" format.names duplicate$ empty$ 'skip$ + { + " " * + get.bbl.editor +% capitalize + "(" swap$ * ")" * + * + } + if$ +} +FUNCTION {format.note} +{ + note empty$ + { "" } + { note #1 #1 substring$ + duplicate$ "{" = + 'skip$ + { output.state mid.sentence = + { "l" } + { "u" } + if$ + change.case$ + } + if$ + note #2 global.max$ substring$ * "note" bibinfo.check + } + if$ +} + +FUNCTION {format.title} +{ title + duplicate$ empty$ 'skip$ + { "t" change.case$ } + if$ + "title" bibinfo.check +} +FUNCTION {output.bibitem} +{ newline$ + "\bibitem{" write$ + cite$ write$ + "}" write$ + newline$ + "" + before.all 'output.state := +} + +FUNCTION {n.dashify} +{ + 't := + "" + { t empty$ not } + { t #1 #1 substring$ "-" = + { t #1 #2 substring$ "--" = not + { "--" * + t #2 global.max$ substring$ 't := + } + { { t #1 #1 substring$ "-" = } + { "-" * + t #2 global.max$ substring$ 't := + } + while$ + } + if$ + } + { t #1 #1 substring$ * + t #2 global.max$ substring$ 't := + } + if$ + } + while$ +} + +FUNCTION {word.in} +{ bbl.in capitalize + ":" * + " " * } + +FUNCTION {format.date} +{ + month "month" bibinfo.check + duplicate$ empty$ + year "year" bibinfo.check duplicate$ empty$ + { swap$ 'skip$ + { "there's a month but no year in " cite$ * warning$ } + if$ + * + } + { swap$ 'skip$ + { + swap$ + " " * swap$ + } + if$ + * + remove.dots + } + if$ + duplicate$ empty$ + 'skip$ + { + before.all 'output.state := + " (" swap$ * ")" * + } + if$ +} +FUNCTION {format.btitle} +{ title "title" bibinfo.check + duplicate$ empty$ 'skip$ + { + } + if$ +} +FUNCTION {either.or.check} +{ empty$ + 'pop$ + { "can't use both " swap$ * " fields in " * cite$ * warning$ } + if$ +} +FUNCTION {format.bvolume} +{ volume empty$ + { "" } + { bbl.volume volume tie.or.space.prefix + "volume" bibinfo.check * * + series "series" bibinfo.check + duplicate$ empty$ 'pop$ + { emphasize ", " * swap$ * } + if$ + "volume and number" number either.or.check + } + if$ +} +FUNCTION {format.number.series} +{ volume empty$ + { number empty$ + { series field.or.null } + { output.state mid.sentence = + { bbl.number } + { bbl.number capitalize } + if$ + number tie.or.space.prefix "number" bibinfo.check * * + series empty$ + { "there's a number but no series in " cite$ * warning$ } + { bbl.in space.word * + series "series" bibinfo.check * + } + if$ + } + if$ + } + { "" } + if$ +} + +FUNCTION {format.edition} +{ edition duplicate$ empty$ 'skip$ + { + output.state mid.sentence = + { "l" } + { "t" } + if$ change.case$ + "edition" bibinfo.check + " " * bbl.edition * + } + if$ +} +INTEGERS { multiresult } +FUNCTION {multi.page.check} +{ 't := + #0 'multiresult := + { multiresult not + t empty$ not + and + } + { t #1 #1 substring$ + duplicate$ "-" = + swap$ duplicate$ "," = + swap$ "+" = + or or + { #1 'multiresult := } + { t #2 global.max$ substring$ 't := } + if$ + } + while$ + multiresult +} +FUNCTION {format.pages} +{ pages duplicate$ empty$ 'skip$ + { duplicate$ multi.page.check + { + bbl.pages swap$ + n.dashify + } + { + bbl.page swap$ + } + if$ + tie.or.space.prefix + "pages" bibinfo.check + * * + } + if$ +} +FUNCTION {format.journal.pages} +{ pages duplicate$ empty$ 'pop$ + { swap$ duplicate$ empty$ + { pop$ pop$ format.pages } + { + ", " * + swap$ + n.dashify + pages multi.page.check + 'titto.bbl.pages + 'titto.bbl.page + if$ + swap$ tie.or.space.prefix + "pages" bibinfo.check + * * + * + } + if$ + } + if$ +} +FUNCTION {format.journal.eid} +{ eid "eid" bibinfo.check + duplicate$ empty$ 'pop$ + { swap$ duplicate$ empty$ 'skip$ + { + ", " * + } + if$ + swap$ * + } + if$ +} +FUNCTION {format.vol.num.pages} % this function is used only for journal entries +{ volume field.or.null + duplicate$ empty$ 'skip$ + { +% bbl.volume swap$ tie.or.space.prefix + titto.bbl.volume swap$ titto.space.prefix +% rationale for the change above: for journals you don't want "vol." label +% hence it does not make sense to attach the journal number to the label when +% it is short + "volume" bibinfo.check + * * + } + if$ + number "number" bibinfo.check duplicate$ empty$ 'skip$ + { + swap$ duplicate$ empty$ + { "there's a number but no volume in " cite$ * warning$ } + 'skip$ + if$ + swap$ + "(" swap$ * ")" * + } + if$ * + eid empty$ + { format.journal.pages } + { format.journal.eid } + if$ +} + +FUNCTION {format.chapter.pages} +{ chapter empty$ + 'format.pages + { type empty$ + { bbl.chapter } + { type "l" change.case$ + "type" bibinfo.check + } + if$ + chapter tie.or.space.prefix + "chapter" bibinfo.check + * * + pages empty$ + 'skip$ + { ", " * format.pages * } + if$ + } + if$ +} + +FUNCTION {format.booktitle} +{ + booktitle "booktitle" bibinfo.check +} +FUNCTION {format.in.ed.booktitle} +{ format.booktitle duplicate$ empty$ 'skip$ + { +% editor "editor" format.names.ed duplicate$ empty$ 'pop$ % changed by titto + editor "editor" format.names duplicate$ empty$ 'pop$ + { + " " * + get.bbl.editor +% capitalize + "(" swap$ * ") " * + * swap$ + * } + if$ + word.in swap$ * + } + if$ +} +FUNCTION {empty.misc.check} +{ author empty$ title empty$ howpublished empty$ + month empty$ year empty$ note empty$ + and and and and and + key empty$ not and + { "all relevant fields are empty in " cite$ * warning$ } + 'skip$ + if$ +} +FUNCTION {format.thesis.type} +{ type duplicate$ empty$ + 'pop$ + { swap$ pop$ + "t" change.case$ "type" bibinfo.check + } + if$ +} +FUNCTION {format.tr.number} +{ number "number" bibinfo.check + type duplicate$ empty$ + { pop$ bbl.techrep } + 'skip$ + if$ + "type" bibinfo.check + swap$ duplicate$ empty$ + { pop$ "t" change.case$ } + { tie.or.space.prefix * * } + if$ +} +FUNCTION {format.article.crossref} +{ + key duplicate$ empty$ + { pop$ + journal duplicate$ empty$ + { "need key or journal for " cite$ * " to crossref " * crossref * warning$ } + { "journal" bibinfo.check emphasize word.in swap$ * } + if$ + } + { word.in swap$ * " " *} + if$ + " \cite{" * crossref * "}" * +} +FUNCTION {format.crossref.editor} +{ editor #1 "{vv~}{ll}" format.name$ + "editor" bibinfo.check + editor num.names$ duplicate$ + #2 > + { pop$ + "editor" bibinfo.check + " " * bbl.etal + * + } + { #2 < + 'skip$ + { editor #2 "{ff }{vv }{ll}{ jj}" format.name$ "others" = + { + "editor" bibinfo.check + " " * bbl.etal + * + } + { + bbl.and space.word + * editor #2 "{vv~}{ll}" format.name$ + "editor" bibinfo.check + * + } + if$ + } + if$ + } + if$ +} +FUNCTION {format.book.crossref} +{ volume duplicate$ empty$ + { "empty volume in " cite$ * "'s crossref of " * crossref * warning$ + pop$ word.in + } + { bbl.volume + capitalize + swap$ tie.or.space.prefix "volume" bibinfo.check * * bbl.of space.word * + } + if$ + editor empty$ + editor field.or.null author field.or.null = + or + { key empty$ + { series empty$ + { "need editor, key, or series for " cite$ * " to crossref " * + crossref * warning$ + "" * + } + { series emphasize * } + if$ + } + { key * } + if$ + } + { format.crossref.editor * } + if$ + " \cite{" * crossref * "}" * +} +FUNCTION {format.incoll.inproc.crossref} +{ + editor empty$ + editor field.or.null author field.or.null = + or + { key empty$ + { format.booktitle duplicate$ empty$ + { "need editor, key, or booktitle for " cite$ * " to crossref " * + crossref * warning$ + } + { word.in swap$ * } + if$ + } + { word.in key * " " *} + if$ + } + { word.in format.crossref.editor * " " *} + if$ + " \cite{" * crossref * "}" * +} +FUNCTION {format.org.or.pub} +{ 't := + "" + address empty$ t empty$ and + 'skip$ + { + t empty$ + { address "address" bibinfo.check * + } + { t * + address empty$ + 'skip$ + { ", " * address "address" bibinfo.check * } + if$ + } + if$ + } + if$ +} +FUNCTION {format.publisher.address} +{ publisher "publisher" bibinfo.warn format.org.or.pub +} + +FUNCTION {format.organization.address} +{ organization "organization" bibinfo.check format.org.or.pub +} + +FUNCTION {article} +{ output.bibitem + format.authors "author" output.check + add.colon + new.block + format.title "title" output.check + new.block + crossref missing$ + { + journal + "journal" bibinfo.check + "journal" output.check + add.blank + format.vol.num.pages output + format.date "year" output.check + } + { format.article.crossref output.nonnull + format.pages output + } + if$ +% new.block + format.url output +% new.block + format.note output + fin.entry +} +FUNCTION {book} +{ output.bibitem + author empty$ + { format.editors "author and editor" output.check + add.colon + } + { format.authors output.nonnull + add.colon + crossref missing$ + { "author and editor" editor either.or.check } + 'skip$ + if$ + } + if$ + new.block + format.btitle "title" output.check + crossref missing$ + { format.bvolume output + new.block + new.sentence + format.number.series output + format.publisher.address output + } + { + new.block + format.book.crossref output.nonnull + } + if$ + format.edition output + format.date "year" output.check +% new.block + format.url output +% new.block + format.note output + fin.entry +} +FUNCTION {booklet} +{ output.bibitem + format.authors output + add.colon + new.block + format.title "title" output.check + new.block + howpublished "howpublished" bibinfo.check output + address "address" bibinfo.check output + format.date output +% new.block + format.url output +% new.block + format.note output + fin.entry +} + +FUNCTION {inbook} +{ output.bibitem + author empty$ + { format.editors "author and editor" output.check + add.colon + } + { format.authors output.nonnull + add.colon + crossref missing$ + { "author and editor" editor either.or.check } + 'skip$ + if$ + } + if$ + new.block + format.btitle "title" output.check + crossref missing$ + { + format.bvolume output + format.chapter.pages "chapter and pages" output.check + new.block + new.sentence + format.number.series output + format.publisher.address output + } + { + format.chapter.pages "chapter and pages" output.check + new.block + format.book.crossref output.nonnull + } + if$ + format.edition output + format.date "year" output.check +% new.block + format.url output +% new.block + format.note output + fin.entry +} + +FUNCTION {incollection} +{ output.bibitem + format.authors "author" output.check + add.colon + new.block + format.title "title" output.check + new.block + crossref missing$ + { format.in.ed.booktitle "booktitle" output.check + format.bvolume output + format.chapter.pages output + new.sentence + format.number.series output + format.publisher.address output + format.edition output + format.date "year" output.check + } + { format.incoll.inproc.crossref output.nonnull + format.chapter.pages output + } + if$ +% new.block + format.url output +% new.block + format.note output + fin.entry +} +FUNCTION {inproceedings} +{ output.bibitem + format.authors "author" output.check + add.colon + new.block + format.title "title" output.check + new.block + crossref missing$ + { format.in.ed.booktitle "booktitle" output.check + new.sentence % added by titto + format.bvolume output + format.pages output + new.sentence + format.number.series output + publisher empty$ + { format.organization.address output } + { organization "organization" bibinfo.check output + format.publisher.address output + } + if$ + format.date "year" output.check + } + { format.incoll.inproc.crossref output.nonnull + format.pages output + } + if$ +% new.block + format.url output +% new.block + format.note output + fin.entry +} +FUNCTION {conference} { inproceedings } +FUNCTION {manual} +{ output.bibitem + author empty$ + { organization "organization" bibinfo.check + duplicate$ empty$ 'pop$ + { output + address "address" bibinfo.check output + } + if$ + } + { format.authors output.nonnull } + if$ + add.colon + new.block + format.btitle "title" output.check + author empty$ + { organization empty$ + { + address new.block.checka + address "address" bibinfo.check output + } + 'skip$ + if$ + } + { + organization address new.block.checkb + organization "organization" bibinfo.check output + address "address" bibinfo.check output + } + if$ + format.edition output + format.date output +% new.block + format.url output +% new.block + format.note output + fin.entry +} + +FUNCTION {mastersthesis} +{ output.bibitem + format.authors "author" output.check + add.colon + new.block + format.btitle + "title" output.check + new.block + bbl.mthesis format.thesis.type output.nonnull + school "school" bibinfo.warn output + address "address" bibinfo.check output + format.date "year" output.check +% new.block + format.url output +% new.block + format.note output + fin.entry +} + +FUNCTION {misc} +{ output.bibitem + format.authors output + add.colon + title howpublished new.block.checkb + format.title output + howpublished new.block.checka + howpublished "howpublished" bibinfo.check output + format.date output +% new.block + format.url output +% new.block + format.note output + fin.entry + empty.misc.check +} +FUNCTION {phdthesis} +{ output.bibitem + format.authors "author" output.check + add.colon + new.block + format.btitle + "title" output.check + new.block + bbl.phdthesis format.thesis.type output.nonnull + school "school" bibinfo.warn output + address "address" bibinfo.check output + format.date "year" output.check +% new.block + format.url output +% new.block + format.note output + fin.entry +} + +FUNCTION {proceedings} +{ output.bibitem + editor empty$ + { organization "organization" bibinfo.check output + } + { format.editors output.nonnull } + if$ + add.colon + new.block + format.btitle "title" output.check + format.bvolume output + editor empty$ + { publisher empty$ + { format.number.series output } + { + new.sentence + format.number.series output + format.publisher.address output + } + if$ + } + { publisher empty$ + { + new.sentence + format.number.series output + format.organization.address output } + { + new.sentence + format.number.series output + organization "organization" bibinfo.check output + format.publisher.address output + } + if$ + } + if$ + format.date "year" output.check +% new.block + format.url output +% new.block + format.note output + fin.entry +} + +FUNCTION {techreport} +{ output.bibitem + format.authors "author" output.check + add.colon + new.block + format.title + "title" output.check + new.block + format.tr.number output.nonnull + institution "institution" bibinfo.warn output + address "address" bibinfo.check output + format.date "year" output.check +% new.block + format.url output +% new.block + format.note output + fin.entry +} + +FUNCTION {unpublished} +{ output.bibitem + format.authors "author" output.check + add.colon + new.block + format.title "title" output.check + format.date output +% new.block + format.url output +% new.block + format.note "note" output.check + fin.entry +} + +FUNCTION {default.type} { misc } +READ +FUNCTION {sortify} +{ purify$ + "l" change.case$ +} +INTEGERS { len } +FUNCTION {chop.word} +{ 's := + 'len := + s #1 len substring$ = + { s len #1 + global.max$ substring$ } + 's + if$ +} +FUNCTION {sort.format.names} +{ 's := + #1 'nameptr := + "" + s num.names$ 'numnames := + numnames 'namesleft := + { namesleft #0 > } + { s nameptr + "{ll{ }}{ ff{ }}{ jj{ }}" + format.name$ 't := + nameptr #1 > + { + " " * + namesleft #1 = t "others" = and + { "zzzzz" * } + { t sortify * } + if$ + } + { t sortify * } + if$ + nameptr #1 + 'nameptr := + namesleft #1 - 'namesleft := + } + while$ +} + +FUNCTION {sort.format.title} +{ 't := + "A " #2 + "An " #3 + "The " #4 t chop.word + chop.word + chop.word + sortify + #1 global.max$ substring$ +} +FUNCTION {author.sort} +{ author empty$ + { key empty$ + { "to sort, need author or key in " cite$ * warning$ + "" + } + { key sortify } + if$ + } + { author sort.format.names } + if$ +} +FUNCTION {author.editor.sort} +{ author empty$ + { editor empty$ + { key empty$ + { "to sort, need author, editor, or key in " cite$ * warning$ + "" + } + { key sortify } + if$ + } + { editor sort.format.names } + if$ + } + { author sort.format.names } + if$ +} +FUNCTION {author.organization.sort} +{ author empty$ + { organization empty$ + { key empty$ + { "to sort, need author, organization, or key in " cite$ * warning$ + "" + } + { key sortify } + if$ + } + { "The " #4 organization chop.word sortify } + if$ + } + { author sort.format.names } + if$ +} +FUNCTION {editor.organization.sort} +{ editor empty$ + { organization empty$ + { key empty$ + { "to sort, need editor, organization, or key in " cite$ * warning$ + "" + } + { key sortify } + if$ + } + { "The " #4 organization chop.word sortify } + if$ + } + { editor sort.format.names } + if$ +} +FUNCTION {presort} +{ type$ "book" = + type$ "inbook" = + or + 'author.editor.sort + { type$ "proceedings" = + 'editor.organization.sort + { type$ "manual" = + 'author.organization.sort + 'author.sort + if$ + } + if$ + } + if$ + " " + * + year field.or.null sortify + * + " " + * + title field.or.null + sort.format.title + * + #1 entry.max$ substring$ + 'sort.key$ := +} +ITERATE {presort} +SORT +STRINGS { longest.label } +INTEGERS { number.label longest.label.width } +FUNCTION {initialize.longest.label} +{ "" 'longest.label := + #1 'number.label := + #0 'longest.label.width := +} +FUNCTION {longest.label.pass} +{ number.label int.to.str$ 'label := + number.label #1 + 'number.label := + label width$ longest.label.width > + { label 'longest.label := + label width$ 'longest.label.width := + } + 'skip$ + if$ +} +EXECUTE {initialize.longest.label} +ITERATE {longest.label.pass} +FUNCTION {begin.bib} +{ preamble$ empty$ + 'skip$ + { preamble$ write$ newline$ } + if$ + "\begin{thebibliography}{" longest.label * "}" * + write$ newline$ + "\providecommand{\url}[1]{\texttt{#1}}" + write$ newline$ + "\providecommand{\urlprefix}{URL }" + write$ newline$ +} +EXECUTE {begin.bib} +EXECUTE {init.state.consts} +ITERATE {call.type$} +FUNCTION {end.bib} +{ newline$ + "\end{thebibliography}" write$ newline$ +} +EXECUTE {end.bib} +%% End of customized bst file +%% +%% End of file `titto.bst'. + + diff --git a/cryptominisat/cppsrc/docs/satrace19-pdf/yalsat/Makefile b/cryptominisat/cppsrc/docs/satrace19-pdf/yalsat/Makefile new file mode 100644 index 00000000..4f654285 --- /dev/null +++ b/cryptominisat/cppsrc/docs/satrace19-pdf/yalsat/Makefile @@ -0,0 +1,24 @@ +TEX = pdflatex -shell-escape -interaction=nonstopmode -file-line-error +PRE = $(TEX) -ini -job-name="preamble" "&pdflatex preamble.tex\dump" +BIB = bibtex + +all: cmsv56-yalsat.pdf + +view : + okular cmsv56-yalsat.pdf + +cmsv56-yalsat.pdf : clean cmsv56-yalsat.tex cmsv56-yalsat.bbl cmsv56-yalsat.blg + $(TEX) cmsv56-yalsat.tex + $(TEX) cmsv56-yalsat.tex + +cmsv56-yalsat.bbl cmsv5.blg : cmsv56-yalsat.bib cmsv56-yalsat.aux + $(BIB) cmsv56-yalsat + +cmsv56-yalsat.aux : cmsv56-yalsat.tex + $(TEX) cmsv56-yalsat.tex + +cmsv56-yalsat.bib : cmsv56-yalsat.tex + $(TEX) cmsv56-yalsat.tex + +clean: + rm -f *.log *.pdf *.blg *.bbl *.aux *.out *.backup diff --git a/cryptominisat/cppsrc/docs/satrace19-pdf/yalsat/cmsv56-yalsat.tex b/cryptominisat/cppsrc/docs/satrace19-pdf/yalsat/cmsv56-yalsat.tex new file mode 100644 index 00000000..efd33297 --- /dev/null +++ b/cryptominisat/cppsrc/docs/satrace19-pdf/yalsat/cmsv56-yalsat.tex @@ -0,0 +1,82 @@ +%\documentclass[runningheads]{llncs} +\documentclass[final]{ieee} + +\usepackage{microtype} %This gives MUCH better PDF results! +%\usepackage[active]{srcltx} %DVI search +\usepackage[cmex10]{amsmath} +\usepackage{amssymb} +\usepackage{fnbreak} %warn for split footnotes +\usepackage{url} +%\usepackage{qtree} %for drawing trees +%\usepackage{fancybox} % if we need rounded corners +%\usepackage{pict2e} % large circles can be drawn +%\usepackage{courier} %for using courier in texttt{} +%\usepackage{nth} %allows to \nth{4} to make 1st 2nd, etc. +%\usepackage{subfigure} %allows to have side-by-side figures +%\usepackage{booktabs} %nice tables +%\usepackage{multirow} %allow multiple cells with rows in tabular +\usepackage[utf8]{inputenc} % allows to write Faugere correctly +\usepackage[bookmarks=true, citecolor=black, linkcolor=black, colorlinks=true]{hyperref} +\hypersetup{ +pdfauthor = {Mate Soos, Armin Biere}, +pdftitle = {CryptoMiniSat v5.6 + yalsat}, +pdfsubject = {SAT Race 2019}, +pdfkeywords = {SAT Solver, DPLL, SLS}, +pdfcreator = {PdfLaTeX with hyperref package}, +pdfproducer = {PdfLaTex}} +%\usepackage{butterma} + +%\usepackage{pstricks} +\usepackage{graphicx,epsfig,xcolor} + +\begin{document} +\title{CryptoMiniSat 5.6 with YalSAT at the SAT Race 2019} +\author{Mate Soos (National University of Singapore), Armin Biere (JKU Linz)} + +\maketitle +\thispagestyle{empty} +\pagestyle{empty} + +\section{Introduction} +This paper presents the conflict-driven clause-learning (CLDL) SAT solver CryptoMiniSat v5.6 (\emph{CMS}) augmented with the Stochastic Local Search (SLS)~\cite{Selman95localsearch} solver YalSAT 03v as submitted to SAT Race 2019. + +CryptoMiniSat aims to be a modern, open source SAT solver using inprocessing techniques, optimized data structures and finely-tuned timeouts to have good control over both memory and time usage of inprocessing steps. It also supports, when compiled as such, to recover XOR constraints and perform Gauss-Jordan elimination on them at every decision level. For the competition, this option was disabled. CryptoMiniSat is authored by Mate Soos. + +Yet Another Local Search SAT Solver (YalSAT) implements several variants of ProbSAT's~\cite{probsat} algorithm and recent extensions~\cite{balint-improving-sls}. These variants are selected randomly at restarts, scheduled by a reluctant doubling scheme (Luby). For further details, see~\cite{sat-comp-2014-armin}. YalSAT is authored by Armin Biere. + +\subsection{Composing the Two Solvers} +The two solvers are composed together in a way that does \emph{not} resemble portfolio solvers. The system runs the CDCL solver CryptoMiniSat, along with its periodic inprocessing, by default. However, at every N inprocessing step, CryptoMiniSat's irredundant clauses are pushed into the SLS solver (in case the predicted memory use is not too high). The SLS solver is then allowed to run for a predefined number of steps. In case the SLS solver finds a solution, this is given back to the CDCL solver, which then performs all the necessary extension to the solution (e.g. for Bounded Variable Elimination, BVE~\cite{BVE}) and then outputs the solution. + +Note that the inclusion of the SLS solver is full in the sense that assumptions-based solving, library-based solver use, and all other uses of the SAT solver is fully supported with SLS solving enabled. Hence, this is not some form of portfolio where a simple shell script determines which solver to run and then runs that solver. Instead, the SLS solver is a full member of the CDCL solver, much like any other inprocessing system, and works in tandem with it. For example, in case an inprocessing step has reduced the number of variables through BVE or increased it through BVA~\cite{BVA}, the SLS solver will then try to solve the problem thus modified. In case the SLS solver finds a solution, the main solver will then correctly manipulate it to fit the needs of the ``outside world'', i.e. the caller. + +As the two solvers are well-coupled, the combination of the two solvers can solve problems that neither system can solve on its own. Hence, \emph{the system is more than just a union of its parts} which is not the case for traditional portfolio solvers. + +\section{Major Improvements} +\subsection{Via Negativa} +The system has been subjected to a thorough investigation whether all the different systems that have been implemented into it actually make the solver faster. In this spirit, failed literal probing~\cite{DBLP:conf/ictai/LynceS03}, stamping~\cite{stamping}, burst searching (random variable picking), and blocked clause elimination~\cite{TACAS-2010-JarvisaloBH} have all been disabled. + +\subsection{Chronological Backtracking} +Chronological backtracking~\cite{chronobt} has been implemented into a branch of the solver. However, chronological backtracking (CBT) is a double-edged sword. Firstly, it slows down the solver's normal functionality as it adds a number of expensive checks to both the propagation and the backtracking code. Secondly, it changes the trail of the solver in ways that make it hard to reason about the current state of the solver. Finally, it seems only to help with satisfiable instances which are theoretically less interesting for the author of CryptoMiniSat. These issues make CBT a difficult addition. + +Currently, CryptoMiniSat by default does not implement CBT. The SAT Race has two versions submitted, clearly marked, one with, an one without CBT. + +\subsection{Cluster Tuning} +The author has been generously given time on the ASPIRE-1 cluster of the National Supercomputing Center Singapore\cite{nscc}. This allowed experimentation and tuning that would have been impossible otherwise. Without this opportunity, CryptoMiniSat would not stand a chance at the SAT Race. + +\section{General Notes} +\subsection{On-the-fly Gaussian Elimination} +On-the-fly Gaussian elimination is again part of CryptoMiniSat. This is explicitly disabled for the competition, but the code is available and well-tested. This allows for special uses of the solver that other solvers, without on-the-fly Gaussian elimination, are not capable of. + +\subsection{Robustness} +CMS aims to be usable in both industry and academia. CMS has over 150 test cases and over 2000 lines of Python just for fuzzing orchestration, and runs without fault under both the ASAN and UBSAN sanitisers of clang. It also compiles and runs under Windows, Linux and MacOS X. This is in contrast many academic winning SAT solvers that produce results that are non-reproducible, cannot be compiled on anything but a few select systems, and/or produce segmentation faults if used as a library. CryptoMiniSat has extensive fuzzing setup for library usage and is very robust under strange/unexpected use cases. + +\section{Thanks} +This work was supported in part by NUS ODPRT Grant R-252-000-685-133 and AI Singapore Grant R-252- 000-A16-490. The computational work for this article was performed on resources of the National Supercomputing Center, Singapore\cite{nscc}. The author would also like to thank all the users of CryptoMiniSat who have submitted over 500 issues and many pull requests to the GitHub CMS repository\cite{CMS}. + +\bibliographystyle{splncs03} +\bibliography{sigproc} + +\vfill +\pagebreak + +\end{document} diff --git a/cryptominisat/cppsrc/docs/satrace19-pdf/yalsat/ieee.cls b/cryptominisat/cppsrc/docs/satrace19-pdf/yalsat/ieee.cls new file mode 100644 index 00000000..3c57bba5 --- /dev/null +++ b/cryptominisat/cppsrc/docs/satrace19-pdf/yalsat/ieee.cls @@ -0,0 +1,1497 @@ +% Copyright 2014 IEEEE +% for terms of use see https://www.ieee.org/publications_standards/publications/rights/copyrightpolicy.html + +% ========================================================================= +% ------------------------------------------------------------------------- +% XX X +% X +% XX XXX XXX XXX XXX X XXXX +% X X X X X X X X X X X +% X XXXXX XXXXX XXXXX X X XXX +% X X X X XX X X X X +% XXX XXX XXX XXX XX XXX X XXXX +% ------------------------------------------------------------------------- +% ========================================================================= +% ieee.cls --- For formatting IEEE conference & journal papers +% --- Compiled by Gregory Plett, Sept 1997 +% +% This class was inspired by one first compiled by Gerry Murray and +% Silvano Balemi for LaTeX209. It was later updated for use with +% LaTeX2e, and some bugs were fixed, all by Istvan Kollar. Lastly, +% I have tried to make the class easier to use by paper authors. +% Significant new functionality has been added. Many routines are +% "borrowed" from other people's packages and modified extensively. +% When I rembered where I got the routines from, I gave the author +% credit. +% +% After I made many changes on my own, I found a version by Peter +% N"uchter, and tried to retain some amount of compatibility with his +% version. To be completely compatible with him, you may need to +% manually: +% \usepackage{rawfonts}\usepackage{oldlfont} +% \AtBeginDocument{\parindent1.0em} (?) +% +%=========================================================================== +% +% Usage: +% \documentclass[main-mode,sub-mode,misc-options]{ieee} +% \usepackage{your own packages} +% \begin{document} +% \bibliographystyle{IEEEbib} +% \title[short]{regular} +% \author[short]{full} +% \maketitle +% \begin{abstract}...\end{abstract} +% \begin{keywords}...\end{keywords} +% \section{...} +% \PARstart ... or \PARstartCal ... +% ... +% \begin{biography}[picname.ps]{Author's name}...\end{biography} +% \end{document} +% +% The document class options are: +% +% main-mode: One of the following is required. (draft is the default) +% draft: Double-spaced, single column with date/time stamp. +% submission: Double-spaced, suitable for submission for review. +% compressed: Same as "submission", only single spaced. +% final: Double-column, for assessing page-length and +% format of final version. +% +% sub-mode: +% techreport: This can modify "final" to produce a two-col +% technical report. +% internal: This can modify "submission", "compressed" or "final". +% It changes the header to notify the reader that +% this is a version of the manuscript to be used for +% internal review processes only, and not to be +% distributed. +% submitted: This can modify "compressed" or "final". It changes +% the header to notify the reader that this +% is a preprint and not to be distributed. +% inpress: This can modify "compressed" or "final". It changes the +% header to notify the reader that this paper has +% been accepted for publishing, but it is not yet to be +% distributed. +% reprint: This can modify "final". It changes the header +% to notify the reader where the paper is reprinted from. +% +% misc-options: +% narroweqnarray: Changes the spacing around the "=" sign in +% equation arrays to make it the same as in displayed math. +% inline: Compresses the horizontal spacing of inline math equations. +% notitlepage: No separate title page. (default) +% titlepage: Separate title page. +% anonymous: Omit all author information from main part of paper. +% Author info only prints on titlepage. +% 9pt,10pt,11pt,12pt: Choose the appropriate type size. You should +% not need to do this as the "correct" size is automatically +% chosen. However, if you want, you may use these to change +% the type size of the main text. "9pt" is a bit of a hack +% to retain backward-compatibility. +% invited: If the paper is an "invited" paper, then this option +% prints "(Invited Paper)" under the authors' names. +% +% For regular IEEE submissions, define the journal name as: +% \journal{IEEE Trans. Inst. Meas.} +% +% To specify the conference place and date: +% \confplacedate{Ottawa, Canada, May 19--21, 1997} +% +% Before \maketitle, define: +% \title{Title of paper} +% \author{Author1\member{Fellow}\authorinfo{Department of +% Electrical Engineering\\ Some University, Somewhere, CA 94305 +% USA} \and Author2\member{Senior Member}\authorinfo{Deptartment of +% Measurement and Instrument Eng., Another University, ...}} +% +% Note, the contents of \authorinfo tends to vary depending on if it is +% a conference or journal paper. The amount of manual changes are +% small, and must be done by a human anyway. The example given is for an +% IMTC conference. +% +% See also IEEEbib.bst and ieeefig.sty +% Also very useful for document preparation is the style file "endfloat", +% available on all CTAN TeX archives. +% +%=========================================================================== +% modified 14 October 2002: +% - fixed bibliography listing of [#] when # < 10 and number of +% references is greater than 9. Thanks for Janos Markus for finding +% this bug and suggesting a solution. +% modified 15 January 2000: +% - "fixed" narroweqnarray. Never implemented! Now it is... +% modified 12 January 2000: +% - modified so only first \title and \author commands are recognized. +% This allows LyX to have \title and \author with full syntax in +% header, but dummy \title and \author show up in GUI. +% - added "\date" so the \date command can change "submitted" and +% "draft" date headers. +% modified 11 January 2000: +% - added PARstartLyX and PARstartCalLyX for LyX compatibility +% - added biographyLyX +% modified 1 Dec 1997: +% - fixed first page in reprint mode to be same length as other pages +% - added "invited" misc-option +% modified 5 Sept 1997: +% - added the inpress, reprint and internal sub-modes +% - removed IMTC-conf and CDC-conf to separate files +% modified 1 Sept 1997: +% - included Babel package compatibility +% - removed paper title from header on first page of draft +% manuscript +% - removed the fixed option "letterpaper" to allow a4paper (etc) +% modified 1 Aug 1997: +% - included the CDC-conf option +%=========================================================================== +% ************************************************************************** +% ****** ****************************************** +% ***** LaTeX2e INITIALIZATION ***************************************** +% ****** ****************************************** +% ************************************************************************** +\typeout{Document Class `ieee' .} +\NeedsTeXFormat{LaTeX2e}[1993/11/11] % Oldest acceptable version of LaTeX2e +\ProvidesClass{ieee}[2000/01/11] % Name of package provided, date +\def\i@@@cls{exists} + +% Initial Code & Declaration of Options +% ------------------------------------- +\newif\ifev@l \ev@lfalse % true if "final" mode. +\newif\ifsubm@t \subm@tfalse % true if "submission" mode. +\newif\ifdr@ft \dr@fttrue % true if "draft" mode. +\newif\ifc@mpress \c@mpressfalse % true if "compressed" mode. + +\newif\if@technote \@technotefalse % true if "technote" sub-mode. +\newif\ifintern@l \intern@lfalse % true if "internal" sub-mode. +\newif\ifprepr@nt \prepr@ntfalse % true if "preprint" sub-mode. +\newif\ifinpr@ss \inpr@ssfalse % true if "inpress" sub-mode. +\newif\ifrepr@nt \repr@ntfalse % true if "reprint" sub-mode. + +\newif\iftitlep@ge \titlep@gefalse % true if has own titlepage +\newif\if@non \@nonfalse % true if anonymous +\newif\ifixpt \ixptfalse % true if trying to do 9 pt +\newif\if@nvited \@nvitedfalse % true if an invited paper + +% Main options +% ------------ +\DeclareOption{draft}{\ev@lfalse\subm@tfalse\dr@fttrue% + \typeout{ieee: `Draft' mode selected.}} +\DeclareOption{submission}{\ev@lfalse\dr@ftfalse\subm@ttrue% + \typeout{ieee: `Submission' mode selected.}} +\DeclareOption{compressed}{\ev@lfalse\dr@ftfalse\subm@tfalse\c@mpresstrue% + \typeout{ieee: `Compressed' mode selected.}} +\DeclareOption{final}{\ev@ltrue\dr@ftfalse\subm@tfalse% + \typeout{ieee: `Final' mode selected.}} +\DeclareOption{evaluation}{\ev@ltrue\dr@ftfalse\subm@tfalse% + \typeout{ieee: `Final' mode selected.}} % synonym for final + +% Sub options +% ----------- +\DeclareOption{technote}{\@technotetrue% + \typeout{ieee: `Technote' sub-mode selected.}} +\DeclareOption{internal}{\intern@ltrue\prepr@ntfalse\inpr@ssfalse\repr@ntfalse% + \typeout{ieee: `Internal-Review' sub-mode selected.}} +\DeclareOption{submitted}{\intern@lfalse\prepr@nttrue\inpr@ssfalse\repr@ntfalse% + \typeout{ieee: `Submitted' sub-mode selected.}} +\DeclareOption{preprint}{\intern@lfalse\prepr@nttrue\inpr@ssfalse\repr@ntfalse% + \typeout{ieee: `Submitted' sub-mode selected.}} % synonym for submitted +\DeclareOption{inpress}{\intern@lfalse\prepr@ntfalse\inpr@sstrue\repr@ntfalse% + \typeout{ieee: `Inpress' sub-mode selected.}} +\DeclareOption{reprint}{\intern@lfalse\prepr@ntfalse\inpr@ssfalse\repr@nttrue% + \typeout{ieee: `Reprint' sub-mode selected.}} + +% Misc options +% ------------ + % regular or compressed "=" spacing in +\def\eqnarr@ysep{\arraycolsep} % eqnarray (this is the default) + % NOTE: we must use "def" and not "=" + % as arraycolsep not yet defined. +\DeclareOption{narroweqnarray}{\gdef\eqnarr@ysep{0.28em\relax}% + \typeout{ieee: Narrow equation arrays selected.}} +\DeclareOption{inline}{\everymath{\thinmuskip=2mu plus 1mu + \medmuskip=3mu plus 1mu minus 2mu + \thickmuskip=4mu plus 2mu\relax}% + \typeout{ieee: Narrower inline equations selected.}} +\DeclareOption{notitlepage}{\titlep@gefalse% + \typeout{ieee: No separate title page.}} +\DeclareOption{titlepage}{\titlep@getrue% + \typeout{ieee: Use separate title page.}} +\DeclareOption{anonymous}{\@nontrue\AtBeginDocument{\glpexclude{biography}} + \typeout{ieee: Omit author information from paper.}} +\DeclareOption{invited}{\@nvitedtrue% + \typeout{ieee: (Invited Paper).}} + +\DeclareOption{9pt}{\ixpttrue% + \typeout{ieee: Trying to emulate old `9pt' document class.}} + +\DeclareOption*{\PassOptionsToClass{\CurrentOption}{article}} + +% Execution of Options/Package Loading +% ------------------------------------ +\newlength\narrowcol +\newlength\parindentsave % recover parindent in blsone text + +\ProcessOptions +\ifev@l % if "final" mode... + \if@technote\ixpttrue\typeout{ieee: Trying to emulate old `9pt' + document class.}\fi% + \LoadClass[twoside,final,twocolumn,10pt]{article} +\else % if "draft"/"submission"/(compressed) mode... + \ifixpt + \LoadClass[oneside,final,onecolumn,10pt]{article} + \else + \LoadClass[oneside,final,onecolumn,12pt]{article} + \fi +\fi +\RequirePackage[final]{graphicx} +\RequirePackage{ifthen} + +% Re-Definitions of English words which must be done before +% the Babel package (optional) is loaded. +% --------------------------------------------------------- +\def\keywordsname{Index Terms} +\def\indexterms#1{\def\keywordsname{#1}} +\def\appendicesname{Appendices} +\def\figurename{Fig.} + +% ************************************************************************** +% ***** Check Sub-Options for Compatibility w/ Main-Options ************ +% ************************************************************************** +\if@technote\ifev@l\else\ClassError{ieee}{`technote' sub-mode may be + used only with the `final' ^^Jmain-mode. It may not be used + with either the `draft,' `submission,' or ^^J`compressed' + main-modes}{}\endinput\fi\fi +\ifintern@l\ifdr@ft\ClassError{ieee}{`internal' sub-mode may be + used only with the ^^J`submission,' `compressed,' or `final' main-modes. + It may not be used ^^Jwith the `draft' main-mode}{}\endinput\fi\fi +\ifprepr@nt\ifc@mpress\else\ifev@l\else\ClassError{ieee}{`submitted' + sub-mode may be used only with the ^^J`compressed' or `final' + main-modes. It may not be used with either the ^^J`draft' or + `submission' main-modes}{}\endinput\fi\fi\fi +\ifinpr@ss\ifc@mpress\else\ifev@l\else\ClassError{ieee}{`inpress' + sub-mode may be used only with the `compressed' ^^Jor `final' + main-modes. It may not be used with either the `draft' or + ^^J`submission' main-modes}{}\endinput\fi\fi\fi +\ifrepr@nt\ifev@l\else\ClassError{ieee}{`reprint' + sub-mode may be used only with the `final' ^^Jmain-mode. It may not be + used with either the `draft,' `submission,' or ^^J`compressed' + main-modes}{}\endinput\fi\fi + +% ************************************************************************** +% ***** Page Layout Definition ***************************************** +% ************************************************************************** +%% Layout definitions (mostly) common to all options. + +\hoffset 0in \voffset 0in +\headheight 12pt \headsep 7mm +\marginparsep 10pt \marginparwidth 20pt +\marginparpush 25pt +\columnsep 4mm +\parindent 1.0em +\lineskip 1pt +\normallineskip 1pt +\def\baselinestretch{1} + +\partopsep \z@ +\topsep 1.3ex +\parsep \z@ +\itemsep \z@ + +\setlength{\parindentsave}{\parindent} + +\ifev@l % if "evaluation" mode + % if camera-ready or A4paper ... + \ifdim\paperwidth<211mm + \oddsidemargin -11.4mm \evensidemargin -11.4mm + % for regular US Letter, not camera-ready + \else + \oddsidemargin -8.45mm \evensidemargin -8.45mm + \fi + \ifrepr@nt + \textheight 237.5mm % leave 6mm for cpyright on first page + \else + \textheight 243.5mm + \fi + \voffset -0.5in + \textwidth 182.0mm + \topmargin -12pt + \setlength{\narrowcol}{89mm} +\else % if "draft"/"submission" mode... + \ifc@mpress % and "compressed" + \oddsidemargin -0.25in \evensidemargin -0.25in + \textheight 9in \textwidth 7in + \topmargin -0.25in + \setlength{\narrowcol}{7in} + \else % and NOT "compressed" + \renewcommand\baselinestretch{1.8}\renewcommand{\arraystretch}{0.8} + \parindent=1.8\parindent + \oddsidemargin 0pt \evensidemargin 0pt + \headheight 12pt \headsep 0.375in + \topmargin 0pt + \textheight 8.5in \textwidth 6.5in + \marginparsep 0in \marginparwidth 0pt + \marginparpush 5pt + \setlength{\narrowcol}{6.5in} + \fi +\fi + +\def\normalstyle{\rmfamily} + +% ************************************************************************** +% ***** Font Definition ************************************************ +% ************************************************************************** +%% The 9-point option is being faked since it is not supported by the +%% article base class. + +%% Check if we have selected 9 points +\ifixpt +\typeout{-- This is a 9 point document} +\gdef\@ptsize{9} +\def\@normalsize{\@setsize\normalsize{10.7pt}\ixpt\@ixpt +\abovedisplayskip 1em plus2pt minus5pt\belowdisplayskip \abovedisplayskip +\abovedisplayshortskip \z@ plus3pt\belowdisplayshortskip .6em plus3pt minus3pt +\topsep \belowdisplayshortskip%!PN +} +\def\small{\@setsize\small{9.12pt}\viiipt\@viipt} +\def\footnotesize{\@setsize\footnotesize{8.15pt}\viipt\@vipt} +\def\scriptsize{\@setsize\scriptsize{8pt}\vipt\@vpt} +\def\tiny{\@setsize\tiny{5pt}\vpt\@vpt} +\def\large{\@setsize\large{12pt}\xpt\@xpt} +\def\Large{\@setsize\Large{14pt}\xiipt\@xiipt} +\def\LARGE{\@setsize\LARGE{18pt}\xivpt\@xivpt} +\def\huge{\@setsize\huge{22pt}\xviipt\@xviipt} +\def\Huge{\@setsize\Huge{25pt}\xxpt\@xxpt} +\fi +%% +%% Check if we have selected 10 points +\def\@tempa{0}\if\@ptsize\@tempa +\typeout{-- This is a 10 point document} +\def\@normalsize{\@setsize\normalsize{11.9pt}\xpt\@xpt +\abovedisplayskip 1em plus2pt minus5pt\belowdisplayskip \abovedisplayskip +\abovedisplayshortskip \z@ plus3pt\belowdisplayshortskip .6em plus3pt minus3pt +\topsep \belowdisplayshortskip%!PN +} +\def\small{\@setsize\small{9.2pt}\viiipt\@viiipt} +\def\footnotesize{\@setsize\footnotesize{8.8pt}\viiipt\@viiipt} +\def\scriptsize{\@setsize\scriptsize{8pt}\viipt\@viipt} +\def\tiny{\@setsize\tiny{6pt}\vpt\@vpt} +\def\normalsize{\@setsize\normalsize{11.9pt}\xpt\@xpt} +\def\large{\@setsize\large{14pt}\xiipt\@xiipt} +\def\Large{\@setsize\Large{18pt}\xivpt\@xivpt} +\def\LARGE{\@setsize\LARGE{22pt}\xviipt\@xviipt} +\def\huge{\@setsize\huge{22pt}\xxpt\@xxpt} +\def\Huge{\@setsize\Huge{28pt}\xxvpt\@xxvpt} +\fi +%% +%% Check if we have selected 11 points +\def\@tempa{1}\if\@ptsize\@tempa +\typeout{-- This is an 11 point document} +\def\@normalsize{\@setsize\normalsize{13.6pt}\xipt\@xipt +\abovedisplayskip 1em plus2pt minus5pt\belowdisplayskip \abovedisplayskip +\abovedisplayshortskip \z@ plus3pt\belowdisplayshortskip .6em plus3pt minus3pt +\topsep \belowdisplayshortskip%!PN +} +\def\small{\@setsize\small{12pt}\xpt\@xpt} +\def\footnotesize{\@setsize\footnotesize{11pt}\ixpt\@ixpt} +\def\scriptsize{\@setsize\scriptsize{9.5pt}\viiipt\@viiipt} +\def\tiny{\@setsize\tiny{7pt}\vipt\@vipt} +\def\normalsize{\@setsize\normalsize{13.6pt}\xipt\@xipt} +\def\large{\@setsize\large{14pt}\xiipt\@xiipt} +\def\Large{\@setsize\Large{18pt}\xivpt\@xivpt} +\def\LARGE{\@setsize\LARGE{22pt}\xviipt\@xviipt} +\def\huge{\@setsize\huge{25pt}\xxpt\@xxpt} +\def\Huge{\@setsize\Huge{30pt}\xxvpt\@xxvpt} +\fi +%% +%% Check if we have selected 12 points +\def\@tempa{2}\if\@ptsize\@tempa +\typeout{-- This is a 12 point document} +\def\@normalsize{\@setsize\normalsize{14pt}\xiipt\@xiipt +\abovedisplayskip 1em plus3pt minus6pt\belowdisplayskip \abovedisplayskip +\abovedisplayshortskip \z@ plus3pt\belowdisplayshortskip .6em plus4pt minus4pt +\topsep \belowdisplayshortskip%!PN +} +\def\small{\@setsize\small{11.4pt}\xpt\@xpt} +\def\footnotesize{\@setsize\footnotesize{10pt}\ixpt\@ixpt} +\def\scriptsize{\@setsize\scriptsize{9pt}\viiipt\@viiipt} +\def\tiny{\@setsize\tiny{8pt}\vipt\@vipt} +\def\normalsize{\@setsize\normalsize{14pt}\xiipt\@xiipt} +\def\large{\@setsize\large{18pt}\xivpt\@xivpt} +\def\Large{\@setsize\Large{22pt}\xviipt\@xviipt} +\def\LARGE{\@setsize\LARGE{25pt}\xxpt\@xxpt} +\def\huge{\@setsize\huge{30pt}\xxvpt\@xxvpt} +\let\Huge=\huge +\fi + +\AtBeginDocument{\normalsize\normalstyle\ps@headings\pagenumbering{arabic}} + +% ************************************************************************** +% ***** List Definition ************************************************ +% ************************************************************************** +%% Change aspect of lists with +%% 1) \itemindent, label indentation wrt to left list margin +%% 2) \leftmargini, the indentation of the whole list (on left, first level) +\ifev@l + \itemindent -1em + \leftmargini 2em + \leftmarginii 1em + \leftmarginiii 1.5em + \leftmarginiv 1.5em + \leftmarginv 1.0em + \leftmarginvi 1.0em +\else + \itemindent -1em + \leftmargini 3em + \leftmarginii 3em + \leftmarginiii 3em + \leftmarginiv 3em + \leftmarginv 3em + \leftmarginvi 3em +\fi +%\itemindent 2em % Alternative values: sometimes used.. +%\leftmargini 0em +\labelsep 5pt +\leftmargin\leftmargini +\labelwidth \z@ + +\def\@listI{\leftmargin\leftmargini} \@listI +\def\@listi{\leftmargin\leftmargini \topsep \z@ plus 1pt minus 1pt} +\def\@listii{\leftmargin\leftmarginii\labelwidth\leftmarginii + \advance\labelwidth-\labelsep \topsep \z@} +\def\@listiii{\leftmargin\leftmarginiii\labelwidth\leftmarginiii + \advance\labelwidth-\labelsep \topsep \z@} +\def\@listiv{\leftmargin\leftmarginiv\labelwidth\leftmarginiv + \advance\labelwidth-\labelsep \topsep \z@} +\def\@listv{\leftmargin\leftmarginv\labelwidth\leftmarginv + \advance\labelwidth-\labelsep \topsep \z@} +\def\@listvi{\leftmargin\leftmarginvi\labelwidth\leftmarginvi + \advance\labelwidth-\labelsep \topsep \z@} + +\def\labelenumi{\theenumi.} \def\theenumi{\arabic{enumi}} +\def\labelenumii{(\theenumii)} \def\theenumii{\alph{enumii}} +\def\labelenumiii{\theenumiii.} \def\theenumiii{\roman{enumiii}} +\def\labelenumiv{\theenumiv.} \def\theenumiv{\Alph{enumiv}} +\def\p@enumii{\theenumi} +\def\p@enumiii{\theenumi(\theenumii)} +\def\p@enumiv{\p@enumiii\theenumiii} + +\def\labelitemi{$\scriptstyle\bullet$} +\def\labelitemii{\bf --} +\def\labelitemiii{$\ast$} +\def\labelitemiv{$\cdot$} + +%% \itemindent is set to \z@ by list, so define new temporary variable +\newdimen\tmpitemindent +\def\verse{\let\\=\@centercr + \list{}{\itemsep\z@ \itemindent -1.5em \listparindent \itemindent + \rightmargin\leftmargin\advance\leftmargin 1.5em}\item[]} +\let\endverse\endlist +\def\quotation{\list{}{\listparindent 1.5em \itemindent\listparindent + \rightmargin\leftmargin \parsep 0pt plus 1pt}\item[]} +\let\endquotation=\endlist +\def\quote{\list{}{\rightmargin\leftmargin}\item[]} +\let\endquote=\endlist +\def\@mklab#1{#1} +\def\description{\tmpitemindent\itemindent\list{}{\itemindent\tmpitemindent + \labelwidth\z@\def\makelabel##1{\hspace\labelsep\emph{##1}}}} +\def\enddescription{\endlist\par} +\def\enumerate{\tmpitemindent\itemindent\ifnum \@enumdepth >3 \@toodeep\else + \advance\@enumdepth \@ne \edef\@enumctr{enum\romannumeral\the\@enumdepth}% + \list{\csname label\@enumctr\endcsname}{\itemindent\tmpitemindent + \usecounter{\@enumctr}\def\makelabel##1{\hspace\labelsep\hfil{##1}}}\fi} +\def\endenumerate{\endlist\par} +\def\itemize{\tmpitemindent\itemindent\ifnum \@itemdepth >3 \@toodeep\else + \advance\@itemdepth\@ne + \edef\@itemitem{labelitem\romannumeral\the\@itemdepth}% + \list{\csname\@itemitem\endcsname}{\itemindent\tmpitemindent + \def\makelabel##1{\hspace\labelsep\hfil\emph{##1}}}\fi} +\def\enditemize{\endlist\par} + +\newif\if@restonecol +\def\titlepage{\@restonecolfalse\if@twocolumn\@restonecoltrue\onecolumn + \else \newpage \fi \thispagestyle{coverpagestyle}\c@page\z@} +\def\endtitlepage{\if@restonecol\twocolumn \else \newpage \fi% +\if@twoside\mbox{}\thispagestyle{coverpagestyle}\c@page\z@\cleardoublepage\fi} + +\arraycolsep 5pt +\tabcolsep 6pt +\arrayrulewidth .4pt +\doublerulesep 2pt +\tabbingsep\labelsep + +% ************************************************************************** +% ***** Footnote Definition ******************************************** +% ************************************************************************** +\skip\footins 10pt plus 5pt minus 2pt +\footnotesep 7pt +\footskip 6mm +\skip\@mpfootins = \skip\footins +\fboxsep = 3pt \fboxrule = .4pt +\long\def\@makefntext#1{\parindent .8em\indent$^{\@thefnmark}$#1} +\def\footnoterule{} + +% Reset baselinestretch within footnotes. +% Originally stolen from Stanford University thesis style. +% -------------------------------------------------------- +\long\def\@footnotetext#1{\insert\footins{\blsone% + \footnotesize\interlinepenalty\interfootnotelinepenalty + \splittopskip\footnotesep + \splitmaxdepth \dp\strutbox \floatingpenalty \@MM + \hsize\columnwidth \@parboxrestore + \edef\@currentlabel{\csname p@footnote\endcsname\@thefnmark}\@makefntext + \let\par\\ + {\rule{\z@}{\footnotesep}\ignorespaces + #1\strut}}} + +% ************************************************************************** +% ***** Keep track of Sections ***************************************** +% ************************************************************************** +\if@technote + \setcounter{secnumdepth}{3} +\else + \setcounter{secnumdepth}{4} +\fi + +\def\thesection{\@Roman\c@section} +\def\thesubsection{\Alph{subsection}} +\def\thesubsubsection{\thesubsection.\arabic{subsubsection}} +\def\thesubsubsectiondis{\Alph{subsection}.\arabic{subsubsection}} +\def\theparagraph{\thesubsubsection.\alph{paragraph}} +\def\theparagraphdis{\thesubsubsectiondis.\alph{paragraph}} + +\def\theequation{\arabic{equation}} + +% ************************************************************************** +% ***** Table of Contents, List of Figures/Tables Definitions ********** +% ************************************************************************** +\def\@pnumwidth{1.55em} +\def\@tocrmarg {2.55em} +\def\@dotsep{4.5} +\setcounter{tocdepth}{3} + +\def\tableofcontents{\section*{\contentsname}\@starttoc{toc}} +\def\l@section#1#2{\addpenalty{\@secpenalty} \addvspace{1.0em plus 1pt} + \@tempdima 1.8em \begingroup \parindent \z@ \rightskip \@pnumwidth + \parfillskip-\@pnumwidth \bf\leavevmode #1\hfil\hbox to\@pnumwidth{\hss #2} + \par \endgroup} +\def\l@subsection{\@dottedtocline{2}{1.5em}{2.3em}} +\def\l@subsubsection{\@dottedtocline{3}{3.8em}{3.2em}} +\def\listoffigures{\section*{\listfigurename}\@starttoc{lof}} +\def\l@figure{\@dottedtocline{1}{1em}{1.8em}} +\def\listoftables{\section*{\listtablename}\@starttoc{lot}} +\let\l@table\l@figure + +% ************************************************************************** +% ***** Float Definitions ********************************************** +% ************************************************************************** +%% Normal Floats %% Double Column Floats +\floatsep 12pt plus 2pt minus 2pt \dblfloatsep 12pt plus 2pt minus 2pt +\textfloatsep 20pt plus 2pt minus 4pt \dbltextfloatsep 20pt plus 2pt minus 4pt +%\@maxsep 20pt \@dblmaxsep 20pt %!PN +\@fptop 0pt plus 1fil \@dblfptop 0pt plus 1fil +\@fpsep 8pt plus 2fil \@dblfpsep 8pt plus 2fil +\@fpbot 0pt plus 1fil \@dblfpbot 0pt plus 1fil +\def\topfraction{1.0} \def\dbltopfraction{1.0} +\def\floatpagefraction{0.8} \def\dblfloatpagefraction{0.8} +\setcounter{topnumber}{2} \setcounter{dbltopnumber}{4} +% +\intextsep 12pt plus 2pt minus 2pt +\setcounter{bottomnumber}{2} +\def\bottomfraction{.4} +\setcounter{totalnumber}{4} +\def\textfraction{.2} + +% Reset baselinestretch within floats. +% Originally stolen from Stanford University thesis style. +% -------------------------------------------------------- +\def\@xfloat#1[#2]{\ifhmode \@bsphack\@floatpenalty -\@Mii\else + \@floatpenalty-\@Miii\fi\def\@captype{#1}\ifinner + \@parmoderr\@floatpenalty\z@ + \else\@next\@currbox\@freelist{\@tempcnta\csname ftype@#1\endcsname + \multiply\@tempcnta\@xxxii\advance\@tempcnta\sixt@@n + \@tfor \@tempa :=#2\do + {\if\@tempa h\advance\@tempcnta \@ne\fi + \if\@tempa t\advance\@tempcnta \tw@\fi + \if\@tempa b\advance\@tempcnta 4\relax\fi + \if\@tempa p\advance\@tempcnta 8\relax\fi + }\global\count\@currbox\@tempcnta}\@fltovf\fi + \global\setbox\@currbox\vbox\bgroup + \def\baselinestretch{1}\small\normalsize + \hsize\columnwidth \@parboxrestore} + +% ************************************************************************** +% ***** Caption Definition ********************************************* +% ************************************************************************** +% some journals do not have centered captions for figures. +\newif\ifc@ptionleft \c@ptionlefttrue +\def\leftfigcaptions{\c@ptionlefttrue} +\def\centerfigcaptions{\c@ptionleftfalse} + +\long\def\caption{\refstepcounter\@captype \@dblarg{\@caption\@captype}} + +\long\def\@caption#1[#2]#3{\par\addcontentsline{\csname ext@#1\endcsname}{#1}{% + \protect\numberline{\csname the#1\endcsname}{\ignorespaces #2}} + \begingroup \@parboxrestore \normalsize + \@makecaption{\csname fnum@#1\endcsname}{\ignorespaces #3}{#1}\par + \endgroup} + +\def\tablestring{table} +\def\figurestring{figure} + +% changed by GLP to allow table captions to be set to a specific maximum +% width "\captionwidth", if defined. +\newlength{\captionindent} +\long\def\@makecaption#1#2#3{ +\ifx\figurestring#3 + \vskip 5pt + \setbox\@tempboxa\hbox{\small #1.~ #2} + \ifdim \wd\@tempboxa >\hsize + \setbox\@tempboxa\hbox{\small #1.~ } + %\setlength\captionindent{\wd\@tempboxa} \divide\captionindent by 2 + %\parbox[t]{\hsize}{\small \hangindent \captionindent \hangafter=1% + \parbox[t]{\hsize}{\small + \unhbox\@tempboxa#2} + \else \hbox + to\hsize{\small\ifc@ptionleft\else\hfil\fi\box\@tempboxa\hfil} + \fi +\else + \begin{center} + \ifx\captionwidth\undefined {\small #1}\\{\small\scshape #2} + \else + \begin{minipage}{\captionwidth} + \begin{center}{\small #1}\\{\small\scshape #2}\end{center} + \end{minipage} + \fi + \end{center}\vskip 4pt +\fi} + +\def\thefigure{\@arabic\c@figure} +\def\fps@figure{tbp} +\def\ftype@figure{1} +\def\ext@figure{lof} +\def\fnum@figure{\figurename\ \thefigure} +%\def\figure{\@float{figure}} % GLP +%\let\endfigure\end@float +\@namedef{figure*}{\@dblfloat{figure}} +\@namedef{endfigure*}{\end@dblfloat} + +\def\thetable{\@Roman\c@table} +\def\fps@table{tbp} +\def\ftype@table{2} +\def\ext@table{lot} +\def\fnum@table{TABLE~\thetable} +\def\table{\@float{table}} +\let\endtable\end@float +\@namedef{table*}{\@dblfloat{table}} +\@namedef{endtable*}{\end@dblfloat} + +% ************************************************************************** +% ***** Header/Footer Definition *************************************** +% ************************************************************************** +% compute the time in hours and minutes; make new vars \timehh and \timemm +\newcount\timehh\newcount\timemm\timehh=\time\divide\timehh by 60 +\timemm=\time\count255=\timehh\multiply\count255 by-60 +\advance\timemm by \count255 +\ifnum\timehh=12\def\apm{pm}\else +\ifnum\timehh>12\def\apm{pm}\advance\timehh by-12\else +\def\apm{am}\fi\fi +\def\t@me{\number\timehh\,:\,\ifnum\timemm<10 0\fi\number\timemm\,\apm} + +% default definitions +% ------------------- +\def\theevenhe@d{\footnotesize\thepage \hfil \leftmark\hbox{}} +\def\theoddhe@d{\hbox{}\footnotesize\rightmark \hfil \thepage} +\def\theevenf@@t{} +\def\theoddf@@t{} + +\def\theeventphe@d{\footnotesize\thepage \hfil \hbox{}} +\def\theoddtphe@d{\hbox{}\footnotesize \hfil \thepage} +\def\theeventpf@@t{} +\def\theoddtpf@@t{} + +\def\theevencphe@d{} +\def\theoddcphe@d{} +\def\theevencpf@@t{} +\def\theoddcpf@@t{} + +\def\internalmsg{Preliminary version for evaluation: Please do not + circulate without the permission of the author(s)} +\def\submittedmsg{SUBMITTED FOR PUBLICATION TO:} +\def\acceptedmsg{ACCEPTED FOR PUBLICATION:} +\def\inpressmsg{(IN PRESS)} +\def\reprintmsg{REPRINTED FROM:} + +% default cover page style (optional cover page) +% ---------------------------------------------- +\def\ps@coverpagestyle{ + \def\@oddhead{\theoddcphe@d} \def\@evenhead{\theevencphe@d} + \def\@oddfoot{\theoddcpf@@t} \def\@evenfoot{\theevencpf@@t} +} + +% default title page style (first page of paper) +% ---------------------------------------------- +\def\ps@titlepagestyle{ + \def\@oddhead{\theoddtphe@d} \def\@evenhead{\theeventphe@d} + \def\@oddfoot{\theoddtpf@@t} \def\@evenfoot{\theeventpf@@t} +} + +% default regular page style +% -------------------------- +\if@twoside + \def\ps@headings{ + \def\@oddhead{\theoddhe@d} + \def\@evenhead{\theevenhe@d} + \def\@oddfoot{\theoddf@@t} \def\@evenfoot{\theevenf@@t} + } +\else + \def\ps@headings{ + \def\@oddhead{\theoddhe@d} + \def\@oddfoot{\theoddf@@t} + \def\@evenhead{} \def\@evenfoot{} + } +\fi + +% For draft mode (no sub-modes allowed) +% ------------------------------------- +\ifdr@ft + \def\leftmark{\sh@rttitle}\let\rightmark\leftmark + \def\theoddf@@t{\footnotesize\today---\t@me\hfil DRAFT} + \def\theevenf@@t{\footnotesize DRAFT\hfil\today---\t@me} + \def\theoddtpf@@t{\footnotesize\today---\t@me\hfil DRAFT} + \def\theeventpf@@t{\footnotesize DRAFT\hfil\today---\t@me} +\fi + +% For submission mode (default plus internal sub-modes allowed) +% ------------------------------------------------------------- +\ifsubm@t + \def\leftmark{\sh@rttitle}\def\rightmark{\titl@line} + \ifintern@l + \def\theeventphe@d{\footnotesize\thepage \hfil \rightmark\hbox{}} + \def\theoddtphe@d{\hbox{}\footnotesize\rightmark \hfil \thepage} + \def\rightmark{\vbox to 0pt{\vss\hbox{\internalmsg} \hbox{\sh@rttitle}}} + \def\leftmark{\vbox to 0pt{\vss\hbox{\internalmsg} + \hbox{\phantom{\internalmsg}\llap{\sh@rttitle}}}} + \else % put date on first page. + \edef\TODAY{\uppercase{\today}} + \def\theeventphe@d{\footnotesize\thepage \hfil \submittedmsg\ + \@journal\@titletext, \TODAY} + \def\theoddtphe@d{\footnotesize\submittedmsg\ + \@journal\@titletext, \TODAY\hfil \thepage} + \def\theevencphe@d{\footnotesize\hbox{} \hfil \submittedmsg\ + \@journal\@titletext, \TODAY} + \def\theoddcphe@d{\footnotesize\submittedmsg\ + \@journal\@titletext, \TODAY\hfil \hbox{}} + \fi +\fi + +% For compressed mode (default, internal, submitted and +% inpress sub-modes allowed) +% ----------------------------------------------------- +\ifc@mpress + \def\leftmark{\sh@rttitle}\def\rightmark{\titl@line} + \ifintern@l + \def\theeventphe@d{\footnotesize\thepage \hfil \rightmark\hbox{}} + \def\theoddtphe@d{\hbox{}\footnotesize\rightmark \hfil \thepage} + \def\rightmark{\vbox to 0pt{\vss\hbox{\internalmsg} \hbox{\sh@rttitle}}} + \def\leftmark{\vbox to 0pt{\vss\hbox{\internalmsg} + \hbox{\phantom{\internalmsg}\llap{\sh@rttitle}}}} + \fi + \ifprepr@nt + \edef\TODAY{\uppercase{\today}} + \def\theeventphe@d{\footnotesize\thepage \hfil \submittedmsg\ + \@journal\@titletext, \TODAY} + \def\theoddtphe@d{\footnotesize\submittedmsg\ + \@journal\@titletext, \TODAY\hfil \thepage} + \def\theevencphe@d{\footnotesize\hbox{} \hfil \submittedmsg\ + \@journal\@titletext, \TODAY} + \def\theoddcphe@d{\footnotesize\submittedmsg\ + \@journal\@titletext, \TODAY\hfil \hbox{}} + \fi + \ifinpr@ss + \def\leftmark{\acceptedmsg\ \@journal\@titletext, \inpressmsg} + \def\theeventphe@d{\footnotesize\thepage \hfil \leftmark\hbox{}} + \def\theoddtphe@d{\hbox{}\footnotesize\leftmark \hfil \thepage} + \fi +\fi + +% For final (evaluate) mode (default, techreport, internal, +% submitted, inpress and reprint sub-modes allowed) +% --------------------------------------------------------- +\ifev@l + \edef\TODAY{\uppercase{\today}} + \def\leftmark{\@journal\@titletext}\def\rightmark{\titl@line} + \def\theeventphe@d{\footnotesize\thepage \hfil \leftmark\hbox{}} + \def\theoddtphe@d{\hbox{}\footnotesize\leftmark \hfil \thepage} + \if@technote % make header a little bigger + \def\theevenhe@d{\small\thepage \hfil \leftmark\hbox{}} + \def\theoddhe@d{\hbox{}\small\rightmark \hfil \thepage} + \def\theeventphe@d{\small\thepage \hfil \leftmark\hbox{}} + \def\theoddtphe@d{\hbox{}\small\leftmark \hfil \thepage} + \fi + \ifintern@l + \def\theeventphe@d{\footnotesize\thepage \hfil \rightmark\hbox{}} + \def\theoddtphe@d{\hbox{}\footnotesize\rightmark \hfil \thepage} + \def\rightmark{\vbox to 0pt{\vss\hbox{\internalmsg} \hbox{\sh@rttitle}}} + \def\leftmark{\vbox to 0pt{\vss\hbox{\internalmsg} + \hbox{\phantom{\internalmsg}\llap{\sh@rttitle}}}} + \fi + \ifprepr@nt + \def\leftmark{\submittedmsg\ \@journal\@titletext, \TODAY} + \fi + \ifinpr@ss + \def\leftmark{\acceptedmsg\ \@journal\@titletext, \inpressmsg} + \fi + \ifrepr@nt + % reset page size on second and following pages b/c no copyright info + \let\oldshipout\shipout + \gdef\shipout{\global\textheight 243.5mm\oldshipout} + \def\theeventpf@@t{\footnotesize\hfil\@ieeecopyright\hfil} + \def\theoddtpf@@t{\footnotesize\hfil\@ieeecopyright\hfil} + \def\leftmark{\reprintmsg\ \@journal\@titletext} + \fi +\fi + +%% Defines the command for putting the header. footernote{TEXT} is the same +%% as markboth{TEXT}{TEXT}. Here for compatibility with other style files. +\def\markboth#1#2{\def\leftmark{#1}\def\rightmark{#2}} +\def\footernote#1{\markboth{#1}{#1}} + +% ************************************************************************** +% ***** Citation/Bibliography Definitions ****************************** +% ************************************************************************** +%% separate citations with "], [" +\def\@citex[#1]#2{\if@filesw\immediate\write\@auxout{\string\citation{#2}}\fi +\def\@citea{}\@cite{\@for\@citeb:=#2\do {\@citea\def\@citea{], +[}\@ifundefined {b@\@citeb}{{\bf ?}\@warning {Citation `\@citeb' on +page \thepage \space undefined}}% +{\csname b@\@citeb\endcsname}}}{#1}} + +\def\@cite#1#2{[{#1\if@tempswa, #2\fi}]} + +%% Allow short (name-less) citations, when used in conjunction with a +%% bibliography style that creates labels like \citename{, } +\let\@internalcite\cite +\def\cite{\def\citename##1{##1}\@internalcite} +\def\shortcite{\def\citename##1{}\@internalcite} +\def\@biblabel#1{\def\citename##1{##1}[#1]\hfill} + +\def\thebibliography#1{\section*{\refname}\footnotesize\list + {\hss[\arabic{enumi}]}{\settowidth\labelwidth{[#1]}\leftmargin\labelwidth + \advance\leftmargin\labelsep \itemsep 0pt plus .5pt + \usecounter{enumi}} + \def\newblock{\hskip .11em plus .33em minus .07em} + \sloppy\clubpenalty4000\widowpenalty4000 + \sfcode`\.=1000\relax + \ifev@l\else\normalsize\fi %added by GLP +} +\let\endthebibliography=\endlist + +% ************************************************************************** +% ***** Appendix/Appendices Definitions ******************************** +% ************************************************************************** +\newcounter{numappendices}\setcounter{numappendices}{0} +\newif\ifappendix \appendixfalse +%% appendix command for one single appendix +\def\appendix{\par + \appendixtrue + \typeout{appendices: \arabic{numappendices}} + \setcounter{section}{0}\setcounter{subsection}{0} + \gdef\thesection{\Alph{section}} + \ifnum \value{numappendices}>1 + \section*{\appendicesname} + \else + \section*{\appendixname} + \fi + \setcounter{numappendices}{0} +} +%% appendices command for multiple appendicies +\def\appendices{\par + \appendixtrue + \typeout{appendices: \arabic{numappendices}} + \setcounter{section}{0}\setcounter{subsection}{0} + \gdef\thesection{\Alph{section}} \section*{\appendicesname} + \setcounter{numappendices}{0} +} +\AtEndDocument{\if@filesw\immediate\write\@auxout{\string\setcounter{numappendices}{\arabic{numappendices}}}\fi} + +% ************************************************************************** +% ***** Title Definitions ********************************************** +% ************************************************************************** +\def\titl@line{\sh@rttitle} %for the header at the top of the page. + +\def\@title{\typeout{ieee: Warning! No \noexpand\title given!}} +\def\title{\@ifnextchar [{\titlea}{\titleb}}%] + +\def\set@title#1{\gdef\@title{#1}\global\def\set@title##1{}} +\def\setsh@rttitle#1{\gdef\sh@rttitle{#1}\global\def\setsh@rttitle##1{}} +\def\titlea[#1]#2{\set@title{#2}\setsh@rttitle{\uppercase{#1}}} +\def\titleb#1{\set@title{#1}\setsh@rttitle{\uppercase{#1}}} + +\def\authorinfo#1{\let\\\relax\thanks{#1}} + +\ifev@l + \if@technote + \def\member#1{} + \else + \def\member#1{, \emph{#1, IEEE}} + \fi +\else + \def\member#1{} +\fi + +\def\and{\unskip% % \begin{tabular} +\end{tabular}% +\hskip 0pt plus 0.1pt% +\begin{tabular}[t]{@{}c@{}}\ }% + +\def\@author{\typeout{ieee: Warning! No \noexpand\author given!}} +\def\author{\@ifnextchar [{\authora}{\authorb}}%] +\def\set@author#1{\gdef\@author{#1}\global\def\set@author##1{}} +\def\settitl@line#1{\gdef\titl@line{#1}\global\def\settitl@line##1{}} +\def\authora[#1]#2{\set@author{#2}\if@non\else\settitl@line{#1: \sh@rttitle}\fi} +\def\authorb#1{\set@author{#1}} + +\def\date#1{\def\today{#1}\edef\TODAY{\uppercase{\today}}} + +\long\def\maketitle{% + \begingroup + \let\@thanks\@empty + \renewcommand\thefootnote{} % the \thanks{} mark type is empty + \iftitlep@ge\begin{titlepage}\@maketitlepage\@thanks\end{titlepage}% + \let\@thanks\@empty\fi + \thispagestyle{titlepagestyle} + \if@twocolumn + \if@technote + %\if@twoside\newpage\cleardoublepage\else\newpage\fi% + \newpage\global\@topnum\z@ + \ifrepr@nt + \ifx\@loginfo\undefined\typeout{ieee: Warning! No \noexpand\loginfo + given!}\else\let\\\relax\thanks{\@loginfo}\fi% + \fi + \@maketitle + \else + \ifnum \col@number=\@ne + \ifrepr@nt + \ifx\@loginfo\undefined\typeout{ieee: Warning! No \noexpand\loginfo + given!}\else\let\\\relax\thanks{\@loginfo}\fi% + \fi + \@maketitle + \else \twocolumn[% + \ifrepr@nt% + \ifx\@loginfo\undefined\typeout{ieee: Warning! No \noexpand\loginfo% + given!}\else\let\\\relax\thanks{\@loginfo}\fi% + \fi% + \@maketitle]% + \fi + \fi + \else + \newpage + \global\@topnum\z@ % Prevents figures from going at top of page. + \ifrepr@nt + \ifx\@loginfo\undefined\typeout{ieee: Warning! No \noexpand\loginfo + given!}\else\let\\\relax\thanks{\@loginfo}\fi + \fi + \@maketitle + \fi + \thispagestyle{titlepagestyle}% + \@thanks + \endgroup + \setcounter{footnote}{0}% + \global\let\thanks\relax \global\let\maketitle\relax + \global\let\@maketitle\relax \global\let\@thanks\@empty + \global\let\@author\@empty \global\let\@date\@empty + \global\let\@title\@empty \global\let\title\relax + \global\let\author\relax \global\let\date\relax + \global\let\and\relax +} + +\long\def\@maketitle{\unskip\newpage% + \begin{center}\blsone + \let \footnote \thanks + \if@technote + {\bfseries\@title\par}\if@non\else\vskip 1.3em{\lineskip .5em + \noindent\begin{tabular}[t]{@{}c@{}}\@author\end{tabular}}\fi\par + \else\unskip + \noindent{\Huge\@title\par}% + \if@non\else\vskip1.0em% + \noindent{\large\lineskip .5em% + \begin{tabular}[t]{@{}c@{}}\@author\end{tabular}}% + \fi\par% + \if@nvited\vskip1.0em\noindent\emph{\large(Invited Paper)}\par\fi + \fi + \ifrepr@nt + \ifx\@lognumber\undefined\typeout{ieee: Warning! No + \noexpand\pubitemident or \noexpand\lognumber + given!}\else\thanks{\@lognumber}\fi% + \fi + \end{center}\par\vskip 0.5em}% + +\long\def\@maketitlepage{\newpage% + \mbox{}\vfil + \begin{center}\blsone + \let \footnote \thanks + \if@technote + {\bfseries\@title\par}\vskip 1.3em{\lineskip .5em + \noindent\begin{tabular}[t]{@{}c@{}}\@author\end{tabular}\par} + \else + \vskip0.2em{\Huge\@title\par}\vskip1.0em% + \iftitlep@ge\vfil\fi + \noindent{\large\lineskip .5em% + \begin{tabular}[t]{@{}c@{}}\@author\end{tabular}\par}% + \fi + \end{center}\par\vfil\mbox{}} + +\def\@journal{\typeout{ieee: Warning! No \noexpand\journal given!}} +\def\journal#1{\def\@journal{\uppercase{#1}}} + +\def\@ieeecopyright{\typeout{ieee: Warning! No \noexpand\ieeecopyright given!}} +\def\ieeecopyright#1{\def\@ieeecopyright{#1}} + +\def\lognumber#1{\def\@lognumber{IEEE Log Number #1.}} +\def\pubitemident#1{\def\@lognumber{Publisher Item Identifier #1.}} +\long\def\loginfo#1{\long\def\@loginfo{\hbox{\vrule height 3ex width \z@}#1}} + +\def\sh@rttitle{} +\def\@titletext{} +\def\titletext#1{\def\@titletext{#1}} + +\def\firstpage#1{\setcounter{page}{#1}} + +% ************************************************************************** +% ***** Abstract Definition ******************************************** +% ************************************************************************** +\def\abstract{% + \if@twocolumn + \small\bfseries{\itshape\abstractname\/---}% + \else + \begin{center}\vspace{-0.8em}\small\bf\abstractname\end{center} + \quotation\small + \fi\ignorespaces} +\def\endabstract{\vspace{0.6em}\par\if@twocolumn\else\endquotation\fi + \normalsize\normalstyle} + +% ************************************************************************** +% ***** Keywords Definition ******************************************** +% ************************************************************************** +\def\keywords{\vspace{-.3em} + \if@twocolumn + \small\bfseries{\itshape\keywordsname\/---}% + \else + \begin{center}\small\bf\keywordsname\end{center}\quotation\small + \fi\ignorespaces} +\def\endkeywords{\vspace{0.6em}\par\if@twocolumn\else\endquotation\fi + \normalsize\normalstyle} + +% ************************************************************************** +% ***** Fix Section Numbering ****************************************** +% ************************************************************************** +\gdef\@punct{.\ \ } % Punctuation after run-in section heading +\def\@sect#1#2#3#4#5#6[#7]#8{% + \ifnum #2>\c@secnumdepth + \def\@svsec\@empty + \else + \refstepcounter{#1}% + \protected@edef\@svsec{% + %\ifnum #2=1\Roman{#1}.\fi\ifnum #2=2\Alph{#1}.\fi + \ifnum #2=1\thesection.\fi + \ifnum #2=2\thesubsection.\fi + \ifnum #2>2{\csname the#1dis\endcsname}\if@technote.\fi\fi \hskip .5em} + \ifnum #2=1\ifappendix\stepcounter{numappendices}\fi\fi + \fi + \@tempskipa #5\relax + \ifdim \@tempskipa>\z@ + \begingroup #6\relax + \@hangfrom{\hskip #3\relax\@svsec}{\interlinepenalty \@M #8\par} + \endgroup + \csname #1mark\endcsname{#7} + \addcontentsline{toc}{#1}{\ifnum #2>\c@secnumdepth\else + \protect\numberline{\csname the#1\endcsname}\fi#7} + \else + \def\@svsechd{#6\hskip #3\@svsec #8\@punct\csname #1mark\endcsname{#7} + \addcontentsline{toc}{#1}{\ifnum #2>\c@secnumdepth \else + \protect\numberline{\csname the#1\endcsname}\fi#7}} + \fi + \@xsect{#5}} + +\def\@ssect#1#2#3#4#5{\@tempskipa #3\relax + \ifdim \@tempskipa>\z@ + \begingroup #4\@hangfrom{\hskip #1}{\interlinepenalty \@M #5\par}\endgroup + \else \def\@svsechd{#4\hskip #1\relax #5\@punct}\fi + \@xsect{#3}} + +% ************************************************************************** +% ***** Section Definitions ******************************************** +% ************************************************************************** +\def\section{\@startsection{section}{1}{\z@}{2.0ex plus .5ex + minus .2ex}{1.0ex plus .2ex}{\centering\scshape}} +\def\subsection{\@startsection{subsection}{2}{\z@}{2.0ex plus .5ex + minus .2ex}{1.0ex plus .2ex}{\itshape}} +\if@technote + \def\subsubsection{\@startsection{subsubsection}{3}{\z@}{2.0ex plus .5ex + minus .1ex}{0pt}{\itshape}} +\else + \def\subsubsection{\@startsection{subsubsection}{3}{\z@}{2.0ex plus .5ex + minus .2ex}{1.0ex plus .2ex}{\normalstyle}} + \def\paragraph{\@startsection{paragraph}{4}{\z@}{1.0ex plus .5ex + minus .2ex}{0ex}{\normalstyle}} +\fi + +% ************************************************************************** +% ***** Special Environment Definitions ******************************** +% ************************************************************************** +\def\QED{\mbox{\rule[0pt]{1.5ex}{1.5ex}}} +\def\proof{\noindent\hspace{1em}{\it Proof: }} +\def\endproof{\hspace*{\fill}~\QED\par\endtrivlist\unskip} +\def\@begintheorem#1#2{\tmpitemindent\itemindent\topsep 0pt\normalstyle\trivlist + \item[\hskip \labelsep{\indent\it #1\ #2:}]\itemindent\tmpitemindent} +\def\@opargbegintheorem#1#2#3{\tmpitemindent\itemindent\topsep 0pt\normalstyle \trivlist + \item[\hskip\labelsep{\indent\it #1\ #2\ \normalstyle(#3)}]\itemindent\tmpitemindent} +\def\@endtheorem{\endtrivlist\unskip} + +% ************************************************************************** +% ***** Special Environment Definitions ******************************** +% ************************************************************************** +\if@twoside\else\raggedbottom\fi + +%% Definition for Big letter at the beginning of a paragraph +%% +\def\PARstart#1#2 {\begingroup\def\par{\endgraf\endgroup\lineskiplimit=0pt} + \setbox2=\hbox{\uppercase{#2} }\newdimen\tmpht \tmpht \ht2 + \advance\tmpht by \baselineskip\font\hhuge=cmr10 at \tmpht + \setbox1=\hbox{{\hhuge #1}} + \count7=\tmpht \count8=\ht1\divide\count8 by 1000 \divide\count7 by\count8 + \tmpht=.001\tmpht\multiply\tmpht by \count7\font\hhuge=cmr10 at \tmpht + \setbox1=\hbox{{\hhuge #1}} \noindent \hangindent1.05\wd1 + \hangafter=-2 {\hskip-\hangindent \lower1\ht1\hbox{\raise1.0\ht2\copy1}% + \kern-0\wd1}\copy2\lineskiplimit=-1000pt} + +\def\PARstartCal#1#2 {\begingroup\def\par{\endgraf\endgroup\lineskiplimit=0pt} + \setbox2=\hbox{\uppercase{#2} }\newdimen\tmpht \tmpht \ht2 + \advance\tmpht by \baselineskip\font\hhuge=cmsy10 at \tmpht + \setbox1=\hbox{{\hhuge #1\/}} + \count7=\tmpht \count8=\ht1\divide\count8 by 1000 \divide\count7 by\count8 + \tmpht=.001\tmpht\multiply\tmpht by \count7\font\hhuge=cmsy10 at \tmpht + \setbox1=\hbox{{\hhuge #1\/}} \noindent \hangindent1.05\wd1 + \hangafter=-2 {\hskip-\hangindent \lower1\ht1\hbox{\raise1.0\ht2\copy1}% + \kern-0\wd1}\copy2\lineskiplimit=-1000pt} + +\def\PARstartLyX#1{\PARstart #1} +\def\PARstartCalLyX#1{\PARstartCal #1} + +\if@technote\def\PARstart#1#2{#1#2}\fi % if technical note, disable it +\if@technote\def\PARstartCal#1#2{#1#2}\fi % if technical note, disable it +\if@technote\def\PARstartLyX#1{#1}\fi % if technical note, disable it +\if@technote\def\PARstartCalLyx#1{#1}\fi % if technical note, disable it + +% ************************************************************************** +% ***** Misc. Definitions ********************************************** +% ************************************************************************** +%Restore single spacing +\newcommand{\blsone}{\renewcommand\baselinestretch{1}% + \renewcommand\arraystretch{1.2}\setlength{\parindent}{\parindentsave}% + \normalsize} +\newcommand{\capitem}[1]{{\hspace{0.2ex}(#1)}~} +\newcommand{\insdate}{} + +% ************************************************************************** +% ***** MATH Definitions *********************************************** +% ************************************************************************** +\def\eqnarray{% + \stepcounter{equation}% + \def\@currentlabel{\p@equation\theequation}% + \global\@eqnswtrue + \m@th + \global\@eqcnt\z@ + \tabskip\@centering + \let\\\@eqncr + $$\everycr{}\halign to\displaywidth\bgroup + \hskip\@centering$\displaystyle\tabskip\z@skip{##}$\@eqnsel + &\global\@eqcnt\@ne\hskip \eqnarr@ysep\hfil${##}$\hfil + &\global\@eqcnt\tw@ \hskip \eqnarr@ysep + $\displaystyle{##}$\hfil\tabskip\@centering + &\global\@eqcnt\thr@@ \hb@xt@\z@\bgroup\hss##\egroup + \tabskip\z@skip + \cr +} +\def\endeqnarray{% + \@@eqncr + \egroup + \global\advance\c@equation\m@ne + $$\@ignoretrue +} + +% ************************************************************************** +% ***** Biography Definitions ****************************************** +% ************************************************************************** +% This is the main code for the biography environment of the IEEE +% transactions class. The previous biography code had some known +% problems which were difficult to fix. The crux of the issue was that +% the photo frame was overlaid by text when \baselinestretch>1 or when +% the biography consisted of multiple short paragraphs. +% +% The fix was done by extracting code from the excellent package: +% 'picinpar.sty' version 1.2a as of july 13, 1993 +% by Friedhelm Sowa +% +% (At least most of) The bugs you find in this code were introduced +% unwittingly by myself. +% +%---------------- +% Known problems: +% +% - Don't use multiple blank lines to separate paragraphs. A single +% blank line works well, but multiple blank lines will confuse +% the code. This has something to do with the \def\par{\\\indent} +% line, but I can't think of an appropriate fix. Similarly, make +% sure the environment doesn't end with an extra blank line. +% - Don't use \samepage +% - Use \footnotemark within and \footnotetext outside the +% window-environment instead of \footnote +% - When using the epic-package load picinpar before epic +% like \documentstyle[...,picinpar,epic]{...} +% +% Counts +\newcount\br \newcount\nb \newcount\tcdsav \newcount\tcl \newcount\tcd +\newcount\tcn \newcount\cumtcl +% Dimens +\newdimen\rtside \newdimen\hpic \newdimen\vpic \newdimen\strutilg +\newdimen\picwd \newdimen\topheight \newdimen\ilg \newdimen\lpic +\newdimen\lwindowsep \newdimen\rwindowsep % VK 10 Feb 93 +\lwindowsep0.5\baselineskip % " +\rwindowsep0.5\baselineskip % " +\newdimen\cumpar +% Tokens +\newtoks\twa \newtoks\la \newtoks\ra \newtoks\ha \newtoks\pictoc +% Boxes +\newbox\rawtext \newbox\holder \newbox\windowbox \newbox\wartext +\newbox\finaltext \newbox\aslice \newbox\bslice \newbox\wbox +\newbox\wstrutbox \newbox\picbox \newbox\waslice \newbox\wbslice +\newbox\fslice + % Another strut +\def\wstrut{\relax\ifmmode\copy\wstrutbox\else\unhcopy\wstrutbox\fi} +% + +\def\getpic#1{\sbox{\@tempboxa}{\includegraphics{#1}}% +\newcount\tmpcta \tmpcta=\ht\@tempboxa% +\newcount\tmpctb \tmpctb=\wd\@tempboxa% +\divide\tmpctb by 100% +\divide\tmpcta by\tmpctb% +\ifnum\tmpcta>133% +\typeout{ieee: Biography picture `#1' too tall.}% +\frame{\hbox to 25mm{\hfil\resizebox{!}{32mm}{\usebox{\@tempboxa}}\hfil}}% +\else \ifnum\tmpcta<123% +\typeout{ieee: Biography picture `#1' too wide.}% +\frame{\vbox to 32mm{\vss\hbox{\resizebox{25mm}{!}{\usebox{\@tempboxa}}}\vss}}% +\else% +\resizebox{25mm}{32mm}{\usebox{\@tempboxa}} +\fi\fi} + +\long\def\biographyLyX#1{\if@non\else\begin{biography} #1\end{biography}\fi} + +\if@non + \long\def\biography{} +\else + \long\def\biography{\@ifnextchar [{\@biographyb}{\@biographya[{\unitlength + 1mm\hbox{\framebox(25,32){}}}]}} +\fi + +\long\def\@biographyb[#1]{\@biographya[\getpic{#1}]} + +\long\def\@biographya[#1]#2{\bgroup +\footnotesize\bigskip\bigskip\bigskip\parskip=0pt\par% +\rule{0pt}{35mm}\vspace*{-35mm}\par% garantees correct page breaking +\begin{main@bio}[{#1}]% +\noindent{\bf #2}% +} +\def\endbiography{\if@non\else\end{main@bio}\egroup\fi} + +\long\def\main@bio[#1]{% #1 is the material for setting a graphic box +\vskip\parskip\everypar{} +\global\cumpar=0pt +\global\cumtcl=0 + \tcd=0 + \rtside=0pt +% \hpic=\linewidth + \twa={} \la={} \ra={} \ha={} +\setbox\wbox=\hbox{(} +\computeilg +\pictoc={#1} +\setbox\windowbox=\vbox{\hbox{#1}} +\picwd=\wd\windowbox +\hpic=\picwd +\vpic=\ht\windowbox\advance\vpic\dp\windowbox +\rtside=\linewidth\advance\rtside-\picwd +\setbox\picbox=\vbox{\hsize=\hpic\vbox to\vpic{\box\windowbox}}% \vfill}}% + +\vpic=\ht\picbox\advance\vpic\dp\picbox +\ifdim\rtside>0pt\advance\rtside-\rwindowsep\fi % " +\global\br=\rtside +\ifnum\picwd=0 +\ifdim\vpic>0pt\picwd=\hpic +\else\vpic=\ht\picbox\advance\vpic\dp\picbox +\fi +\fi + \global\tcl=0 \lpic=0pt + \loop\global\advance\tcl by 1 \lpic=\tcl\baselineskip + \ifdim\lpic<\vpic\repeat + \vpic=\lpic + \global\cumtcl=\tcl +% +% Here we know exactly the number of indented lines and +% are able to generate the tokens for the \parshape list +% + \ifnum\br>0\ra={ 0pt \rtside}\fi + \ifnum\tcd>0\ha={ 0pt \linewidth}\fi + \ifnum\tcl<1\global\tcl=1\fi + \createparshapespec + \tcd=0 % restore the lintel + \global\tcdsav=0 +% +% This is a very tricky part of the package. Some day there +% will exist a detailed documentation. +% +\def\par{\\\indent} +% +% This is where we start to pick up the paragraph(s) +% + \setbox\rawtext=\vbox\bgroup\unvbox\rawtext\unskip + \clubpenalty=0\widowpenalty=0 + \ifnum\brokenpenalty<\maxdimen\else\brokenpenalty=9999\fi + \tolerance=1000 + \parshape=\tcn \the\twa } +% +\def\endmain@bio{% + %\par + \global\tcd=\tcdsav + \egroup\vskip\parskip\parshape=0 % reset parshape; end \box\rawtext + \vbadness=10000 + \splittopskip=0pt +% +% Now we build the boxes beside the window +% +\global\topheight=\tcl\baselineskip +\ifnum\br>0\setbox\holder=\vsplit\rawtext to\topheight\fi +\tcn=\tcl \nb=0 +\ifnum\br>0\nb=\tcn\fi +% +% text on the right side +% +\ifnum\nb>0 + \loop\advance\nb -1 + \setbox\bslice=\vsplit\holder to\baselineskip + \prune\bslice\rtside + \setbox\wbslice=\vbox{\unvbox\wbslice\hbox + to\rtside{\box\bslice\hfil}} + \ifdim\ht\holder>0pt\repeat +\fi +%GLP add fix to make sure bio starts at top of picture +\setbox\wbslice=\vbox to\topheight{\unvbox\wbslice\vfill\vss} +% +% fixing the dimensions of the window part +% +\topheight=\ht\wbslice +% +% ship out the window material to the main vertical list +% +\setbox\windowbox=\vbox{\hbox to\linewidth{% +\vbox to\topheight{\hrule width\picwd height0pt depth0pt\vskip0pt% +\vfill\unvbox\picbox% +\ifnum\picwd>0\vfill\fi% +\vss}\ifnum\br>0\hfill\vbox{\box\wbslice}\fi}}% +% +\unvbox\windowbox% +\loop% lines below picture.... + \setbox\bslice=\vsplit\rawtext to\baselineskip + \prune\bslice\linewidth + \setbox\wbslice=\vbox{\hbox to\linewidth{\box\bslice\hfil}} + \unvbox\wbslice + \ifdim\ht\rawtext>0pt +\repeat +%GLP +%\ifnum\nb>0\topheight=\nb\baselineskip %\advance\topheight by\ilg +%\vspace*{\topheight} +%\fi +}% FINITO +% +% What else do we need? +% +\def\prune#1#2{ +% take a \vbox containing a single \hbox, +% \unvbox it, and cancel the \lastskip +% put in a \hbox of width #2 + \unvbox#1 \setbox#1=\lastbox % \box#1 now is an \hbox + \ifdim\ht#1=\parskip + \setbox#1=\hbox to#2{\vrule height\parskip depth0pt width0pt\hfill} + \else\ifdim\ht#1=0pt\relax + \else\setbox#1=\hbox to#2{\wstrut\unhbox#1\unskip}\fi\fi} +% +% Here the token \twa is generated. +% It's not so difficult as it looks like. +% +\def\createparshapespec{% +\global\tcn=0 +\ifnum\br>0\global\tcn=\tcl\fi +\nb=0 +\ifnum\br>0\nb=\tcn\fi +\global\advance\tcn by\tcd \global\advance\tcn by1 +\ifnum\tcd>0 +\loop\twa=\expandafter{\the\twa\the\ha}\advance\tcd -1 +\ifnum\tcd>0\repeat +\fi +\ifnum\nb>0 +\loop\twa=\expandafter{\the\twa\the\ra}\advance\nb -1 +\ifnum\nb>0\repeat +\fi +\global\twa=\expandafter{\the\twa 0pt \the\linewidth}} +% +\def\computeilg{% compute the interline glue + \tcl=0\ilg=0pt\strutilg=0pt + \loop\setbox\wbox=\hbox{\char\tcl} + \ifdim\ht\wbox>\ilg\ilg=\ht\wbox\fi + \ifdim\dp\wbox>\strutilg\strutilg=\dp\wbox\fi + \advance\tcl by 1 + \ifnum\tcl<128\repeat + \ht\wbox=\ilg + \dp\wbox=\strutilg + \strutilg=\ht\wbox %\advance\strutilg by\ilg + \ifdim\strutilg>\baselineskip + \typeout{character with height greater baselineskip found in font} + \typeout{baselineskip changed to 1.5 of that height!} + \baselineskip=1.5\strutilg + \fi + \global\ilg=\baselineskip + \global\advance\ilg-\ht\wbox \global\advance\ilg-\dp\wbox + \strutilg=\ht\wbox \advance\strutilg by\ilg + \setbox\wstrutbox=\hbox{\vrule height\strutilg depth\dp\wbox width0pt}} + + +% the following code from version.sty by Stephen Bellantoni 1990, loosely +% based on "annotation.sty" by Tom Hofmann. Used to exclude "biography" from +% anonymous mode. +\begingroup +\catcode`@=11\relax% +\catcode`{=12\relax\catcode`}=12\relax% +\catcode`(=1\relax \catcode`)=2\relax% +\gdef\glpinclude#1(% + \expandafter\gdef\csname #1\endcsname% + ()% + \expandafter\gdef\csname end#1\endcsname% + ()% +)% +\gdef\glpexclude#1(% + \expandafter\gdef\csname #1\endcsname% + (\@bsphack\catcode`{=12\relax\catcode`}=12\relax\csname #1@NOTE\endcsname)% + \long\expandafter\gdef\csname #1@NOTE\endcsname ##1\end{#1}% + (\csname #1END@NOTE\endcsname)% + \expandafter\gdef\csname #1END@NOTE\endcsname% + (\@esphack\end(#1))% +)% +\endgroup + +%------- +\def\@confplacedate{\typeout{ieee: Warning! No \noexpand\confplacedate set!} +\bfseries `confplacedate' needs to be set. For example, to: Stanford, CA, USA, +September 29--30, 1991} +\def\confplacedate#1{\def\@confplacedate{#1}} + +%%%%%%%%%%%%%%%%%%%%%%%%% End of ieee.cls %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% diff --git a/cryptominisat/cppsrc/docs/satrace19-pdf/yalsat/sigproc.bib b/cryptominisat/cppsrc/docs/satrace19-pdf/yalsat/sigproc.bib new file mode 100644 index 00000000..6ecd1c74 --- /dev/null +++ b/cryptominisat/cppsrc/docs/satrace19-pdf/yalsat/sigproc.bib @@ -0,0 +1,202 @@ +@InProceedings{stamping, +author="Heule, Marijn J. H. +and J{\"a}rvisalo, Matti +and Biere, Armin", +editor="Sakallah, Karem A. +and Simon, Laurent", +title="Efficient {CNF} Simplification Based on Binary Implication Graphs", +booktitle="Theory and Applications of Satisfiability Testing - SAT 2011", +year="2011", +publisher="Springer Berlin Heidelberg", +address="Berlin, Heidelberg", +pages="201--215", +abstract="This paper develops techniques for efficiently detecting redundancies in CNF formulas. We introduce the concept of hidden literals, resulting in the novel technique of hidden literal elimination. We develop a practical simplification algorithm that enables ``Unhiding'' various redundancies in a unified framework. Based on time stamping literals in the binary implication graph, the algorithm applies various binary clause based simplifications, including techniques that, when run repeatedly until fixpoint, can be too costly. Unhiding can also be applied during search, taking learnt clauses into account. We show that Unhiding gives performance improvements on real-world SAT competition benchmarks.", +isbn="978-3-642-21581-0" +} + +@inproceedings{TACAS-2010-JarvisaloBH, + author = "Matti Järvisalo and Armin Biere and Marijn Heule", + booktitle = "{Proceedings of the 16th International Conference on Tools and Algorithms for the Construction and Analysis of Systems}", + doi = "10.1007/978-3-642-12002-2_10", + pages = "129--144", + publisher = "{Springer International Publishing}", + series = "{Lecture Notes in Computer Science}", + title = "{Blocked Clause Elimination}", + volume = 6015, + year = 2010, +} + +@InProceedings{probsat, +author="Balint, Adrian +and Sch{\"o}ning, Uwe", +editor="Cimatti, Alessandro +and Sebastiani, Roberto", +title="Choosing Probability Distributions for Stochastic Local Search and the Role of Make versus Break", +booktitle="Theory and Applications of Satisfiability Testing -- SAT 2012", +year="2012", +publisher="Springer Berlin Heidelberg", +address="Berlin, Heidelberg", +pages="16--29", +abstract="Stochastic local search solvers for SAT made a large progress with the introduction of probability distributions like the ones used by the SAT Competition 2011 winners Sparrow2010 and EagleUp. These solvers though used a relatively complex decision heuristic, where probability distributions played a marginal role.", +isbn="978-3-642-31612-8" +} + +@InProceedings{balint-improving-sls, +author="Balint, Adrian +and Biere, Armin +and Fr{\"o}hlich, Andreas +and Sch{\"o}ning, Uwe", +editor="Sinz, Carsten +and Egly, Uwe", +title="Improving Implementation of {SLS} Solvers for {SAT} and New Heuristics for {k-SAT} with Long Clauses", +booktitle="Theory and Applications of Satisfiability Testing -- SAT 2014", +year="2014", +publisher="Springer International Publishing", +address="Cham", +pages="302--316", +abstract="Stochastic Local Search (SLS) solvers are considered one of the best solving technique for randomly generated problems and more recently also have shown great promise for several types of hard combinatorial problems. Within this work, we provide a thorough analysis of different implementation variants of SLS solvers on random and on hard combinatorial problems. By analyzing existing SLS implementations, we are able to discover new improvements inspired by CDCL solvers, which can speed up the search of all types of SLS solvers. Further, our analysis reveals that the multilevel break values of variables can be easily computed and used within the decision heuristic. By augmenting the probSAT solver with the new heuristic, we are able to reach new state-of-the-art performance on several types of SAT problems, especially on those with long clauses. We further provide a detailed analysis of the clause selection policy used in focused search SLS solvers.", +isbn="978-3-319-09284-3" +} + + + +@inproceedings{DBLP:conf/ictai/LynceS03, + author = {In{\^{e}}s Lynce and + Jo{\~{a}}o P. Marques Silva}, + title = {Probing-Based Preprocessing Techniques for Propositional Satisfiability}, + booktitle = {15th {IEEE} International Conference on Tools with Artificial Intelligence + {(ICTAI} 2003), 3-5 November 2003, Sacramento, California, {USA}}, + pages = {105}, + year = {2003}, + crossref = {DBLP:conf/ictai/2003}, + url = {https://doi.org/10.1109/TAI.2003.1250177}, + doi = {10.1109/TAI.2003.1250177}, + timestamp = {Fri, 02 Nov 2018 09:48:27 +0100}, + biburl = {https://dblp.org/rec/bib/conf/ictai/LynceS03}, + bibsource = {dblp computer science bibliography, https://dblp.org} +} + +@proceedings{DBLP:conf/ictai/2003, + title = {15th {IEEE} International Conference on Tools with Artificial Intelligence + {(ICTAI} 2003), 3-5 November 2003, Sacramento, California, {USA}}, + publisher = {{IEEE} Computer Society}, + year = {2003}, + url = {http://ieeexplore.ieee.org/xpl/mostRecentIssue.jsp?punumber=8840}, + isbn = {0-7695-2038-3}, + timestamp = {Thu, 18 Dec 2014 16:57:40 +0100}, + biburl = {https://dblp.org/rec/bib/conf/ictai/2003}, + bibsource = {dblp computer science bibliography, https://dblp.org} +} + +@InProceedings{chronobt, +author="Nadel, Alexander +and Ryvchin, Vadim", +editor="Beyersdorff, Olaf +and Wintersteiger, Christoph M.", +title="Chronological Backtracking", +booktitle="Theory and Applications of Satisfiability Testing -- {SAT} 2018", +year="2018", +publisher="Springer International Publishing", +address="Cham", +pages="111--121", +abstract="Non-Chronological Backtracking (NCB) has been implemented in every modern CDCL SAT solver since the original CDCL solver GRASP. NCB's importance has never been questioned. This paper argues that NCB is not always helpful. We show how one can implement the alternative to NCB--Chronological Backtracking (CB)--in a modern SAT solver. We demonstrate that CB improves the performance of the winner of the latest SAT Competition, Maple{\_}LCM{\_}Dist, and the winner of the latest MaxSAT Evaluation Open-WBO.", +isbn="978-3-319-94144-8" +} + +@inproceedings{smith94phase, + author = "Barbara Smith", + title = "The Phase Transition in Constraint Satisfaction Problems: {A} {CL}oser Look at the Mushy Region", + booktitle = {{ECAI}'94}, + year = "1994" +} + +@inproceedings{swdia, + author = "Chanseok Oh", + title = "{MiniSat HACK 999ED, MiniSat HACK 1430ED and SWDiA5BY}", + booktitle = "SAT Competition 2014 Booklet", + year = "201", +} + +@inproceedings{lingeling, + author = "Armin Biere", + title = "Yet another Local Search Solver and Lingeling and Friends Entering the SAT Competition 2014", + booktitle = "SAT Competition 2014 Booklet", + year = "2014", +} + +@inproceedings{maple, + author="Tomas Balyo and Marijn J. H. Heule and Matti Jarvisalo", + title="{MapleLRB\_LCM, Maple\_LCM, Maple\_LCM\_Dist, MapleLRB\_LCMoccRestart and Glucose-3.0+width in SAT Competition 2017}", + booktitle = "Proceedings of SAT Competition 2017", + year="2018" +} + +@inproceedings{sat-comp-2014-armin, + author="Belov Anton and Diepold Daniel and Marijn J. H. Heule and Matti Jarvisalo", + title="{Yet another Local Search Solver and Lingeling and Friends Entering the SAT Competition 2014}", + booktitle = "Proceedings of SAT Competition 2014", + year="2014" +} + +@misc {nscc, + author="ASTAR and NTU and NUS and SUTD", + title="{National Supercomputing Centre (NSCC)} {S}ingapore", + url="https://www.nscc.sg/about-nscc/overview/", + year="2018" +} + +@misc {CMS, + author="Mate Soos", + title="{CryptoMiniSat SAT solver GitHub page}", + url="https://github.com/msoos/cryptominisat", + year="2018" +} + +@inproceedings{cheeseman91where, + author = "Peter Cheeseman and Bob Kanefsky and William M. Taylor", + title = "Where the Really Hard Problems Are", + booktitle = "IJCAI-91", + pages = "331--337", + year = "1991", +} + +@InProceedings{BVA, +author="Manthey, Norbert +and Heule, Marijn J. H. +and Biere, Armin", +editor="Biere, Armin +and Nahir, Amir +and Vos, Tanja", +title="Automated Reencoding of Boolean Formulas", +booktitle="Hardware and Software: Verification and Testing", +year="2013", +publisher="Springer Berlin Heidelberg", +address="Berlin, Heidelberg", +pages="102--117", +abstract="We present a novel preprocessing technique to automatically reduce the size of Boolean formulas. This technique, called Bounded Variable Addition (BVA), exchanges clauses for variables. Similar to other preprocessing techniques, BVA greedily lowers the sum of variables and clauses, a rough measure for the hardness to solve a formula. We show that cardinality constraints (CCs) can efficiently be reencoded: from a naive CC encoding, BVA automatically generates a compact encoding, which is smaller than sophisticated encodings. Experimental results show that applying BVA can improve SAT solving performance.", +isbn="978-3-642-39611-3" +} + +@InProceedings{BVE, +author="E{\'e}n, Niklas +and Biere, Armin", +editor="Bacchus, Fahiem +and Walsh, Toby", +title="Effective Preprocessing in {SAT} Through Variable and Clause Elimination", +booktitle="Theory and Applications of Satisfiability Testing", +year="2005", +publisher="Springer Berlin Heidelberg", +address="Berlin, Heidelberg", +pages="61--75", +abstract="Preprocessing SAT instances can reduce their size considerably. We combine variable elimination with subsumption and self-subsuming resolution, and show that these techniques not only shrink the formula further than previous preprocessing efforts based on variable elimination, but also decrease runtime of SAT solvers substantially for typical industrial SAT problems. We discuss critical implementation details that make the reduction procedure fast enough to be practical.", +isbn="978-3-540-31679-4" +} + +@INPROCEEDINGS{Selman95localsearch, + author = {Bart Selman and Henry Kautz and Bram Cohen}, + title = {Local Search Strategies for Satisfiability Testing}, + booktitle = {{DIMACS} Series in Discrete Mathematics and Theoretical Computer Science}, + year = {1995}, + pages = {521--532}, + publisher = {} +} diff --git a/cryptominisat/cppsrc/docs/satrace19-pdf/yalsat/splncs03.bst b/cryptominisat/cppsrc/docs/satrace19-pdf/yalsat/splncs03.bst new file mode 100644 index 00000000..32791691 --- /dev/null +++ b/cryptominisat/cppsrc/docs/satrace19-pdf/yalsat/splncs03.bst @@ -0,0 +1,1519 @@ +%% BibTeX bibliography style `splncs03' +%% +%% BibTeX bibliography style for use with numbered references in +%% Springer Verlag's "Lecture Notes in Computer Science" series. +%% (See Springer's documentation for llncs.cls for +%% more details of the suggested reference format.) Note that this +%% file will not work for author-year style citations. +%% +%% Use \documentclass{llncs} and \bibliographystyle{splncs03}, and cite +%% a reference with (e.g.) \cite{smith77} to get a "[1]" in the text. +%% +%% This file comes to you courtesy of Maurizio "Titto" Patrignani of +%% Dipartimento di Informatica e Automazione Universita' Roma Tre +%% +%% ================================================================================================ +%% This was file `titto-lncs-02.bst' produced on Wed Apr 1, 2009 +%% Edited by hand by titto based on `titto-lncs-01.bst' (see below) +%% +%% CHANGES (with respect to titto-lncs-01.bst): +%% - Removed the call to \urlprefix (thus no "URL" string is added to the output) +%% ================================================================================================ +%% This was file `titto-lncs-01.bst' produced on Fri Aug 22, 2008 +%% Edited by hand by titto based on `titto.bst' (see below) +%% +%% CHANGES (with respect to titto.bst): +%% - Removed the "capitalize" command for editors string "(eds.)" and "(ed.)" +%% - Introduced the functions titto.bbl.pages and titto.bbl.page for journal pages (without "pp.") +%% - Added a new.sentence command to separate with a dot booktitle and series in the inproceedings +%% - Commented all new.block commands before urls and notes (to separate them with a comma) +%% - Introduced the functions titto.bbl.volume for handling journal volumes (without "vol." label) +%% - Used for editors the same name conventions used for authors (see function format.in.ed.booktitle) +%% - Removed a \newblock to avoid long spaces between title and "In: ..." +%% - Added function titto.space.prefix to add a space instead of "~" after the (removed) "vol." label +%% ================================================================================================ +%% This was file `titto.bst', +%% generated with the docstrip utility. +%% +%% The original source files were: +%% +%% merlin.mbs (with options: `vonx,nm-rvvc,yr-par,jttl-rm,volp-com,jwdpg,jwdvol,numser,ser-vol,jnm-x,btit-rm,bt-rm,edparxc,bkedcap,au-col,in-col,fin-bare,pp,ed,abr,mth-bare,xedn,jabr,and-com,and-com-ed,xand,url,url-blk,em-x,nfss,') +%% ---------------------------------------- +%% *** Tentative .bst file for Springer LNCS *** +%% +%% Copyright 1994-2007 Patrick W Daly + % =============================================================== + % IMPORTANT NOTICE: + % This bibliographic style (bst) file has been generated from one or + % more master bibliographic style (mbs) files, listed above. + % + % This generated file can be redistributed and/or modified under the terms + % of the LaTeX Project Public License Distributed from CTAN + % archives in directory macros/latex/base/lppl.txt; either + % version 1 of the License, or any later version. + % =============================================================== + % Name and version information of the main mbs file: + % \ProvidesFile{merlin.mbs}[2007/04/24 4.20 (PWD, AO, DPC)] + % For use with BibTeX version 0.99a or later + %------------------------------------------------------------------- + % This bibliography style file is intended for texts in ENGLISH + % This is a numerical citation style, and as such is standard LaTeX. + % It requires no extra package to interface to the main text. + % The form of the \bibitem entries is + % \bibitem{key}... + % Usage of \cite is as follows: + % \cite{key} ==>> [#] + % \cite[chap. 2]{key} ==>> [#, chap. 2] + % where # is a number determined by the ordering in the reference list. + % The order in the reference list is alphabetical by authors. + %--------------------------------------------------------------------- + +ENTRY + { address + author + booktitle + chapter + edition + editor + eid + howpublished + institution + journal + key + month + note + number + organization + pages + publisher + school + series + title + type + url + volume + year + } + {} + { label } +INTEGERS { output.state before.all mid.sentence after.sentence after.block } +FUNCTION {init.state.consts} +{ #0 'before.all := + #1 'mid.sentence := + #2 'after.sentence := + #3 'after.block := +} +STRINGS { s t} +FUNCTION {output.nonnull} +{ 's := + output.state mid.sentence = + { ", " * write$ } + { output.state after.block = + { add.period$ write$ +% newline$ +% "\newblock " write$ % removed for titto-lncs-01 + " " write$ % to avoid long spaces between title and "In: ..." + } + { output.state before.all = + 'write$ + { add.period$ " " * write$ } + if$ + } + if$ + mid.sentence 'output.state := + } + if$ + s +} +FUNCTION {output} +{ duplicate$ empty$ + 'pop$ + 'output.nonnull + if$ +} +FUNCTION {output.check} +{ 't := + duplicate$ empty$ + { pop$ "empty " t * " in " * cite$ * warning$ } + 'output.nonnull + if$ +} +FUNCTION {fin.entry} +{ duplicate$ empty$ + 'pop$ + 'write$ + if$ + newline$ +} + +FUNCTION {new.block} +{ output.state before.all = + 'skip$ + { after.block 'output.state := } + if$ +} +FUNCTION {new.sentence} +{ output.state after.block = + 'skip$ + { output.state before.all = + 'skip$ + { after.sentence 'output.state := } + if$ + } + if$ +} +FUNCTION {add.blank} +{ " " * before.all 'output.state := +} + + +FUNCTION {add.colon} +{ duplicate$ empty$ + 'skip$ + { ":" * add.blank } + if$ +} + +FUNCTION {date.block} +{ + new.block +} + +FUNCTION {not} +{ { #0 } + { #1 } + if$ +} +FUNCTION {and} +{ 'skip$ + { pop$ #0 } + if$ +} +FUNCTION {or} +{ { pop$ #1 } + 'skip$ + if$ +} +STRINGS {z} +FUNCTION {remove.dots} +{ 'z := + "" + { z empty$ not } + { z #1 #1 substring$ + z #2 global.max$ substring$ 'z := + duplicate$ "." = 'pop$ + { * } + if$ + } + while$ +} +FUNCTION {new.block.checka} +{ empty$ + 'skip$ + 'new.block + if$ +} +FUNCTION {new.block.checkb} +{ empty$ + swap$ empty$ + and + 'skip$ + 'new.block + if$ +} +FUNCTION {new.sentence.checka} +{ empty$ + 'skip$ + 'new.sentence + if$ +} +FUNCTION {new.sentence.checkb} +{ empty$ + swap$ empty$ + and + 'skip$ + 'new.sentence + if$ +} +FUNCTION {field.or.null} +{ duplicate$ empty$ + { pop$ "" } + 'skip$ + if$ +} +FUNCTION {emphasize} +{ skip$ } +FUNCTION {tie.or.space.prefix} +{ duplicate$ text.length$ #3 < + { "~" } + { " " } + if$ + swap$ +} +FUNCTION {titto.space.prefix} % always introduce a space +{ duplicate$ text.length$ #3 < + { " " } + { " " } + if$ + swap$ +} + + +FUNCTION {capitalize} +{ "u" change.case$ "t" change.case$ } + +FUNCTION {space.word} +{ " " swap$ * " " * } + % Here are the language-specific definitions for explicit words. + % Each function has a name bbl.xxx where xxx is the English word. + % The language selected here is ENGLISH +FUNCTION {bbl.and} +{ "and"} + +FUNCTION {bbl.etal} +{ "et~al." } + +FUNCTION {bbl.editors} +{ "eds." } + +FUNCTION {bbl.editor} +{ "ed." } + +FUNCTION {bbl.edby} +{ "edited by" } + +FUNCTION {bbl.edition} +{ "edn." } + +FUNCTION {bbl.volume} +{ "vol." } + +FUNCTION {titto.bbl.volume} % for handling journals +{ "" } + +FUNCTION {bbl.of} +{ "of" } + +FUNCTION {bbl.number} +{ "no." } + +FUNCTION {bbl.nr} +{ "no." } + +FUNCTION {bbl.in} +{ "in" } + +FUNCTION {bbl.pages} +{ "pp." } + +FUNCTION {bbl.page} +{ "p." } + +FUNCTION {titto.bbl.pages} % for journals +{ "" } + +FUNCTION {titto.bbl.page} % for journals +{ "" } + +FUNCTION {bbl.chapter} +{ "chap." } + +FUNCTION {bbl.techrep} +{ "Tech. Rep." } + +FUNCTION {bbl.mthesis} +{ "Master's thesis" } + +FUNCTION {bbl.phdthesis} +{ "Ph.D. thesis" } + +MACRO {jan} {"Jan."} + +MACRO {feb} {"Feb."} + +MACRO {mar} {"Mar."} + +MACRO {apr} {"Apr."} + +MACRO {may} {"May"} + +MACRO {jun} {"Jun."} + +MACRO {jul} {"Jul."} + +MACRO {aug} {"Aug."} + +MACRO {sep} {"Sep."} + +MACRO {oct} {"Oct."} + +MACRO {nov} {"Nov."} + +MACRO {dec} {"Dec."} + +MACRO {acmcs} {"ACM Comput. Surv."} + +MACRO {acta} {"Acta Inf."} + +MACRO {cacm} {"Commun. ACM"} + +MACRO {ibmjrd} {"IBM J. Res. Dev."} + +MACRO {ibmsj} {"IBM Syst.~J."} + +MACRO {ieeese} {"IEEE Trans. Software Eng."} + +MACRO {ieeetc} {"IEEE Trans. Comput."} + +MACRO {ieeetcad} + {"IEEE Trans. Comput. Aid. Des."} + +MACRO {ipl} {"Inf. Process. Lett."} + +MACRO {jacm} {"J.~ACM"} + +MACRO {jcss} {"J.~Comput. Syst. Sci."} + +MACRO {scp} {"Sci. Comput. Program."} + +MACRO {sicomp} {"SIAM J. Comput."} + +MACRO {tocs} {"ACM Trans. Comput. Syst."} + +MACRO {tods} {"ACM Trans. Database Syst."} + +MACRO {tog} {"ACM Trans. Graphic."} + +MACRO {toms} {"ACM Trans. Math. Software"} + +MACRO {toois} {"ACM Trans. Office Inf. Syst."} + +MACRO {toplas} {"ACM Trans. Progr. Lang. Syst."} + +MACRO {tcs} {"Theor. Comput. Sci."} + +FUNCTION {bibinfo.check} +{ swap$ + duplicate$ missing$ + { + pop$ pop$ + "" + } + { duplicate$ empty$ + { + swap$ pop$ + } + { swap$ + pop$ + } + if$ + } + if$ +} +FUNCTION {bibinfo.warn} +{ swap$ + duplicate$ missing$ + { + swap$ "missing " swap$ * " in " * cite$ * warning$ pop$ + "" + } + { duplicate$ empty$ + { + swap$ "empty " swap$ * " in " * cite$ * warning$ + } + { swap$ + pop$ + } + if$ + } + if$ +} +FUNCTION {format.url} +{ url empty$ + { "" } +% { "\urlprefix\url{" url * "}" * } + { "\url{" url * "}" * } % changed in titto-lncs-02.bst + if$ +} + +INTEGERS { nameptr namesleft numnames } + + +STRINGS { bibinfo} + +FUNCTION {format.names} +{ 'bibinfo := + duplicate$ empty$ 'skip$ { + 's := + "" 't := + #1 'nameptr := + s num.names$ 'numnames := + numnames 'namesleft := + { namesleft #0 > } + { s nameptr + "{vv~}{ll}{, jj}{, f{.}.}" + format.name$ + bibinfo bibinfo.check + 't := + nameptr #1 > + { + namesleft #1 > + { ", " * t * } + { + s nameptr "{ll}" format.name$ duplicate$ "others" = + { 't := } + { pop$ } + if$ + "," * + t "others" = + { + " " * bbl.etal * + } + { " " * t * } + if$ + } + if$ + } + 't + if$ + nameptr #1 + 'nameptr := + namesleft #1 - 'namesleft := + } + while$ + } if$ +} +FUNCTION {format.names.ed} +{ + 'bibinfo := + duplicate$ empty$ 'skip$ { + 's := + "" 't := + #1 'nameptr := + s num.names$ 'numnames := + numnames 'namesleft := + { namesleft #0 > } + { s nameptr + "{f{.}.~}{vv~}{ll}{ jj}" + format.name$ + bibinfo bibinfo.check + 't := + nameptr #1 > + { + namesleft #1 > + { ", " * t * } + { + s nameptr "{ll}" format.name$ duplicate$ "others" = + { 't := } + { pop$ } + if$ + "," * + t "others" = + { + + " " * bbl.etal * + } + { " " * t * } + if$ + } + if$ + } + 't + if$ + nameptr #1 + 'nameptr := + namesleft #1 - 'namesleft := + } + while$ + } if$ +} +FUNCTION {format.authors} +{ author "author" format.names +} +FUNCTION {get.bbl.editor} +{ editor num.names$ #1 > 'bbl.editors 'bbl.editor if$ } + +FUNCTION {format.editors} +{ editor "editor" format.names duplicate$ empty$ 'skip$ + { + " " * + get.bbl.editor +% capitalize + "(" swap$ * ")" * + * + } + if$ +} +FUNCTION {format.note} +{ + note empty$ + { "" } + { note #1 #1 substring$ + duplicate$ "{" = + 'skip$ + { output.state mid.sentence = + { "l" } + { "u" } + if$ + change.case$ + } + if$ + note #2 global.max$ substring$ * "note" bibinfo.check + } + if$ +} + +FUNCTION {format.title} +{ title + duplicate$ empty$ 'skip$ + { "t" change.case$ } + if$ + "title" bibinfo.check +} +FUNCTION {output.bibitem} +{ newline$ + "\bibitem{" write$ + cite$ write$ + "}" write$ + newline$ + "" + before.all 'output.state := +} + +FUNCTION {n.dashify} +{ + 't := + "" + { t empty$ not } + { t #1 #1 substring$ "-" = + { t #1 #2 substring$ "--" = not + { "--" * + t #2 global.max$ substring$ 't := + } + { { t #1 #1 substring$ "-" = } + { "-" * + t #2 global.max$ substring$ 't := + } + while$ + } + if$ + } + { t #1 #1 substring$ * + t #2 global.max$ substring$ 't := + } + if$ + } + while$ +} + +FUNCTION {word.in} +{ bbl.in capitalize + ":" * + " " * } + +FUNCTION {format.date} +{ + month "month" bibinfo.check + duplicate$ empty$ + year "year" bibinfo.check duplicate$ empty$ + { swap$ 'skip$ + { "there's a month but no year in " cite$ * warning$ } + if$ + * + } + { swap$ 'skip$ + { + swap$ + " " * swap$ + } + if$ + * + remove.dots + } + if$ + duplicate$ empty$ + 'skip$ + { + before.all 'output.state := + " (" swap$ * ")" * + } + if$ +} +FUNCTION {format.btitle} +{ title "title" bibinfo.check + duplicate$ empty$ 'skip$ + { + } + if$ +} +FUNCTION {either.or.check} +{ empty$ + 'pop$ + { "can't use both " swap$ * " fields in " * cite$ * warning$ } + if$ +} +FUNCTION {format.bvolume} +{ volume empty$ + { "" } + { bbl.volume volume tie.or.space.prefix + "volume" bibinfo.check * * + series "series" bibinfo.check + duplicate$ empty$ 'pop$ + { emphasize ", " * swap$ * } + if$ + "volume and number" number either.or.check + } + if$ +} +FUNCTION {format.number.series} +{ volume empty$ + { number empty$ + { series field.or.null } + { output.state mid.sentence = + { bbl.number } + { bbl.number capitalize } + if$ + number tie.or.space.prefix "number" bibinfo.check * * + series empty$ + { "there's a number but no series in " cite$ * warning$ } + { bbl.in space.word * + series "series" bibinfo.check * + } + if$ + } + if$ + } + { "" } + if$ +} + +FUNCTION {format.edition} +{ edition duplicate$ empty$ 'skip$ + { + output.state mid.sentence = + { "l" } + { "t" } + if$ change.case$ + "edition" bibinfo.check + " " * bbl.edition * + } + if$ +} +INTEGERS { multiresult } +FUNCTION {multi.page.check} +{ 't := + #0 'multiresult := + { multiresult not + t empty$ not + and + } + { t #1 #1 substring$ + duplicate$ "-" = + swap$ duplicate$ "," = + swap$ "+" = + or or + { #1 'multiresult := } + { t #2 global.max$ substring$ 't := } + if$ + } + while$ + multiresult +} +FUNCTION {format.pages} +{ pages duplicate$ empty$ 'skip$ + { duplicate$ multi.page.check + { + bbl.pages swap$ + n.dashify + } + { + bbl.page swap$ + } + if$ + tie.or.space.prefix + "pages" bibinfo.check + * * + } + if$ +} +FUNCTION {format.journal.pages} +{ pages duplicate$ empty$ 'pop$ + { swap$ duplicate$ empty$ + { pop$ pop$ format.pages } + { + ", " * + swap$ + n.dashify + pages multi.page.check + 'titto.bbl.pages + 'titto.bbl.page + if$ + swap$ tie.or.space.prefix + "pages" bibinfo.check + * * + * + } + if$ + } + if$ +} +FUNCTION {format.journal.eid} +{ eid "eid" bibinfo.check + duplicate$ empty$ 'pop$ + { swap$ duplicate$ empty$ 'skip$ + { + ", " * + } + if$ + swap$ * + } + if$ +} +FUNCTION {format.vol.num.pages} % this function is used only for journal entries +{ volume field.or.null + duplicate$ empty$ 'skip$ + { +% bbl.volume swap$ tie.or.space.prefix + titto.bbl.volume swap$ titto.space.prefix +% rationale for the change above: for journals you don't want "vol." label +% hence it does not make sense to attach the journal number to the label when +% it is short + "volume" bibinfo.check + * * + } + if$ + number "number" bibinfo.check duplicate$ empty$ 'skip$ + { + swap$ duplicate$ empty$ + { "there's a number but no volume in " cite$ * warning$ } + 'skip$ + if$ + swap$ + "(" swap$ * ")" * + } + if$ * + eid empty$ + { format.journal.pages } + { format.journal.eid } + if$ +} + +FUNCTION {format.chapter.pages} +{ chapter empty$ + 'format.pages + { type empty$ + { bbl.chapter } + { type "l" change.case$ + "type" bibinfo.check + } + if$ + chapter tie.or.space.prefix + "chapter" bibinfo.check + * * + pages empty$ + 'skip$ + { ", " * format.pages * } + if$ + } + if$ +} + +FUNCTION {format.booktitle} +{ + booktitle "booktitle" bibinfo.check +} +FUNCTION {format.in.ed.booktitle} +{ format.booktitle duplicate$ empty$ 'skip$ + { +% editor "editor" format.names.ed duplicate$ empty$ 'pop$ % changed by titto + editor "editor" format.names duplicate$ empty$ 'pop$ + { + " " * + get.bbl.editor +% capitalize + "(" swap$ * ") " * + * swap$ + * } + if$ + word.in swap$ * + } + if$ +} +FUNCTION {empty.misc.check} +{ author empty$ title empty$ howpublished empty$ + month empty$ year empty$ note empty$ + and and and and and + key empty$ not and + { "all relevant fields are empty in " cite$ * warning$ } + 'skip$ + if$ +} +FUNCTION {format.thesis.type} +{ type duplicate$ empty$ + 'pop$ + { swap$ pop$ + "t" change.case$ "type" bibinfo.check + } + if$ +} +FUNCTION {format.tr.number} +{ number "number" bibinfo.check + type duplicate$ empty$ + { pop$ bbl.techrep } + 'skip$ + if$ + "type" bibinfo.check + swap$ duplicate$ empty$ + { pop$ "t" change.case$ } + { tie.or.space.prefix * * } + if$ +} +FUNCTION {format.article.crossref} +{ + key duplicate$ empty$ + { pop$ + journal duplicate$ empty$ + { "need key or journal for " cite$ * " to crossref " * crossref * warning$ } + { "journal" bibinfo.check emphasize word.in swap$ * } + if$ + } + { word.in swap$ * " " *} + if$ + " \cite{" * crossref * "}" * +} +FUNCTION {format.crossref.editor} +{ editor #1 "{vv~}{ll}" format.name$ + "editor" bibinfo.check + editor num.names$ duplicate$ + #2 > + { pop$ + "editor" bibinfo.check + " " * bbl.etal + * + } + { #2 < + 'skip$ + { editor #2 "{ff }{vv }{ll}{ jj}" format.name$ "others" = + { + "editor" bibinfo.check + " " * bbl.etal + * + } + { + bbl.and space.word + * editor #2 "{vv~}{ll}" format.name$ + "editor" bibinfo.check + * + } + if$ + } + if$ + } + if$ +} +FUNCTION {format.book.crossref} +{ volume duplicate$ empty$ + { "empty volume in " cite$ * "'s crossref of " * crossref * warning$ + pop$ word.in + } + { bbl.volume + capitalize + swap$ tie.or.space.prefix "volume" bibinfo.check * * bbl.of space.word * + } + if$ + editor empty$ + editor field.or.null author field.or.null = + or + { key empty$ + { series empty$ + { "need editor, key, or series for " cite$ * " to crossref " * + crossref * warning$ + "" * + } + { series emphasize * } + if$ + } + { key * } + if$ + } + { format.crossref.editor * } + if$ + " \cite{" * crossref * "}" * +} +FUNCTION {format.incoll.inproc.crossref} +{ + editor empty$ + editor field.or.null author field.or.null = + or + { key empty$ + { format.booktitle duplicate$ empty$ + { "need editor, key, or booktitle for " cite$ * " to crossref " * + crossref * warning$ + } + { word.in swap$ * } + if$ + } + { word.in key * " " *} + if$ + } + { word.in format.crossref.editor * " " *} + if$ + " \cite{" * crossref * "}" * +} +FUNCTION {format.org.or.pub} +{ 't := + "" + address empty$ t empty$ and + 'skip$ + { + t empty$ + { address "address" bibinfo.check * + } + { t * + address empty$ + 'skip$ + { ", " * address "address" bibinfo.check * } + if$ + } + if$ + } + if$ +} +FUNCTION {format.publisher.address} +{ publisher "publisher" bibinfo.warn format.org.or.pub +} + +FUNCTION {format.organization.address} +{ organization "organization" bibinfo.check format.org.or.pub +} + +FUNCTION {article} +{ output.bibitem + format.authors "author" output.check + add.colon + new.block + format.title "title" output.check + new.block + crossref missing$ + { + journal + "journal" bibinfo.check + "journal" output.check + add.blank + format.vol.num.pages output + format.date "year" output.check + } + { format.article.crossref output.nonnull + format.pages output + } + if$ +% new.block + format.url output +% new.block + format.note output + fin.entry +} +FUNCTION {book} +{ output.bibitem + author empty$ + { format.editors "author and editor" output.check + add.colon + } + { format.authors output.nonnull + add.colon + crossref missing$ + { "author and editor" editor either.or.check } + 'skip$ + if$ + } + if$ + new.block + format.btitle "title" output.check + crossref missing$ + { format.bvolume output + new.block + new.sentence + format.number.series output + format.publisher.address output + } + { + new.block + format.book.crossref output.nonnull + } + if$ + format.edition output + format.date "year" output.check +% new.block + format.url output +% new.block + format.note output + fin.entry +} +FUNCTION {booklet} +{ output.bibitem + format.authors output + add.colon + new.block + format.title "title" output.check + new.block + howpublished "howpublished" bibinfo.check output + address "address" bibinfo.check output + format.date output +% new.block + format.url output +% new.block + format.note output + fin.entry +} + +FUNCTION {inbook} +{ output.bibitem + author empty$ + { format.editors "author and editor" output.check + add.colon + } + { format.authors output.nonnull + add.colon + crossref missing$ + { "author and editor" editor either.or.check } + 'skip$ + if$ + } + if$ + new.block + format.btitle "title" output.check + crossref missing$ + { + format.bvolume output + format.chapter.pages "chapter and pages" output.check + new.block + new.sentence + format.number.series output + format.publisher.address output + } + { + format.chapter.pages "chapter and pages" output.check + new.block + format.book.crossref output.nonnull + } + if$ + format.edition output + format.date "year" output.check +% new.block + format.url output +% new.block + format.note output + fin.entry +} + +FUNCTION {incollection} +{ output.bibitem + format.authors "author" output.check + add.colon + new.block + format.title "title" output.check + new.block + crossref missing$ + { format.in.ed.booktitle "booktitle" output.check + format.bvolume output + format.chapter.pages output + new.sentence + format.number.series output + format.publisher.address output + format.edition output + format.date "year" output.check + } + { format.incoll.inproc.crossref output.nonnull + format.chapter.pages output + } + if$ +% new.block + format.url output +% new.block + format.note output + fin.entry +} +FUNCTION {inproceedings} +{ output.bibitem + format.authors "author" output.check + add.colon + new.block + format.title "title" output.check + new.block + crossref missing$ + { format.in.ed.booktitle "booktitle" output.check + new.sentence % added by titto + format.bvolume output + format.pages output + new.sentence + format.number.series output + publisher empty$ + { format.organization.address output } + { organization "organization" bibinfo.check output + format.publisher.address output + } + if$ + format.date "year" output.check + } + { format.incoll.inproc.crossref output.nonnull + format.pages output + } + if$ +% new.block + format.url output +% new.block + format.note output + fin.entry +} +FUNCTION {conference} { inproceedings } +FUNCTION {manual} +{ output.bibitem + author empty$ + { organization "organization" bibinfo.check + duplicate$ empty$ 'pop$ + { output + address "address" bibinfo.check output + } + if$ + } + { format.authors output.nonnull } + if$ + add.colon + new.block + format.btitle "title" output.check + author empty$ + { organization empty$ + { + address new.block.checka + address "address" bibinfo.check output + } + 'skip$ + if$ + } + { + organization address new.block.checkb + organization "organization" bibinfo.check output + address "address" bibinfo.check output + } + if$ + format.edition output + format.date output +% new.block + format.url output +% new.block + format.note output + fin.entry +} + +FUNCTION {mastersthesis} +{ output.bibitem + format.authors "author" output.check + add.colon + new.block + format.btitle + "title" output.check + new.block + bbl.mthesis format.thesis.type output.nonnull + school "school" bibinfo.warn output + address "address" bibinfo.check output + format.date "year" output.check +% new.block + format.url output +% new.block + format.note output + fin.entry +} + +FUNCTION {misc} +{ output.bibitem + format.authors output + add.colon + title howpublished new.block.checkb + format.title output + howpublished new.block.checka + howpublished "howpublished" bibinfo.check output + format.date output +% new.block + format.url output +% new.block + format.note output + fin.entry + empty.misc.check +} +FUNCTION {phdthesis} +{ output.bibitem + format.authors "author" output.check + add.colon + new.block + format.btitle + "title" output.check + new.block + bbl.phdthesis format.thesis.type output.nonnull + school "school" bibinfo.warn output + address "address" bibinfo.check output + format.date "year" output.check +% new.block + format.url output +% new.block + format.note output + fin.entry +} + +FUNCTION {proceedings} +{ output.bibitem + editor empty$ + { organization "organization" bibinfo.check output + } + { format.editors output.nonnull } + if$ + add.colon + new.block + format.btitle "title" output.check + format.bvolume output + editor empty$ + { publisher empty$ + { format.number.series output } + { + new.sentence + format.number.series output + format.publisher.address output + } + if$ + } + { publisher empty$ + { + new.sentence + format.number.series output + format.organization.address output } + { + new.sentence + format.number.series output + organization "organization" bibinfo.check output + format.publisher.address output + } + if$ + } + if$ + format.date "year" output.check +% new.block + format.url output +% new.block + format.note output + fin.entry +} + +FUNCTION {techreport} +{ output.bibitem + format.authors "author" output.check + add.colon + new.block + format.title + "title" output.check + new.block + format.tr.number output.nonnull + institution "institution" bibinfo.warn output + address "address" bibinfo.check output + format.date "year" output.check +% new.block + format.url output +% new.block + format.note output + fin.entry +} + +FUNCTION {unpublished} +{ output.bibitem + format.authors "author" output.check + add.colon + new.block + format.title "title" output.check + format.date output +% new.block + format.url output +% new.block + format.note "note" output.check + fin.entry +} + +FUNCTION {default.type} { misc } +READ +FUNCTION {sortify} +{ purify$ + "l" change.case$ +} +INTEGERS { len } +FUNCTION {chop.word} +{ 's := + 'len := + s #1 len substring$ = + { s len #1 + global.max$ substring$ } + 's + if$ +} +FUNCTION {sort.format.names} +{ 's := + #1 'nameptr := + "" + s num.names$ 'numnames := + numnames 'namesleft := + { namesleft #0 > } + { s nameptr + "{ll{ }}{ ff{ }}{ jj{ }}" + format.name$ 't := + nameptr #1 > + { + " " * + namesleft #1 = t "others" = and + { "zzzzz" * } + { t sortify * } + if$ + } + { t sortify * } + if$ + nameptr #1 + 'nameptr := + namesleft #1 - 'namesleft := + } + while$ +} + +FUNCTION {sort.format.title} +{ 't := + "A " #2 + "An " #3 + "The " #4 t chop.word + chop.word + chop.word + sortify + #1 global.max$ substring$ +} +FUNCTION {author.sort} +{ author empty$ + { key empty$ + { "to sort, need author or key in " cite$ * warning$ + "" + } + { key sortify } + if$ + } + { author sort.format.names } + if$ +} +FUNCTION {author.editor.sort} +{ author empty$ + { editor empty$ + { key empty$ + { "to sort, need author, editor, or key in " cite$ * warning$ + "" + } + { key sortify } + if$ + } + { editor sort.format.names } + if$ + } + { author sort.format.names } + if$ +} +FUNCTION {author.organization.sort} +{ author empty$ + { organization empty$ + { key empty$ + { "to sort, need author, organization, or key in " cite$ * warning$ + "" + } + { key sortify } + if$ + } + { "The " #4 organization chop.word sortify } + if$ + } + { author sort.format.names } + if$ +} +FUNCTION {editor.organization.sort} +{ editor empty$ + { organization empty$ + { key empty$ + { "to sort, need editor, organization, or key in " cite$ * warning$ + "" + } + { key sortify } + if$ + } + { "The " #4 organization chop.word sortify } + if$ + } + { editor sort.format.names } + if$ +} +FUNCTION {presort} +{ type$ "book" = + type$ "inbook" = + or + 'author.editor.sort + { type$ "proceedings" = + 'editor.organization.sort + { type$ "manual" = + 'author.organization.sort + 'author.sort + if$ + } + if$ + } + if$ + " " + * + year field.or.null sortify + * + " " + * + title field.or.null + sort.format.title + * + #1 entry.max$ substring$ + 'sort.key$ := +} +ITERATE {presort} +SORT +STRINGS { longest.label } +INTEGERS { number.label longest.label.width } +FUNCTION {initialize.longest.label} +{ "" 'longest.label := + #1 'number.label := + #0 'longest.label.width := +} +FUNCTION {longest.label.pass} +{ number.label int.to.str$ 'label := + number.label #1 + 'number.label := + label width$ longest.label.width > + { label 'longest.label := + label width$ 'longest.label.width := + } + 'skip$ + if$ +} +EXECUTE {initialize.longest.label} +ITERATE {longest.label.pass} +FUNCTION {begin.bib} +{ preamble$ empty$ + 'skip$ + { preamble$ write$ newline$ } + if$ + "\begin{thebibliography}{" longest.label * "}" * + write$ newline$ + "\providecommand{\url}[1]{\texttt{#1}}" + write$ newline$ + "\providecommand{\urlprefix}{URL }" + write$ newline$ +} +EXECUTE {begin.bib} +EXECUTE {init.state.consts} +ITERATE {call.type$} +FUNCTION {end.bib} +{ newline$ + "\end{thebibliography}" write$ newline$ +} +EXECUTE {end.bib} +%% End of customized bst file +%% +%% End of file `titto.bst'. + + diff --git a/cryptominisat/cppsrc/manpage-extras b/cryptominisat/cppsrc/manpage-extras new file mode 100644 index 00000000..41d29148 --- /dev/null +++ b/cryptominisat/cppsrc/manpage-extras @@ -0,0 +1,17 @@ +[=see also] +More documentation for the cryptominisat5 SAT solver can be found at https://www.msoos.org/cryptominisat5/ + +[=bug tracker] +Please don't hesitate to file any and all issues at: + +https://github.com/msoos/cryptominisat/issues + +[=copyright] +cryptominisat5 is under the +.B MIT +license. Please see https://opensource.org/licenses/MIT for the full text + + +[=authors] +cryptominisat5 is written and maintained by +.B Mate Soos soos.mate@gmail.com diff --git a/cryptominisat/cppsrc/pyproject.toml b/cryptominisat/cppsrc/pyproject.toml new file mode 100644 index 00000000..9a3eec39 --- /dev/null +++ b/cryptominisat/cppsrc/pyproject.toml @@ -0,0 +1,24 @@ +[build-system] +requires = ["setuptools>=42", "wheel", "toml", "pathlib"] +build-backend = "setuptools.build_meta" + +[project] +name = "pycryptosat" +version = "5.11.21" +description = "Bindings to CryptoMiniSat, an advanced SAT solver" +keywords = ["sat", "cryptography"] +license = { file = "LICENSE.txt" } +maintainers = [{name="Mate Soos", email="soos.mate@gmail.com"}] +authors = [{name="Mate Soos", email="soos.mate@gmail.com"}] +classifiers = [ + "Development Status :: 4 - Beta", + "Intended Audience :: Developers", + "Operating System :: OS Independent", + "Programming Language :: C++", + "Programming Language :: Python :: 3", + "Programming Language :: Python :: 3.5", + "License :: OSI Approved :: MIT License", + "Topic :: Utilities" + ] +requires-python = ">=3.5" +readme = "python/README.md" diff --git a/cryptominisat/cppsrc/python/LICENSE b/cryptominisat/cppsrc/python/LICENSE new file mode 100644 index 00000000..0323ff51 --- /dev/null +++ b/cryptominisat/cppsrc/python/LICENSE @@ -0,0 +1,26 @@ +pycryptominisat (all of the python bindings, including makefile, test, etc) +License: MIT +=========================== +Copyright (c) 2013, Ilan Schnell, Continuum Analytics, Inc. + 2014, Mate Soos + 2017, Pierre Vignet + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to +deal in the Software without restriction, including without limitation the +rights to use, copy, modify, merge, publish, distribute, sublicense, and/or +sell copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS +IN THE SOFTWARE. + +CryptoMiniSat is under an MIT license. Please see LICENSE.txt file diff --git a/cryptominisat/cppsrc/python/README.md b/cryptominisat/cppsrc/python/README.md new file mode 100644 index 00000000..c0958928 --- /dev/null +++ b/cryptominisat/cppsrc/python/README.md @@ -0,0 +1,108 @@ +# pycryptosat SAT solver + +This directory provides Python bindings to CryptoMiniSat on the C++ level, +i.e. when importing pycryptosat, the CryptoMiniSat solver becomes part of the +Python process itself. + +## Installing + +``` +pip install pycryptosat +``` + +## Compiling +If you don't want to use the pip package, you can compile it as: + +``` +apt-get install python-dev +python -m build +``` + +To help with debug, you can also: +``` +python setup.py bdist_wheel +``` + +## Usage + +The `pycryptosat` module has one object, `Solver` that has two functions +`solve` and `add_clause`. + +The funcion `add_clause()` takes an iterable list of literals such as +`[1, 2]` which represents the truth `1 or 2 = True`. For example, +`add_clause([1])` sets variable `1` to `True`. + +The function `solve()` solves the system of equations that have been added +with `add_clause()`: + +``` +>>> from pycryptosat import Solver +>>> s = Solver() +>>> s.add_clause([1, 2]) +>>> sat, solution = s.solve() +>>> print sat +True +>>> print solution +(None, True, True) +``` + +The return value is a tuple. First part of the tuple indicates whether the +problem is satisfiable. In this case, it's `True`, i.e. satisfiable. The second +part is a tuple contains the solution, preceded by None, so you can index into +it with the variable number. E.g. `solution[1]` returns the value for +variable `1`. + +The `solve()` method optionally takes an argument `assumptions` that +allows the user to set values to specific variables in the solver in a temporary +fashion. This means that in case the problem is satisfiable but e.g it's +unsatisfiable if variable 2 is FALSE, then `solve([-2])` will return +UNSAT. However, a subsequent call to `solve()` will still return a solution. +If instead of an assumption `add_clause()` would have been used, subsequent +`solve()` calls would have returned unsatisfiable. + +`Solver` takes the following keyword arguments: + * `time_limit`: the time limit (integer) + * `confl_limit`: the propagation limit (integer) + * `verbose`: the verbosity level (integer) + +Both `time_limit` and `confl_limit` set a budget to the solver. The former is based on time elapsed while the former is based on number of conflicts met during search. If the solver runs out of budget, it returns with `(None, None)`. If both limits are used, the solver will terminate whenever one of the limits are hit (whichever first). Warning: Results from `time_limit` may differ from run to run, depending on compute load, etc. Use `confl_limit` for more reproducible runs. + +## Example + +Let us consider the following clauses, represented using +the DIMACS `cnf `_ +format:: + +``` +p cnf 5 3 +1 -5 4 0 +-1 5 3 4 0 +-3 -4 0 +``` + +Here, we have 5 variables and 3 clauses, the first clause being +(x\ :sub:`1` or not x\ :sub:`5` or x\ :sub:`4`). +Note that the variable x\ :sub:`2` is not used in any of the clauses, +which means that for each solution with x\ :sub:`2` = True, we must +also have a solution with x\ :sub:`2` = False. In Python, each clause is +most conveniently represented as a list of integers. Naturally, it makes +sense to represent each solution also as a list of integers, where the sign +corresponds to the Boolean value (+ for True and - for False) and the +absolute value corresponds to i\ :sup:`th` variable:: + +``` +>>> import pycryptosat +>>> solver = pycryptosat.Solver() +>>> solver.add_clause([1, -5, 4]) +>>> solver.add_clause([-1, 5, 3, 4]) +>>> solver.add_clause([-3, -4]) +>>> solver.solve() +(True, (None, True, False, False, True, True)) +``` + +This solution translates to: x\ :sub:`1` = x\ :sub:`4` = x\ :sub:`5` = True, +x\ :sub:`2` = x\ :sub:`3` = False + +# Special options (e.g. LARGEMEM, etc) + +In case you need to e.g. have LARGEMEM, you must modify `setup.py` and add `'-DLARGE_OFFSETS'` to `extra_compile_args`. Similarly for other options. diff --git a/cryptominisat/cppsrc/python/src/GitSHA1.cpp b/cryptominisat/cppsrc/python/src/GitSHA1.cpp new file mode 100644 index 00000000..10b9d687 --- /dev/null +++ b/cryptominisat/cppsrc/python/src/GitSHA1.cpp @@ -0,0 +1,41 @@ +/****************************************** +Copyright (c) 2022, Mate Soos + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. +***********************************************/ + +#include "../../src/GitSHA1.h" + +const char* CMSat::get_version_sha1() +{ + static const char myversion_sha1[] = "python"; + return myversion_sha1; +} + +const char* CMSat::get_version_tag() +{ + static const char myversion_tag[] = "see-python-package-version"; + return myversion_tag; +} + +const char* CMSat::get_compilation_env() +{ + static const char compilation_env[] = "python"; + return compilation_env; +} diff --git a/cryptominisat/cppsrc/python/src/pycryptosat.cpp b/cryptominisat/cppsrc/python/src/pycryptosat.cpp new file mode 100644 index 00000000..a76dfd29 --- /dev/null +++ b/cryptominisat/cppsrc/python/src/pycryptosat.cpp @@ -0,0 +1,913 @@ +/************* +Python bindings to CryptoMiniSat (http://msoos.org) + +Copyright (c) 2013, Ilan Schnell, Continuum Analytics, Inc. + 2014, Mate Soos + 2017, Pierre Vignet + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. +**********************************/ + +#include +#include +#include +#include +#include +#include "../../src/cryptominisat.h" +using namespace CMSat; + +#define MODULE_NAME "pycryptosat" +#define MODULE_DOC "CryptoMiniSAT satisfiability solver." + +#define IS_INT(x) PyLong_Check(x) +#define MODULE_INIT_FUNC(name) \ +PyMODINIT_FUNC PyInit_ ## name(void); \ +PyMODINIT_FUNC PyInit_ ## name(void) + +typedef struct { + PyObject_HEAD + /* Type-specific fields go here. */ + SATSolver* cmsat; + std::vector tmp_cl_lits; + + int verbose; + double time_limit; + long confl_limit; +} Solver; +typedef void (*sighandler_t)(int); + +static const char solver_create_docstring[] = \ +"Solver(verbose=0, time_limit=max_numeric_limits, confl_limit=max_numeric_limits, threads=1)\n\ +Create Solver object.\n\ +\n\ +:param verbose: Verbosity level: 0: nothing printed; 15: very verbose.\n\ +:param time_limit: Propagation limit: abort after this many seconds has elapsed.\n\ +:param confl_limit: Propagation limit: abort after this many conflicts.\n\ + Default: never abort.\n\ +:param threads: Number of threads to use.\n\ +:type verbose: \n\ +:type time_limit: \n\ +:type confl_limit: \n\ +:type threads: "; + +static void setup_solver(Solver *self, PyObject *args, PyObject *kwds) +{ + static char const* kwlist[] = {"verbose", "time_limit", "confl_limit", "threads", NULL}; + + int num_threads = 1; + self->cmsat = NULL; + self->verbose = 0; + self->time_limit = std::numeric_limits::max(); + self->confl_limit = std::numeric_limits::max(); + + if (!PyArg_ParseTupleAndKeywords(args, kwds, "|idli", const_cast(kwlist), + &self->verbose, &self->time_limit, &self->confl_limit, &num_threads)) + { + return; + } + + if (self->verbose < 0) { + PyErr_SetString(PyExc_ValueError, "verbosity must be at least 0"); + return; + } + if (self->time_limit < 0) { + PyErr_SetString(PyExc_ValueError, "time_limit must be at least 0"); + return; + } + if (self->confl_limit < 0) { + PyErr_SetString(PyExc_ValueError, "conflict limit must be at least 0"); + return; + } + if (num_threads <= 0) { + PyErr_SetString(PyExc_ValueError, "number of threads must be at least 1"); + return; + } + + self->cmsat = new SATSolver; + self->cmsat->set_verbosity(self->verbose); + self->cmsat->set_max_time(self->time_limit); + self->cmsat->set_max_confl(self->confl_limit); + self->cmsat->set_num_threads(num_threads); + + return; +} + +static int convert_lit_to_sign_and_var(PyObject* lit, long& var, bool& sign) +{ + if (!IS_INT(lit)) { + PyErr_SetString(PyExc_TypeError, "integer expected !"); + return 0; + } + + long val = PyLong_AsLong(lit); + if (val == 0) { + PyErr_SetString(PyExc_ValueError, "non-zero integer expected"); + return 0; + } + if (val > std::numeric_limits::max()/2 + || val < std::numeric_limits::min()/2 + ) { + PyErr_Format(PyExc_ValueError, "integer %ld is too small or too large", val); + return 0; + } + + sign = (val < 0); + var = std::abs(val) - 1; + + return 1; +} + +static int parse_clause( + Solver *self + , PyObject *clause + , std::vector& lits +) { + PyObject *iterator = PyObject_GetIter(clause); + if (iterator == NULL) { + PyErr_SetString(PyExc_TypeError, "iterable object expected"); + return 0; + } + + PyObject *lit; + long int max_var = 0; + while ((lit = PyIter_Next(iterator)) != NULL) { + long var; + bool sign; + int ret = convert_lit_to_sign_and_var(lit, var, sign); + Py_DECREF(lit); + if (!ret) { + Py_DECREF(iterator); + return 0; + } + max_var = std::max(var, max_var); + + lits.push_back(Lit(var, sign)); + } + + if (!lits.empty() && max_var >= (long int)self->cmsat->nVars()) { + self->cmsat->new_vars(max_var-(long int)self->cmsat->nVars()+1); + } + + Py_DECREF(iterator); + if (PyErr_Occurred()) { + return 0; + } + + return 1; +} + +static int parse_xor_clause( + Solver *self + , PyObject *clause + , std::vector& vars +) { + PyObject *iterator = PyObject_GetIter(clause); + if (iterator == NULL) { + PyErr_SetString(PyExc_TypeError, "iterable object expected"); + return 0; + } + + PyObject *lit; + while ((lit = PyIter_Next(iterator)) != NULL) { + long var; + bool sign; + int ret = convert_lit_to_sign_and_var(lit, var, sign); + Py_DECREF(lit); + if (!ret) { + Py_DECREF(iterator); + return 0; + } + if (sign) { + PyErr_SetString(PyExc_ValueError, "XOR clause must contiain only positive variables (not inverted literals)"); + Py_DECREF(iterator); + return 0; + } + + if (var >= self->cmsat->nVars()) { + for(long i = (long)self->cmsat->nVars(); i <= var ; i++) { + self->cmsat->new_var(); + } + } + + vars.push_back(var); + } + Py_DECREF(iterator); + if (PyErr_Occurred()) { + return 0; + } + + return 1; +} + +PyDoc_STRVAR(start_getting_small_clauses_doc, +"EXPERIMENTAL\n\ +Start getting clauses." +); +static PyObject* start_getting_small_clauses(Solver *self, PyObject *args, PyObject *kwds) +{ + static char const* kwlist[] = {"max_len", "max_glue", NULL}; + + unsigned max_len; + unsigned max_glue; + if (!PyArg_ParseTupleAndKeywords(args, kwds, "II", const_cast(kwlist), &max_len, &max_glue)) { + return NULL; + } + + self->cmsat->start_getting_small_clauses(max_len, max_glue); + + Py_INCREF(Py_None); + return Py_None; +} + +PyDoc_STRVAR(get_next_small_clause_doc, +"EXPERIMENTAL\n\ +Start getting clauses." +); +static PyObject* get_next_small_clause(Solver *self, PyObject *args, PyObject *kwds) +{ + static char const* kwlist[] = {NULL}; + if (!PyArg_ParseTupleAndKeywords(args, kwds, "", const_cast(kwlist))) { + return NULL; + } + + std::vector lits; + bool ret = self->cmsat->get_next_small_clause(lits); + if (!ret) { + Py_INCREF(Py_None); + return Py_None; + } + + + PyObject* list = PyList_New(lits.size()); + for(size_t i = 0; i < lits.size(); i++) { + Lit l = lits[i]; + long ll = l.var()+1; + if (l.sign()) { + ll *= -1; + } + + PyList_SetItem(list, i, PyLong_FromLong(ll)); + } + return list; +} + + +PyDoc_STRVAR(end_getting_small_clauses_doc, +"EXPERIMENTAL\n\ +End getting clauses." +); +static PyObject* end_getting_small_clauses(Solver *self, PyObject *args, PyObject *kwds) +{ + static char const* kwlist[] = {NULL}; + if (!PyArg_ParseTupleAndKeywords(args, kwds, "", const_cast(kwlist))) { + return NULL; + } + self->cmsat->end_getting_small_clauses(); + + Py_INCREF(Py_None); + return Py_None; +} + +static int _add_clause(Solver *self, PyObject *clause) +{ + self->tmp_cl_lits.clear(); + if (!parse_clause(self, clause, self->tmp_cl_lits)) { + return 0; + } + self->cmsat->add_clause(self->tmp_cl_lits); + + return 1; +} + +PyDoc_STRVAR(add_clause_doc, +"add_clause(clause)\n\ +Add a clause to the solver.\n\ +\n\ +:param clause: A clause contains literals (ints)\n\ +:type clause: \n\ +:return: None\n\ +:rtype: " +); + +static PyObject* add_clause(Solver *self, PyObject *args, PyObject *kwds) +{ + static char const* kwlist[] = {"clause", NULL}; + PyObject *clause; + if (!PyArg_ParseTupleAndKeywords(args, kwds, "O", const_cast(kwlist), &clause)) { + return NULL; + } + + if (_add_clause(self, clause) == 0 ) { + return NULL; + } + + Py_INCREF(Py_None); + return Py_None; +} + +template +static int _add_clauses_from_array(Solver *self, const size_t array_length, const T *array) +{ + if (array_length == 0) { + return 1; + } + if (array[array_length - 1] != 0) { + PyErr_SetString(PyExc_ValueError, "last clause not terminated by zero"); + return 0; + } + size_t k = 0; + long val = 0; + std::vector& lits = self->tmp_cl_lits; + for (val = (long) array[k]; k < array_length; val = (long) array[++k]) { + lits.clear(); + long int max_var = 0; + for (; k < array_length && val != 0; val = (long) array[++k]) { + long var; + bool sign; + if (val > std::numeric_limits::max()/2 + || val < std::numeric_limits::min()/2 + ) { + PyErr_Format(PyExc_ValueError, "integer %ld is too small or too large", val); + return 0; + } + + sign = (val < 0); + var = std::abs(val) - 1; + max_var = std::max(var, max_var); + + lits.push_back(Lit(var, sign)); + } + if (!lits.empty()) { + if (max_var >= (long int)self->cmsat->nVars()) { + self->cmsat->new_vars(max_var-(long int)self->cmsat->nVars()+1); + } + self->cmsat->add_clause(lits); + } + } + return 1; +} + +static int _add_clauses_from_buffer(Solver *self, Py_buffer *view) +{ + if (view->ndim != 1) { + PyErr_Format(PyExc_ValueError, "invalid clause array: expected 1-D array, got %d-D", view->ndim); + return 0; + } + if (strcmp(view->format, "i") != 0 && strcmp(view->format, "l") != 0 && strcmp(view->format, "q") != 0) { + PyErr_Format(PyExc_ValueError, "invalid clause array: invalid format '%s'", view->format); + return 0; + } + + void * array_address = view->buf; + size_t itemsize = view->itemsize; + size_t array_length = view->len / itemsize; + + if (itemsize == sizeof(int)) { + return _add_clauses_from_array(self, array_length, (const int *) array_address); + } + if (itemsize == sizeof(long)) { + return _add_clauses_from_array(self, array_length, (const long *) array_address); + } + if (itemsize == sizeof(long long)) { + return _add_clauses_from_array(self, array_length, (const long long *) array_address); + } + PyErr_Format(PyExc_ValueError, "invalid clause array: invalid itemsize '%ld'", itemsize); + return 0; +} + +PyDoc_STRVAR(add_clauses_doc, +"add_clauses(clauses)\n\ +Add iterable of clauses to the solver.\n\ +\n\ +:param clauses: List of clauses. Each clause contains literals (ints)\n\ + Alternatively, this can be a flat array.array or other contiguous\n\ + buffer (format 'i', 'l', or 'q') of zero separated and terminated\n\ + clauses of literals (ints).\n\ +:type clauses: or \n\ +:return: None\n\ +:rtype: " +); + +static PyObject* add_clauses(Solver *self, PyObject *args, PyObject *kwds) +{ + static char const* kwlist[] = {"clauses", NULL}; + PyObject *clauses; + if (!PyArg_ParseTupleAndKeywords(args, kwds, "O", const_cast(kwlist), &clauses)) { + return NULL; + } + + if (PyObject_CheckBuffer(clauses)) { + Py_buffer view; + memset(&view, 0, sizeof(view)); + if (PyObject_GetBuffer(clauses, &view, PyBUF_CONTIG_RO | PyBUF_FORMAT) != 0) { + return NULL; + } + + int ret = _add_clauses_from_buffer(self, &view); + PyBuffer_Release(&view); + + if (ret == 0 || PyErr_Occurred()) { + return 0; + } + Py_INCREF(Py_None); + return Py_None; + } + + PyObject *iterator = PyObject_GetIter(clauses); + if (iterator == NULL) { + PyErr_SetString(PyExc_TypeError, "iterable object expected"); + return NULL; + } + + PyObject *clause; + while ((clause = PyIter_Next(iterator)) != NULL) { + _add_clause(self, clause); + /* release reference when done */ + Py_DECREF(clause); + } + + /* release reference when done */ + Py_DECREF(iterator); + if (PyErr_Occurred()) { + return NULL; + } + + Py_INCREF(Py_None); + return Py_None; +} + +static PyObject* add_xor_clause(Solver *self, PyObject *args, PyObject *kwds) +{ + static char const* kwlist[] = {"xor_clause", "rhs", NULL}; + PyObject *rhs; + PyObject *clause; + if (!PyArg_ParseTupleAndKeywords(args, kwds, "OO", const_cast(kwlist), &clause, &rhs)) { + return NULL; + } + if (!PyBool_Check(rhs)) { + PyErr_SetString(PyExc_TypeError, "rhs must be boolean"); + return NULL; + } + bool real_rhs = PyObject_IsTrue(rhs); + + std::vector vars; + if (!parse_xor_clause(self, clause, vars)) { + return 0; + } + + self->cmsat->add_xor_clause(vars, real_rhs); + + Py_INCREF(Py_None); + return Py_None; +} + +static PyObject* get_solution(SATSolver *cmsat) +{ + // Create tuple with the size of number of variables in model + unsigned max_idx = cmsat->nVars(); + PyObject *tuple = PyTuple_New((Py_ssize_t) max_idx+1); + if (tuple == NULL) { + PyErr_SetString(PyExc_SystemError, "failed to create a tuple"); + return NULL; + } + + Py_INCREF(Py_None); + PyTuple_SET_ITEM(tuple, (Py_ssize_t)0, Py_None); + + PyObject *py_value = NULL; + lbool v; + for (unsigned i = 0; i < max_idx; i++) { + v = cmsat->get_model()[i]; + + if (v == l_True) { + py_value = Py_True; + } else if (v == l_False) { + py_value = Py_False; + } else if (v == l_Undef) { + py_value = Py_None; + } else { + // v can only be l_False, l_True, l_Undef + assert((v == l_False) || (v == l_True) || (v == l_Undef)); + } + Py_INCREF(py_value); + PyTuple_SET_ITEM(tuple, (Py_ssize_t)i+1, py_value); + } + return tuple; +} + +static PyObject* get_raw_solution(SATSolver *cmsat) { + + // Create tuple with the size of number of variables in model + unsigned max_idx = cmsat->nVars(); + PyObject *tuple = PyTuple_New((Py_ssize_t) max_idx); + if (tuple == NULL) { + PyErr_SetString(PyExc_SystemError, "failed to create a tuple"); + return NULL; + } + + // Add each variable in model to the tuple + PyObject *py_value = NULL; + int sign; + for (long var = 0; var != (long)max_idx; var++) { + + if (cmsat->get_model()[var] != l_Undef) { + + sign = (cmsat->get_model()[var] == l_True) ? 1 : -1; + + py_value = PyLong_FromLong((var + 1) * sign); + PyTuple_SET_ITEM(tuple, (Py_ssize_t)var, py_value); + } + } + return tuple; +} + +PyDoc_STRVAR(nb_vars_doc, +"nb_vars()\n\ +Return the number of literals in the solver.\n\ +\n\ +:return: Number of literals\n\ +:rtype: " +); + +static PyObject* nb_vars(Solver *self) +{ + return PyLong_FromLong(self->cmsat->nVars()); + +} + +static int parse_assumption_lits(PyObject* assumptions, SATSolver* cmsat, std::vector& assumption_lits) +{ + PyObject *iterator = PyObject_GetIter(assumptions); + if (iterator == NULL) { + PyErr_SetString(PyExc_TypeError, "interable object expected"); + return 0; + } + + PyObject *lit; + while ((lit = PyIter_Next(iterator)) != NULL) { + long var; + bool sign; + int ret = convert_lit_to_sign_and_var(lit, var, sign); + Py_DECREF(lit); + if (!ret) { + Py_DECREF(iterator); + return 0; + } + + if (var >= cmsat->nVars()) { + Py_DECREF(iterator); + PyErr_Format(PyExc_ValueError, "Variable %ld not used in clauses", var+1); + return 0; + } + + assumption_lits.push_back(Lit(var, sign)); + } + Py_DECREF(iterator); + if (PyErr_Occurred()) { + return 0; + } + + return 1; +} + +PyDoc_STRVAR(solve_doc, +"solve(assumptions=None, verbose=None, time_limit=None, confl_limit=None)\n\ +Solve the system of equations that have been added with add_clause();\n\ +\n\ +.. example:: \n\ + from pycryptosat import Solver\n\ + >>> s = Solver()\n\ + >>> s.add_clause([1])\n\ + >>> s.add_clause([-2])\n\ + >>> s.add_clause([3])\n\ + >>> s.add_clause([-1, 2, 3])\n\ + >>> sat, solution = s.solve()\n\ + >>> print sat\n\ + True\n\ + >>> print solution\n\ + (None, True, False, True)\n\ + \n\ + We can also try to assume any variable values for a single solver run:\n\ + \n\ + sat, solution = s.solve([-3])\n\ + >>> print sat\n\ + False\n\ + >>> print solution\n\ + None\n\ +\n\ +:param assumptions: (Optional) Allows the user to set values to specific\n\ + ariables in the solver in a temporary fashion. This means that in case\n\ + the problem is satisfiable but e.g it's unsatisfiable if variable 2 is\n\ + FALSE, then solve([-2]) will return UNSAT. However, a subsequent call to\n\ + solve() will still return a solution.\n\ +:type assumptions: \n\ +:param verbose: (Optional) Allows the user to set a verbosity for just this\n\ + solve.\n\ +:type verbose: \n\ +:param time_limit: (Optional) Allows the user to set a timeout for just this\n\ + solve.\n\ +:type time_limit: \n\ +:param confl_limit: (Optional) Allows the user to set a conflict limit for just\n\ + this solve.\n\ +:type confl_limit: \n\ +:return: A tuple. First part of the tuple indicates whether the problem\n\ + is satisfiable. The second part is a tuple contains the solution,\n\ + preceded by None, so you can index into it with the variable number.\n\ + E.g. solution[1] returns the value for variable 1.\n\ +:rtype: >" +); + + +static PyObject* solve(Solver *self, PyObject *args, PyObject *kwds) +{ + PyObject* assumptions = NULL; + + int verbose = self->verbose; + double time_limit = self->time_limit; + long confl_limit = self->confl_limit; + + static char const* kwlist[] = {"assumptions", "verbose", "time_limit", "confl_limit", NULL}; + if (!PyArg_ParseTupleAndKeywords(args, kwds, "|Oidl", const_cast(kwlist), &assumptions, &verbose, &time_limit, &confl_limit)) { + return NULL; + } + if (verbose < 0) { + PyErr_SetString(PyExc_ValueError, "verbosity must be at least 0"); + return NULL; + } + if (time_limit < 0) { + PyErr_SetString(PyExc_ValueError, "time_limit must be at least 0"); + return NULL; + } + if (confl_limit < 0) { + PyErr_SetString(PyExc_ValueError, "conflict limit must be at least 0"); + return NULL; + } + + std::vector assumption_lits; + if (assumptions) { + if (!parse_assumption_lits(assumptions, self->cmsat, assumption_lits)) { + return 0; + } + } + + self->cmsat->set_verbosity(verbose); + self->cmsat->set_max_time(time_limit); + self->cmsat->set_max_confl(confl_limit); + + PyObject *result = PyTuple_New((Py_ssize_t) 2); + if (result == NULL) { + PyErr_SetString(PyExc_SystemError, "failed to create a tuple"); + return NULL; + } + + lbool res; + Py_BEGIN_ALLOW_THREADS /* release GIL */ + res = self->cmsat->solve(&assumption_lits); + Py_END_ALLOW_THREADS + + self->cmsat->set_verbosity(self->verbose); + self->cmsat->set_max_time(self->time_limit); + self->cmsat->set_max_confl(self->confl_limit); + + if (res == l_True) { + PyObject* solution = get_solution(self->cmsat); + if (!solution) { + Py_DECREF(result); + return NULL; + } + Py_INCREF(Py_True); + + PyTuple_SET_ITEM(result, 0, Py_True); + PyTuple_SET_ITEM(result, 1, solution); + + } else if (res == l_False) { + Py_INCREF(Py_False); + Py_INCREF(Py_None); + + PyTuple_SET_ITEM(result, 0, Py_False); + PyTuple_SET_ITEM(result, 1, Py_None); + + } else if (res == l_Undef) { + Py_INCREF(Py_None); + Py_INCREF(Py_None); + + PyTuple_SET_ITEM(result, 0, Py_None); + PyTuple_SET_ITEM(result, 1, Py_None); + } else { + // res can only be l_False, l_True, l_Undef + assert((res == l_False) || (res == l_True) || (res == l_Undef)); + Py_DECREF(result); + return PyErr_NewExceptionWithDoc("pycryptosat.IllegalState", "Error Occurred in CyrptoMiniSat", NULL, NULL); + } + + return result; +} + +PyDoc_STRVAR(is_satisfiable_doc, +"is_satisfiable()\n\ +Return satisfiability of the system.\n\ +\n\ +:return: True or False\n\ +:rtype: " +); + +static PyObject* is_satisfiable(Solver *self) +{ + lbool res; + Py_BEGIN_ALLOW_THREADS /* release GIL */ + res = self->cmsat->solve(); + Py_END_ALLOW_THREADS + + if (res == l_True) { + Py_INCREF(Py_True); + return Py_True; + } else if (res == l_False) { + Py_INCREF(Py_False); + return Py_False; + } else if (res == l_Undef) { + return Py_None; + } else { + // res can only be l_False, l_True, l_Undef + assert((res == l_False) || (res == l_True) || (res == l_Undef)); + return NULL; + } +} + +PyDoc_STRVAR(get_conflict_doc, +"get_conflict()\n\ +Returns the conflicts in the assumptions when the last call to solve(...)\n\ +was unsatisfiable.\n\ +\n\ +:return: Which assumptions (as passed to solve(...)) are incorrect\n\ +:rtype: >" +); + +static PyObject* get_conflict(Solver *self) +{ + const std::vector conflicts = self->cmsat->get_conflict(); + PyObject *result = PyList_New(0); + + for (unsigned long i = 0; i < conflicts.size(); i++) { + Lit lit = conflicts[i]; + long value = lit.var() + 1; + + if (lit.sign()) { + value *= -1; + } + + PyObject *item = PyLong_FromLong(value); + PyList_Append(result, item); + } + + return result; +} + +/*************************** Method definitions *************************/ + +static PyMethodDef Solver_methods[] = { + {"solve", (PyCFunction) solve, METH_VARARGS | METH_KEYWORDS, solve_doc}, + {"add_clause",(PyCFunction) add_clause, METH_VARARGS | METH_KEYWORDS, add_clause_doc}, + {"add_clauses", (PyCFunction) add_clauses, METH_VARARGS | METH_KEYWORDS, add_clauses_doc}, + {"add_xor_clause",(PyCFunction) add_xor_clause, METH_VARARGS | METH_KEYWORDS, "adds an XOR clause to the system"}, + {"nb_vars", (PyCFunction) nb_vars, METH_VARARGS | METH_KEYWORDS, nb_vars_doc}, + //{"nb_clauses", (PyCFunction) nb_clauses, METH_VARARGS | METH_KEYWORDS, "returns number of clauses"}, + {"is_satisfiable", (PyCFunction) is_satisfiable, METH_VARARGS | METH_KEYWORDS, is_satisfiable_doc}, + {"get_conflict", (PyCFunction) get_conflict, METH_VARARGS | METH_KEYWORDS, get_conflict_doc}, + + {"start_getting_small_clauses", (PyCFunction) start_getting_small_clauses, METH_VARARGS | METH_KEYWORDS, start_getting_small_clauses_doc}, + {"get_next_small_clause", (PyCFunction) get_next_small_clause, METH_VARARGS | METH_KEYWORDS, get_next_small_clause_doc}, + {"end_getting_small_clauses", (PyCFunction) end_getting_small_clauses, METH_VARARGS | METH_KEYWORDS, end_getting_small_clauses_doc}, + {NULL, NULL} /* sentinel - marks the end of this structure */ +}; + +static void +Solver_dealloc(Solver* self) +{ + delete self->cmsat; + Py_TYPE(self)->tp_free ((PyObject*) self); +} + +static int +Solver_init(Solver *self, PyObject *args, PyObject *kwds) +{ + if (self->cmsat != NULL) { + delete self->cmsat; + } + + setup_solver(self, args, kwds); + if (!self->cmsat) { + return -1; + } + return 0; +} + +static PyTypeObject pycryptosat_SolverType = { + PyVarObject_HEAD_INIT(NULL, 0) /*ob_size*/ + "pycryptosat.Solver", /*tp_name*/ + sizeof(Solver), /*tp_basicsize*/ + 0, /*tp_itemsize*/ + (destructor)Solver_dealloc, /*tp_dealloc*/ + 0, /*tp_print*/ + 0, /*tp_getattr*/ + 0, /*tp_setattr*/ + 0, /*tp_compare*/ + 0, /*tp_repr*/ + 0, /*tp_as_number*/ + 0, /*tp_as_sequence*/ + 0, /*tp_as_mapping*/ + 0, /*tp_hash */ + 0, /*tp_call*/ + 0, /*tp_str*/ + 0, /*tp_getattro*/ + 0, /*tp_setattro*/ + 0, /*tp_as_buffer*/ + Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /*tp_flags*/ + solver_create_docstring, /* tp_doc */ + 0, /* tp_traverse */ + 0, /* tp_clear */ + 0, /* tp_richcompare */ + 0, /* tp_weaklistoffset */ + 0, /* tp_iter */ + 0, /* tp_iternext */ + Solver_methods, /* tp_methods */ + 0, /* tp_members */ + 0, /* tp_getset */ + 0, /* tp_base */ + 0, /* tp_dict */ + 0, /* tp_descr_get */ + 0, /* tp_descr_set */ + 0, /* tp_dictoffset */ + (initproc)Solver_init, /* tp_init */ +}; + +MODULE_INIT_FUNC(pycryptosat) +{ + PyObject* m; + + pycryptosat_SolverType.tp_new = PyType_GenericNew; + if (PyType_Ready(&pycryptosat_SolverType) < 0) { + // Return NULL on Python3 and on Python2 with MODULE_INIT_FUNC macro + // In pure Python2: return nothing. + return NULL; + } + + static struct PyModuleDef moduledef = { + PyModuleDef_HEAD_INIT, /* m_base */ + MODULE_NAME, /* m_name */ + MODULE_DOC, /* m_doc */ + -1, /* m_size */ + NULL, /* m_methods */ + NULL, /* m_reload */ + NULL, /* m_traverse */ + NULL, /* m_clear */ + NULL, /* m_free */ + }; + + m = PyModule_Create(&moduledef); + + // Return NULL on Python3 and on Python2 with MODULE_INIT_FUNC macro + // In pure Python2: return nothing. + if (!m) { + return NULL; + } + + // Add the version string so users know what version of CryptoMiniSat + // they're using. +#if defined(_MSC_VER) +#else + if (PyModule_AddStringConstant(m, "__version__", CMS_FULL_VERSION) == -1) { + Py_DECREF(m); + return NULL; + } + if (PyModule_AddStringConstant(m, "VERSION", CMS_FULL_VERSION) == -1) { + Py_DECREF(m); + return NULL; + } +#endif + + + // Add the Solver type. + Py_INCREF(&pycryptosat_SolverType); + if (PyModule_AddObject(m, "Solver", (PyObject *)&pycryptosat_SolverType)) { + Py_DECREF(m); + return NULL; + } + + return m; +} diff --git a/cryptominisat/cppsrc/python/tests/__init__.py b/cryptominisat/cppsrc/python/tests/__init__.py new file mode 100644 index 00000000..a46f08c7 --- /dev/null +++ b/cryptominisat/cppsrc/python/tests/__init__.py @@ -0,0 +1 @@ +from .test_pycryptosat import * diff --git a/cryptominisat/cppsrc/python/tests/f400-r425-x000.cnf b/cryptominisat/cppsrc/python/tests/f400-r425-x000.cnf new file mode 100644 index 00000000..ec7907bd --- /dev/null +++ b/cryptominisat/cppsrc/python/tests/f400-r425-x000.cnf @@ -0,0 +1,1702 @@ +c seed= 2121884153 +p cnf 400 1700 +329 -142 -192 0 +-391 -76 350 0 +305 380 -359 0 +260 16 383 0 +119 71 388 0 +106 171 398 0 +-387 -91 -237 0 +322 -202 -32 0 +-136 -106 380 0 +91 -70 267 0 +-237 69 -232 0 +-347 304 22 0 +187 -113 -73 0 +-183 -79 -24 0 +358 -190 -395 0 +284 -8 -26 0 +398 -92 198 0 +-338 -13 53 0 +-280 317 -27 0 +276 -387 268 0 +180 398 -46 0 +-99 -14 -281 0 +-189 -321 -71 0 +189 161 121 0 +-294 243 -137 0 +199 244 400 0 +-180 -314 297 0 +84 -42 -278 0 +-30 318 -233 0 +-238 -204 239 0 +97 -156 233 0 +-145 -101 83 0 +78 -298 400 0 +-373 -196 -115 0 +-283 381 -337 0 +109 331 97 0 +62 171 -118 0 +-103 -241 278 0 +-251 120 -191 0 +-147 158 313 0 +-377 291 29 0 +-42 -245 -176 0 +90 -395 -132 0 +362 -347 -302 0 +-37 362 -287 0 +47 373 6 0 +81 -38 -385 0 +147 -190 -271 0 +-60 -22 -216 0 +-89 113 41 0 +91 60 10 0 +-188 -167 396 0 +352 120 236 0 +-92 360 317 0 +386 -361 -106 0 +-14 -377 130 0 +-333 -164 -334 0 +374 -191 379 0 +105 56 191 0 +-365 299 -375 0 +92 290 190 0 +389 196 -329 0 +134 49 311 0 +-295 -314 -330 0 +52 250 -190 0 +-238 -315 -306 0 +192 -77 269 0 +-192 -388 -296 0 +-328 346 18 0 +148 34 104 0 +-305 -248 194 0 +-284 370 309 0 +-399 -186 -198 0 +-350 -167 -146 0 +173 -74 -113 0 +107 -219 322 0 +181 -216 70 0 +252 -318 -248 0 +-201 -65 157 0 +25 156 205 0 +211 394 336 0 +184 26 83 0 +316 317 -271 0 +105 -118 49 0 +344 -40 139 0 +169 291 19 0 +324 159 -289 0 +360 230 271 0 +-166 1 -258 0 +198 -61 -264 0 +-313 -280 283 0 +195 212 -319 0 +-37 -81 111 0 +399 -27 312 0 +128 -38 137 0 +335 189 -79 0 +-378 266 130 0 +177 -337 379 0 +-150 194 -266 0 +137 129 -48 0 +-72 -359 113 0 +-69 -104 -49 0 +-96 128 -333 0 +217 69 -273 0 +-92 -218 3 0 +16 -66 384 0 +-312 -236 -214 0 +-308 -80 -245 0 +271 -273 183 0 +17 -398 33 0 +397 104 43 0 +90 94 397 0 +-372 -265 60 0 +-331 -279 388 0 +-280 -343 -291 0 +-290 -261 82 0 +142 -282 358 0 +-119 61 -179 0 +246 110 -66 0 +-126 54 -333 0 +-346 207 -58 0 +243 -231 -132 0 +114 -39 -280 0 +79 -13 -217 0 +38 -323 -349 0 +120 -188 -72 0 +379 -361 -392 0 +281 177 -350 0 +-220 50 82 0 +-331 135 -153 0 +96 128 -135 0 +279 186 -165 0 +181 -80 -356 0 +-151 -11 -377 0 +-14 232 207 0 +113 -157 390 0 +3 106 -335 0 +-346 -108 -261 0 +227 243 -14 0 +-276 391 147 0 +297 221 -317 0 +-387 -21 -248 0 +55 36 234 0 +270 -66 -169 0 +149 96 -137 0 +-55 -377 65 0 +65 153 55 0 +391 -80 -228 0 +101 215 -132 0 +-319 -198 399 0 +-251 98 8 0 +-301 37 279 0 +-147 291 384 0 +-344 118 -96 0 +-379 209 341 0 +56 -17 -82 0 +189 -183 -90 0 +323 -235 232 0 +186 -55 -366 0 +377 107 16 0 +253 43 -246 0 +-340 247 -262 0 +-370 -139 184 0 +353 -134 -349 0 +126 -294 88 0 +-323 15 -118 0 +-200 -192 373 0 +11 -93 280 0 +89 -149 -361 0 +370 -96 172 0 +84 -110 -300 0 +376 -381 344 0 +89 51 112 0 +196 285 -57 0 +-337 -147 -122 0 +393 -191 371 0 +-397 319 -84 0 +359 259 -127 0 +-331 326 159 0 +-366 -321 82 0 +-300 373 331 0 +-374 213 192 0 +86 15 -172 0 +87 367 -179 0 +-180 -223 -83 0 +-353 -161 388 0 +-157 -308 17 0 +214 2 87 0 +238 252 90 0 +-130 228 121 0 +-227 345 94 0 +369 -336 -287 0 +-9 49 -157 0 +-219 -174 125 0 +-159 318 352 0 +212 260 -239 0 +236 345 354 0 +-278 290 -142 0 +-308 107 300 0 +156 -77 -310 0 +2 -119 -154 0 +-258 163 -74 0 +-303 -162 197 0 +122 -6 192 0 +364 -145 186 0 +167 205 -162 0 +1 -205 -251 0 +381 222 -248 0 +166 290 352 0 +370 -178 -389 0 +-198 -121 -348 0 +400 393 -100 0 +336 351 240 0 +-32 149 298 0 +227 -26 -240 0 +359 281 -362 0 +-154 239 -297 0 +271 327 170 0 +22 -45 301 0 +381 158 334 0 +-14 -283 297 0 +279 -294 128 0 +369 197 115 0 +-52 -206 -119 0 +254 293 -312 0 +-39 -52 225 0 +-196 -38 -143 0 +220 -104 -210 0 +105 137 128 0 +250 -216 108 0 +41 -232 -279 0 +81 -343 -60 0 +-188 389 298 0 +-271 379 -120 0 +213 -356 -297 0 +99 61 -320 0 +400 310 -362 0 +-205 -225 -71 0 +85 396 275 0 +238 -109 -384 0 +-174 -383 -64 0 +113 -311 -203 0 +-108 125 -63 0 +-74 -263 135 0 +329 -160 140 0 +267 18 -5 0 +271 -127 226 0 +263 -212 222 0 +65 15 214 0 +-181 -243 295 0 +295 324 -108 0 +-215 76 -201 0 +-90 362 -69 0 +214 303 -376 0 +114 -234 -37 0 +98 351 18 0 +-232 -16 298 0 +241 48 -311 0 +222 76 4 0 +391 -120 241 0 +-122 -177 248 0 +-314 -117 -64 0 +112 341 22 0 +74 -374 -264 0 +85 -161 -389 0 +174 -261 197 0 +22 -264 -199 0 +-12 138 143 0 +-221 136 316 0 +305 249 149 0 +-265 299 100 0 +142 -245 -266 0 +-142 245 -333 0 +-178 -354 131 0 +-34 245 143 0 +-22 257 117 0 +123 -363 -137 0 +184 -348 -167 0 +-63 -361 -253 0 +87 390 -389 0 +-48 145 -238 0 +-8 292 -68 0 +65 367 -221 0 +34 98 -363 0 +-30 -329 -309 0 +-399 108 -128 0 +-293 -231 -188 0 +138 -342 -289 0 +-360 -158 21 0 +194 25 -190 0 +-134 345 -358 0 +109 376 363 0 +-218 -377 -230 0 +382 -246 15 0 +263 -313 -387 0 +-255 -99 277 0 +393 372 -287 0 +-195 389 -55 0 +281 28 -186 0 +257 196 169 0 +127 54 185 0 +-314 -209 371 0 +-278 310 131 0 +273 165 -109 0 +-314 267 -284 0 +-167 187 -88 0 +350 358 65 0 +62 -339 -41 0 +-273 -95 393 0 +-21 -321 270 0 +-291 73 -21 0 +-235 277 71 0 +-31 -210 -71 0 +300 178 -340 0 +-295 -82 -316 0 +399 133 341 0 +-132 249 144 0 +286 129 -53 0 +-249 -51 -87 0 +-134 189 230 0 +-270 303 203 0 +-29 -357 65 0 +-367 -348 244 0 +329 104 -397 0 +163 -376 -79 0 +15 246 189 0 +338 388 -17 0 +117 -30 27 0 +259 -329 385 0 +98 -59 106 0 +-62 320 -279 0 +262 -378 225 0 +309 -48 -268 0 +216 170 149 0 +330 74 -54 0 +-117 214 -279 0 +185 277 296 0 +199 -367 -226 0 +-286 -69 -306 0 +-30 -150 -356 0 +-394 -254 322 0 +-143 289 -165 0 +-217 -399 141 0 +82 -255 -63 0 +-221 -173 384 0 +-237 -153 -326 0 +398 120 -318 0 +-336 -278 -68 0 +70 -304 243 0 +-318 -63 207 0 +374 379 118 0 +-328 86 -214 0 +-314 -87 -152 0 +-17 184 -277 0 +-245 185 -132 0 +368 -11 204 0 +131 -140 -329 0 +-218 249 165 0 +294 -150 -63 0 +192 -157 -66 0 +-149 78 66 0 +-195 245 -66 0 +-154 -358 -202 0 +-197 -76 133 0 +-92 340 201 0 +164 315 -388 0 +-156 13 -345 0 +174 -240 42 0 +-310 -306 346 0 +-86 111 -34 0 +148 383 -114 0 +-236 -319 344 0 +-264 217 -222 0 +128 53 236 0 +-119 -132 365 0 +304 117 -370 0 +39 -198 196 0 +34 57 -46 0 +-369 252 163 0 +-64 30 -333 0 +-24 19 -136 0 +245 -212 165 0 +-216 367 -13 0 +-141 129 16 0 +-272 -89 -294 0 +224 184 -215 0 +326 -372 200 0 +-399 130 99 0 +127 84 386 0 +359 -162 -100 0 +-400 -141 91 0 +-153 -329 -93 0 +36 322 184 0 +-392 -363 -162 0 +388 15 213 0 +346 169 -223 0 +157 -39 -107 0 +-255 -330 350 0 +-68 -54 149 0 +-232 -370 171 0 +-127 305 -61 0 +-175 400 -336 0 +-261 54 159 0 +-348 -111 -179 0 +-204 -123 -82 0 +218 -245 -345 0 +-175 -319 -235 0 +292 -364 -87 0 +174 -73 191 0 +-64 -228 -156 0 +137 -323 70 0 +268 -326 -133 0 +87 231 198 0 +206 358 348 0 +-29 -325 199 0 +-57 -158 -274 0 +-340 58 -303 0 +-210 150 73 0 +-234 31 -213 0 +104 -7 -350 0 +206 199 31 0 +8 -168 -230 0 +-152 352 41 0 +-31 -97 249 0 +-221 285 186 0 +43 392 -126 0 +246 31 -121 0 +-366 -395 167 0 +-225 -201 77 0 +252 -216 142 0 +364 -331 -223 0 +-43 153 -180 0 +378 97 66 0 +-76 231 -387 0 +362 -106 -101 0 +-334 -57 -272 0 +-305 92 -284 0 +-155 -183 110 0 +-358 -306 394 0 +-230 -371 -306 0 +271 310 360 0 +321 -322 -148 0 +-217 -63 -88 0 +394 -144 223 0 +188 173 202 0 +396 -326 -87 0 +364 339 -328 0 +-17 -263 -347 0 +-373 -134 228 0 +-26 212 391 0 +356 -204 -323 0 +-49 75 232 0 +-212 106 187 0 +-195 134 -13 0 +-192 258 249 0 +-179 392 -260 0 +394 385 -45 0 +101 76 -239 0 +-118 -284 -84 0 +-167 48 173 0 +71 312 151 0 +300 -358 24 0 +-29 234 364 0 +170 191 -337 0 +-120 390 241 0 +-4 -26 285 0 +193 -159 -158 0 +-104 35 -77 0 +72 23 243 0 +152 299 -56 0 +-317 -145 389 0 +-354 -395 -55 0 +354 219 -95 0 +35 -260 370 0 +-343 -371 47 0 +362 231 285 0 +-198 -289 -81 0 +-264 258 62 0 +306 -273 -110 0 +375 -396 250 0 +161 -259 346 0 +-83 -358 169 0 +6 -376 -330 0 +-269 -190 393 0 +257 -391 -89 0 +270 -76 245 0 +-47 154 -314 0 +-239 -226 -1 0 +-288 112 -75 0 +325 298 -34 0 +-351 273 24 0 +-152 -37 200 0 +91 346 -292 0 +329 352 -247 0 +46 59 185 0 +379 326 364 0 +-48 177 -390 0 +313 284 -41 0 +292 -207 -9 0 +-329 159 202 0 +204 119 -55 0 +-120 -167 255 0 +-157 277 -284 0 +254 -276 321 0 +6 -294 -192 0 +-336 -114 -2 0 +-68 352 239 0 +-322 121 -31 0 +367 75 339 0 +272 246 -102 0 +-298 339 125 0 +371 -348 -309 0 +363 -143 -393 0 +56 266 239 0 +154 -327 -324 0 +218 -238 -295 0 +-58 -45 -111 0 +-180 8 327 0 +180 -124 330 0 +231 -105 284 0 +255 -186 381 0 +352 330 74 0 +-349 -278 -298 0 +318 -181 280 0 +160 -40 115 0 +206 332 -249 0 +-167 383 -3 0 +178 -393 -379 0 +231 89 -112 0 +-73 47 -361 0 +250 198 -320 0 +-172 -53 334 0 +275 21 274 0 +185 -230 -85 0 +-217 316 370 0 +118 304 160 0 +-292 173 99 0 +107 173 -315 0 +329 163 143 0 +-336 -227 -302 0 +-266 -25 260 0 +23 257 386 0 +-14 92 8 0 +241 -304 100 0 +322 203 240 0 +-83 277 171 0 +106 275 392 0 +-278 -361 -68 0 +-223 81 -347 0 +-335 337 369 0 +-321 145 -256 0 +-130 144 -335 0 +-49 64 193 0 +160 -123 -113 0 +-272 330 64 0 +220 327 -271 0 +-134 -51 -68 0 +124 -300 -93 0 +351 322 237 0 +280 198 379 0 +-243 131 375 0 +51 102 -285 0 +-370 -301 -372 0 +187 91 44 0 +-291 -330 -61 0 +326 196 394 0 +85 -67 -147 0 +41 -106 175 0 +-134 306 -357 0 +40 -124 336 0 +364 -270 -37 0 +354 205 119 0 +326 -118 311 0 +-367 -215 288 0 +281 335 -195 0 +9 350 360 0 +-49 -163 -189 0 +372 92 383 0 +-264 110 -231 0 +223 264 60 0 +60 -391 -395 0 +-355 -35 -319 0 +-8 77 -176 0 +6 -174 380 0 +-361 -51 -226 0 +66 30 -199 0 +-216 355 172 0 +-171 8 -400 0 +-216 -354 36 0 +-109 101 -314 0 +-141 138 314 0 +76 317 -172 0 +122 -173 -179 0 +335 237 -33 0 +-185 -91 -226 0 +286 116 -387 0 +16 34 51 0 +310 353 225 0 +-118 -265 82 0 +-227 -323 106 0 +301 -209 149 0 +-373 374 140 0 +-380 373 275 0 +2 -130 -69 0 +-99 57 128 0 +237 -312 260 0 +91 -75 144 0 +-104 381 132 0 +135 91 225 0 +-8 -224 16 0 +-187 217 -339 0 +-168 -196 -162 0 +-23 -33 -144 0 +-249 -49 322 0 +-384 -210 223 0 +-25 -83 -370 0 +-51 200 -270 0 +279 -85 182 0 +205 391 -96 0 +-173 -351 108 0 +-149 -373 -87 0 +144 338 -270 0 +-163 -331 -321 0 +-392 109 -102 0 +385 -359 19 0 +47 -54 -291 0 +-155 267 -67 0 +261 -393 2 0 +244 328 -14 0 +-365 -350 158 0 +253 40 -68 0 +273 -231 -9 0 +-362 -19 184 0 +-221 394 399 0 +385 -206 266 0 +-157 -344 -249 0 +-14 -263 -107 0 +-165 -67 -331 0 +-19 154 -75 0 +-284 -323 -74 0 +-359 -172 -109 0 +83 313 361 0 +53 -51 35 0 +-16 121 42 0 +267 -333 382 0 +-278 72 -207 0 +-71 332 -217 0 +-216 -220 150 0 +136 308 110 0 +289 251 -352 0 +-133 -174 208 0 +-191 -76 232 0 +-216 16 -236 0 +34 271 -329 0 +114 229 -97 0 +-67 121 372 0 +242 79 -191 0 +89 -247 354 0 +298 -198 311 0 +-376 -6 384 0 +-222 -40 140 0 +309 -59 11 0 +390 -172 -241 0 +-336 248 153 0 +1 353 50 0 +355 -198 63 0 +379 252 290 0 +-335 244 -144 0 +130 75 342 0 +327 225 -271 0 +352 -67 -45 0 +-198 395 190 0 +-59 -270 -192 0 +-248 173 -356 0 +107 334 357 0 +224 117 -87 0 +158 231 -146 0 +-247 280 302 0 +-368 233 -70 0 +-7 79 -361 0 +-383 230 -290 0 +172 111 -106 0 +350 -208 255 0 +148 -165 -72 0 +245 397 122 0 +-331 245 -358 0 +-47 -37 -372 0 +127 208 93 0 +172 -158 6 0 +286 123 345 0 +-135 161 -52 0 +353 331 -325 0 +162 -18 -301 0 +266 185 147 0 +394 -185 39 0 +86 224 248 0 +-34 39 -21 0 +-118 234 248 0 +112 97 11 0 +353 -149 210 0 +187 -138 49 0 +102 -252 146 0 +-304 230 356 0 +-329 216 331 0 +317 -378 187 0 +-303 -106 -377 0 +58 146 -398 0 +326 123 291 0 +-68 106 210 0 +84 -265 164 0 +-61 -244 -140 0 +135 156 -329 0 +193 188 -173 0 +-78 135 -7 0 +73 -120 -219 0 +270 355 308 0 +-192 -30 208 0 +123 -258 305 0 +-244 -322 -11 0 +-156 232 -215 0 +-38 336 110 0 +397 40 386 0 +-226 185 -307 0 +-7 275 72 0 +64 184 62 0 +385 -147 -367 0 +-51 -391 254 0 +85 373 -53 0 +-94 13 310 0 +-348 44 -122 0 +-393 -258 281 0 +-126 306 313 0 +198 329 -336 0 +237 -366 354 0 +388 -30 282 0 +243 384 363 0 +-45 -20 -75 0 +273 51 -248 0 +-149 41 -36 0 +339 -79 148 0 +-326 382 -73 0 +-10 -101 290 0 +-355 -234 242 0 +272 141 -86 0 +-25 36 -255 0 +-214 85 -374 0 +157 285 82 0 +-189 -227 276 0 +27 -299 -360 0 +192 -183 92 0 +-391 71 -287 0 +-297 -369 -399 0 +-20 -106 -145 0 +-66 -65 -375 0 +33 224 314 0 +327 212 -194 0 +-328 376 -22 0 +197 325 45 0 +369 189 -100 0 +-74 -198 -4 0 +-63 104 388 0 +262 148 -345 0 +-174 222 -126 0 +-302 34 -388 0 +-133 2 -302 0 +-264 -355 -182 0 +-172 -23 150 0 +-318 -383 -396 0 +-242 54 47 0 +-286 139 -376 0 +265 -393 -222 0 +400 318 -358 0 +-324 -303 149 0 +-333 -91 355 0 +-305 -157 51 0 +147 111 -220 0 +351 -60 284 0 +-26 132 -124 0 +-27 -287 -62 0 +294 122 393 0 +-172 -148 -349 0 +309 18 20 0 +365 254 -359 0 +59 -358 -248 0 +-5 -184 -139 0 +-188 300 239 0 +-97 103 323 0 +-295 -163 -308 0 +166 -308 -148 0 +382 -337 221 0 +211 -73 -200 0 +-355 209 48 0 +-332 -170 360 0 +-30 92 -69 0 +214 391 336 0 +286 225 294 0 +382 132 -215 0 +-179 -197 212 0 +347 -17 229 0 +15 -358 -228 0 +123 -181 65 0 +373 151 -374 0 +-181 310 82 0 +-81 -347 37 0 +146 -279 -90 0 +-166 255 -117 0 +-24 146 -35 0 +282 17 -380 0 +-384 40 -277 0 +-153 -398 20 0 +-179 -39 6 0 +-179 -196 325 0 +235 -25 177 0 +145 276 -79 0 +-162 400 375 0 +-285 372 239 0 +-21 -349 -206 0 +105 -348 -374 0 +-320 258 -140 0 +328 392 339 0 +54 -9 8 0 +-351 272 -173 0 +105 225 138 0 +-343 329 60 0 +-373 157 -328 0 +-346 -64 13 0 +178 -259 38 0 +140 -23 -382 0 +-79 347 318 0 +-26 352 304 0 +-357 112 -282 0 +-136 193 399 0 +330 186 340 0 +-301 -92 242 0 +269 -206 125 0 +-390 -68 353 0 +12 75 161 0 +327 -81 -392 0 +-113 244 -400 0 +126 234 386 0 +-44 347 115 0 +12 -133 81 0 +-331 -20 -313 0 +231 301 99 0 +10 332 296 0 +-395 128 152 0 +115 -87 -5 0 +379 142 -118 0 +-146 198 111 0 +-307 390 199 0 +-7 -282 11 0 +382 57 -173 0 +35 -135 -124 0 +314 -171 289 0 +291 -272 -209 0 +-373 384 330 0 +21 -378 -281 0 +127 -349 170 0 +-293 -318 269 0 +-353 183 -58 0 +-209 -196 18 0 +362 103 -391 0 +-230 373 -205 0 +-49 -68 78 0 +103 104 -153 0 +-194 -377 172 0 +-176 29 308 0 +22 3 -126 0 +-387 -354 320 0 +386 -373 127 0 +-65 -277 319 0 +-41 -166 -366 0 +53 -304 -94 0 +79 67 352 0 +-20 -98 146 0 +77 -9 359 0 +-257 164 -261 0 +209 -349 44 0 +17 -96 346 0 +386 101 -169 0 +-219 -190 262 0 +24 -262 376 0 +186 -131 322 0 +175 -86 350 0 +-95 36 132 0 +-115 -337 -386 0 +188 -88 204 0 +-87 -60 -256 0 +-262 320 361 0 +-243 -85 -47 0 +-170 366 101 0 +-49 -32 -204 0 +-330 -233 -90 0 +-60 -6 153 0 +-384 -59 -132 0 +147 154 -300 0 +316 -261 -224 0 +-101 -394 105 0 +375 -141 -254 0 +175 -96 128 0 +-240 -176 216 0 +-331 193 -240 0 +-378 -316 249 0 +331 -31 70 0 +205 236 278 0 +-394 381 -34 0 +-141 -2 152 0 +187 36 -282 0 +364 -400 273 0 +167 -387 170 0 +-255 -216 -243 0 +200 -21 -315 0 +318 138 -361 0 +-41 -39 30 0 +198 142 151 0 +277 -296 -187 0 +385 -335 87 0 +-176 155 -127 0 +166 249 240 0 +358 311 -308 0 +32 106 -244 0 +-237 -113 266 0 +-265 -92 -257 0 +-145 -344 -314 0 +-102 -48 -337 0 +-309 90 -270 0 +-36 -48 111 0 +4 186 -117 0 +-325 -225 -191 0 +217 -214 328 0 +317 35 76 0 +184 126 -286 0 +272 381 345 0 +235 -69 201 0 +306 123 125 0 +-170 144 -237 0 +-83 -65 52 0 +-127 -182 -362 0 +47 -356 -222 0 +-110 238 -155 0 +37 -143 77 0 +-151 -374 326 0 +-182 20 -369 0 +248 40 -397 0 +-102 -347 118 0 +141 -121 -185 0 +-78 -95 -50 0 +-239 382 -362 0 +249 276 394 0 +77 -398 129 0 +236 298 286 0 +-48 144 277 0 +39 289 -10 0 +-354 296 312 0 +-81 -120 157 0 +374 52 -163 0 +-42 71 323 0 +346 157 -262 0 +344 -13 -157 0 +15 -343 320 0 +36 -125 -236 0 +378 -377 -281 0 +273 144 -107 0 +-394 -345 130 0 +350 214 -334 0 +-4 372 160 0 +1 98 23 0 +183 222 -364 0 +6 -300 -310 0 +78 -351 274 0 +-95 126 -180 0 +-253 269 398 0 +95 188 -120 0 +23 -386 -230 0 +-392 -150 -133 0 +73 -207 -380 0 +105 -216 -69 0 +-353 -137 -261 0 +-2 169 -227 0 +-13 -43 352 0 +-351 331 222 0 +130 -191 -1 0 +175 -149 -180 0 +228 -125 94 0 +-256 -271 139 0 +-223 -269 -327 0 +-229 280 -204 0 +-176 107 -100 0 +184 320 300 0 +-373 84 381 0 +-107 -65 -168 0 +47 241 149 0 +-202 149 187 0 +-28 -239 151 0 +38 -392 -111 0 +-221 113 -369 0 +210 -144 -221 0 +39 99 -342 0 +57 331 -140 0 +186 -199 150 0 +-153 -341 269 0 +54 -90 62 0 +-19 -391 -57 0 +309 -176 -289 0 +-206 -72 296 0 +-63 376 356 0 +200 6 229 0 +-171 249 179 0 +-69 65 378 0 +273 -373 323 0 +-241 -124 -197 0 +275 -130 -165 0 +258 161 115 0 +125 -389 -20 0 +130 -328 294 0 +294 -299 164 0 +-26 -247 -369 0 +86 -143 392 0 +155 -207 -300 0 +94 -342 -234 0 +380 -190 -142 0 +334 209 313 0 +134 -35 292 0 +-389 -340 179 0 +-195 206 332 0 +-271 -76 -370 0 +78 -104 361 0 +-139 42 -296 0 +-354 107 20 0 +-75 -92 -290 0 +-187 -342 13 0 +-309 -383 189 0 +-131 -14 139 0 +-107 300 315 0 +210 -363 304 0 +36 59 269 0 +-85 -74 -108 0 +371 377 348 0 +270 -60 -145 0 +-348 -347 -43 0 +-178 384 -373 0 +171 67 212 0 +164 214 -34 0 +356 96 -47 0 +85 131 130 0 +-41 111 109 0 +102 279 61 0 +322 -176 -118 0 +294 -146 39 0 +-123 -282 352 0 +377 352 395 0 +-79 370 -334 0 +-43 108 -121 0 +56 -259 -9 0 +268 -272 -392 0 +-7 51 -255 0 +56 -69 91 0 +-286 -154 384 0 +-269 -274 -208 0 +386 187 -229 0 +-280 -315 -306 0 +207 274 365 0 +174 51 229 0 +105 -229 368 0 +-221 394 -25 0 +351 250 199 0 +-152 -141 -291 0 +-191 -163 -107 0 +-113 -328 247 0 +-270 11 -248 0 +-130 362 371 0 +-345 -272 -398 0 +-242 -129 102 0 +366 -212 -251 0 +370 65 356 0 +339 -40 -280 0 +-118 -216 272 0 +-54 243 -339 0 +78 -60 -249 0 +-226 -145 109 0 +-99 205 362 0 +330 -135 96 0 +-362 -255 -292 0 +289 390 -397 0 +133 -95 -269 0 +163 -326 338 0 +-5 137 -90 0 +-101 -202 97 0 +-329 294 -46 0 +-49 -116 -314 0 +51 71 19 0 +247 103 362 0 +130 -256 3 0 +282 -80 302 0 +146 -5 -351 0 +-200 -276 -281 0 +395 13 129 0 +-109 -29 -91 0 +119 87 -320 0 +-256 -63 233 0 +64 274 -381 0 +322 -390 160 0 +238 358 40 0 +72 -139 -332 0 +-171 -366 -263 0 +-108 -187 210 0 +-187 356 193 0 +-356 -147 399 0 +-192 49 -109 0 +323 -163 184 0 +-121 177 -93 0 +-134 -354 33 0 +319 207 40 0 +-239 296 -18 0 +-118 244 123 0 +160 101 16 0 +281 116 -137 0 +-159 264 145 0 +167 -275 -145 0 +145 -243 -310 0 +-10 -207 -391 0 +-160 195 40 0 +-234 -218 247 0 +180 135 -157 0 +342 366 124 0 +141 194 -378 0 +-103 -282 86 0 +126 -362 314 0 +-206 -71 -320 0 +-195 -288 107 0 +90 232 -36 0 +-310 17 391 0 +91 235 -81 0 +190 268 -395 0 +-201 -328 132 0 +149 -239 -54 0 +-246 -119 -31 0 +-355 108 -327 0 +-359 205 -305 0 +-197 -66 -317 0 +-150 25 257 0 +170 -358 -137 0 +292 -101 261 0 +-207 397 33 0 +-52 49 -315 0 +-339 -78 214 0 +165 2 -332 0 +-6 45 177 0 +94 -373 212 0 +-376 -39 65 0 +-31 297 -71 0 +-170 208 -256 0 +-130 -17 4 0 +-73 -280 143 0 +253 -333 -168 0 +-310 -156 375 0 +234 -122 -177 0 +-96 255 -204 0 +221 -137 -269 0 +-44 177 -62 0 +-290 -355 -342 0 +-186 -167 -367 0 +102 254 -347 0 +246 -78 147 0 +243 -36 -248 0 +90 40 -247 0 +-229 40 -250 0 +-238 -55 -262 0 +-194 -157 -243 0 +-364 -17 -222 0 +-56 314 11 0 +-338 77 257 0 +-147 -60 216 0 +173 -389 234 0 +154 -292 -376 0 +250 62 -160 0 +76 156 84 0 +93 -41 270 0 +-386 172 53 0 +-178 -244 177 0 +400 19 196 0 +119 -258 218 0 +12 186 -104 0 +-345 382 323 0 +282 330 257 0 +-193 -386 397 0 +3 166 35 0 +-284 283 -265 0 +-90 -11 -243 0 +-24 -193 -276 0 +258 395 247 0 +-31 -385 -60 0 +-97 392 -213 0 +221 67 289 0 +57 -54 392 0 +194 142 140 0 +383 378 11 0 +325 -43 -110 0 +-16 223 58 0 +-55 -294 -93 0 +191 372 -119 0 +309 -346 394 0 +390 -263 334 0 +90 367 63 0 +-187 229 145 0 +255 -369 -294 0 +342 159 202 0 +227 370 -355 0 +-352 110 -224 0 +-265 -347 -225 0 +-283 32 -19 0 +32 -249 331 0 +325 -362 233 0 +136 376 314 0 +-307 157 -21 0 +134 -400 -229 0 +276 111 -385 0 +68 -220 -33 0 +104 -233 -337 0 +92 -49 -386 0 +309 217 -102 0 +-225 147 -292 0 +232 372 6 0 +224 327 -239 0 +-389 387 381 0 +-76 -311 -281 0 +-310 175 -251 0 +339 -118 -78 0 +-398 -157 -226 0 +-168 -256 59 0 +-164 304 -323 0 +149 -246 48 0 +-153 336 -4 0 +82 -180 -92 0 +380 -86 -215 0 +-2 -349 299 0 +197 45 80 0 +-81 -148 364 0 +-20 10 325 0 +374 -200 328 0 +-184 -143 365 0 +221 -214 -305 0 +329 -42 -46 0 +-342 96 336 0 +-61 -132 355 0 +-356 -7 -238 0 +180 213 117 0 +-335 -392 -118 0 +306 -81 290 0 +-397 310 -84 0 +-47 157 314 0 +-138 -160 -70 0 +283 -130 -77 0 +98 -319 -296 0 +-339 108 -55 0 +281 105 12 0 +3 78 152 0 +156 117 28 0 +-399 118 358 0 +39 -348 225 0 +-300 -153 -292 0 +-255 252 260 0 +304 31 -163 0 +322 213 -253 0 +396 -48 -208 0 +7 -343 233 0 +80 -364 334 0 +386 176 191 0 +283 -379 -168 0 +-347 -206 177 0 +235 335 115 0 +-101 -216 187 0 +-195 -44 -186 0 +-340 377 174 0 +237 10 188 0 +-185 -350 3 0 +123 -21 -354 0 +272 -201 7 0 +-300 -124 78 0 +-56 -371 101 0 +-311 -168 117 0 +-52 -94 -9 0 +368 178 -167 0 +-74 87 -26 0 +-243 118 131 0 +-63 223 -186 0 +-119 139 -249 0 +93 -62 -333 0 +-113 -61 -205 0 +-251 -357 385 0 +351 -218 -72 0 +-291 -19 -298 0 +294 -94 54 0 +-297 -17 52 0 +-368 309 -75 0 +201 191 -95 0 +31 169 365 0 +271 105 -106 0 +-268 -179 378 0 +37 -151 -392 0 +341 255 -327 0 +-334 -109 324 0 +-262 -258 -288 0 +329 -1 252 0 +341 -260 184 0 +-67 215 141 0 +-149 135 327 0 +207 -246 -171 0 +167 45 256 0 +51 -194 290 0 +72 -47 -378 0 +334 -140 218 0 +-125 369 399 0 +-151 180 -159 0 +-85 -152 157 0 +89 361 -183 0 +197 10 265 0 +-168 346 -348 0 +232 392 -93 0 +353 386 345 0 +-245 -399 194 0 +153 -213 -280 0 +-396 298 46 0 +-257 246 -230 0 +142 -91 -164 0 +-319 395 24 0 +382 -77 -251 0 +-313 -41 278 0 +245 -240 -89 0 +-156 -282 -365 0 +296 190 -61 0 +-357 -236 -62 0 +-140 -361 148 0 +-261 67 -323 0 +176 247 296 0 +-207 -12 357 0 +157 -238 397 0 +277 -137 357 0 +-106 366 -293 0 +394 43 134 0 +-8 245 -213 0 +126 -220 331 0 +-118 266 -368 0 +-204 -346 390 0 +383 -271 -251 0 +-317 24 -133 0 +174 -16 -368 0 +-336 -159 -126 0 +-327 -340 264 0 +-124 -322 363 0 +-214 306 50 0 +95 -160 -356 0 +275 -103 -155 0 +-366 283 -231 0 +-321 274 -91 0 +-261 -365 -338 0 +-154 357 -35 0 +57 -245 257 0 +-102 -161 -96 0 +-149 -213 72 0 +271 308 -187 0 +-83 -275 6 0 +-271 391 -172 0 +341 254 80 0 +186 -285 -185 0 +31 -346 -92 0 +218 -187 -39 0 +-151 -78 -267 0 +-194 97 -273 0 +197 173 -294 0 +165 11 -266 0 +20 -397 -108 0 +-334 -323 -391 0 +-171 -294 -195 0 +3 267 -355 0 +168 -316 -346 0 +-354 143 122 0 +279 -390 -167 0 +-368 312 -160 0 +-296 -260 96 0 +138 -275 162 0 +112 -165 -380 0 +77 8 73 0 +110 195 77 0 +51 156 146 0 +-344 47 -127 0 +342 -193 103 0 +356 -5 239 0 +194 -310 261 0 +-108 -133 276 0 +57 173 -232 0 +25 170 57 0 +-358 45 -390 0 +-261 -170 98 0 +193 -2 -264 0 +-206 -214 265 0 +350 325 263 0 +343 -8 -349 0 +-120 -367 94 0 +-349 -232 38 0 +257 -9 57 0 +167 347 233 0 +333 246 -242 0 +158 -249 315 0 +288 -318 137 0 +-120 -339 -349 0 +85 130 -244 0 +152 395 345 0 +-293 -337 -322 0 +112 -27 -256 0 +93 -71 -228 0 +-339 236 -320 0 +-281 -208 375 0 +-251 -398 139 0 +-14 -220 305 0 +-110 64 -278 0 +-79 394 -216 0 +-331 -8 79 0 +59 -387 133 0 +-26 -75 11 0 +89 -5 -45 0 +-347 324 94 0 +33 156 -181 0 +246 118 -304 0 +170 244 40 0 +162 -214 -339 0 +258 -30 108 0 +-76 175 88 0 +173 -387 -217 0 +392 -37 229 0 +365 -330 71 0 +-39 -297 -231 0 +-382 275 99 0 +168 -255 225 0 +321 273 -177 0 +-7 220 -226 0 +230 -66 -209 0 +336 97 -234 0 +224 -284 -170 0 +141 -44 276 0 +-166 -103 398 0 +-303 360 -42 0 +22 -210 252 0 +123 -370 204 0 +295 62 -370 0 +-300 48 -216 0 +-274 -293 257 0 +70 329 388 0 +194 -258 -55 0 +275 -397 38 0 +-309 -66 -367 0 +21 -140 -249 0 +359 -75 83 0 +-31 93 76 0 +14 -268 -173 0 +-323 324 356 0 +-197 -20 361 0 +-200 159 40 0 +-100 87 -384 0 +303 137 149 0 +-366 14 -135 0 +-94 3 106 0 +371 150 16 0 +-253 -35 -111 0 +117 63 -323 0 +28 -103 379 0 +200 -20 186 0 +114 -347 286 0 +-201 -113 -255 0 +-97 -322 -30 0 +-336 -118 -174 0 +-97 -335 168 0 +-371 257 -91 0 +29 139 15 0 +202 -49 189 0 +301 306 -395 0 +174 -268 -113 0 +36 24 -112 0 +-28 211 -140 0 +-262 199 141 0 +-279 -233 -369 0 +-3 -384 6 0 +-322 -263 -82 0 +-83 -320 -75 0 +313 -127 270 0 +116 -311 35 0 +-174 -90 -228 0 +-190 78 -269 0 +-88 -145 -129 0 +234 -183 -121 0 +-257 254 62 0 +-87 -15 -239 0 +-272 335 -72 0 +-349 197 -231 0 +374 -96 -235 0 +198 6 179 0 +-360 286 33 0 +-144 -374 -65 0 +301 14 323 0 +-136 367 -280 0 +294 -210 -35 0 +91 -331 -120 0 +-253 -223 -196 0 +-42 -290 -274 0 +-148 60 233 0 +-56 -275 54 0 +-227 388 356 0 +-120 315 -258 0 +175 224 -89 0 +-266 -287 -25 0 +-343 321 279 0 +-373 188 -164 0 +-364 205 -140 0 +-20 197 98 0 +-72 61 -123 0 +101 52 -308 0 +155 -372 361 0 +-96 215 202 0 +-61 -359 -372 0 +346 89 179 0 +56 285 340 0 +136 -322 -262 0 +93 287 280 0 +-69 -135 -177 0 +110 -190 283 0 +128 265 -303 0 +309 -316 390 0 +235 -104 20 0 +285 370 -179 0 +207 -71 212 0 +-59 389 237 0 +-382 315 332 0 +-104 223 -397 0 +167 -126 267 0 +-368 297 249 0 +-103 -348 -99 0 +355 -242 372 0 +-132 219 -183 0 +377 60 148 0 +-374 -324 -87 0 +-284 60 -323 0 +-40 -305 -376 0 +275 225 -358 0 +-31 233 262 0 +-368 353 93 0 +-381 10 -157 0 +-390 -335 362 0 +57 -123 232 0 +-168 162 -273 0 +-198 211 252 0 +339 -149 338 0 +-105 394 167 0 +-73 -367 90 0 +-344 -100 382 0 +-115 -230 35 0 +-247 10 -400 0 +-369 -112 348 0 +-54 202 176 0 +316 -2 -111 0 +-73 -284 -371 0 +-358 -399 -3 0 +-263 7 26 0 +372 -99 -308 0 +111 -13 -367 0 +314 -285 66 0 +278 -300 169 0 +-193 -71 -213 0 +324 156 -308 0 +-197 317 65 0 +297 3 161 0 +85 -116 -3 0 +-364 -43 232 0 +385 -136 124 0 +-296 67 -247 0 +188 -30 -337 0 +3 332 242 0 +-118 -51 183 0 +-269 211 82 0 +274 -350 67 0 +-54 -1 181 0 +-117 -207 359 0 +50 -232 97 0 +178 -354 85 0 +260 170 41 0 +29 295 206 0 +-236 -305 264 0 +192 -217 -210 0 +162 -226 247 0 +-289 248 -313 0 +-134 -106 48 0 +-349 54 -92 0 +94 -390 75 0 +-148 -342 -299 0 +-90 -332 134 0 +-107 -297 -268 0 +-293 -87 138 0 +243 -296 230 0 +-390 249 -352 0 +-79 -236 326 0 +375 -248 385 0 +-278 -198 162 0 +208 376 163 0 +-47 -186 113 0 +297 -56 95 0 +-263 194 -35 0 +-323 217 138 0 +-352 343 199 0 +378 -179 -90 0 +176 164 42 0 +213 -129 264 0 +334 -283 292 0 +272 -312 313 0 +363 220 -85 0 +351 274 355 0 +-173 36 -66 0 +-239 332 -367 0 +-196 -76 248 0 +14 23 309 0 +241 -328 232 0 +-133 397 -394 0 +281 -222 275 0 +-87 -99 154 0 +-375 -172 -188 0 +-145 13 -44 0 +-335 -340 -312 0 +-272 322 117 0 +224 158 70 0 +142 369 351 0 +45 -347 -136 0 +356 -161 235 0 +-113 359 148 0 +152 280 -377 0 +-1 -302 340 0 +74 179 -41 0 +-104 -126 -27 0 +116 -9 -377 0 +-35 -293 265 0 +334 -114 326 0 +368 91 -191 0 +227 306 87 0 +271 263 390 0 +232 160 375 0 +72 56 -105 0 +-9 -200 164 0 +-160 337 -272 0 +-227 -364 -280 0 +-251 395 116 0 +-216 114 245 0 +41 -23 276 0 +170 285 -275 0 +10 308 -379 0 +-246 -230 88 0 +103 -221 194 0 +375 -133 231 0 +-139 58 240 0 +380 11 180 0 +4 -50 389 0 +219 -65 167 0 +-172 -289 392 0 +-309 -180 -289 0 +20 124 -300 0 +311 37 153 0 +-245 298 131 0 +270 385 333 0 +-92 -247 105 0 +221 -318 -325 0 +-176 -379 -395 0 +-394 -74 370 0 +168 307 -100 0 +211 304 33 0 +315 168 -158 0 +114 -167 109 0 +-386 -69 -103 0 +-276 364 -5 0 +303 -244 -365 0 +120 -252 334 0 +392 255 -287 0 +185 -232 303 0 +-77 -167 323 0 +94 -299 -248 0 +176 -305 388 0 +230 124 -383 0 +-302 -264 12 0 +115 -131 21 0 +-344 -160 315 0 +-279 345 -355 0 +-346 187 -211 0 +108 155 -154 0 +325 376 339 0 +-313 -308 213 0 +-278 -329 232 0 +-92 -69 82 0 +-31 -29 76 0 +378 218 -222 0 +-139 41 -390 0 +146 -322 153 0 +200 111 -8 0 +-204 63 -214 0 +-162 45 322 0 +-113 360 47 0 diff --git a/cryptominisat/cppsrc/python/tests/test.cnf b/cryptominisat/cppsrc/python/tests/test.cnf new file mode 100644 index 00000000..a15ad908 --- /dev/null +++ b/cryptominisat/cppsrc/python/tests/test.cnf @@ -0,0 +1,928 @@ +c generated by FuzzSAT +p cnf 281 926 +2 -3 -4 0 +-2 3 -4 0 +2 3 4 0 +-2 -3 4 0 +5 -1 0 +5 4 0 +1 -4 -5 0 +9 7 0 +9 -8 0 +-7 8 -9 0 +10 -6 0 +10 -9 0 +6 9 -10 0 +5 -10 -11 0 +-5 10 -11 0 +5 10 11 0 +-5 -10 11 0 +13 10 0 +13 -12 0 +-10 12 -13 0 +15 -16 -17 0 +-15 16 -17 0 +15 16 17 0 +-15 -16 17 0 +-14 -17 -18 0 +14 17 -18 0 +-14 17 18 0 +14 -17 18 0 +-18 -1 -19 0 +18 1 -19 0 +-18 1 19 0 +18 -1 19 0 +21 19 0 +21 -20 0 +-19 20 -21 0 +24 -22 0 +24 23 0 +22 -23 -24 0 +25 21 0 +25 24 0 +-21 -24 -25 0 +26 -3 -27 0 +-26 3 -27 0 +26 3 27 0 +-26 -3 27 0 +28 25 0 +28 -27 0 +-25 27 -28 0 +29 3 0 +29 -27 0 +-3 27 -29 0 +-30 12 0 +-30 -15 0 +-12 15 30 0 +-32 -30 0 +-32 -31 0 +30 31 32 0 +-29 -32 -33 0 +29 32 -33 0 +-29 32 33 0 +29 -32 33 0 +35 34 0 +35 9 0 +-34 -9 -35 0 +-23 -1 -36 0 +23 1 -36 0 +-23 1 36 0 +23 -1 36 0 +-35 -36 -37 0 +35 36 -37 0 +-35 36 37 0 +35 -36 37 0 +38 -33 0 +38 -37 0 +33 37 -38 0 +39 -28 0 +39 38 0 +28 -38 -39 0 +40 41 -42 0 +-40 -41 -42 0 +40 -41 42 0 +-40 41 42 0 +42 24 -43 0 +-42 -24 -43 0 +42 -24 43 0 +-42 24 43 0 +-39 -43 -44 0 +39 43 -44 0 +-39 43 44 0 +39 -43 44 0 +-13 -44 -45 0 +13 44 -45 0 +-13 44 45 0 +13 -44 45 0 +46 -6 -47 0 +-46 6 -47 0 +46 6 47 0 +-46 -6 47 0 +48 34 0 +48 47 0 +-34 -47 -48 0 +-50 41 0 +-50 -2 0 +-41 2 50 0 +26 -50 -51 0 +-26 50 -51 0 +26 50 51 0 +-26 -50 51 0 +-52 15 0 +-52 7 0 +-15 -7 52 0 +-53 -51 0 +-53 52 0 +51 -52 53 0 +49 -53 -54 0 +-49 53 -54 0 +49 53 54 0 +-49 -53 54 0 +55 -50 0 +55 -20 0 +50 20 -55 0 +-56 -14 0 +-56 55 0 +14 -55 56 0 +54 56 -57 0 +-54 -56 -57 0 +54 -56 57 0 +-54 56 57 0 +58 48 0 +58 57 0 +-48 -57 -58 0 +59 45 0 +59 58 0 +-45 -58 -59 0 +11 59 -60 0 +-11 -59 -60 0 +11 -59 60 0 +-11 59 60 0 +61 25 0 +61 53 0 +-25 -53 -61 0 +-63 -35 0 +-63 3 0 +35 -3 63 0 +-62 63 -64 0 +62 -63 -64 0 +-62 -63 64 0 +62 63 64 0 +64 -52 -65 0 +-64 52 -65 0 +64 52 65 0 +-64 -52 65 0 +67 -66 0 +67 -7 0 +66 7 -67 0 +68 26 0 +68 -23 0 +-26 23 -68 0 +70 68 0 +70 -69 0 +-68 69 -70 0 +-71 70 0 +-71 19 0 +-70 -19 71 0 +-46 62 -72 0 +46 -62 -72 0 +-46 -62 72 0 +46 62 72 0 +72 -12 -73 0 +-72 12 -73 0 +72 12 73 0 +-72 -12 73 0 +74 -71 0 +74 -73 0 +71 73 -74 0 +67 -74 -75 0 +-67 74 -75 0 +67 74 75 0 +-67 -74 75 0 +76 66 0 +76 -69 0 +-66 69 -76 0 +78 41 0 +78 -77 0 +-41 77 -78 0 +79 76 0 +79 78 0 +-76 -78 -79 0 +-80 75 0 +-80 -79 0 +-75 79 80 0 +-65 80 -81 0 +65 -80 -81 0 +-65 -80 81 0 +65 80 81 0 +82 -73 0 +82 -41 0 +73 41 -82 0 +83 -81 0 +83 82 0 +81 -82 -83 0 +61 83 -84 0 +-61 -83 -84 0 +61 -83 84 0 +-61 83 84 0 +-60 84 -85 0 +60 -84 -85 0 +-60 -84 85 0 +60 84 85 0 +86 46 0 +86 3 0 +-46 -3 -86 0 +-87 -26 0 +-87 -86 0 +26 86 87 0 +77 -87 -88 0 +-77 87 -88 0 +77 87 88 0 +-77 -87 88 0 +-90 20 0 +-90 -89 0 +-20 89 90 0 +1 -90 -91 0 +-1 90 -91 0 +1 90 91 0 +-1 -90 91 0 +-91 34 -92 0 +91 -34 -92 0 +-91 -34 92 0 +91 34 92 0 +93 -88 0 +93 92 0 +88 -92 -93 0 +-4 93 -94 0 +4 -93 -94 0 +-4 -93 94 0 +4 93 94 0 +95 -49 0 +95 -62 0 +49 62 -95 0 +-97 -49 0 +-97 -96 0 +49 96 97 0 +98 -95 0 +98 97 0 +95 -97 -98 0 +94 98 -99 0 +-94 -98 -99 0 +94 -98 99 0 +-94 98 99 0 +-100 -2 0 +-100 9 0 +2 -9 100 0 +-101 17 0 +-101 -15 0 +-17 15 101 0 +102 -101 0 +102 26 0 +101 -26 -102 0 +-100 102 -103 0 +100 -102 -103 0 +-100 -102 103 0 +100 102 103 0 +104 16 0 +104 1 0 +-16 -1 -104 0 +15 -14 -105 0 +-15 14 -105 0 +15 14 105 0 +-15 -14 105 0 +-104 105 -106 0 +104 -105 -106 0 +-104 -105 106 0 +104 105 106 0 +-107 -106 0 +-107 20 0 +106 -20 107 0 +108 -103 0 +108 -107 0 +103 107 -108 0 +-99 108 -109 0 +99 -108 -109 0 +-99 -108 109 0 +99 108 109 0 +-8 -46 -110 0 +8 46 -110 0 +-8 46 110 0 +8 -46 110 0 +111 31 0 +111 -110 0 +-31 110 -111 0 +-112 52 0 +-112 -111 0 +-52 111 112 0 +-112 71 -113 0 +112 -71 -113 0 +-112 -71 113 0 +112 71 113 0 +114 106 0 +114 -34 0 +-106 34 -114 0 +114 -105 -115 0 +-114 105 -115 0 +114 105 115 0 +-114 -105 115 0 +-116 113 0 +-116 115 0 +-113 -115 116 0 +-117 69 0 +-117 -20 0 +-69 20 117 0 +-118 -117 0 +-118 104 0 +117 -104 118 0 +116 118 -119 0 +-116 -118 -119 0 +116 -118 119 0 +-116 118 119 0 +120 89 0 +120 -24 0 +-89 24 -120 0 +-69 -102 -121 0 +69 102 -121 0 +-69 102 121 0 +69 -102 121 0 +-122 120 0 +-122 -121 0 +-120 121 122 0 +123 -55 0 +123 10 0 +55 -10 -123 0 +-124 -122 0 +-124 123 0 +122 -123 124 0 +-125 -119 0 +-125 124 0 +119 -124 125 0 +-26 63 -126 0 +26 -63 -126 0 +-26 -63 126 0 +26 63 126 0 +126 19 -127 0 +-126 -19 -127 0 +126 -19 127 0 +-126 19 127 0 +127 4 -128 0 +-127 -4 -128 0 +127 -4 128 0 +-127 4 128 0 +-29 129 -130 0 +29 -129 -130 0 +-29 -129 130 0 +29 129 130 0 +131 -128 0 +131 -130 0 +128 130 -131 0 +131 -20 -132 0 +-131 20 -132 0 +131 20 132 0 +-131 -20 132 0 +-133 125 0 +-133 132 0 +-125 -132 133 0 +134 -15 0 +134 -62 0 +15 62 -134 0 +-62 -134 -135 0 +62 134 -135 0 +-62 134 135 0 +62 -134 135 0 +42 112 -136 0 +-42 -112 -136 0 +42 -112 136 0 +-42 112 136 0 +137 135 0 +137 136 0 +-135 -136 -137 0 +-138 133 0 +-138 137 0 +-133 -137 138 0 +-139 -109 0 +-139 -138 0 +109 138 139 0 +-140 -85 0 +-140 139 0 +85 -139 140 0 +-42 -35 -141 0 +42 35 -141 0 +-42 35 141 0 +42 -35 141 0 +-63 -129 -142 0 +63 129 -142 0 +-63 129 142 0 +63 -129 142 0 +-143 142 0 +-143 -20 0 +-142 20 143 0 +144 68 0 +144 6 0 +-68 -6 -144 0 +-143 144 -145 0 +143 -144 -145 0 +-143 -144 145 0 +143 144 145 0 +146 141 0 +146 -145 0 +-141 145 -146 0 +-147 -9 0 +-147 -96 0 +9 96 147 0 +-148 147 0 +-148 -40 0 +-147 40 148 0 +-149 -34 0 +-149 -50 0 +34 50 149 0 +-150 -22 0 +-150 -34 0 +22 34 150 0 +-151 -46 0 +-151 50 0 +46 -50 151 0 +-152 150 0 +-152 151 0 +-150 -151 152 0 +153 149 0 +153 -152 0 +-149 152 -153 0 +-148 153 -154 0 +148 -153 -154 0 +-148 -153 154 0 +148 153 154 0 +155 -18 0 +155 37 0 +18 -37 -155 0 +27 96 -156 0 +-27 -96 -156 0 +27 -96 156 0 +-27 96 156 0 +-157 156 0 +-157 63 0 +-156 -63 157 0 +158 -155 0 +158 157 0 +155 -157 -158 0 +-154 158 -159 0 +154 -158 -159 0 +-154 -158 159 0 +154 158 159 0 +130 -160 0 +-130 -160 0 +-161 160 0 +-161 -8 0 +-160 8 161 0 +-162 4 0 +-162 129 0 +-4 -129 162 0 +-163 162 0 +-163 -93 0 +-162 93 163 0 +-163 104 -164 0 +163 -104 -164 0 +-163 -104 164 0 +163 104 164 0 +-161 -164 -165 0 +161 164 -165 0 +-161 164 165 0 +161 -164 165 0 +-166 -36 0 +-166 53 0 +36 -53 166 0 +167 -166 0 +167 -104 0 +166 104 -167 0 +168 69 0 +168 36 0 +-69 -36 -168 0 +169 167 0 +169 -168 0 +-167 168 -169 0 +170 -165 0 +170 -169 0 +165 169 -170 0 +-159 -170 -171 0 +159 170 -171 0 +-159 170 171 0 +159 -170 171 0 +-172 146 0 +-172 171 0 +-146 -171 172 0 +-26 1 -173 0 +26 -1 -173 0 +-26 -1 173 0 +26 1 173 0 +-63 -26 -174 0 +63 26 -174 0 +-63 26 174 0 +63 -26 174 0 +-175 -173 0 +-175 174 0 +173 -174 175 0 +-176 -113 0 +-176 -34 0 +113 34 176 0 +-177 175 0 +-177 -176 0 +-175 176 177 0 +178 -106 0 +178 77 0 +106 -77 -178 0 +179 -88 0 +179 178 0 +88 -178 -179 0 +-180 88 0 +-180 -179 0 +-88 179 180 0 +-181 -180 0 +-181 53 0 +180 -53 181 0 +-96 37 -182 0 +96 -37 -182 0 +-96 -37 182 0 +96 37 182 0 +2 182 -183 0 +-2 -182 -183 0 +2 -182 183 0 +-2 182 183 0 +-183 87 -184 0 +183 -87 -184 0 +-183 -87 184 0 +183 87 184 0 +-185 184 0 +-185 41 0 +-184 -41 185 0 +181 185 -186 0 +-181 -185 -186 0 +181 -185 186 0 +-181 185 186 0 +188 -52 0 +188 -187 0 +52 187 -188 0 +-189 -64 0 +-189 -188 0 +64 188 189 0 +-190 186 0 +-190 -189 0 +-186 189 190 0 +-92 168 -191 0 +92 -168 -191 0 +-92 -168 191 0 +92 168 191 0 +-192 -89 0 +-192 62 0 +89 -62 192 0 +193 -191 0 +193 -192 0 +191 192 -193 0 +-190 -193 -194 0 +190 193 -194 0 +-190 193 194 0 +190 -193 194 0 +-177 194 -195 0 +177 -194 -195 0 +-177 -194 195 0 +177 194 195 0 +-196 -172 0 +-196 195 0 +172 -195 196 0 +-197 52 0 +-197 168 0 +-52 -168 197 0 +198 -105 0 +198 -46 0 +105 46 -198 0 +-199 -77 0 +-199 76 0 +77 -76 199 0 +-200 -198 0 +-200 -199 0 +198 199 200 0 +-201 27 0 +-201 -62 0 +-27 62 201 0 +-202 201 0 +-202 -68 0 +-201 68 202 0 +-3 8 -203 0 +3 -8 -203 0 +-3 -8 203 0 +3 8 203 0 +-203 91 -204 0 +203 -91 -204 0 +-203 -91 204 0 +203 91 204 0 +205 -204 0 +205 110 0 +204 -110 -205 0 +202 205 -206 0 +-202 -205 -206 0 +202 -205 206 0 +-202 205 206 0 +2 46 -207 0 +-2 -46 -207 0 +2 -46 207 0 +-2 46 207 0 +208 -180 0 +208 207 0 +180 -207 -208 0 +-209 -206 0 +-209 208 0 +206 -208 209 0 +-210 66 0 +-210 -127 0 +-66 127 210 0 +-18 88 -211 0 +18 -88 -211 0 +-18 -88 211 0 +18 88 211 0 +-212 211 0 +-212 -55 0 +-211 55 212 0 +210 -212 -213 0 +-210 212 -213 0 +210 212 213 0 +-210 -212 213 0 +-214 -209 0 +-214 -213 0 +209 213 214 0 +-215 -200 0 +-215 214 0 +200 -214 215 0 +-197 -215 -216 0 +197 215 -216 0 +-197 215 216 0 +197 -215 216 0 +-217 -64 0 +-217 -162 0 +64 162 217 0 +-218 217 0 +-218 -10 0 +-217 10 218 0 +96 -179 -219 0 +-96 179 -219 0 +96 179 219 0 +-96 -179 219 0 +220 16 0 +220 -15 0 +-16 15 -220 0 +-221 -178 0 +-221 -4 0 +178 4 221 0 +222 -220 0 +222 -221 0 +220 221 -222 0 +-223 -219 0 +-223 222 0 +219 -222 223 0 +224 218 0 +224 223 0 +-218 -223 -224 0 +225 -183 0 +225 -22 0 +183 22 -225 0 +147 -225 -226 0 +-147 225 -226 0 +147 225 226 0 +-147 -225 226 0 +-227 226 0 +-227 130 0 +-226 -130 227 0 +-187 180 -228 0 +187 -180 -228 0 +-187 -180 228 0 +187 180 228 0 +112 63 -229 0 +-112 -63 -229 0 +112 -63 229 0 +-112 63 229 0 +-228 229 -230 0 +228 -229 -230 0 +-228 -229 230 0 +228 229 230 0 +-231 227 0 +-231 230 0 +-227 -230 231 0 +-232 224 0 +-232 231 0 +-224 -231 232 0 +-233 216 0 +-233 232 0 +-216 -232 233 0 +234 -142 0 +234 -27 0 +142 27 -234 0 +235 -33 0 +235 25 0 +33 -25 -235 0 +-234 -235 -236 0 +234 235 -236 0 +-234 235 236 0 +234 -235 236 0 +236 -62 -237 0 +-236 62 -237 0 +236 62 237 0 +-236 -62 237 0 +238 -147 0 +238 -78 0 +147 78 -238 0 +239 -237 0 +239 -238 0 +237 238 -239 0 +241 -33 0 +241 240 0 +33 -240 -241 0 +242 22 0 +242 126 0 +-22 -126 -242 0 +-243 241 0 +-243 242 0 +-241 -242 243 0 +-244 29 0 +-244 42 0 +-29 -42 244 0 +-245 -90 0 +-245 244 0 +90 -244 245 0 +-246 -22 0 +-246 -86 0 +22 86 246 0 +247 246 0 +247 -23 0 +-246 23 -247 0 +-248 -245 0 +-248 247 0 +245 -247 248 0 +-249 -188 0 +-249 106 0 +188 -106 249 0 +182 183 -250 0 +-182 -183 -250 0 +182 -183 250 0 +-182 183 250 0 +251 -86 0 +251 178 0 +86 -178 -251 0 +250 -251 -252 0 +-250 251 -252 0 +250 251 252 0 +-250 -251 252 0 +-249 -252 -253 0 +249 252 -253 0 +-249 252 253 0 +249 -252 253 0 +254 -51 0 +254 55 0 +51 -55 -254 0 +255 254 0 +255 -102 0 +-254 102 -255 0 +256 -253 0 +256 255 0 +253 -255 -256 0 +257 -248 0 +257 -256 0 +248 256 -257 0 +-258 2 0 +-258 4 0 +-2 -4 258 0 +-259 -258 0 +-259 -6 0 +258 6 259 0 +261 -73 0 +261 260 0 +73 -260 -261 0 +-262 259 0 +-262 -261 0 +-259 261 262 0 +-263 -2 0 +-263 142 0 +2 -142 263 0 +263 191 -264 0 +-263 -191 -264 0 +263 -191 264 0 +-263 191 264 0 +265 31 0 +265 -263 0 +-31 263 -265 0 +113 -265 -266 0 +-113 265 -266 0 +113 265 266 0 +-113 -265 266 0 +263 -266 -267 0 +-263 266 -267 0 +263 266 267 0 +-263 -266 267 0 +264 267 -268 0 +-264 -267 -268 0 +264 -267 268 0 +-264 267 268 0 +-269 20 0 +-269 -26 0 +-20 26 269 0 +-102 269 -270 0 +102 -269 -270 0 +-102 -269 270 0 +102 269 270 0 +-271 -30 0 +-271 -270 0 +30 270 271 0 +272 -89 0 +272 160 0 +89 -160 -272 0 +-273 271 0 +-273 -272 0 +-271 272 273 0 +274 -268 0 +274 -273 0 +268 273 -274 0 +275 -262 0 +275 274 0 +262 -274 -275 0 +-257 275 -276 0 +257 -275 -276 0 +-257 -275 276 0 +257 275 276 0 +277 -243 0 +277 -276 0 +243 276 -277 0 +278 -239 0 +278 277 0 +239 -277 -278 0 +279 233 0 +279 278 0 +-233 -278 -279 0 +280 -196 0 +280 279 0 +196 -279 -280 0 +-140 -280 -281 0 +140 280 -281 0 +-140 280 281 0 +140 -280 281 0 +184 177 -155 192 0 +34 -53 280 0 +234 114 0 +248 -114 82 140 0 +16 221 -52 -253 0 +-122 83 0 +171 51 -229 189 0 +186 -5 -104 0 +-243 -50 252 0 +-39 -236 -80 0 +-257 42 -96 0 +109 -77 141 0 +-250 117 -131 -207 57 0 +-12 160 -113 -137 -76 234 0 +98 -217 -110 -254 58 281 0 +64 -243 18 -90 161 0 +215 85 -45 0 +65 261 -53 0 +-166 -183 0 +-168 90 -277 151 121 -144 0 +-51 170 -185 -252 -180 0 +-149 184 27 -228 0 +-70 264 226 -169 0 +179 -3 0 +-254 59 -156 255 0 +69 -86 270 -42 0 +-91 140 0 +-3 184 -85 192 0 +155 46 -11 -115 0 +153 -147 0 +-195 -281 -127 -191 197 141 0 +180 32 251 -21 0 +111 85 149 -105 0 +-2 -224 -14 159 84 0 +-53 -192 0 +-162 128 -188 -27 136 0 +-128 -104 -87 2 -109 0 +46 181 188 249 105 0 +-97 269 -103 0 +-243 197 0 +232 244 -28 265 102 0 +-79 195 -117 190 0 +276 -6 -100 -237 98 29 0 +65 3 0 +249 140 63 -181 4 197 0 +-64 -55 -244 0 +99 -165 -100 142 -84 0 +-92 112 278 -71 0 +197 -111 26 -216 215 -110 0 +-54 273 243 0 +104 -260 -269 0 +232 -111 -21 0 +26 -181 51 -56 -3 0 +-221 241 142 -184 0 +-9 241 256 -243 0 +42 -246 -164 0 +-169 -23 0 +64 -21 -107 -9 112 245 0 +109 -191 -33 0 +94 -66 137 119 0 +184 -153 -167 -118 214 0 +-47 -144 25 218 0 +-160 191 247 0 +-13 165 -79 -248 -86 0 +-92 244 0 +102 -142 -122 0 +123 -138 0 +244 -110 -171 178 -21 0 +-140 53 0 +-168 -254 0 +166 -56 181 280 177 0 +103 152 0 +243 92 214 158 164 122 0 +65 -187 208 0 +-81 38 176 0 +204 -246 -233 90 273 0 +-70 -177 -10 0 +141 -140 241 -34 0 +195 -52 233 30 10 -185 0 +-120 13 -248 80 117 -232 0 +33 -152 -133 140 0 +209 -88 -221 148 -147 197 0 +-105 87 0 +211 -242 -17 -25 -238 127 0 +281 0 diff --git a/cryptominisat/cppsrc/python/tests/test_pycryptosat.py b/cryptominisat/cppsrc/python/tests/test_pycryptosat.py new file mode 100644 index 00000000..850769dd --- /dev/null +++ b/cryptominisat/cppsrc/python/tests/test_pycryptosat.py @@ -0,0 +1,368 @@ +# -*- coding: utf-8 -*- +# +# CryptoMiniSat +# +# Permission is hereby granted, free of charge, to any person obtaining a copy +# of this software and associated documentation files (the "Software"), to deal +# in the Software without restriction, including without limitation the rights +# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +# copies of the Software, and to permit persons to whom the Software is +# furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in +# all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +# THE SOFTWARE. + +from __future__ import unicode_literals +from __future__ import print_function +from array import array as _array +import os +import sys +import unittest +import time + + +import pycryptosat +from pycryptosat import Solver + +_MODULE_DIR = os.path.dirname(os.path.realpath(__file__))+os.path.sep + +def array(typecode, initializer=()): + return _array(str(typecode), initializer) + + +def check_clause(clause, solution): + for lit in clause: + var = abs(lit) + if lit < 0: + inverted = True + else: + inverted = False + + if solution[var] != inverted: + return True + + +def check_solution(clauses, solution): + for clause in clauses: + if check_clause(clause, solution) is False: + return False + + return True + +# -------------------------- test clauses -------------------------------- + +# p cnf 5 3 +# 1 -5 4 0 +# -1 5 3 4 0 +# -3 -4 0 +clauses1 = [[1, -5, 4], [-1, 5, 3, 4], [-3, -4]] + +# p cnf 2 2 +# -1 0 +# 1 0 +clauses2 = [[-1], [1]] + +# p cnf 2 3 +# -1 2 0 +# -1 -2 0 +# 1 -2 0 +clauses3 = [[-1, 2], [-1, -2], [1, -2]] + +# -------------------------- actual unit tests --------------------------- + + +class TestXor(unittest.TestCase): + + def setUp(self): + self.solver = Solver(threads=2) + + def test_wrong_args(self): + self.assertRaises(TypeError, self.solver.add_xor_clause, [1, 2]) + self.assertRaises(ValueError, self.solver.add_xor_clause, [1, 0], True) + self.assertRaises( + ValueError, self.solver.add_xor_clause, [-1, 2], True) + + def test_binary(self): + self.solver.add_xor_clause([1, 2], False) + res, solution = self.solver.solve([1]) + self.assertEqual(res, True) + self.assertEqual(solution, (None, True, True)) + + def test_unit(self): + self.solver.add_xor_clause([1], False) + res, solution = self.solver.solve() + self.assertEqual(res, True) + self.assertEqual(solution, (None, False)) + + def test_unit2(self): + self.solver.add_xor_clause([1], True) + res, solution = self.solver.solve() + self.assertEqual(res, True) + self.assertEqual(solution, (None, True)) + + def test_3_long(self): + self.solver.add_xor_clause([1, 2, 3], False) + res, solution = self.solver.solve([1, 2]) + self.assertEqual(res, True) + # self.assertEqual(solution, (None, True, True, False)) + + def test_3_long2(self): + self.solver.add_xor_clause([1, 2, 3], True) + res, solution = self.solver.solve([1, -2]) + self.assertEqual(res, True) + self.assertEqual(solution, (None, True, False, False)) + + def test_long(self): + for l in range(10, 30): + self.setUp() + toadd = [] + toassume = [] + solution_expected = [None] + for i in range(1, l): + toadd.append(i) + solution_expected.append(False) + if i != l - 1: + toassume.append(i * -1) + + self.solver.add_xor_clause(toadd, False) + res, solution = self.solver.solve(toassume) + self.assertEqual(res, True) + self.assertEqual(solution, tuple(solution_expected)) + + +class InitTester(unittest.TestCase): + + def test_wrong_args_to_solver(self): + self.assertRaises(ValueError, Solver, threads=-1) + self.assertRaises(ValueError, Solver, threads=0) + self.assertRaises(ValueError, Solver, verbose=-1) + self.assertRaises(ValueError, Solver, time_limit=-1) + self.assertRaises(ValueError, Solver, confl_limit=-1) + self.assertRaises(TypeError, Solver, threads="fail") + self.assertRaises(TypeError, Solver, verbose="fail") + self.assertRaises(TypeError, Solver, time_limit="fail") + self.assertRaises(TypeError, Solver, confl_limit="fail") + + +class TestDump(unittest.TestCase): + + def setUp(self): + self.solver = Solver() + + def test_max_glue_missing(self): + self.assertRaises(TypeError, + self.solver.start_getting_small_clauses, 4) + + def test_one_dump(self): + with open(_MODULE_DIR+"test.cnf", "r") as x: + for line in x: + line = line.strip() + if "p" in line or "c" in line: + continue + + out = [int(x) for x in line.split()[:-1]] + self.solver.add_clause(out) + + res, _ = self.solver.solve() + self.assertEqual(res, True) + + self.solver.start_getting_small_clauses(4, max_glue=10) + x = self.solver.get_next_small_clause() + self.assertNotEquals(x, None) + self.solver.end_getting_small_clauses() + + +class TestSolve(unittest.TestCase): + + def setUp(self): + self.solver = Solver(threads=2) + + def test_wrong_args(self): + self.assertRaises(TypeError, self.solver.add_clause, 'A') + self.assertRaises(TypeError, self.solver.add_clause, 1) + self.assertRaises(TypeError, self.solver.add_clause, 1.0) + self.assertRaises(TypeError, self.solver.add_clause, object()) + self.assertRaises(TypeError, self.solver.add_clause, ['a']) + self.assertRaises( + TypeError, self.solver.add_clause, [[1, 2], [3, None]]) + self.assertRaises(ValueError, self.solver.add_clause, [1, 0]) + + def test_no_clauses(self): + for _ in range(7): + self.assertEqual(self.solver.solve([]), (True, (None,))) + + def test_cnf1(self): + for cl in clauses1: + self.solver.add_clause(cl) + res, solution = self.solver.solve() + self.assertEqual(res, True) + self.assertTrue(check_solution(clauses1, solution)) + + def test_add_clauses(self): + self.solver.add_clauses([[1], [-1]]) + res, solution = self.solver.solve() + self.assertEqual(res, False) + + def test_add_clauses_wrong_zero(self): + self.assertRaises(TypeError, self.solver.add_clause, [[1, 0], [-1]]) + + def test_add_clauses_array_SAT(self): + cls = array('i', [1, 2, 0, 1, 2, 0]) + self.solver.add_clauses(cls) + res, solution = self.solver.solve() + self.assertEqual(res, True) + + def test_add_clauses_array_UNSAT(self): + cls = array('i', [-1, 0, 1, 0]) + self.solver.add_clauses(cls) + res, solution = self.solver.solve() + self.assertEqual(res, False) + + def test_add_clauses_array_unterminated(self): + cls = array('i', [1, 2, 0, 1, 2]) + self.assertRaises(ValueError, self.solver.add_clause, cls) + + def test_bad_iter(self): + class Liar: + + def __iter__(self): + return None + self.assertRaises(TypeError, self.solver.add_clause, Liar()) + + def test_get_conflict(self): + self.solver.add_clauses([[-1], [2], [3], [-4]]) + assume = [-2, 3, 4] + + res, model = self.solver.solve(assumptions=assume) + self.assertEqual(res, False) + + confl = self.solver.get_conflict() + self.assertEqual(isinstance(confl, list), True) + self.assertNotIn(3, confl) + + if 2 in confl: + self.assertIn(2, confl) + elif -4 in confl: + self.assertIn(-4, confl) + else: + self.assertEqual(False, True, msg="Either -2 or 4 should be conflicting!") + + assume = [2, 4] + res, model = self.solver.solve(assumptions=assume) + self.assertEqual(res, False) + + confl = self.solver.get_conflict() + self.assertEqual(isinstance(confl, list), True) + self.assertNotIn(2, confl) + self.assertIn(-4, confl) + + def test_cnf2(self): + for cl in clauses2: + self.solver.add_clause(cl) + self.assertEqual(self.solver.solve(), (False, None)) + + def test_cnf3(self): + for cl in clauses3: + self.solver.add_clause(cl) + res, solution = self.solver.solve() + self.assertEqual(res, True) + self.assertTrue(check_solution(clauses3, solution)) + + def test_cnf1_confl_limit(self): + for _ in range(1, 20): + self.setUp() + for cl in clauses1: + self.solver.add_clause(cl) + + res, solution = self.solver.solve() + self.assertTrue(res is None or check_solution(clauses1, solution)) + + def test_by_re_curse(self): + self.solver.add_clause([-1, -2, 3]) + res, _ = self.solver.solve() + self.assertEqual(res, True) + + self.solver.add_clause([-5, 1]) + self.solver.add_clause([4, -3]) + self.solver.add_clause([2, 3, 5]) + res, _ = self.solver.solve() + self.assertEqual(res, True) + + +class TestSolveTimeLimit(unittest.TestCase): + + def get_clauses(self): + cls = [] + with open(_MODULE_DIR+"f400-r425-x000.cnf", "r") as f: + for line in f: + line = line.strip() + if len(line) == 0: + continue + if line[0] == "p": + continue + if line[0] == "c": + continue + line = line.split() + line = [int(l.strip()) for l in line] + assert line[-1] == 0 + cls.append(line[:-1]) + + return cls + + + def test_time(self): + SAT_TIME_LIMIT = 1 + clauses = self.get_clauses() #returns a few hundred short clauses + t0 = time.time() + solver = Solver(threads=4, time_limit=SAT_TIME_LIMIT) + solver.add_clauses(clauses) + sat, sol = solver.solve() + took_time = time.time() - t0 + + # NOTE: the above CNF solves in about 1 hour. + # So anything below 10min is good. Setting 2s would work... no most + # systems, but not on overloaded CI servers + self.assertLess(took_time, 4) + +# ------------------------------------------------------------------------ + + +def run(): + print("sys.prefix: %s" % sys.prefix) + print("sys.version: %s" % sys.version) + try: + print("pycryptosat version: %r" % pycryptosat.__version__) + except AttributeError: + pass + suite = unittest.TestSuite() + suite.addTest(unittest.makeSuite(TestXor)) + suite.addTest(unittest.makeSuite(InitTester)) + suite.addTest(unittest.makeSuite(TestSolve)) + suite.addTest(unittest.makeSuite(TestDump)) + suite.addTest(unittest.makeSuite(TestSolveTimeLimit)) + + runner = unittest.TextTestRunner(verbosity=2) + result = runner.run(suite) + + n_errors = len(result.errors) + n_failures = len(result.failures) + + if n_errors or n_failures: + print('\n\nSummary: %d errors and %d failures reported\n'%\ + (n_errors, n_failures)) + + print() + + sys.exit(n_errors+n_failures) + + +if __name__ == '__main__': + run() diff --git a/cryptominisat/cppsrc/scripts/bnn_create_random.py b/cryptominisat/cppsrc/scripts/bnn_create_random.py new file mode 100755 index 00000000..ae7a3c47 --- /dev/null +++ b/cryptominisat/cppsrc/scripts/bnn_create_random.py @@ -0,0 +1,129 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- + +# Copyright (C) 2022 Authors of CryptoMiniSat, see AUTHORS file +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; version 2 +# of the License. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +# 02110-1301, USA. + + +# hard example +# ---------------- +# ../scripts/create_random_bnn.py 300 3000 100 4 > test.bnn +# ./cryptominisat5 --occsimp 0 --scc 0 test.bnn --presimp 0 --varelim 0 --verb 1 -n1 --printsol 0 + +# very hard example +#------------- +# ../scripts/create_random_bnn.py 300 2000 100 7 > test.bnn +# ./cryptominisat5 --occsimp 0 --scc 0 test.bnn --presimp 0 --varelim 0 --verb 4 -n1 --printsol 0 +# appmc counting this: +# c [appmc] [ 21.46 ] bounded_sol_count looking for 73 solutions -- hashes active: 128 +# c [appmc] [ 39.18 ] bounded_sol_count looking for 73 solutions -- hashes active: 256 +# c [appmc] [ 117.86 ] bounded_sol_count looking for 73 solutions -- hashes active: 512 + +# more constraints than above +# -------------- +# ../scripts/create_random_bnn.py 400 2000 100 9 > test.bnn +#c [appmc+arjun] Total time: 214.48 +#c [appmc] Number of solutions is: 33*2**257 +#s SATISFIABLE +#s mc 7642277889662868897955685010573401918315818987932277226604200544522266556235776 +# BUG in appmc: test.bnn-appmcbug (also, bug-appmc in approxmc/build directory) + +# kinda interesting one to run +# --------------- +# ../scripts/create_random_bnn.py 20 100 50 9 > test.bnn +# c Total time (this thread) : 41.60 +# c [appmc+arjun] Total time: 41.59 +# c [appmc] Number of solutions is: 52*2**59 + + + + +import random +import sys + +n = 100 # number of constraints +v = 1000 # number of variables +s = 30 # max size of constraints +seed = 1 + +if len(sys.argv) != 1: + if len(sys.argv) != 5: + print("ERROR: must give: n v s seed") + exit(-1) + + n = int(sys.argv[1]) + v = int(sys.argv[2]) + s = int(sys.argv[3]) + seed = int(sys.argv[4]) + + assert n > 10 + assert v > 0 + +random.seed(seed) +print("c n=%d v=%d seed=%d" % (n, v, seed)) + + + + +for x in range(n): + sz = random.randint(1,s) + + # get input + output + ks = [] + while len(ks) < sz+1: + x = random.randint(1,v) + if x in ks or -x in ks: + continue + else: + ks.append(x) + + # get cutoff + cutoff = random.randint(0, sz) + + # get output + output = ks[len(ks)-1] + ks = ks[:-1] + + pr = "b " + for k in ks: + if random.choice([True, False]): + pr+="-" + pr += "%d " % k + pr += "0 " + pr += "%d " % cutoff + pr += "%d" % output + print("%s" % pr) + + +# add some clauses +for x in range(n): + sz = random.randint(1,8) + ks = [] + while len(ks) < sz: + x = random.randint(1, v) + if x in ks or -x in ks: + continue + + if random.choice([True, False]): + ks.append(x) + else: + ks.append(-x) + + pr = "" + for k in ks: + pr += "%d " % k + print("%s0" % pr) diff --git a/cryptominisat/cppsrc/scripts/build_scripts b/cryptominisat/cppsrc/scripts/build_scripts new file mode 160000 index 00000000..e9085dee --- /dev/null +++ b/cryptominisat/cppsrc/scripts/build_scripts @@ -0,0 +1 @@ +Subproject commit e9085dee5b361f3ee57809d1a19c9703d697f742 diff --git a/cryptominisat/cppsrc/scripts/check_all_licenses.sh b/cryptominisat/cppsrc/scripts/check_all_licenses.sh new file mode 100755 index 00000000..ee2c025c --- /dev/null +++ b/cryptominisat/cppsrc/scripts/check_all_licenses.sh @@ -0,0 +1,21 @@ +#!/usr/bin/bash +set -e +set -x + +check_license_fnames() { + #license check -- first print and then fail in case of problems + find $1 -type f -name $2 -exec ../utils/licensecheck/licensecheck.pl -m {} \; + NUM=$(find $1 -type f -name $2 -exec ../utils/licensecheck/licensecheck.pl -m {} \; | grep UNK | wc -l) + shopt -s extglob + NUM="${NUM##*( )}" + NUM="${NUM%%*( )}" + shopt -u extglob + if [ "$NUM" -ne 0 ]; then + echo "There are some files without license information!" + exit -1 + fi +} + +check_license_fnames ../tests/ CMakeLists.txt +check_license_fnames ../src/ CMakeLists.txt +check_license_fnames ../scripts/ CMakeLists.txt diff --git a/cryptominisat/cppsrc/scripts/check_lpn_solution.py b/cryptominisat/cppsrc/scripts/check_lpn_solution.py new file mode 100755 index 00000000..bf022d3b --- /dev/null +++ b/cryptominisat/cppsrc/scripts/check_lpn_solution.py @@ -0,0 +1,109 @@ +#!/usr/bin/env python3 +# -*- coding: utf-8 -*- + +# Copyright (C) 2009-2020 Authors of CryptoMiniSat, see AUTHORS file +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; version 2 +# of the License. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +# 02110-1301, USA. + +import optparse +import random +import sys + +lpnfile = sys.argv[1] +satout = sys.argv[2] + +sat = None +sol = {} +with open(satout, "r") as f: + for line in f: + line = line.strip() + if len(line) < 1: + continue + + if line[0] == "s": + if "s SATISFIABLE" in line: + sat = True + continue + if "s UNSATISFIABLE" in line: + sat = False + continue + print("ERROR: Nether SAT, nor UNSAT on solution line!") + exit(-1) + + if line[0] == "v": + line=line.strip() + line=line[1:] + for lit in line.split(): + lit = int(lit) + var = abs(lit) + if var == 0: + continue + sol[var] = lit > 0 + +if sat is None: + print("ERRROR could not recover solution from SAT output") + exit(-1) + +# print("Recovered SAT: ", sat) +# print("Recovered Solution : ", sol) + +corr_sat = None +corr_sol = {} +with open(lpnfile, "r") as f: + for line in f: + line=line.strip() + if "correct output" not in line: + continue + if "UNSAT" in line: + corr_sat = False + break + corr_sat = True + assert "SAT" in line + + line = line.split(":")[1] + for lit in line.split()[1:]: # first is text "SAT" + lit = int(lit) + var = abs(lit) + corr_sol[var] = lit > 0 + +if corr_sat is None: + print("ERROR: could not recover correct solution from problem file") + exit(-1) + +if corr_sat is False: + if sat == False: + print("UNSAT both, all good!") + exit(0) + if sat == True: + print("ERROR: buuuug!!! Should be UNSAT but it's SAT!!") + exit(-1) + +assert corr_sat == True +if sat == False: + print("ERROR: buuuug!!! Should be SAT but it's UNSAT!!") + exit(-1) + +for v,val in corr_sol.items(): + if v not in sol: + print("ERROR: Var %d is in problem, but not in solution" % v) + exit(-1) + if sol[v] != corr_sol[v]: + print("ERROR: Var %d is %s in problem, but %s in solution" % (v, corr_sol[v], sol[v])) + exit(-1) + assert sol[v] == corr_sol[v] + +print("OK, SAT, checked all solution values") #: %s" % corr_sol) +exit(0) diff --git a/cryptominisat/cppsrc/scripts/crystal/ballofcrystal.sh b/cryptominisat/cppsrc/scripts/crystal/ballofcrystal.sh new file mode 100755 index 00000000..42341902 --- /dev/null +++ b/cryptominisat/cppsrc/scripts/crystal/ballofcrystal.sh @@ -0,0 +1,282 @@ +#!/bin/bash + +# Copyright (C) 2009-2020 Authors of CryptoMiniSat, see AUTHORS file +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; version 2 +# of the License. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +# 02110-1301, USA. + +# This file wraps CMake invocation for TravisCI +# so we can set different configurations via environment variables. + +set -e +set -x +set -o pipefail # needed so " | tee xyz " doesn't swallow the last command's error + +source ./setparams_ballofcrystal.sh + +if [ "$1" == "--skip" ]; then + echo "Will skip running CMS stats + FRAT" + SKIP="1" + NEXT_OP="$2" +else + SKIP="0" + NEXT_OP="$1" +fi + +if [ "$NEXT_OP" == "" ]; then + while true; do + echo "No CNF command line parameter, running predefined CNFs" + echo "Options are:" + echo "1 -- velev-pipe-uns-1.0-9.cnf" + echo "2 -- goldb-heqc-i10mul.cnf" + echo "3 -- Haystacks-ext-13_c18.cnf" + echo "4 -- NONE" + echo "5 -- AProVE07-16.cnf" + echo "6 -- UTI-20-10p0.cnf-unz" + echo "7 -- UCG-20-5p0.cnf" + + read -r -p "Which CNF do you want to run? " myinput + case $myinput in + ["1"]* ) + FNAME="velev-pipe-uns-1.0-9.cnf" + break;; + [2]* ) + FNAME="goldb-heqc-i10mul.cnf"; + break;; + [3]* ) + FNAME="dist6.c-sc2018.cnf"; + break;; + [5]* ) + FNAME="AProVE07-16.cnf"; + break;; + [6]* ) + DUMPRATIO="0.01" + FNAME="UTI-20-10p0.cnf-unz"; + FIXED="20000"; + break;; + [7]* ) + DUMPRATIO="0.50" + FNAME="UCG-20-5p0.cnf"; + break;; + * ) echo "Please answer 1-7";; + esac + done +else + if [ "$NEXT_OP" == "-h" ] || [ "$NEXT_OP" == "--help" ]; then + echo "You must give a CNF file as input" + exit + fi + initial="$(echo ${NEXT_OP} | head -c 1)" + if [ "$1" == "-" ]; then + echo "Cannot understand opion, there are no options" + exit 255 + fi + FNAME="${NEXT_OP}" +fi + +set -e +set -o pipefail + +echo "--> Running on file $FNAME" +echo "--> Outputting to data $FNAMEOUT" +echo "--> Using clause gather ratio of $DUMPRATIO" +echo "--> Locking in ratio of $CLLOCK" +echo "--> with fixed number of data points $FIXED" + +if [ "$FNAMEOUT" == "" ]; then + echo "Error: FNAMEOUT is not set, it's empty. Exiting." + exit 255 +fi + + +if [ "$SKIP" != "1" ]; then + echo "Cleaning up" + ( + rm -rf "$FNAME-dir" + mkdir "$FNAME-dir" + cd "$FNAME-dir" + rm -f $FNAMEOUT.d* + rm -f $FNAMEOUT.lemma* + ) + + set -e + + ######################## + # Build statistics-gathering CryptoMiniSat + ######################## + if [[ $SANITIZE -eq 0 ]]; then + ./build_stats.sh + else + ./build_stats_sanitize.sh + fi + + ( + ######################## + # Obtain dynamic data in SQLite and FRAT info + ######################## + cd "$FNAME-dir" + # for var, we need: --bva 0 --scc 0 + $NOBUF ../cryptominisat5 --maxnummatrices 0 --presimp 1 -n1 --sqlitedbover 1 --cldatadumpratio "$DUMPRATIO" --cllockdatagen "$CLLOCK" --clid --sql 2 --sqlitedb "$FNAMEOUT.db-raw" --frat "$FNAMEOUT.frat" --zero-exit-status "../$FNAME" | tee cms-pred-run.out + grep "c conflicts" cms-pred-run.out + + ######################## + # Run frat-rs + ######################## + set +e + grep "s SATIS" cms-pred-run.out > /dev/null + retval=$? + set -e + if [[ retval -eq 1 ]]; then + /usr/bin/time -v ../frat-rs elab "$FNAMEOUT.frat" "../$FNAME" -m -v + + echo "If the following fails, you MUST compile frat-rs with 'ascii' feature through 'cargo build --features=ascii --release' !" + set +e + /usr/bin/time -v ../frat-rs elab "$FNAMEOUT.frat" + /usr/bin/time -v ../frat-rs refrat "$FNAMEOUT.frat.temp" correct + set -e + + + else + echo "Not UNSAT!!!" + exit 255 + fi + echo "CMS+FRAT done now" + ) +fi + +( +set -e +cd "$FNAME-dir" + +######################## +# Augment, fix up and sample the SQLite data +######################## + +rm -f "$FNAMEOUT.db" +rm -f "$FNAMEOUT-min.db" +rm -f "${FNAMEOUT}-min.db-cldata-*" +rm -f out_pred_* +rm -f sample.out +rm -f check_quality.out +rm -f clean_update.out +rm -f fill_clauses.out + +../fix_up_frat.py correct "$FNAMEOUT.db-raw" | tee fill_used_clauses.out +cp "$FNAMEOUT.db-raw" "$FNAMEOUT.db" +/usr/bin/time -v ../clean_update_data.py "$FNAMEOUT.db" | tee clean_update_data.out +../check_data_quality.py --slow "$FNAMEOUT.db" | tee check_data_quality.out +cp "$FNAMEOUT.db" "$FNAMEOUT-min.db" +/usr/bin/time -v ../sample_data.py "$FNAMEOUT-min.db" | tee sample_data.out + + +######################## +# Denormalize the data into a Pandas Table, label it and sample it +######################## +../cldata_gen_pandas.py "${FNAMEOUT}-min.db" --cut1 "$cut1" --cut2 "$cut2" --limit "$FIXED" ${EXTRA_GEN_PANDAS_OPTS} | tee cldata_gen_pandas.out +# ../vardata_gen_pandas.py "${FNAMEOUT}.db" --limit 1000 + + +#################################### +# Clustering for cldata, using cldata dataframe +#################################### +# ../clustering.py ${FNAMEOUT}-min.db-cldata-*short*.dat ${FNAMEOUT}-min.db-cldata-*long*.dat --basedir ../../src/predict/ --clusters 4 --scale --nocomputed + + +#################################### +# Create the classifiers +#################################### + +# TODO: add --csv to dump CSV +# then you can play with Weka +#../vardata_predict.py mydata.db-vardata.dat --picktimeonly -q 2 --only 0.99 +#../vardata_predict.py vardata-comb --final -q 20 --basedir ../src/predict/ --depth 7 --tree + +set -e +set -o pipefail +rm -f .*.json +regressors=("xgb") # "lgbm" ) +tiers=("short" "long" "forever") +tables=("used_later" "used_later_anc") +for tier in "${tiers[@]}"; do + for table in "${tables[@]}"; do + for regressor in "${regressors[@]}"; do + $NOBUF ../cldata_predict.py "${FNAMEOUT}-min.db-cldata-${table}-${tier}-cut1-$cut1-cut2-$cut2-limit-${FIXED}.dat" --tier "${tier}" --table "${table}" --features best_only --regressor "$regressor" --basedir "." --bestfeatfile "$bestf"| tee "cldata_predict_${tier}-${table}-${regressor}.out" + done + done +done + +############################ +# To get feature importances +############################ +# ../cldata_predict.py "${FNAMEOUT}-min.db-cldata-long-cut1-$cut1-cut2-$cut2-limit-${FIXED}.dat" --tier long --top 200 --xgb --allcomputed > output_long +# ../cldata_predict.py "${FNAMEOUT}-min.db-cldata-long-cut1-$cut1-cut2-$cut2-limit-${FIXED}.dat" --tier long --top 200 --xgb --nocomputed > output_long_nocomputed +# ../cldata_predict.py "${FNAMEOUT}-min.db-cldata-short-cut1-$cut1-cut2-$cut2-limit-${FIXED}.dat" --tier short --top 200 --xgb --allcomputed > output_short +# ../cldata_predict.py "${FNAMEOUT}-min.db-cldata-short-cut1-$cut1-cut2-$cut2-limit-${FIXED}.dat" --tier short --top 200 --xgb --nocomputed > output_short_nocomputed +# ../cldata_predict.py "${FNAMEOUT}-min.db-cldata-forever-cut1-$cut1-cut2-$cut2-limit-${FIXED}.dat" --tier forever --top 2000 --xgb --nocomputed --topperc > "output_forever_nocomputed" +# ../cldata_predict.py "${FNAMEOUT}-min.db-cldata-forever-cut1-$cut1-cut2-$cut2-limit-${FIXED}.dat" --tier forever --top 2000 --xgb --allcomputed --topperc > "output_forever" + + +) + + +######################## +# Build final CryptoMiniSat with the classifier +######################## +if [[ $SANITIZE -eq 1 ]]; then + ./build_final_predictor_sanitize.sh +else + ./build_final_predictor.sh +fi + +( +cd "$FNAME-dir" +ln -fs ../ml_module.py . + +TODO="000" +../cryptominisat5 "../$FNAME" --predtype py --simfrat 1 --printsol 0 --predloc "./" --predbestfeats "$bestf" --predtables $TODO --distillsort 3 > cms-final-run.out-${TODO}-distillsort3 & + +TODO="001" +../cryptominisat5 "../$FNAME" --predtype py --simfrat 1 --printsol 0 --predloc "./" --predbestfeats "$bestf" --predtables $TODO --distillsort 3 > cms-final-run.out-${TODO}-distillsort3 & + +TODO="010" +../cryptominisat5 "../$FNAME" --predtype py --simfrat 1 --printsol 0 --predloc "./" --predbestfeats "$bestf" --predtables $TODO --distillsort 3 > cms-final-run.out-${TODO}-distillsort3 & + +TODO="011" +../cryptominisat5 "../$FNAME" --predtype py --simfrat 1 --printsol 0 --predloc "./" --predbestfeats "$bestf" --predtables $TODO --distillsort 3 > cms-final-run.out-${TODO}-distillsort3 & + +TODO="100" +../cryptominisat5 "../$FNAME" --predtype py --simfrat 1 --printsol 0 --predloc "./" --predbestfeats "$bestf" --predtables $TODO --distillsort 3 > cms-final-run.out-${TODO}-distillsort3 & + +TODO="101" +../cryptominisat5 "../$FNAME" --predtype py --simfrat 1 --printsol 0 --predloc "./" --predbestfeats "$bestf" --predtables $TODO --distillsort 3 > cms-final-run.out-${TODO}-distillsort3 & + +TODO="110" +../cryptominisat5 "../$FNAME" --predtype py --simfrat 1 --printsol 0 --predloc "./" --predbestfeats "$bestf" --predtables $TODO --distillsort 3 > cms-final-run.out-${TODO}-distillsort3 & + +TODO="111" +../cryptominisat5 "../$FNAME" --predtype py --simfrat 1 --printsol 0 --predloc "./" --predbestfeats "$bestf" --predtables $TODO --distillsort 3 > cms-final-run.out-${TODO}-distillsort3 & + +) +exit + + +# old +# ./cryptominisat5 goldb-heqc-i10mul.cnf --simfrat 1 --printsol 0 --predloc ./data/14-april-2021-69bad529f962c-cut1-3.0-cut2-25.0-limit-1000-est10-w0-xbmin50-xbmd6/ --predtype py --predbestfeats ./best_features-b93210018231ab04d2.txt + +# current +# ./cryptominisat5 goldb-heqc-i10mul.cnf --simfrat 1 --printsol 0 --predloc ./data/18-sept-2021-a408d53c665f9305b-cut1-3.0-cut2-25.0-limit-1000-est15-w0-xbmin50-xbmd4-regxgb/ --predtype py --predbestfeats ./best_features-rdb0-only.txt + +# newest +# ./cryptominisat5 goldb-heqc-i10mul.cnf --simfrat 1 --printsol 0 --predloc ./data/29-sept-a408d53c665f9305b-ccf121255372-cut1-3.0-cut2-25.0-limit-3000-est8-w0-xbmin10-xbmd6-regxgb/ --predtype py --predbestfeats ./best_features-correlaton.txt diff --git a/cryptominisat/cppsrc/scripts/crystal/best_features-b93210018231ab04d2.txt b/cryptominisat/cppsrc/scripts/crystal/best_features-b93210018231ab04d2.txt new file mode 100644 index 00000000..90f3daf9 --- /dev/null +++ b/cryptominisat/cppsrc/scripts/crystal/best_features-b93210018231ab04d2.txt @@ -0,0 +1,46 @@ +rdb0.uip1_ranking_rel +(rdb0.act_ranking_rel/rdb0.last_touched_diff) +rdb0.prop_ranking_rel +(rdb0.props_made/rdb0_common.avg_props) +rdb0.last_touched_diff +(rdb0.glue/cl.glueHist_avg) +rdb0.glue +(rdb0.sum_props_made/cl.time_inside_solver) +((rdb0.sum_props_made/cl.time_inside_solver)/(rdb0.glue/rdb0_common.avg_glue)) +(log2(cl.glue_before_minim)/(rdb0.sum_uip1_used/cl.time_inside_solver)) +cl.orig_glue +(log2(cl.num_antecedents)/cl.num_total_lits_antecedents) +(cl.glueHist_longterm_avg/cl.glue_before_minim) +(rdb0.glue/rdb0_common.conflSizeHistLT_avg) +(rdb0.discounted_props_made/cl.numResolutionsHistLT_avg) +((rdb0.sum_uip1_used/cl.time_inside_solver)/rdb0.discounted_props_made) +(rdb0.glue/(rdb0.props_made/rdb0_common.avg_props)) +((rdb0.sum_props_made/cl.time_inside_solver)/cl.num_total_lits_antecedents) +(rdb0.glue/cl.glueHistLT_avg) +(rdb0.prop_ranking_rel/(rdb0.uip1_used/rdb0_common.avg_uip1_used)) +(cl.overlapHistLT_avg/cl.conflSizeHist_avg) +(cl.glueHistLT_avg/rdb0.uip1_used) +(rdb0.size/rdb0_common.avg_glue) +(rdb0.size/rdb0.sum_uip1_used) +rdb0.discounted_uip1_used +(cl.glueHistLT_avg/rdb0.discounted_props_made) +(rdb0.uip1_ranking_rel/rdb0_common.avg_uip1_used) +(cl.num_antecedents/(rdb0.discounted_uip1_used/rdb0_common.avg_uip1_used)) +rdb0.sum_uip1_per_time_ranking_rel +rdb0.sum_props_per_time_ranking_rel +(cl.glueHist_avg/cl.atedecents_binRed) +((rdb0.act_ranking_rel/rdb0.last_touched_diff)*(rdb0.uip1_ranking_rel/rdb0_common.avg_uip1_used)) +((cl.overlapHistLT_avg/cl.conflSizeHist_avg)*(rdb0.discounted_uip1_used)) +((rdb0.sum_props_made/cl.time_inside_solver)*(rdb0.sum_props_made/cl.time_inside_solver)/(rdb0.glue/rdb0_common.avg_glue)) +(rdb0.discounted_uip1_used3*rdb0_common.glueHistLT_avg) +(cl.atedecents_binIrred*rdb0_common.avg_uip1_used) +# +#(cl.conflicts-rdb0.introduced_at_conflict) +#cl.atedecents_binRed +#rdb0.discounted_uip1_used3 +#rdb0_common.num_vars +#cl.glueHist_avg +#rdb0.discounted_props_made3 +#cl.num_antecedents +#rdb0_common.num_bin_irred_cls +#cl.trailDepthHistLT_avg diff --git a/cryptominisat/cppsrc/scripts/crystal/best_features-correlation2.txt b/cryptominisat/cppsrc/scripts/crystal/best_features-correlation2.txt new file mode 100644 index 00000000..9f18121e --- /dev/null +++ b/cryptominisat/cppsrc/scripts/crystal/best_features-correlation2.txt @@ -0,0 +1,44 @@ +#ranking +rdb0.sum_uip1_per_time_ranking_rel +rdb0.sum_props_per_time_ranking_rel +rdb0.act_ranking_rel +rdb0.uip1_ranking_rel +rdb0.prop_ranking_rel +# +# +# discounted and raw +rdb0.props_made +rdb0.uip1_used +rdb0.discounted_props_made +rdb0.discounted_props_made2 +rdb0.discounted_props_made3 +rdb0.discounted_uip1_used +rdb0.discounted_uip1_used2 +rdb0.discounted_uip1_used3 +# +# rdb80 +# rdb80.sum_discounted_uip1_used +# rdb80.sum_discounted_props_made +# rdb80.sum_uip1_used +# rdb80.sum_props_made +# rdb80.sum_conflicts_made + +# sum features +# rdb0.sum_uip1_used +# rdb0.sum_props_made + +# +# relative features +(cl.glue_before_minim/cl.glueHist_longterm_avg) +(rdb0.uip1_used/rdb0_common.avg_uip1_used) +(rdb0.glue/rdb0_common.glueHistLT_avg) +(rdb0.props_made/rdb0_common.avg_props) +(rdb0.sum_props_made/cl.time_inside_solver) +(rdb0.sum_uip1_used/cl.time_inside_solver) +(cl.num_antecedents/cl.num_total_lits_antecedents) +# +# +# other +(rdb0.glue/cl.trail_depth_level) +cl.orig_glue + diff --git a/cryptominisat/cppsrc/scripts/crystal/best_features-correlaton.txt b/cryptominisat/cppsrc/scripts/crystal/best_features-correlaton.txt new file mode 100644 index 00000000..571a3490 --- /dev/null +++ b/cryptominisat/cppsrc/scripts/crystal/best_features-correlaton.txt @@ -0,0 +1,20 @@ +rdb0.sum_props_per_time_ranking +rdb0.act_ranking_rel +rdb0_common.avg_props +rdb0.discounted_props_made3 +rdb0_common.glueHistLT_avg +(rdb0.sum_props_made/cl.time_inside_solver) +rdb0.uip1_ranking_rel +(rdb0.props_made/rdb0_common.avg_props) +rdb0.discounted_props_made +rdb0.sum_uip1_per_time_ranking_rel +rdb0_common.avg_uip1_used +rdb0.prop_ranking_rel +rdb0.sum_props_per_time_ranking_rel +(cl.glueHist_longterm_avg/cl.glue_before_minim) +rdb0.discounted_uip1_used3 +rdb0.discounted_props_made2 +rdb0.props_made +rdb0.discounted_uip1_used +rdb0.discounted_uip1_used2 +rdb0.uip1_used diff --git a/cryptominisat/cppsrc/scripts/crystal/best_features-d6e51325f8046.txt b/cryptominisat/cppsrc/scripts/crystal/best_features-d6e51325f8046.txt new file mode 100644 index 00000000..989965ad --- /dev/null +++ b/cryptominisat/cppsrc/scripts/crystal/best_features-d6e51325f8046.txt @@ -0,0 +1,40 @@ +rdb0.uip1_ranking_rel +(rdb0.act_ranking_rel/rdb0.last_touched_diff) +rdb0.prop_ranking_rel +(rdb0.props_made/rdb0_common.avg_props) +rdb0.last_touched_diff +(rdb0.glue/cl.glueHist_avg) +rdb0.glue +(rdb0.sum_props_made/cl.time_inside_solver) +((rdb0.sum_props_made/cl.time_inside_solver)/(rdb0.glue/rdb0_common.avg_glue)) +(log2(cl.glue_before_minim)/(rdb0.sum_uip1_used/cl.time_inside_solver)) +cl.orig_glue +(log2(cl.num_antecedents)/cl.num_total_lits_antecedents) +(cl.glueHist_longterm_avg/cl.glue_before_minim) +(rdb0.glue/rdb0_common.conflSizeHistLT_avg) +(rdb0.discounted_props_made/cl.numResolutionsHistLT_avg) +((rdb0.sum_uip1_used/cl.time_inside_solver)/rdb0.discounted_props_made) +(rdb0.glue/(rdb0.props_made/rdb0_common.avg_props)) +((rdb0.sum_props_made/cl.time_inside_solver)/cl.num_total_lits_antecedents) +(rdb0.glue/cl.glueHistLT_avg) +(rdb0.prop_ranking_rel/(rdb0.uip1_used/rdb0_common.avg_uip1_used)) +(cl.overlapHistLT_avg/cl.conflSizeHist_avg) +(cl.glueHistLT_avg/rdb0.uip1_used) +(rdb0.size/rdb0_common.avg_glue) +(rdb0.size/rdb0.sum_uip1_used) +rdb0.discounted_uip1_used +(cl.glueHistLT_avg/rdb0.discounted_props_made) +(rdb0.uip1_ranking_rel/rdb0_common.avg_uip1_used) +(cl.num_antecedents/(rdb0.discounted_uip1_used/rdb0_common.avg_uip1_used)) +rdb0.sum_uip1_per_time_ranking_rel +rdb0.sum_props_per_time_ranking_rel +(cl.glueHist_avg/cl.atedecents_binRed) +#(cl.conflicts-rdb0.introduced_at_conflict) +#cl.atedecents_binRed +#rdb0.discounted_uip1_used3 +#rdb0_common.num_vars +#cl.glueHist_avg +#rdb0.discounted_props_made3 +#cl.num_antecedents +#rdb0_common.num_bin_irred_cls +#cl.trailDepthHistLT_avg diff --git a/cryptominisat/cppsrc/scripts/crystal/best_features-kissat.txt b/cryptominisat/cppsrc/scripts/crystal/best_features-kissat.txt new file mode 100644 index 00000000..aee73dac --- /dev/null +++ b/cryptominisat/cppsrc/scripts/crystal/best_features-kissat.txt @@ -0,0 +1,16 @@ +#ranking +rdb0.sum_uip1_per_time_ranking_rel +rdb0.sum_props_per_time_ranking_rel +rdb0.uip1_ranking_rel +rdb0.prop_ranking_rel +# +# discounted and raw +rdb0.props_made +rdb0.uip1_used +rdb0.discounted_props_made +rdb0.discounted_props_made2 +rdb0.discounted_uip1_used +rdb0.discounted_uip1_used2 + +rdb0.glue +rdb0.last_touched_diff diff --git a/cryptominisat/cppsrc/scripts/crystal/best_features-rdb0-only.txt b/cryptominisat/cppsrc/scripts/crystal/best_features-rdb0-only.txt new file mode 100644 index 00000000..64792377 --- /dev/null +++ b/cryptominisat/cppsrc/scripts/crystal/best_features-rdb0-only.txt @@ -0,0 +1,63 @@ +rdb0.uip1_ranking_rel +(rdb0.act_ranking_rel/rdb0.last_touched_diff) +(rdb0.props_made/rdb0_common.avg_props) +rdb0.last_touched_diff +(rdb0.glue/cl.glueHist_avg) +rdb0.glue +(rdb0.sum_props_made/cl.time_inside_solver) +((rdb0.sum_props_made/cl.time_inside_solver)/(rdb0.glue/rdb0_common.avg_glue)) +(cl.glueHist_longterm_avg/cl.glue_before_minim) +((rdb0.sum_uip1_used/cl.time_inside_solver)/rdb0.discounted_props_made) +(rdb0.glue/(rdb0.props_made/rdb0_common.avg_props)) +(rdb0.prop_ranking_rel/(rdb0.uip1_used/rdb0_common.avg_uip1_used)) +(cl.overlapHistLT_avg/cl.conflSizeHist_avg) +rdb0.discounted_uip1_used +(cl.glueHistLT_avg/rdb0.discounted_props_made) +(rdb0.uip1_ranking_rel/rdb0_common.avg_uip1_used) +(cl.num_antecedents/(rdb0.discounted_uip1_used/rdb0_common.avg_uip1_used)) +(cl.glueHist_avg/cl.atedecents_binRed) +((rdb0.act_ranking_rel/rdb0.last_touched_diff)*(rdb0.uip1_ranking_rel/rdb0_common.avg_uip1_used)) +(cl.atedecents_binIrred*rdb0_common.avg_uip1_used) +# Correlation check wants these: +#rdb0_common.avg_uip1_used +#rdb0.uip1_used +#rdb0.discounted_uip1_used2 +#rdb0.discounted_props_made2 +#rdb0.props_made +#rdb0.sum_props_per_time_ranking_rel +#rdb0.discounted_uip1_used3 +#rdb0.sum_uip1_per_time_ranking_rel + +# +# Some old stuff +#(cl.conflicts-rdb0.introduced_at_conflict) +#cl.atedecents_binRed +#rdb0.discounted_uip1_used3 +#rdb0_common.num_vars +#cl.glueHist_avg +#rdb0.discounted_props_made3 +#cl.num_antecedents +#rdb0_common.num_bin_irred_cls +#cl.trailDepthHistLT_avg +# +# +################ +# Features we deleted due to high correlation +# (based on data forever-comb-cut1-3.0-cut2-25.0-limit-1000.dat, MD5: c95208f18684a1c93887b161a4380e1a) +################ +#rdb0.prop_ranking_rel +#cl.orig_glue +#(log2(cl.glue_before_minim)/(rdb0.sum_uip1_used/cl.time_inside_solver)) +#(rdb0.glue/cl.glueHistLT_avg) +#((rdb0.sum_props_made/cl.time_inside_solver)/cl.num_total_lits_antecedents) +#(rdb0.discounted_uip1_used3*rdb0_common.glueHistLT_avg) +#((rdb0.sum_props_made/cl.time_inside_solver)*(rdb0.sum_props_made/cl.time_inside_solver)/(rdb0.glue/rdb0_common.avg_glue)) +#rdb0.sum_props_per_time_ranking_rel +#(rdb0.glue/rdb0_common.conflSizeHistLT_avg) +#(cl.glueHistLT_avg/rdb0.uip1_used) +#rdb0.sum_uip1_per_time_ranking_rel +#(rdb0.size/rdb0_common.avg_glue) +#(rdb0.discounted_props_made/cl.numResolutionsHistLT_avg) +#((cl.overlapHistLT_avg/cl.conflSizeHist_avg)*(rdb0.discounted_uip1_used)) +#(log2(cl.num_antecedents)/cl.num_total_lits_antecedents) +#(rdb0.size/rdb0.sum_uip1_used) diff --git a/cryptominisat/cppsrc/scripts/crystal/ccg.py b/cryptominisat/cppsrc/scripts/crystal/ccg.py new file mode 100644 index 00000000..abb758be --- /dev/null +++ b/cryptominisat/cppsrc/scripts/crystal/ccg.py @@ -0,0 +1,198 @@ +#!/usr/bin/env python3 +# -*- coding: utf-8 -*- + +# Copyright (C) 2009-2020 Authors of CryptoMiniSat, see AUTHORS file +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; version 2 +# of the License. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +# 02110-1301, USA. + +import ast + +BINOP_SYMBOLS = {} +BINOP_SYMBOLS[ast.Add] = '+' +BINOP_SYMBOLS[ast.Sub] = '-' +BINOP_SYMBOLS[ast.Mult] = '*' +BINOP_SYMBOLS[ast.Div] = '/' +BINOP_SYMBOLS[ast.Mod] = '%' +BINOP_SYMBOLS[ast.Pow] = '**' +BINOP_SYMBOLS[ast.LShift] = '<<' +BINOP_SYMBOLS[ast.RShift] = '>>' +BINOP_SYMBOLS[ast.BitOr] = '|' +BINOP_SYMBOLS[ast.BitXor] = '^' +BINOP_SYMBOLS[ast.BitAnd] = '&' +BINOP_SYMBOLS[ast.FloorDiv] = '//' + +BOOLOP_SYMBOLS = {} +BOOLOP_SYMBOLS[ast.And] = 'and' +BOOLOP_SYMBOLS[ast.Or] = 'or' + +CMPOP_SYMBOLS = {} +CMPOP_SYMBOLS[ast.Eq] = '==' +CMPOP_SYMBOLS[ast.NotEq] = '!=' +CMPOP_SYMBOLS[ast.Lt] = '<' +CMPOP_SYMBOLS[ast.LtE] = '<=' +CMPOP_SYMBOLS[ast.Gt] = '>' +CMPOP_SYMBOLS[ast.GtE] = '>=' +CMPOP_SYMBOLS[ast.Is] = 'is' +CMPOP_SYMBOLS[ast.IsNot] = 'is not' +CMPOP_SYMBOLS[ast.In] = 'in' +CMPOP_SYMBOLS[ast.NotIn] = 'not in' + +class ccg: + def fix_feat_name(x): + return "df[\"%s\"]" % x + + + def to_source(node, updater=fix_feat_name): + """This function can convert a node tree back into python sourcecode. + This is useful for debugging purposes, especially if you're dealing with + custom asts not generated by python itself. + + It could be that the sourcecode is evaluable when the AST itself is not + compilable / evaluable. The reason for this is that the AST contains some + more data than regular sourcecode does, which is dropped during + conversion. + """ + generator = ccg.SourceGenerator() + generator.update=updater + generator.visit(node) + + return ''.join(generator.result) + + class SourceGenerator(ast.NodeVisitor): + """This visitor is able to transform a well formed syntax tree into python + sourcecode. For more details have a look at the docstring of the + `node_to_source` function. + """ + + def __init__(self): + self.result = [] + + def write(self, x): + self.result.append(x) + + def body(self, statements): + for stmt in statements: + self.visit(stmt) + + def body_or_else(self, node): + self.body(node.body) + if node.orelse: + self.write('else:') + self.body(node.orelse) + + def signature(self, node): + want_comma = [] + def write_comma(): + if want_comma: + self.write(', ') + else: + want_comma.append(True) + + padding = [None] * (len(node.args) - len(node.defaults)) + for arg, default in zip(node.args, padding + node.defaults): + write_comma() + self.visit(arg) + if default is not None: + self.write('=') + self.visit(default) + if node.vararg is not None: + write_comma() + self.write('*' + node.vararg) + if node.kwarg is not None: + write_comma() + self.write('**' + node.kwarg) + + # Statements + + def visit_Expr(self, node): + self.write("(") + self.generic_visit(node) + self.write(")") + + # Expressions + + def visit_Attribute(self, node): + x = self.update(node.value.id + '.' + node.attr) + self.write(x) + + + # visiting functions. only log2 + # should be: df[divisor].apply(np.log2) + def visit_Call(self, node): + if node.func.id != "log2": + self.visit(node.func) + self.write('(') + + for arg in node.args: + self.visit(arg) + for keyword in node.keywords: + self.write(keyword.arg + '=') + self.visit(keyword.value) + + self.write(".apply(np.log2)") + self.write(')') + + + def visit_Name(self, node): + #print("type:", type(node.id)) + if node.id != "log2": + x = self.update(node.id) + else: + x = node.id + + self.write(x) + + def visit_Str(self, node): + self.write(repr(node.s)) + + def visit_Bytes(self, node): + self.write(repr(node.s)) + + def visit_Num(self, node): + self.write(repr(node.n)) + + def visit_BinOp(self, node): + self.write('(') + self.visit(node.left) + self.write(' %s ' % BINOP_SYMBOLS[type(node.op)]) + self.visit(node.right) + self.write(')') + + def visit_BoolOp(self, node): + self.write('(') + for idx, value in enumerate(node.values): + if idx: + self.write(' %s ' % BOOLOP_SYMBOLS[type(node.op)]) + self.visit(value) + self.write(')') + + def visit_Compare(self, node): + self.write('(') + self.visit(node.left) + for op, right in zip(node.ops, node.comparators): + self.write(' %s ' % CMPOP_SYMBOLS[type(op)]) + self.visit(right) + self.write(')') + + # Helper Nodes + + def visit_alias(self, node): + self.write(node.name) + if node.asname is not None: + self.write(' as ' + node.asname) + + def visit_arguments(self, node): + self.signature(node) diff --git a/cryptominisat/cppsrc/scripts/crystal/check_data_quality.py b/cryptominisat/cppsrc/scripts/crystal/check_data_quality.py new file mode 100755 index 00000000..e71d85d6 --- /dev/null +++ b/cryptominisat/cppsrc/scripts/crystal/check_data_quality.py @@ -0,0 +1,337 @@ +#!/usr/bin/env python3 +# -*- coding: utf-8 -*- + +# Copyright (C) 2009-2020 Authors of CryptoMiniSat, see AUTHORS file +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; version 2 +# of the License. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +# 02110-1301, USA. + +from __future__ import print_function +import optparse +import time +import helper + + +class Queries (helper.QueryHelper): + def __init__(self, dbfname): + super(Queries, self).__init__(dbfname) + + def create_indexes(self): + helper.drop_idxs(self.c) + + print("Creating needed indexes...") + t = time.time() + q = """ + create index `idxclid-del` on `cl_last_in_solver` (`clauseID`, `conflicts`); + create index `idxclid-del2` on `used_clauses` (`clauseID`); + create index `idxclid-del3` on `used_clauses` (`clauseID`, `used_at`); + create index `idxclid1-2` on `clause_stats` (`clauseID`); + """ + + for l in q.split('\n'): + t2 = time.time() + + if options.verbose: + print("Creating index: ", l) + self.c.execute(l) + if options.verbose: + print("Index creation T: %-3.2f s" % (time.time() - t2)) + + print("indexes created T: %-3.2f s" % (time.time() - t)) + + + def check_only_one(self): + only_ones = [ + # clause should only be deleted once, since we cleaned this up already + # in clean_update_data.py + {"tbl":"cl_last_in_solver", "elem":"clauseID"}, + {"tbl":"clause_stats", "elem":"clauseID"}, + {"tbl":"restart", "elem":"restartID"}, + {"tbl":"restart_dat_for_cl", "elem":"clauseID"}, + ] + + for only_one in only_ones: + t = time.time() + q = """ + select c, {elem} + from (select count() as c, {elem} + from {tbl} + group by {elem} + ) + where c > 1 + """.format(**only_one) + cursor = self.c.execute(q) + for row in cursor: + if row[0] > 1: + print("ERROR: More than one of {elem} in {tbl} -- clause ID is: {clid}, count is: {cnt}" + .format(**only_one, clid=row[1], cnt=row[0])) + exit(-1) + print("Checked for {tbl} only containing at most one of the same {elem} in {t:2.3f} seconds". + format(**only_one, t=(time.time()-t))) + + def check_all_clauses_have_at_most_one_del(self): + t = time.time() + q = """ + select f.clid, f.cnt, cl_min, cl_max + from ( + select cl_last_in_solver.clauseID as clid, count(cl_last_in_solver.clauseID) as cnt, min(conflicts) as cl_min, max(conflicts) as cl_max + from cl_last_in_solver + group by clauseID) as f + where f.cnt != 1 + order by cl_max + """ + cursor = self.c.execute(q) + bad = False + for row in cursor: + bad = True + print("ERROR: Clause deleted more than once! ClauseID: {clid}, times deleted: {num}, first deleted: {first}, last deleted: {last}".format( + clid=row[0], num=row[1], first=row[2], last=row[3])) + + if bad: + exit(-1) + + print("Checked all clauses have exactly one delete point. T: %-2.3f" % (time.time()-t)) + + def check_all_clauses_have_N(self): + t = time.time() + Ns = [ + {"tbl1":"reduceDB", "tbl2":"cl_last_in_solver", "elem":"clauseID"}, + ] + for n in Ns: + q = """ + select {tbl1}.{elem} + from {tbl1} left join {tbl2} + on {tbl1}.{elem}={tbl2}.{elem} + where {tbl2}.{elem} is NULL + order by {tbl1}.{elem} + """.format(**n) + cursor = self.c.execute(q) + bad = False + for row in cursor: + bad = True + print("ERROR: {elem}={clid} has {tbl1} but no corresponding {tbl2}:".format( + **n, clid=row[0])) + + if bad: + exit(-1) + + print("Checked all clauses have a %s. T: %-2.3f" % (Ns, time.time()-t)) + + def check_glue_sizes(self): + if options.slow: + + queries = """ + create index `idx-check-qual1` on `reduceDB` (`clauseID`); + create index `idx-check-qual2` on `clause_stats` ( `clauseID`); + """ + for l in queries.split('\n'): + self.c.execute(l) + + t = time.time() + q = """ + select * from `clause_stats`,`reduceDB` + where clause_stats.clauseID = reduceDB.clauseID + and glue > orig_glue""" + cursor = self.c.execute(q) + for row in cursor: + print("ERROR: glue is larger than orig_glue!") + print(row) + exit(-1) + + queries = """ + drop index `idx-check-qual1`; + drop index `idx-check-qual2`; + """ + for l in queries.split('\n'): + self.c.execute(l) + + + print("Checked for glue vs orig_glue in %-2.3f seconds" % (time.time()-t)) + + t = time.time() + q = """select * from `clause_stats` where orig_glue > glue_before_minim""" + cursor = self.c.execute(q) + for row in cursor: + print("ERROR: orig_glue is larger than glue_before_minim!") + print(row) + exit(-1) + print("Checked for orig_glue vs glue_before_minim in %-2.3f seconds" % (time.time()-t)) + + t = time.time() + q = """select * from `clause_stats` where orig_glue > orig_size""" + cursor = self.c.execute(q) + for row in cursor: + print("ERROR: orig_glue is larger than orig_size!") + print(row) + exit(-1) + print("Checked for orig_glue vs orig_size in %-2.3f seconds" % (time.time()-t)) + + def check_is_null(self): + + is_nulls = [ + {"tbl":"restart", "col":"clauseID"}, + {"tbl":"restart_data_for_var", "col":"clauseID"} + ] + + t = time.time() + for is_null in is_nulls: + q = """ + select * from {tbl} where {col} is not NULL + """.format(**is_null) + cursor = self.c.execute(q) + bad = False + for row in cursor: + bad = True + print("ERROR: {col} is not null in table {tbl}: {row}".format(**is_null), row=row) + + if bad: + exit(-1) + + print("Checked that some things are NULL. T: %-2.3f" % (time.time()-t)) + + def check_incorrect_data_values(self): + incorrect = [ + {"table":"clause_stats", "cond":" orig_glue = 0 and orig_size >= 2"}, + {"table":"clause_stats", "cond":" orig_glue = 1 and orig_size >= 2"}, + {"table":"clause_stats", "cond":" orig_glue > 100000"}, + {"table":"reduceDB", "cond":" glue > 100000"}, + {"table":"clause_stats", "cond":" glue_before_minim = 0 and orig_size >= 2"}, + {"table":"clause_stats", "cond":" glue_before_minim = 1 and orig_size >= 2"}, + {"table":"reduceDB", "cond":" act_ranking < 0"}, + ] + for incorr in incorrect: + t = time.time() + q = """select * from `{table}` where {cond} """.format(**incorr) + cursor = self.c.execute(q) + for row in cursor: + print("ERROR: Following data in `{table}` has {cond}: ".format(**incorr)) + print(row) + exit(-1) + print("Checked for %s in %-2.3f seconds" % (q, time.time()-t)) + + def check_is_decision_unchanged(self): + print("Checking if is_decision hasn't changed while solving...") + + q = """ + select clstats.clauseID, rdb.is_decision, clstats.is_decision from + reduceDB as rdb + join clause_stats as clstats + on rdb.clauseID = clstats.clauseID + where rdb.is_decision != clstats.is_decision + """ + cursor = self.c.execute(q) + for row in cursor: + clid = int(row[0]) + is_dec_rdb = int(row[1]) + is_dec_clstats = int(row[2]) + print("OOps, for clauseID {clid}, RDB's is_decision is {is_dec_rdb}, while clause_stats's is_decision is {is_dec_clstats}".format(clid=clid, is_dec_rdb=is_dec_rdb, is_dec_clstats=is_dec_clstats)) + exit(-1) + + print("Check for is_decision change finished, all good, it never changed") + + + def check_at_least_n(self): + checks = [ + {"table":"clause_stats", "cond":" orig_glue >= 2", "n": 100}, + {"table":"reduceDB", "cond":" dump_no == 0", "n": 10}, + {"table":"reduceDB", "cond":" dump_no == 1", "n": 10} + ] + for check in checks: + q = """select count() from `{table}` where {cond}""".format(**check) + cursor = self.c.execute(q) + for row in cursor: + num = int(row[0]) + print("Number of {cond} in {table}: {num}".format(num=num, **check)) + if num < check["n"]: + print("ERROR: That's too few") + exit(-1) + + print("Checked for %s" % q) + + + def check_non_negative(self): + tables = ["reduceDB", "clause_stats", "reduceDB_common"] + for table in tables: + cols = helper.get_columns(table, options.verbose, self.c) + for col in cols: + t = time.time() + q = """ + select * from `%s` where `%s` < 0 + """ % (table, col) + cursor = self.c.execute(q) + for row in cursor: + print("ERROR: following data has %s < 0 in table %s: " % (col , table)) + print(row) + exit(-1) + print("Checked for %s < 0 in table %s. All are >= 0. T: %-3.2f s" % + (col, table, time.time() - t)) + + + def check_positive(self): + check_zero = [ + ["glue_before_minim", "clause_stats"], + ["orig_glue", "clause_stats"], + ["orig_size", "clause_stats"], + ["size", "reduceDB"], + ["glue", "reduceDB"], + ["act_ranking", "reduceDB"], # all ranking starts at 1, not 0 + ["uip1_ranking", "reduceDB"], + ["prop_ranking", "reduceDB"] + ] + + for col,table in check_zero: + t = time.time() + q = """ + select * from `%s` where `%s` <= 0 + """ % (table, col) + cursor = self.c.execute(q) + for row in cursor: + print("ERROR: Following data from table %s has %s as non-positive: " % (table, col)) + print(row) + exit(-1) + print("Checked for %s in table %s. All are positive T: %-3.2f s" % + (col, table, time.time() - t)) + + def drop_idxs(self): + helper.drop_idxs(self.c) + +if __name__ == "__main__": + usage = "usage: %prog [options] sqlitedb" + parser = optparse.OptionParser(usage=usage) + parser.add_option("--verbose", "-v", action="store_true", default=False, + dest="verbose", help="Print more output") + parser.add_option("--slow", action="store_true", default=False, + dest="slow", help="Do more checks") + + (options, args) = parser.parse_args() + + if len(args) < 1: + print("ERROR: You must give the sqlite file!") + exit(-1) + + with Queries(args[0]) as q: + #q.create_indexes() + q.check_all_clauses_have_at_most_one_del() + q.check_all_clauses_have_N() + q.check_only_one() + q.check_glue_sizes() + q.check_non_negative() + q.check_positive() + q.check_incorrect_data_values() + q.check_at_least_n() + q.check_is_decision_unchanged() + #q.drop_idxs() + + print("Done.") diff --git a/cryptominisat/cppsrc/scripts/crystal/cldata_gen_pandas.py b/cryptominisat/cppsrc/scripts/crystal/cldata_gen_pandas.py new file mode 100755 index 00000000..ab034934 --- /dev/null +++ b/cryptominisat/cppsrc/scripts/crystal/cldata_gen_pandas.py @@ -0,0 +1,449 @@ +#!/usr/bin/env python3 +# -*- coding: utf-8 -*- + +# Copyright (C) 2009-2020 Authors of CryptoMiniSat, see AUTHORS file +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; version 2 +# of the License. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +# 02110-1301, USA. + +from __future__ import print_function +import optparse +import time +import pickle +import re +import pandas as pd +import numpy as np +import sys +import helper + + +class QueryAddIdxes (helper.QueryHelper): + def __init__(self, dbfname): + super(QueryAddIdxes, self).__init__(dbfname) + + def measure_size(self): + self.c.execute("select count() from reduceDB") + rows = self.c.fetchall() + rdb_rows = rows[0][0] + print("We have %d lines of RDB" % (rdb_rows)) + + self.c.execute("select count() from clause_stats") + rows = self.c.fetchall() + clss_rows = rows[0][0] + print("We have %d lines of clause_stats" % (clss_rows)) + + def create_indexes(self): + t = time.time() + print("Recreating indexes...") + queries = """ + create index `idxclid33` on `sum_cl_use` (`clauseID`, `last_confl_used`); + --- + create index `idxclid1` on `clause_stats` (`clauseID`, conflicts, latest_satzilla_feature_calc); + create index `idxclid1-2` on `clause_stats` (`clauseID`); + create index `idxclid2` on `clause_stats` (clauseID, conflicts, latest_satzilla_feature_calc); + create index `idxclid5` on `tags` ( `name`); + --- + create index `idxclid6` on `reduceDB` (`clauseID`, conflicts); + create index `idxclid6-9` on `reduceDB` (`conflicts`); + create index `idxclid9` on `reduceDB_common` (`conflicts`, `latest_satzilla_feature_calc`); + create index `idxclid9-2` on `reduceDB_common` (`conflicts`, `latest_satzilla_feature_calc`); + create index `idxclid9-3` on `reduceDB_common` (`conflicts`); + create index `idxclid9-4` on `reduceDB_common` (`latest_satzilla_feature_calc`); + create index `idxclid6-2` on `reduceDB` (`clauseID`, `dump_no`); + create index `idxclid6-3` on `reduceDB` (`clauseID`, `conflicts`, `dump_no`); + create index `idxclid6-4` on `reduceDB` (`clauseID`, `conflicts`) + --- + create index `idxclid7` on `satzilla_features` (`latest_satzilla_feature_calc`); + --- + create index `idxclidUCLS-1` on `used_clauses` ( `clauseID`, `used_at`); + create index `idxclidUCLS-2` on `used_clauses` ( `used_at`); + --- + create index `idxcl_last_in_solver-1` on `cl_last_in_solver` ( `clauseID`, `conflicts`); + --- + create index `used_later_percentiles_idx3` on `used_later_percentiles` (`type_of_dat`, `percentile_descr`, `percentile`, `val`); + create index `used_later_percentiles_idx2` on `used_later_percentiles` (`type_of_dat`, `percentile_descr`, `val`); + """ + for l in queries.split('\n'): + t2 = time.time() + + if options.verbose: + print("Creating index: ", l) + self.c.execute(l) + if options.verbose: + print("Index creation T: %-3.2f s" % (time.time() - t2)) + + print("indexes created T: %-3.2f s" % (time.time() - t)) + + +class QueryCls (helper.QueryHelper): + def __init__(self, dbfname, tier, table): + super(QueryCls, self).__init__(dbfname) + self.fill_sql_query(tier, table=table) + + def fill_sql_query(self, tier, table): + # sum_cl_use + self.sum_cl_use = helper.query_fragment( + "sum_cl_use", [], "sum_cl_use", options.verbose, self.c) + + # RDB data + not_cols = [ + "reduceDB_called" + , "clauseID" + , "in_xor" + , "locked" + , "conflicts" + , "activity_rel"] + self.rdb0_dat = helper.query_fragment( + "reduceDB", not_cols, "rdb0", options.verbose, self.c) + + # reduceDB_common data + not_cols = [ + "reduceDB_called" + , "simplifications" + , "restarts" + #, "conflicts" + , "latest_satzilla_feature_calc" + , "runtime" + ] + self.rdb0_common_dat = helper.query_fragment( + "reduceDB_common", not_cols, "rdb0_common", options.verbose, self.c) + + # clause data + not_cols = [ + "simplifications" + , "restarts" + , "prev_restart" + , "antecedents_long_red_age_max" + , "antecedents_long_red_age_min" + , "latest_satzilla_feature_calc" + , "clauseID"] + self.clause_dat = helper.query_fragment( + "clause_stats", not_cols, "cl", options.verbose, self.c) + + # satzilla data + not_cols = [ + "simplifications" + , "restarts" + , "conflicts" + , "latest_satzilla_feature_calc" + , "irred_glue_distr_mean" + , "irred_glue_distr_var"] + self.satzfeat_dat = helper.query_fragment( + "satzilla_features", not_cols, "szfeat", options.verbose, self.c) + + self.common_limits = """ + order by random() + limit {limit} + """ + + q_time_base=""" + join {table}_{tier} on + {table}_{tier}.clauseID = rdb0.clauseID + and {table}_{tier}.rdb0conflicts = rdb0.conflicts + """ + + q_columns_base=""" + , {table}_{tier}.used_later as `x.{table}_{tier}` + , {table}_{tier}.percentile_fit as `x.{table}_{tier}_topperc` + """ + + q_time = q_time_base.format(tier=tier, table=table) + q_columns = q_columns_base.format(tier=tier, table=table) + + # final big query + self.q_select = """ + SELECT + tags.val as `fname` + {clause_dat} + {rdb0_dat} + {rdb0_common_dat} + {sum_cl_use} + , (rdb0.conflicts - rdb0.introduced_at_conflict) as `cl.time_inside_solver` + , (sum_cl_use.last_confl_used - rdb0.introduced_at_conflict) as `x.a_lifetime` + {q_columns} + , sum_cl_use.num_used as `x.sum_cl_use` + + + FROM + reduceDB as rdb0 + + -- this is DELIBERATEY left-join: this way, clauses that as ternary + -- resolvents or otherwise generated during in-processing + -- can still be used + left join clause_stats as cl on + cl.clauseID = rdb0.clauseID + + join reduceDB_common as rdb0_common on + rdb0_common.conflicts = rdb0.conflicts + + join sum_cl_use on + sum_cl_use.clauseID = rdb0.clauseID + + {q_time} + + join cl_last_in_solver on + cl_last_in_solver.clauseID = rdb0.clauseID + + , tags + + WHERE + (cl.clauseID != 0 OR cl.clauseID is NULL) + and tags.name = "filename" + + -- to avoid missing clauses and their missing data to affect results + and rdb0.conflicts + {del_at_least} <= cl_last_in_solver.conflicts + """ + + self.myformat = { + "limit": 1000*1000*1000, + "clause_dat": self.clause_dat, + "satzfeat_dat_cur": self.satzfeat_dat.replace("szfeat.", "szfeat_cur."), + "rdb0_dat": self.rdb0_dat, + "sum_cl_use": self.sum_cl_use, + "rdb0_common_dat": self.rdb0_common_dat, + "q_time": q_time, + "q_columns": q_columns + } + + def get_used_later_percentiles(self, name, table): + cur = self.conn.cursor() + q = """ + select + `type_of_dat`, + `percentile_descr`, + `percentile`, + `val` + from {table}_percentiles + where `type_of_dat` = '{name}' + """.format(name=name, table=table) + cur.execute(q) + rows = cur.fetchall() + lookup = {} + for row in rows: + mystr = "%s_%s_perc" % (row[1], row[2]) + print("table: {table} type: {t}, perc_desc: {perc_desc}, perc: {perc}, val: {val}".format( + table=table, + t=row[0], + perc_desc=row[1], + perc=row[2], + val=row[3])) + lookup[mystr] = row[3] + #print("perc lookup:", lookup) + + return lookup + + def get_one_data(self, tier, table): + perc = self.get_used_later_percentiles(tier, table) + self.myformat["del_at_least"] = getattr(options, tier) + + # when del_at_least is over 2 million, then we need to make this smaller + # or we will delete all data + if self.myformat["del_at_least"] > 2*1000*1000: + self.myformat["del_at_least"] = 100*1000 + + # Make sure these stratas are equally represented + t = time.time() + dfs = self.run_stratified_queries( + limit=options.limit, perc=perc, tier=tier, table=table) + data = pd.concat(dfs) + print("** Queries finished. Total size: %s -- T: %-3.2f" % ( + data.shape, time.time() - t)) + return data + + # perc == percentile distribution + # limit == MAX in total + # tier == forever/long/short + def run_stratified_queries(self, limit, perc, tier, table): + dfs = [] + # NOTE: these are NON-ZERO percentages, but we replace 100 with "0", so the LAST chunk contains ALL, including 0, which is a large part of the data + for beg_perc, end_perc in [(0.0, options.cut1), (options.cut1, options.cut2), (options.cut2, 100.0)]: + beg = perc["top_non_zero_{perc}_perc".format(perc=beg_perc)] + if end_perc == 100.0: + end = 0.0 + else: + end = perc["top_non_zero_{perc}_perc".format(perc=end_perc)] + what_to_strata = "`x.{table}_{tier}`".format(tier=tier, table=table) + + print("Limit is {limit} value strata perc: ({a}, {b}) translates to value strata ({beg}, {end})".format( + limit=limit, a=beg_perc, b=end_perc, beg=beg, end=end)) + + # create one query for (beg,end) with different dump numbers + df, weighted_sizes = self.query_strata_per_dumpno( + str(self.q_select), + limit, + what_to_strata=what_to_strata, + strata=(beg,end)) + dfs.append(df) + return dfs + + def query_strata_per_dumpno(self, q, limit, what_to_strata, strata): + print("* Getting one set of data with limit %s" % limit) + weighted_size = [] + df_parts = [] + + def one_part(mult, dump_no_filter=""): + self.myformat["limit"] = int(limit*mult) + df_parts.append(self.one_query(q + dump_no_filter, what_to_strata, strata)) + print("--> Num rows for strata %s -- '%s': %s" % (strata, dump_no_filter, df_parts[-1].shape[0])) + + ws = df_parts[-1].shape[0]/mult + print("--> The weight was %f so weighted size is: %d" % (mult, int(ws))) + weighted_size.append(ws) + + one_part(1/4.0, dump_no_filter=" and rdb0.dump_no = 1 ") + one_part(1/4.0, dump_no_filter=" and rdb0.dump_no = 2 ") + one_part(1/4.0, dump_no_filter=" and rdb0.dump_no > 2 ") + one_part(1/4.0, dump_no_filter=" and rdb0.dump_no > 20 ") + + df = pd.concat(df_parts) + print("-> size of all dump_no-s, strata {strata} data: {size}".format( + strata=strata, size=df.shape)) + + return df, weighted_size + + def one_query(self, q, what_to_strata, strata): + q = q.format(**self.myformat) + + if strata[1] == 0.0: + my_less_equal = ">=" + else: + my_less_equal = ">" + + q = """ + select * from ( {q} ) + where + {what_to_strata} <= {beg} + and {what_to_strata} {my_less_equal} {end}""".format( + q=q, + what_to_strata=what_to_strata, + beg=strata[0], + end=strata[1], + my_less_equal=my_less_equal) + + q += self.common_limits + q = q.format(**self.myformat) + + t = time.time() + sys.stdout.write("-> Running query for {} stratas {}...".format(what_to_strata, strata)) + sys.stdout.flush() + if options.dump_sql: + print("query:", q) + df = pd.read_sql_query(q, self.conn) + print("T: %-3.1f" % (time.time() - t)) + return df + + +def dump_dataframe(df, name): + if options.dump_csv: + fname = "%s.csv" % name + print("Dumping CSV data to:", fname) + df.to_csv(fname, index=False, columns=sorted(list(df))) + + fname = "%s.dat" % name + print("Dumping pandas data to:", fname) + with open(fname, "wb") as f: + pickle.dump(df, f) + + +def one_database(dbfname): + with QueryAddIdxes(dbfname) as q: + q.measure_size() + helper.drop_idxs(q.c) + q.create_indexes() + + with helper.QueryFill(dbfname) as q: + q.delete_and_create_used_laters() + for tier in ["short", "long", "forever"]: + for table in ["used_later", "used_later_anc"]: + q.fill_used_later_X(tier, duration=getattr(options, tier), table=table) + q.fill_used_later_X_perc_fit(tier, table=table) + + print("Using sqlite3 DB file %s" % dbfname) + for tier in ["short", "long", "forever"]: + for table in ["used_later", "used_later_anc"]: + print("------> Doing tier {tier} table {table}".format( + tier=tier,table=table)) + + with QueryCls(dbfname, tier, table) as q: + df = q.get_one_data(tier, table) + + if options.verbose: + print("Describing----") + dat = df.describe() + print(dat) + print("Describe done.---") + print("Features: ", df.columns.values.flatten().tolist()) + + if options.verbose: + print("Describing post-transform ----") + print(df.describe()) + print("Describe done.---") + print("Features: ", df.columns.values.flatten().tolist()) + + cleanname = re.sub(r'\.cnf.gz.sqlite$', '', dbfname) + cleanname = re.sub(r'\.db$', '', dbfname) + cleanname = re.sub(r'\.sqlitedb$', '', dbfname) + cleanname = "{cleanname}-cldata-{table}-{tier}-cut1-{cut1}-cut2-{cut2}-limit-{limit}".format( + cleanname=cleanname, + cut1=options.cut1, + cut2=options.cut2, + limit=options.limit, + tier=tier, + table=table) + + dump_dataframe(df, cleanname) + + +if __name__ == "__main__": + usage = "usage: %prog [options] file1.sqlite [file2.sqlite ...]" + parser = optparse.OptionParser(usage=usage) + + # verbosity level + parser.add_option("--verbose", "-v", action="store_true", default=False, + dest="verbose", help="Print more output") + parser.add_option("--sql", action="store_true", default=False, + dest="dump_sql", help="Dump SQL queries") + parser.add_option("--csv", action="store_true", default=False, + dest="dump_csv", help="Dump CSV (for weka)") + + # limits + parser.add_option("--limit", default=20000, type=int, + dest="limit", help="Max number of samples to take from each strata (for each table/tier)") + parser.add_option("--cut1", default=5.0, type=float, + dest="cut1", help="Where to cut the distrib. Default: %default") + parser.add_option("--cut2", default=30.0, type=float, + dest="cut2", help="Where to cut the distrib. Default: %default") + + # debugging is faster with this + parser.add_option("--noind", action="store_true", default=False, + dest="no_recreate_indexes", + help="Don't recreate indexes") + + # lengths of short/long + parser.add_option("--short", default=10000, type=int, + dest="short", help="Short duration. Default: %default") + parser.add_option("--long", default=30*1000, type=int, + dest="long", help="Long duration. Default: %default") + parser.add_option("--forever", default=120*1000, type=int, + dest="forever", help="Long duration. Default: %default") + + (options, args) = parser.parse_args() + + if len(args) != 1: + print("ERROR: You must give exactly one file") + exit(-1) + + np.random.seed(2097483) + one_database(args[0]) diff --git a/cryptominisat/cppsrc/scripts/crystal/cldata_predict.py b/cryptominisat/cppsrc/scripts/crystal/cldata_predict.py new file mode 100755 index 00000000..7583885d --- /dev/null +++ b/cryptominisat/cppsrc/scripts/crystal/cldata_predict.py @@ -0,0 +1,634 @@ +#!/usr/bin/env python3 +# -*- coding: utf-8 -*- + +# Copyright (C) 2009-2020 Authors of CryptoMiniSat, see AUTHORS file +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; version 2 +# of the License. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +# 02110-1301, USA. + +# pylint: disable=invalid-name,line-too-long,too-many-locals,consider-using-sys-exit + +import operator +import re +import time +import argparse +import sys +import os +import itertools +import pandas as pd +import pickle +import sklearn +import sklearn.svm +import sklearn.tree +import sklearn.preprocessing +import numpy as np +import sklearn.metrics +import sklearn.impute +import matplotlib.pyplot as plt +import sklearn.ensemble +import sklearn.linear_model +import helper +import xgboost as xgb +import lightgbm as lgbm +import ast +import math +import functools +try: + import mlflow +except ImportError: + mlflow_avail = False +else: + mlflow_avail = True + +ver = sklearn.__version__.split(".") +print("version: ", ver) +if int(ver[0]) == 0 and int(ver[1]) < 20: + from sklearn.cross_validation import train_test_split +else: + from sklearn.model_selection import train_test_split + +MISSING=np.NaN + +class MyEnsemble: + def __init__(self, models): + self.models = models + + def fit(self, X_train, y_train, weights=None): + assert weights is None + for model in self.models: + model.fit(X_train, y_train) + + def predict(self, X_data): + #df = pd.DataFrame(index=range(numRows),columns=range(numCols)) + vals = np.ndarray(shape=(len(self.models), len(X_data)), dtype=float) + for i in range(len(self.models)): + pred = self.models[i].predict(X_data) + vals[i] = pred + + ret = np.median(vals, axis=0) + return ret + + + +class Learner: + def __init__(self, df): + self.df = df + + def count_bad_ok(self, df): + files = df[["x.class", "rdb0.dump_no"]].groupby("x.class").count() + if files["rdb0.dump_no"].index[0] == 0: + bad = files["rdb0.dump_no"][0] + ok = files["rdb0.dump_no"][1] + else: + bad = files["rdb0.dump_no"][1] + ok = files["rdb0.dump_no"][0] + + assert bad > 0, "No need to train, data only contains BAD(0)" + assert ok > 0, "No need to train, data only contains OK(1)" + + return bad, ok + + def filter_percentile(self, df, features, perc): + low = df.quantile(perc, axis=0) + high = df.quantile(1.0-perc, axis=0) + df2 = df.copy() + for i in features: + df2 = df2[(df2[i] >= low[i]) & (df2[i] <= high[i])] + print("Filtered to %f on %-30s, shape now: %s" % + (perc, i, df2.shape)) + + print("Original size:", df.shape) + print("New size:", df2.shape) + return df2 + + def filtered_conf_matrixes(self, dump_no, data, features, to_predict, clf, + toprint, highlight=False): + # filter test data + if dump_no is not None: + print("\nCalculating confusion matrix -- dump_no == %s" % dump_no) + toprint += " dump no %d" % dump_no + data2 = data[data["rdb0.dump_no"] == dump_no] + else: + print("\nCalculating confusion matrix -- ALL dump_no") + data2 = data + + return helper.calc_regression_error( + data2, features, to_predict, clf, toprint, + highlight=highlight) + + def importance_XGB(self, clf, features): + impdf = [] + #print("clf:", clf) + #print("clf-booster:", clf.feature_importances_) + + for i in range(len(clf.feature_importances_)): + score = clf.feature_importances_[i] + ft = features[i] + impdf.append({'feature': ft, 'importance': score}) + impdf = pd.DataFrame(impdf) + impdf = impdf.sort_values(by='importance', ascending=False).reset_index(drop=True) + impdf['importance'] /= impdf['importance'].sum() + pd.set_option('display.max_rows', None) + pd.set_option('display.max_columns', None) + pd.set_option('display.width', None) + pd.set_option('display.max_colwidth', None) + print("impdf:", impdf) + + return impdf + + def dump_ml_test_data(self, test, fname, to_predict) : + f = open(fname, "w") + test.reset_index(inplace=True) + for i in range(test.shape[0]): + towrite = "" + towrite += "%s " % test[TODO_go_through_all_features_here].iloc[i] + assert False, "not implemented, must put all features here in a loop" + towrite += "%s " % test[to_predict].iloc[i] + towrite += "\n" + f.write(towrite) + + def scale_and_impute(self, train, test, features, extra_feats): + trans_train = train[features].values + trans_test = test[features].values + + # Scale data if linear + my_scaler = sklearn.preprocessing.Normalizer( + norm='l1', + copy=False) + my_scaler.fit_transform(trans_train) + my_scaler.transform(trans_test) + + # Impute data + imp_mean = sklearn.impute.SimpleImputer( + #missing_values=MISSING, + copy=False, + strategy='mean') + imp_mean.fit_transform(trans_train) + imp_mean.transform(trans_test) + + # recreate dataframe + trans_train = np.append(trans_train, train[extra_feats].values, axis=1) + df_trans_train = pd.DataFrame(trans_train, columns=features+extra_feats) + train = df_trans_train + + trans_test = np.append(trans_test, test[extra_feats].values, axis=1) + df_trans_test = pd.DataFrame(trans_test, columns=features+extra_feats) + test = df_trans_test + + print("Value distribution of 'rdb0.glue' in test:\n%s" % test["rdb0.glue"].value_counts()) + print("Value distribution of 'rdb0.glue' in train:\n%s" % train["rdb0.glue"].value_counts()) + + return train, test + + def one_regressor(self, features, to_predict): + print("-> Number of features :", len(features)) + print("-> Number of datapoints:", self.df.shape) + print("-> Predicting :", to_predict) + + # these are needed for prediction/later checks, so let's add them in + # if they are not already in the features + extra_feats = [to_predict] + for missing_needed in ["rdb0.glue", "rdb0.dump_no"]: + if missing_needed not in features: + extra_feats.append(missing_needed) + df = self.df[features+extra_feats].copy() + if options.verbose: + pd.set_option('display.max_rows', len(df.dtypes)) + print(df.dtypes) + pd.reset_option('display.max_rows') + + + if options.check_row_data: + helper.check_too_large_or_nan_values(df, features) + + print("Value distribution of 'rdb0.dump_no':\n%s" % df["rdb0.dump_no"].value_counts()) + print("Value distribution of 'rdb0.glue':\n%s" % df["rdb0.glue"].value_counts()) + print("Value distribution of to_predict:\n%s" % df[to_predict].value_counts()) + + train, test = train_test_split(df, test_size=0.33, random_state=prng) + if options.regressor in ["linear", "tree"]: + train, test = self.scale_and_impute(train, test, features, extra_feats) + + + if options.poly_features: + transformed = df[features].values + + # poly transform + poly = sklearn.preprocessing.PolynomialFeatures(2) + transformed = poly.fit_transform(transformed) + features = poly.get_feature_names(input_features=features) + + # recreate dataframe + transformed = np.append(transformed, df[extra_feats].values, axis=1) + df_trans = pd.DataFrame(transformed, columns=features+extra_feats) + df = df_trans + + X_train = train[features] + y_train = train[to_predict] + + t = time.time() + clf = None + + split_point = helper.calc_min_split_point( + df, options.min_samples_split) + + clf_tree = sklearn.tree.DecisionTreeRegressor( + max_depth=options.xboost_max_depth, + min_samples_split=split_point, + random_state=prng) + clf_svm_pre = sklearn.svm.SVC( + C=500, + gamma=10**-5, + random_state=prng) + clf_svm = sklearn.ensemble.BaggingClassifier( + clf_svm_pre, + n_estimators=3, + max_samples=0.5, max_features=0.5, + random_state=prng) + clf_linear = sklearn.linear_model.LinearRegression() + clf_forest = sklearn.ensemble.RandomForestRegressor( + n_estimators=options.num_trees, + max_depth=options.xboost_max_depth, + max_features="sqrt", + #min_samples_leaf=split_point, + random_state=prng) + clf_ridge = sklearn.linear_model.Ridge(alpha=.5) + clf_lasso = sklearn.linear_model.Lasso() + clf_elasticnet = sklearn.linear_model.ElasticNet() + clf_xgboost = xgb.XGBRegressor( + objective='reg:squarederror', + #missing=MISSING, + min_child_weight=options.min_child_weight_xgboost, # from doc: "In linear regression task, this simply corresponds to minimum number of instances needed to be in each node." + max_depth=options.xboost_max_depth, + subsample=options.xgboost_subsample, + n_estimators=options.n_estimators_xgboost) + clf_lgbm = model = lgbm.LGBMRegressor( + subsample=options.xgboost_subsample, + min_child_samples=options.min_child_weight_xgboost, # from doc: "Minimum number of data needed in a child" + max_depth=options.xboost_max_depth, + n_estimators=options.n_estimators_xgboost) + + if options.regressor == "tree": + clf = clf_tree + elif options.regressor == "svm": + clf = clf_svm + elif options.regressor == "linear": + clf = clf_linear + elif options.regressor == "ridge": + clf = clf_ridge + elif options.regressor == "lasso": + clf = clf_lasso + elif options.regressor == "elasticnet": + clf = clf_elasticnet + elif options.regressor == "forest": + clf = clf_forest + elif options.regressor == "lgbm": + clf = clf_lgbm + elif options.regressor == "xgb": + print("Using xgboost no. estimators:", options.n_estimators_xgboost) + clf = clf_xgboost + elif options.regressor == "median": + mylist = [("xgb", clf_xgboost), ("linear", clf_linear), + ("elasticnet", clf_elasticnet), ("lasso", clf_lasso)] + clf = sklearn.ensemble.VotingRegressor(estimators=mylist, weights=[1.0, 0.5, 0.5, 0.5]) + #clf = MyEnsemble(mylist) + else: + print( + "ERROR: You MUST give one of: tree/forest/svm/linear/bagging classifier") + exit(-1) + if options.gen_topfeats: + print("WARNING: Replacing normal forest/xgboost with top feature computation!!!") + if options.regressor == "forest": + print("for TOP calculation, we are replacing the forest predictor!!!") + clf = sklearn.ensemble.RandomForestRegressor( + n_estimators=options.num_trees*5, + max_features="sqrt", + random_state=prng) + elif options.regressor == "xgb": + print("for TOP calculation, we are replacing the XGBOOST predictor!!!") + clf = xgb.XGBRegressor( + objective='reg:squarederror', + min_child_weight=options.min_child_weight_xgboost, + max_depth=options.xboost_max_depth, + #missing=MISSING + ) + else: + print("Error: --topfeats only works with xgboost/forest") + exit(-1) + + + clf.fit(X_train, y_train) + print("Training finished. T: %-3.2f" % (time.time() - t)) + + if mlflow_avail: + mlflow.log_param("features used", features) + # mlflow.log_metric("all features: ", train.columns.values.flatten().tolist()) + mlflow.log_metric("train num rows", train.shape[0]) + mlflow.log_metric("test num rows", test.shape[0]) + + + if options.dot is not None: + if options.regressor == "tree": + helper.output_to_classical_dot( + clf, features, + fname="{name}-{table}-{tier}.dot".format( + name=options.dot, tier=options.tier, table=options.table)) + + elif options.regressor == "xgb": + dot_data = xgb.to_graphviz(booster=clf, num_trees=9) + with open("x.dot", "w") as f: + f.write("%s" % dot_data) + + else: + print("ERROR: You cannot use the DOT function on non-trees") + exit(-1) + + if options.basedir: + fname_pred_out = options.basedir + "/predictor-{table}-{tier}-{regr}.json".format( + tier=options.tier, table=options.table, regr=options.regressor) + if options.regressor == "xgb": + booster = clf.get_booster() + booster.save_model(fname_pred_out) + print("==> Saved XGB model to: ", fname_pred_out) + elif options.basedir and options.regressor == "lgbm": + clf.booster_.save_model(fname_pred_out) + print("==> Saved LGBM model to: ", fname_pred_out) + else: + print("WARNING: NOT writing code -- you must use xgboost/lgbm and give dir for that") + + + # print feature rankings + if options.regressor == "forest": + helper.print_feature_ranking( + clf, X_train, + top_num_features=200, + features=features, + plot=options.show) + elif options.regressor == "xgb": + self.importance_XGB(clf, features=features) + + # print distribution of error + print("--------------------------") + print("- test data -") + print("--------------------------") + for dump_no in [1, 2, 3, 10, 20, 40, None]: + self.filtered_conf_matrixes( + dump_no, test, features, to_predict, clf, "test data", highlight=True) + print("--------------------------------") + print("-- train+test data -") + print("--------------------------------") + for dump_no in [1, None]: + self.filtered_conf_matrixes( + dump_no, pd.concat([test, train]), features, to_predict, clf, "test and train data") + print("--------------------------") + print("- train data -") + print("--------------------------") + self.filtered_conf_matrixes( + dump_no, train, features, to_predict, clf, "train data") + + #print(test[features+to_predict]) + #print(test[to_predict]) + if options.dump_example_data: + with open("example-data.dat", "wb") as f: + pickle.dump(test[features+[to_predict]], f) + self.dump_ml_test_data(test, "../ml_perf_test.txt-{table}-{tier}".format( + table=options.table, tier=options.tier)) + print("Example data dumped") + + def rem_features(self, feat, to_remove): + print("To remove: " , to_remove) + feat_less = list(feat) + for rem in to_remove: + for feat in list(feat_less): + if rem in feat: + if options.verbose: + print("Removing due to ", rem, " feature from feat_less:", feat) + feat_less.remove(feat) + + print("Done.") + return feat_less + + def learn(self): + if options.raw_data_plots: + pd.options.display.mpl_style = "default" + df.hist() + df.boxplot() + + if options.features != "best_only": + features = list(self.df) + + # remove features that would be "cheating" or useless + torem = [] + for table in ["used_later", "used_later_anc"]: + for tier in ["short", "long", "forever"]: + torem. append("x.{table}_{tier}".format(tier=tier, table=table)) + + torem.extend([ + "x.class", + "x.a_lifetime", + "fname", + "sum_cl_use.num_used", + "x.sum_cl_use", + "rdb0.dump_no", + "fname"]) + features = self.rem_features(features, torem) + else: + del df["fname"] + features = helper.get_features(options.best_features_fname) + + to_predict = "x.{table}_{tier}".format(tier=options.tier, table=options.table) + self.one_regressor(features, to_predict) + + +if __name__ == "__main__": + usage = "usage: %(prog)s [options] file.pandas" + parser = argparse.ArgumentParser(usage=usage) + + parser.add_argument("fname", type=str, metavar='PANDASFILE') + parser.add_argument("--seed", default=None, type=int, + dest="seed", help="Seed of PRNG") + parser.add_argument("--verbose", "-v", action="store_true", default=False, + dest="verbose", help="Print more output") + parser.add_argument("--printfeat", action="store_true", default=False, + dest="print_features", help="Print features") + parser.add_argument("--features", default="best_only", type=str, dest="features", + help="What features to use: all_computed, best_only, best_also, no_computed ") + parser.add_argument("--bestfeatfile", type=str, default="../../scripts/crystal/best_features-rdb0-only.txt", + dest="best_features_fname", help="Name and position of best features file that lists the best features in order") + parser.add_argument("--polyfeats", action="store_true", default=False, + dest="poly_features", help="Add polynomial features") + parser.add_argument("--dat", type=str, default=None, + dest="dat_file", help="Output Pickle of dataframe here") + parser.add_argument("--dumpexample", default=False, action="store_true", + dest="dump_example_data", help="Dump example data") + + # tree/forest options + parser.add_argument("--split", default=0.01, type=float, metavar="RATIO", + dest="min_samples_split", help="Split in tree if this many samples or above. Used as a percentage of datapoints") + parser.add_argument("--numtrees", default=100, type=int, + dest="num_trees", help="How many trees to generate for the forest") + + # generation of predictor + parser.add_argument("--dot", type=str, default=None, + dest="dot", help="Create DOT file") + parser.add_argument("--filterdot", default=0.05, type=float, + dest="filter_dot", help="Filter the DOT output from outliers so the graph looks nicer") + parser.add_argument("--show", action="store_true", default=False, + dest="show", help="Show visual graphs") + parser.add_argument("--check", action="store_true", default=False, + dest="check_row_data", help="Check row data for NaN or float overflow") + parser.add_argument("--checkverbose", action="store_true", default=False, + dest="check_row_data_verbose", help="Check row data for NaN or float overflow in a verbose way, printing them all") + parser.add_argument("--rawplots", action="store_true", default=False, + dest="raw_data_plots", help="Display raw data plots") + parser.add_argument("--basedir", type=str, + dest="basedir", help="The base directory of where the CryptoMiniSat source code is") + + # data filtering + parser.add_argument("--only", default=1.00, type=float, + dest="only_perc", help="Only use this percentage of data") + + # final generator top/final + parser.add_argument("--topfeats", default=False, action="store_true", + dest="gen_topfeats", help="Only generate final predictor") + + # type of regressor + parser.add_argument("--regressor", type=str, default="xgb", + dest="regressor", help="Final classifier should be a: tree, svm, linear, forest, xgboost, bagging") + parser.add_argument("--xgboostestimators", default=10, type=int, + dest="n_estimators_xgboost", help="Number of estimators for xgboost") + parser.add_argument("--xgboostminchild", default=10, type=int, + dest="min_child_weight_xgboost", help="Number of elements in the leaf to split it in xgboost") + parser.add_argument("--xboostmaxdepth", default=10, type=int, + dest="xboost_max_depth", help="Max depth of xboost trees") + parser.add_argument("--xgboostsubsample", default=1.0, type=float, + dest="xgboost_subsample", help="Subsample xgboost on each iteration") + + # which one to generate + parser.add_argument("--tier", default=None, type=str, + dest="tier", help="Tier to do") + parser.add_argument("--table", default="used_later", type=str, + dest="table", help="Table to do") + + options = parser.parse_args() + prng = np.random.RandomState(options.seed) + + if options.fname is None: + print("ERROR: You must give the pandas file!") + exit(-1) + + assert options.min_samples_split <= 1.0, "You must give min_samples_split that's smaller than 1.0" + if not os.path.isfile(options.fname): + print("ERROR: '%s' is not a file" % options.fname) + exit(-1) + + if options.tier is None: + print("ERROR: you must set --tier, exiting") + exit(-1) + + if options.table is None: + print("ERROR: you must set --table, exiting") + exit(-1) + + if options.best_features_fname is None and "best" in options.features: + print("You must give best features filename or we cannot add best features") + exit(-1) + + # ------------ + # Log all parameters + # ------------ + if mlflow_avail: + mlflow.log_param("gen_topfeats", options.gen_topfeats) + mlflow.log_param("tier", options.tier) + mlflow.log_param("regressor", options.regressor) + mlflow.log_param("basedir", options.basedir) + mlflow.log_param("only_percentage", options.only_perc) + mlflow.log_param("min_samples_split", options.min_samples_split) + mlflow.log_param("xboost_max_depth", options.xboost_max_depth) + mlflow.log_param("num_trees", options.num_trees) + mlflow.log_param("features", options.features) + mlflow.log_artifact(options.fname) + + # Read in Pandas Dataframe + print("Reading dataframe....") + df = pd.read_pickle(options.fname) + + print("Applying only...") + df_tmp = df.sample(frac=options.only_perc, random_state=prng) + df_before_dtype_conv = pd.DataFrame(df_tmp) + del df_tmp + del df + print("-> Number of datapoints after applying '--only':", df_before_dtype_conv.shape) + + # We must convert these or we'll have trouble with inf, -inf, NaN for NULLs + print("Converting datatypes to those supporting np.NA ...") + if options.verbose: + print("Datatypes before:") + helper.print_datatypes(df_before_dtype_conv) + df = df_before_dtype_conv.convert_dtypes( + convert_integer=False, convert_string=False, + convert_floating=False) + del df_before_dtype_conv + if options.verbose: + print("Datatypes after:") + helper.print_datatypes(df) + + # Check feature type sanity + # only "fname" is allowed to be an object (a string) + for name,ty in zip(list(df), df.dtypes): + if name == "fname": + assert ty == object + else: + if ty == object: + print("name: " , name, " is object!") + assert ty != object + + if options.print_features: + for f in sorted(list(df)): + print(f) + + # make missing (None) into NaN + helper.make_missing_into_nan(df) + + # feature manipulation + if options.features =="all_computed": + helper.cldata_add_computed_features(df, options.verbose) + elif options.features == "best_only" or options.features == "best_also": + helper.add_features_from_fname(df, options.best_features_fname) + elif options.features == "no_computed": + helper.cldata_add_minimum_computed_features(df, options.verbose) + else: + print("ERROR: Unrecognized --features option!") + exit(-1) + + # Check feature type sanity + for name, mytype in df.dtypes.items(): + if str(mytype) == str("Int64") or str(mytype) == str("Float64"): + assert False + + print("Filling NA with MISSING..") + df.replace([np.inf, np.NaN, np.inf, np.NINF, np.Infinity], MISSING, inplace=True) + + if options.dat_file is not None: + cols = list(df) + df.to_pickle(options.dat_file, protocol=3) + print("Dumped DF to pickle: ", options.dat_file) + + if options.check_row_data_verbose: + helper.check_too_large_or_nan_values(df, list(df)) + + # do the heavy lifting + learner = Learner(df) + learner.learn() diff --git a/cryptominisat/cppsrc/scripts/crystal/clean_update_data.py b/cryptominisat/cppsrc/scripts/crystal/clean_update_data.py new file mode 100755 index 00000000..7e1ba6e6 --- /dev/null +++ b/cryptominisat/cppsrc/scripts/crystal/clean_update_data.py @@ -0,0 +1,137 @@ +#!/usr/bin/env python3 +# -*- coding: utf-8 -*- + +# Copyright (C) 2009-2020 Authors of CryptoMiniSat, see AUTHORS file +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; version 2 +# of the License. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +# 02110-1301, USA. + +from __future__ import print_function +import optparse +import time +import helper + + +class QueryFill (helper.QueryHelper): + def __init__(self, dbfname): + super(QueryFill, self).__init__(dbfname) + + def create_indexes(self): + helper.drop_idxs(self.c) + + print("Creating needed indexes...") + t = time.time() + q = """ + create index `idxclid-del` on `cl_last_in_solver` (`clauseID`, `conflicts`); + create index `idxclid-del2` on `used_clauses` (`clauseID`); + create index `idxclid-del3` on `used_clauses` (`clauseID`, `used_at`); + create index `idxclid1-2` on `clause_stats` (`clauseID`); + """ + + for l in q.split('\n'): + t2 = time.time() + + if options.verbose: + print("Creating index: ", l) + self.c.execute(l) + if options.verbose: + print("Index creation T: %-3.2f s" % (time.time() - t2)) + + print("indexes created T: %-3.2f s" % (time.time() - t)) + + def fill_sum_cl_use(self): + print("Filling sum_cl_use...") + + t = time.time() + q = """DROP TABLE IF EXISTS `sum_cl_use`;""" + self.c.execute(q) + q = """ + create table `sum_cl_use` ( + `clauseID` bigint(20) NOT NULL, + `num_used` float(20) NOT NULL, + `first_confl_used` bigint(20), + `last_confl_used` bigint(20) + );""" + self.c.execute(q) + print("sum_cl_use recreated T: %-3.2f s" % (time.time() - t)) + + t = time.time() + q = """insert into sum_cl_use + ( + `clauseID` + , `num_used` + , `first_confl_used` + , `last_confl_used` + ) + select + clauseID + , sum(weight) + , min(used_at) + , max(used_at) + from used_clauses as c + group by clauseID;""" + self.c.execute(q) + print("sum_cl_use filled T: %-3.2f s" % (time.time() - t)) + + t = time.time() + q = """ + create index `idxclid21` on `sum_cl_use` (`clauseID`); + """ + for l in q.split('\n'): + self.c.execute(l) + print("sum_cl_use indexes added T: %-3.2f s" % (time.time() - t)) + + t = time.time() + q = """ + insert into sum_cl_use + ( + `clauseID` + , `num_used` + , `first_confl_used` + , `last_confl_used` + ) + select + clstats.clauseID -- `clauseID` + , 0 -- `num_used`, + , NULL -- `first_confl_used` + , NULL -- `last_confl_used` + from clause_stats as clstats left join sum_cl_use + on clstats.clauseID = sum_cl_use.clauseID + where + sum_cl_use.clauseID is NULL + and clstats.clauseID != 0; + """ + self.c.execute(q) + print("sum_cl_use added bad claues T: %-3.2f s" % (time.time() - t)) + + +if __name__ == "__main__": + usage = "usage: %prog [options] sqlitedb" + parser = optparse.OptionParser(usage=usage) + parser.add_option("--verbose", "-v", action="store_true", default=False, + dest="verbose", help="Print more output") + + (options, args) = parser.parse_args() + + if len(args) < 1: + print("ERROR: You must give the sqlite file!") + exit(-1) + + with QueryFill(args[0]) as q: + q.create_indexes() + q.fill_sum_cl_use() + helper.drop_idxs(q.c) + + print("Done.") diff --git a/cryptominisat/cppsrc/scripts/crystal/clustering.py b/cryptominisat/cppsrc/scripts/crystal/clustering.py new file mode 100755 index 00000000..04356d3c --- /dev/null +++ b/cryptominisat/cppsrc/scripts/crystal/clustering.py @@ -0,0 +1,386 @@ +#!/usr/bin/env python3 +# -*- coding: utf-8 -*- + +# Copyright (C) 2009-2020 Authors of CryptoMiniSat, see AUTHORS file +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; version 2 +# of the License. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +# 02110-1301, USA. + +import operator +import re +import pandas as pd +import pickle +import sklearn +import sklearn.svm +import sklearn.tree +import sklearn.cluster +from sklearn.preprocessing import StandardScaler +import argparse +import sys +import numpy as np +import sklearn.metrics +import time +import itertools +import math +import matplotlib.pyplot as plt +import sklearn.ensemble +import os +import helper +import decimal +try: + from termcolor import cprint +except ImportError: + termcolor_avail = False +else: + termcolor_avail = True + +ver = sklearn.__version__.split(".") +if int(ver[1]) < 20: + from sklearn.cross_validation import train_test_split +else: + from sklearn.model_selection import train_test_split + + +CLUST_TYPE_FILES = 0 +CLUST_TYPE_USEFULNESS = 1 + +def get_cluster_name(clust_type): + name = None + if clust_type == CLUST_TYPE_FILES: + name = "clust_f" + elif clust_type == CLUST_TYPE_USEFULNESS: + name = "clust_u" + else: + assert False + + return name + +def get_clustering_label(df, feats_used: list, scaler, clustering): + this_feats = list(df) + for f in feats_used: + if f not in this_feats: + print("ERROR: Feature '%s' is in the training file but not in the current one!" % f) + exit(-1) + + df_clust = df[feats_used].astype(float).copy() + df_clust = scaler.transform(df_clust) + return clustering.predict(df_clust) + + +def dump_dataframe(df, fname: str): + with open(fname, "wb") as f: + pickle.dump(df, f) + print("Dumped to file %s" % fname) + + +class Clustering: + def __init__(self, df, clust_type): + self.df = df + self.clust_type = clust_type + + def reformat_feats(self, feats): + feats_clean = [] + for feat in feats: + assert "szfeat_cur.conflicts" not in feat + c = str(feat) + c = c.replace(".irred_", ".irred_cl_distrib.") + c = c.replace(".red_", ".red_cl_distrib.") + c = c.replace("szfeat_cur.", "{val}.") + + feats_clean.append(c) + assert len(feats_clean) == len(feats) + + return feats_clean + + def create_code_for_cluster_centers(self, clust, scaler, sz_feats): + sz_feats_clean = self.reformat_feats(sz_feats) + f = open("{basedir}/clustering_imp.cpp".format(basedir=options.basedir), 'w') + + helper.write_mit_header(f) + f.write(""" +#include "satzilla_features.h" +#include "clustering.h" +#include + +using namespace CMSat; + +ClusteringImp::ClusteringImp() {{ + set_up_centers(); +}} + +ClusteringImp::~ClusteringImp() {{ +}} + +""".format(clusters=options.clusters)) + + f.write("void ClusteringImp::set_up_centers() {\n") + f.write("\n centers.resize(%d);\n" % options.clusters) + for i in range(options.clusters): + f.write("\n // Doing cluster center %d\n" % i) + f.write("\n centers[%d].resize(%d);\n" % (i, len(sz_feats_clean)) ) + f.write("\n used_clusters.push_back(%d);\n" % i) + for i2 in range(len(sz_feats_clean)): + feat = sz_feats_clean[i2] + center = clust.cluster_centers_[i][i2] + f.write(" centers[{num}][{feat}] = {center}L;\n".format( + num=i, feat=i2, center=center)) + + f.write(" }\n") + + f.write(""" +double sq(double x) { + return x*x; +} + +double ClusteringImp::norm_dist(const SatZillaFeatures& a, const std::vector& center) const { + double dist = 0; + double tmp; +""") + for feat, i in zip(sz_feats_clean, range(10000)): + printed_scale = "{scale:3.10f}".format(scale=scaler.scale_[i]) + if decimal.Decimal(printed_scale) == decimal.Decimal("0.0") : + f.write(" // feature {feat} would have caused a division by zero, avoiding\n".\ + format(feat=feat.format(val="a"))) + continue + + f.write(" tmp = ((double){feat}-{mean:3.9f})/{printed_scale};\n".format( + feat=feat.format(val="a"), + mean=scaler.mean_[i], + printed_scale=printed_scale + )) + + f.write(" dist+=sq(tmp-center[{feat}]);\n\n".format( + feat=i + )) + + f.write(""" + return dist; +}\n""") + + f.write(""" +int ClusteringImp::which_is_closest(const SatZillaFeatures& p) const { + double closest_dist = numeric_limits::max(); + int closest = -1; + for (int i: used_clusters) { + double dist = norm_dist(p, centers[i]); + if (dist < closest_dist) { + closest_dist = dist; + closest = i; + } + } + return closest; + }\n""") + + def select_features_files(self): + features = list(self.df) + for f in list(features): + if any(ext in f for ext in ["var", "vcg", "pnr", "min", "max", "std"]): + features.remove(f) + + # features from dataframe + feats_used = [] + for feat in features: + if "szfeat_cur" in feat and "szfeat_cur.conflicts" not in feat: + feats_used.append(feat) + + return feats_used + + def select_features_usefulness(self): + features = list(self.df) + feats_used = helper.get_features(options.best_features_fname) + + return feats_used + + def cluster(self): + if self.clust_type == CLUST_TYPE_FILES: + self.feats_used = self.select_features_files() + elif self.clust_type == CLUST_TYPE_USEFULNESS: + self.feats_used = self.select_features_usefulness() + else: + assert False + + print("Features used: ", self.feats_used) + print("Number of features used: ", len(self.feats_used)) + + if options.check_row_data: + helper.check_too_large_or_nan_values(self.df, self.feats_used) + else: + helper.check_too_large_or_nan_values(self.df.sample(100), self.feats_used) + + # fit to slice that only includes CNF features + df_clust = self.df[self.feats_used].astype(float).copy() + if options.scale: + self.scaler = StandardScaler() + self.scaler.fit(df_clust) + if options.verbose: + print("Scaler:") + print(" -- ", self.scaler.mean_) + print(" -- ", self.scaler.scale_) + + if options.verbose: + df_clust_back = df_clust.copy() + df_clust = self.scaler.transform(df_clust) + else: + class ScalerNone: + def __init__(self): + self.mean_ = [0.0 for n in range(df_clust.shape[1])] + self.scale_ = [1.0 for n in range(df_clust.shape[1])] + self.scaler = ScalerNone() + + # test scaler's code generation + if options.scale and options.verbose: + # we rely on this later in code generation + # for scaler.mean_ + # for scaler.scale_ + # for cluster.cluster_centers_ + for i in range(df_clust_back.shape[1]): + assert df_clust_back.columns[i] == self.feats_used[i] + + # checking that scaler works as expected + for feat in range(df_clust_back.shape[1]): + df_clust_back[df_clust_back.columns[feat] + ] -= self.scaler.mean_[feat] + df_clust_back[df_clust_back.columns[feat] + ] /= self.scaler.scale_[feat] + + print(df_clust_back.head()-df_clust.head()) + print(df_clust_back.head()) + print(df_clust.head()) + + self.clust = sklearn.cluster.KMeans(n_clusters=options.clusters, random_state=prng) + self.clust.fit(df_clust) + self.df["clust"] = self.clust.labels_ + + # print information about the clusters + if options.verbose: + print(self.feats_used) + print(self.clust.labels_) + print(self.clust.cluster_centers_) + print(self.clust.get_params()) + + # code for cluster centers + self.create_code_for_cluster_centers( + self.clust, self.scaler, self.feats_used) + + return self.feats_used, self.scaler, self.clust + + +if __name__ == "__main__": + usage = "usage: %(prog)s [options] file.pandas" + parser = argparse.ArgumentParser(usage=usage) + + parser.add_argument("--seed", default=None, type=int, + dest="seed", help="Seed of PRNG") + parser.add_argument("fnames", nargs='+', metavar='FILES', + help="Files to parse, first file is the one to base data off of") + parser.add_argument("--verbose", "-v", action="store_true", default=False, + dest="verbose", help="Print more output") + parser.add_argument("--printfeat", action="store_true", default=False, + dest="print_features", help="Print features") + parser.add_argument("--check", action="store_true", default=False, + dest="check_row_data", help="Check row data for NaN or float overflow") + parser.add_argument("--bestfeatfile", + default="../../scripts/crystal/best_features_usefulness_clust.txt", + type=str, + dest="best_features_fname", + help="Name and position of best features file that lists the best features in order") + + # clustering + parser.add_argument("--clusters", default=4, type=int, + dest="clusters", help="How many clusters to use") + parser.add_argument("--scale", default=False, action="store_true", + dest="scale", help="Scale clustering") + parser.add_argument("--nocomputed", default=True, action="store_false", + dest="computed", help="Don't add computed features") + parser.add_argument("--samples", default=1000, + dest="samples_per_file", help="Samples per file") + + # number of configs to generate + parser.add_argument("--confs", default="2-2", type=str, + dest="confs", help="Configs to generate") + + # code + parser.add_argument("--basedir", type=str, + dest="basedir", help="The base directory of where the CryptoMiniSat source code is") + + options = parser.parse_args() + prng = np.random.RandomState(options.seed) + + if options.basedir is None: + print("ERROR: must set basedir") + exit(-1) + + if options.fnames is None or len(options.fnames) == 0: + print("ERROR: You must give the pandas file!") + exit(-1) + + fnames = [f for f in options.fnames if "clust" not in f] + print("Will add clustering to files: ") + for f in fnames: + print("->", f) + + if options.clusters <= 0: + print("ERROR: You must give a '--clusters' option that is greater than 0") + exit(-1) + + samples = None + for f in fnames: + print("===-- Sampling file %s --" % f) + df = pd.read_pickle(f) + print("options.samples_per_file:", options.samples_per_file) + print("df.shape:", df.shape) + new_samples = df.sample(options.samples_per_file, replace=True, + random_state=prng) + samples = new_samples.append(samples) + print("samples.shape:", samples.shape) + del df + + if options.computed: + helper.cldata_add_computed_features(samples, options.verbose) + + # clustering_setup is: + # feats_used, scaler, clust + clustering_setup = [None, None] + todo = [CLUST_TYPE_FILES, CLUST_TYPE_USEFULNESS] + todo = [CLUST_TYPE_FILES] + for clust_type in todo: + c = Clustering(samples, clust_type) + clustering_setup[clust_type] = c.cluster() + name = get_cluster_name(clust_type) + if termcolor_avail: + cprint("===-- K-Means clustering **created ** type: %s --" % name, + "green", "on_grey") + else: + cprint("===-- K-Means clustering **created ** type: %s --" % name) + + del samples + + for f in fnames: + print("===-- Clustering file %s" % (f)) + df_orig = pd.read_pickle(f) + df = df_orig.copy() + if options.computed: + helper.cldata_add_computed_features(df, options.verbose) + + for clust_type in todo: + name = get_cluster_name(clust_type) + print("===-- type: %s --" % name) + df_orig[name] = get_clustering_label(df, *clustering_setup[clust_type]) + print("Distribution: \n%s" % df_orig[name].value_counts()) + + cleanname = re.sub(r'\.dat$', '', f) + dump_dataframe(df_orig, cleanname+"-clustered.dat") + del df + del df_orig diff --git a/cryptominisat/cppsrc/scripts/crystal/concat_pandas.py b/cryptominisat/cppsrc/scripts/crystal/concat_pandas.py new file mode 100755 index 00000000..26b58072 --- /dev/null +++ b/cryptominisat/cppsrc/scripts/crystal/concat_pandas.py @@ -0,0 +1,86 @@ +#!/usr/bin/env python3 +# -*- coding: utf-8 -*- + +# Copyright (C) 2009-2020 Authors of CryptoMiniSat, see AUTHORS file +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; version 2 +# of the License. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +# 02110-1301, USA. + +from __future__ import print_function +import optparse +import time +import pickle +import pandas as pd +import numpy as np +import sys + + +if __name__ == "__main__": + usage = """usage: %prog [options] file1.dat [file2.dat ...] +Concatenates Pandas dataframes into a single file. The dataframes must have +the same columns.""" + parser = optparse.OptionParser(usage=usage) + + parser.add_option("--verbose", "-v", action="store_true", default=False, + dest="verbose", help="Print more output") + parser.add_option("--out", "-o", default=None, type=str, + dest="out", help="Put combined output here") + parser.add_option("--csv", default=None, type=str, + dest="csv", help="Dump CSV here") + parser.add_option("--csvratio", default=1.0, type=float, + dest="csvratio", help="Ratio of data to dump to CSV") + + (options, args) = parser.parse_args() + + if options.out is None and options.csv is None: + print("ERROR: you must either dump CSV or Pandas. Give either '--out' or '--csv' options") + exit(-1) + + if options.csvratio < 0.0: + print("ERROR: CSV ratio cannot be less than 0.0") + exit(-1) + + if options.csvratio > 1.0: + print("ERROR: CSV ratio cannot be more than 1.0") + exit(-1) + + dfs = [] + for fname in args: + print("----- Reading file %s -------" % fname) + df = pd.read_pickle(fname) + print("Read {num} datapoints from {file}".format(num=df.shape[0], file=fname)) + df["fname"] = df["fname"].astype("str") + #df["cl.cur_restart_type"] = df["cl.cur_restart_type"].astype("str") + #df["rdb0.cur_restart_type"] = df["rdb0.cur_restart_type"].astype("str") + dfs.append(df) + + print("Concatenating dataframes...") + df_full = pd.concat(dfs) + print("Concated frame size: %d" % df_full.shape[0]) + + if options.out is not None: + fname = options.out + print("Dumping {num} datapoint pandas data to: {fname}".format(num=df_full.shape[0], fname=fname)) + with open(fname, "wb") as f: + pickle.dump(df_full, f) + + if options.csv is not None: + import sklearn.model_selection + + fname = options.csv + print("Dumpiing CSV ratio: %-3.2f" % options.csvratio) + _, df_tmp = sklearn.model_selection.train_test_split(df_full, test_size=options.csvratio) + print("Dumping {num} datapoint CSV data to: {fname}".format(num=df_tmp.shape[0], fname=fname)) + df_tmp.to_csv(fname, index=False, columns=sorted(list(df_tmp))) diff --git a/cryptominisat/cppsrc/scripts/crystal/fill_used_clauses.py b/cryptominisat/cppsrc/scripts/crystal/fill_used_clauses.py new file mode 100755 index 00000000..10aa748f --- /dev/null +++ b/cryptominisat/cppsrc/scripts/crystal/fill_used_clauses.py @@ -0,0 +1,161 @@ +#!/usr/bin/env python3 +# -*- coding: utf-8 -*- + +# Copyright (C) 2009-2020 Authors of CryptoMiniSat, see AUTHORS file +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; version 2 +# of the License. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +# 02110-1301, USA. + +from __future__ import print_function +import sqlite3 +import argparse +import os +import struct +import time + + +class Query: + def __init__(self, dbfname): + self.conn = sqlite3.connect(dbfname) + self.c = self.conn.cursor() + + self.cl_used = [] + self.cl_used_num = 0 + self.cl_used_total = 0 + + def __enter__(self): + return self + + def __exit__(self, exc_type, exc_value, traceback): + self.conn.commit() + self.conn.close() + + def delete_tbls(self, table): + queries = """ +DROP TABLE IF EXISTS `{table}`; +create table `{table}` ( `clauseID` bigint(20) NOT NULL, `used_at` bigint(20) NOT NULL, `weight` float NOT NULL); +""".format(table=table) + + for l in queries.split('\n'): + t2 = time.time() + + if options.verbose: + print("Runnin query: ", l) + self.c.execute(l) + if options.verbose: + print("Query T: %-3.2f s" % (time.time() - t2)) + + def get_last_good(self, basefname): + last_good = -1 + for i in range(100): + tfname = "%s-%d" % (basefname, i) + print("Checking if file %s exists" % tfname) + if os.path.isfile(tfname): + last_good = i + + if last_good == -1: + print("ERROR: file does not exist at all") + exit(-1) + + return last_good + + def add_used_clauses(self, usedClFname): + last_good = self.get_last_good(usedClFname) + tfname = "%s-%d" % (usedClFname, last_good) + tfname_anc = tfname.replace("usedCls", "usedCls-anc") + + + for fname,table in [(tfname, "used_clauses"), (tfname_anc, "used_clauses_anc")]: + t = time.time() + print("Adding data from file %s to DB %s" % (fname, table)) + + self.cl_used = [] + self.cl_used_num = 0 + self.cl_used_total = 0 + with open(fname, "rb") as f: + while True: + b1 = f.read(8) + if not b1: + # end of file + break + b2 = f.read(8) + cl_id = struct.unpack(" 10000: + self.dump_used_clauses(table) + + self.dump_used_clauses(table) + print("Added use data to table %s from file %s: %d time: T: %-3.2f s" % + (table, fname, self.cl_used_total, time.time() - t)) + + def dump_used_clauses(self, table): + self.c.executemany(""" + INSERT INTO %s ( + `clauseID`, + `used_at`, + `weight`) + VALUES (?, ?, ?);""" % table, self.cl_used) + self.cl_used = [] + self.cl_used_num = 0 + + +if __name__ == "__main__": + usage = """usage: %(prog)s [options] sqlite_db usedCls + +Adds used_clauses to the SQLite database""" + + parser = argparse.ArgumentParser(usage=usage) + + + parser.add_argument("sqlitedb", type=str, metavar='USEDCLS') + parser.add_argument("usedcls", type=str, metavar='USEDCLS') + parser.add_argument("--verbose", "-v", action="store_true", default=False, + dest="verbose", help="Print more output") + + options = parser.parse_args() + + if options.sqlitedb is None: + print("Error you must give an SQLite DB. Please follow usage.") + print(usage) + exit(-1) + + if options.usedcls is None: + print("Error you must give an Used CLS list. Please follow usage.") + print(usage) + exit(-1) + + print("Using sqlite3db file %s" % options.sqlitedb) + print("Base used_clauses file is %s" % options.usedcls) + + with Query(options.sqlitedb) as q: + q.delete_tbls("used_clauses") + q.delete_tbls("used_clauses_anc") + q.add_used_clauses(options.usedcls) + + print("Finished adding good lemma indicators to db %s" % options.sqlitedb) + + exit(0) diff --git a/cryptominisat/cppsrc/scripts/crystal/fix_up_frat.py b/cryptominisat/cppsrc/scripts/crystal/fix_up_frat.py new file mode 100755 index 00000000..5dd3f727 --- /dev/null +++ b/cryptominisat/cppsrc/scripts/crystal/fix_up_frat.py @@ -0,0 +1,267 @@ +#!/usr/bin/env python3 +# -*- coding: utf-8 -*- + +# Copyright (C) 2009-2020 Authors of CryptoMiniSat, see AUTHORS file +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; version 2 +# of the License. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +# 02110-1301, USA. + +from __future__ import print_function +import sqlite3 +import argparse +import time +#import line_profiler + +cl_to_conflict = {} +new_id_to_old_id = {} +class Query: + def __init__(self, dbfname): + self.conn = sqlite3.connect(dbfname) + self.c = self.conn.cursor() + self.cl_used = [] + self.cl_used_num = 0 + self.cl_used_total = 0 + self.children_set = 0 + + def __enter__(self): + return self + + def __exit__(self, exc_type, exc_value, traceback): + self.conn.commit() + self.conn.close() + + def delete_tbls(self, table): + queries = """ +DROP TABLE IF EXISTS `{table}`; +create table `{table}` ( `clauseID` bigint(20) NOT NULL, `used_at` bigint(20) NOT NULL, `weight` float NOT NULL); +""".format(table=table) + + for l in queries.split('\n'): + t2 = time.time() + + if opts.verbose: + print("Running query: ", l) + self.c.execute(l) + if opts.verbose: + print("Query T: %-3.2f s" % (time.time() - t2)) + + def get_conflicts(self): + query= """select id, conflicts from set_id_confl;""" + self.c.execute(query) + while True: + n = self.c.fetchone() + if n is None: + break + + ID = n[0] + confl = n[1] + if ID in cl_to_conflict: + print("ERROR: ID %d in cl_to_conflict already. Old value: %d new value: %d" % (ID, cl_to_conflict[ID], confl)) + print("Likely, the issue is with `reloc` in FRAT, which is used in varreplacer. That is NOT understood by this system"); + exit(-1) + cl_to_conflict[ID] = confl + + if opts.verbose: + print("Got ID-conflict data") + + def get_updates(self): + query= """select old_id, new_id from update_id order by old_id;""" + self.c.execute(query) + while True: + n = self.c.fetchone() + if n is None: + break + + old_id = n[0] + new_id = n[1] + if old_id in new_id_to_old_id: + real_old_id = new_id_to_old_id[old_id][0] + else: + real_old_id = old_id + + new_id_to_old_id[new_id] = [real_old_id, 1.0, None] + + if opts.verbose: + print("Got ID-update data") + + def dump_used_clauses(self): + for table in ("used_clauses_anc", "used_clauses"): + if table == "used_clauses": + todump = filter(lambda c: c[1] == 1.0, self.cl_used) + else: + todump = self.cl_used + + self.c.executemany(""" + INSERT INTO %s ( + `clauseID`, + `weight`, + `used_at`) + VALUES (?, ?, ?);""" % table, todump) + + self.cl_used = [] + self.cl_used_num = 0 + + #@profile + def deal_with_chain(self, line, final_resolvent_ID, tracked_already, confl): + for chain_str in line: + if chain_str[0] == '0': + break + chain_ID = int(chain_str) + if opts.verbose: + print("Cl ID %8d used for Cl ID %8d" % (chain_ID, final_resolvent_ID)) + if chain_ID in new_id_to_old_id: + if opts.verbose: + print("--> tracked as %s" % new_id_to_old_id[chain_ID]) + data = new_id_to_old_id[chain_ID] + if data[2] == None: + # this is an original parent + count_as_confl = confl + assert data[1] == 1.0 + else: + # this is a child + count_as_confl = data[2] + assert data[1] < 1.0 + + new_item = [data[0], data[1], count_as_confl] + self.cl_used.append(new_item) + self.cl_used_num+=1 + self.cl_used_total+=1 + if opts.verbose: + print("--> USED: %s" % new_item) + if self.cl_used_num > 10000: + self.dump_used_clauses() + + # This chain_ID is tracked. Let's track Clause "final_resolvent_ID", it will be a child + # NOTE: we only track it as ONE of the children... which is not ideal. + if tracked_already: + if opts.verbose: + print("-----> Can't track Cl ID %d as child, already tracked either as MAIN or as a child" % final_resolvent_ID) + continue + + # final_resolvent_ID is not tracked already. We'll track it according to its ancestor + data = new_id_to_old_id[chain_ID] + chain_ID_upd = data[0] + val = 0.5*data[1] + if data[2] is not None: + # This is a child of a child, so parent's conf needs to be bumped + anc_confl = data[2] + else: + # Children of this will need confl to be bumped + anc_confl = confl + + # Don't bother if it's less than 0.05 + if val <= 0.05: + continue + + if opts.verbose: + print("-----> Therefore, we will track ID %d with val %f to count as ID %d, confl %d" % (final_resolvent_ID, val, chain_ID_upd, anc_confl)) + new_id_to_old_id[final_resolvent_ID] = [chain_ID_upd, val, anc_confl] + tracked_already = True + self.children_set += 1 + + #@profile + def fix_up_frat(self, fratfile): + with open(fratfile, "r") as f: + for line in f: + line=line.strip() + if len(line) == 0: + continue + if line[0] != "a": + continue + + if opts.verbose: + print("-------------****----------------------") + print("New line: %s" % line) + line = line.split() + if len(line) < 3: + print("ERROR: Line contains 1 or 2 elements??? It needs a/o/d/l/t + at least ID") + exit(-1) + + final_resolvent_ID = int(line[1]) + line = line[2:] + tracked_already = False + + if final_resolvent_ID not in new_id_to_old_id: + if opts.verbose: + print("MAIN: Cl ID %8d is not tracked" % final_resolvent_ID) + else: + if opts.verbose: + print("MAIN: Cl ID %8d is tracked, it is: %s" % (final_resolvent_ID, new_id_to_old_id[final_resolvent_ID])) + tracked_already = True + + if final_resolvent_ID not in cl_to_conflict: + print("ERROR: ID %8d not in cl_to_conflict" % final_resolvent_ID) + exit(-1) + + confl = cl_to_conflict[final_resolvent_ID] + if opts.verbose: + print("MAIN: Cl ID %8d is generated at confl %d" % (final_resolvent_ID, confl)) + + found = False + for i in range(len(line)): + if line[i] == "l": + line = line[i+1:] + found = True + break + + if not found: + #if opts.verbose: + print("No explanation on line %s for ID %d" % (line, final_resolvent_ID)) + continue + + self.deal_with_chain(line, final_resolvent_ID, tracked_already, confl) + + +if __name__ == "__main__": + usage = """usage: %(prog)s [opts] sqlite_db usedCls + +Adds used_clauses to the SQLite database""" + + parser = argparse.ArgumentParser(usage=usage) + + + parser.add_argument("fratfile", type=str, metavar='FRAT') + parser.add_argument("sqlitedb", type=str, metavar='SQLITEDB') + parser.add_argument("--verbose", "-v", action="store_true", default=False, + dest="verbose", help="Print more output") + + opts = parser.parse_args() + + if opts.sqlitedb is None: + print("Error you must give an SQLite DB. Please follow usage.") + print(usage) + exit(-1) + + if opts.fratfile is None: + print("Error you must give the minimized FRAT file.") + print(usage) + exit(-1) + + print("Using FRAT file %s" % opts.fratfile) + print("Using sqlite3db file %s" % opts.sqlitedb) + + with Query(opts.sqlitedb) as q: + q.delete_tbls("used_clauses") + q.delete_tbls("used_clauses_anc") + q.get_conflicts() + q.get_updates() + q.fix_up_frat(opts.fratfile) + # dump remaining ones (we dump 1000-by-1000) + q.dump_used_clauses() + + print("Total num: %10d" % q.cl_used_total) + print("Children set: %10d" % q.children_set) + + exit(0) diff --git a/cryptominisat/cppsrc/scripts/crystal/gen_best_feats.sh b/cryptominisat/cppsrc/scripts/crystal/gen_best_feats.sh new file mode 100755 index 00000000..4931a135 --- /dev/null +++ b/cryptominisat/cppsrc/scripts/crystal/gen_best_feats.sh @@ -0,0 +1,47 @@ +#!/usr/bin/bash + +set -e +set -x + + +basename="8march-2020-3acd81dc55df3-best-feats" +basename="aes-30-march-2020-a1e0e19be0c1" +mkdir -p ${basename} +rm -f ${basename}/* +git rev-parse HEAD > ${basename}/out_git +cat gen_best_feats.sh >> ${basename}/out_git +md5sum *.dat >> ${basename}/out_git + + +function doit() { + +tiers=( +"short" +"long" +"forever") + +for tier in "${tiers[@]}" +do + echo "Doing ${tier}_${computed}computed" + + /usr/bin/time --verbose -o "${basename}/output_${tier}_${computed}computed.timeout" \ + ../cldata_predict.py "${tier}-comb-cut1-$cut1-cut2-$cut2-limit-${limit}.dat" \ + --tier ${tier} --regressor "xgboost" --only "$only" \ + --features "${computed}_computed" > "${basename}/output_${tier}_${computed}computed-cut1-${cut1}-cut2-${cut2}" + + echo "Done with ${tier}_${computed}computed" +done + +} + +limit=2000 +cut1="5.0" +cut2="30.0" + +only="1.0" +computed="no" +doit + +only="0.02" +computed="all" +doit diff --git a/cryptominisat/cppsrc/scripts/crystal/get_msqe.py b/cryptominisat/cppsrc/scripts/crystal/get_msqe.py new file mode 100755 index 00000000..62d57390 --- /dev/null +++ b/cryptominisat/cppsrc/scripts/crystal/get_msqe.py @@ -0,0 +1,61 @@ +#!/bin/python3 + +import sys +import os + +assert len(sys.argv) >= 2 + + +tiers = {"short":[], "long":[], "forever":[]} + +for mydir in sys.argv[1:]: + if not os.path.isdir(mydir): + print("WARN: %s is not a directory, skipping" % mydir) + continue + print(mydir) + print("========") + for tier in ["short", "long", "forever"]: + for table in ["used_later", "used_later_anc"]: + fname = "%s/out-%s-%s" %(mydir, table, tier) + if not os.path.isfile(fname): + print("ERROR: the file '%s' does not exist!" % fname) + exit(-1) + + test = False + all_dump_no = False + with open(fname, "r") as f: + out = "Tier %-9s " % tier + for line in f: + line = line.strip() + if " test data" in line: + test = True + + if not test: + continue + + if "ALL dump_no" in line: + all_dump_no = True + + if not all_dump_no: + continue + + if "train+test" in line: + break + + if "train data" in line: + break + + assert test + if "Mean squared error is" in line: + mydat = line.split(" ") + val = float(mydat[5]) + tiers[tier].append(["%s-%s" % (mydir, table), val]) + out += line + print(out) + break + +for tier in ["short", "long", "forever"]: + print("TIER: ", tier) + top = sorted(tiers[tier], key=lambda x: x[1], reverse=False) + for t in top: + print(t) diff --git a/cryptominisat/cppsrc/scripts/crystal/helper.py b/cryptominisat/cppsrc/scripts/crystal/helper.py new file mode 100644 index 00000000..42d36637 --- /dev/null +++ b/cryptominisat/cppsrc/scripts/crystal/helper.py @@ -0,0 +1,838 @@ +#!/usr/bin/env python3 +# -*- coding: utf-8 -*- + +# Copyright (C) 2009-2020 Authors of CryptoMiniSat, see AUTHORS file +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; version 2 +# of the License. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +# 02110-1301, USA. + +# pylint: disable=invalid-name,line-too-long,too-many-locals,consider-using-sys-exit + +import numpy as np +import pandas as pd +import matplotlib.pyplot as plt +import sklearn +import sklearn.metrics +import re +import ast +import math +import time +import os.path +import sqlite3 +import functools +from ccg import * + +try: + from termcolor import cprint +except ImportError: + termcolor_avail = False +else: + termcolor_avail = True + +from pprint import pprint +try: + import mlflow +except ImportError: + mlflow_avail = False +else: + mlflow_avail = True + + +class QueryHelper: + def __init__(self, dbfname): + if not os.path.isfile(dbfname): + print("ERROR: Database file '%s' does not exist" % dbfname) + exit(-1) + + self.conn = sqlite3.connect(dbfname) + self.c = self.conn.cursor() + + def __enter__(self): + return self + + def __exit__(self, exc_type, exc_value, traceback): + self.conn.commit() + self.conn.close() + + +class QueryFill (QueryHelper): + def create_indexes(self, verbose=False, used_clauses="used_clauses"): + t = time.time() + print("Recreating indexes...") + queries = """ + create index `idxclid6-4` on `reduceDB` (`clauseID`, `conflicts`) + create index `idxclidUCLS-2` on `{used_clauses}` ( `clauseID`, `used_at`); + create index `idxcl_last_in_solver-1` on `cl_last_in_solver` ( `clauseID`, `conflicts`); + """.format(used_clauses=used_clauses) + for l in queries.split('\n'): + t2 = time.time() + + if verbose: + print("Creating index: ", l) + self.c.execute(l) + if verbose: + print("Index creation T: %-3.2f s" % (time.time() - t2)) + + print("indexes created T: %-3.2f s" % (time.time() - t)) + + def delete_and_create_used_laters(self): + tiers = ["short", "long", "forever"] + tables = ["used_later", "used_later_anc"] + for tier in tiers: + for table in tables: + q = """ + DROP TABLE IF EXISTS `{table}_{tier}`; + """ + self.c.execute(q.format(tier=tier, table=table)) + + # Create and fill used_later_X tables + q_create = """ + create table `{table}_{tier}` ( + `clauseID` bigint(20) NOT NULL, + `rdb0conflicts` bigint(20) NOT NULL, + `used_later` float, + `percentile_fit` float DEFAULT NULL + );""" + # NOTE: "percentile_fit" is the top percentile this use belongs to. Filled in later. + + for tier in tiers: + for table in tables: + self.c.execute(q_create.format(tier=tier, table=table)) + + idxs = """ + create index `{table}_{tier}_idx3` on `{table}_{tier}` (`used_later`); + create index `{table}_{tier}_idx1` on `{table}_{tier}` (`clauseID`, `rdb0conflicts`); + create index `{table}_{tier}_idx2` on `{table}_{tier}` (`clauseID`, `rdb0conflicts`, `used_later`);""" + + t = time.time() + for tier in tiers: + for table in tables: + for l in idxs.format(tier=tier, table=table).split('\n'): + self.c.execute(l) + + print("used_later* dropped and recreated T: %-3.2f s" % (time.time() - t)) + + # The most expesive operation of all, when called with "forever" + def fill_used_later_X(self, tier, duration, used_clauses="used_clauses", + table="used_later"): + + min_del_distance = duration + if min_del_distance > 2*1000*1000: + min_del_distance = 100*1000 + + # Note: "weight" below is because a child has less weight than a parent + # discount is 0.5 (as per fix_up_frat), so a child is 0.5, a grand-child + # is 0.25 etc. Below 0.05 we don't care and it's a 0. + q_fill = """ + insert into {table}_{tier} + ( + `clauseID`, + `rdb0conflicts`, + `used_later` + ) + SELECT + rdb0.clauseID + , rdb0.conflicts + , sum(ucl.weight) as `used_later` + + FROM + reduceDB as rdb0 + left join {used_clauses} as ucl + + -- reduceDB is always present, {used_clauses} may not be, hence left join + on (ucl.clauseID = rdb0.clauseID + and ucl.used_at > (rdb0.conflicts) + and ucl.used_at <= (rdb0.conflicts+{duration})) + + join cl_last_in_solver + on cl_last_in_solver.clauseID = rdb0.clauseID + + WHERE + rdb0.clauseID != 0 + and cl_last_in_solver.conflicts >= (rdb0.conflicts + {min_del_distance}) + + group by rdb0.clauseID, rdb0.conflicts;""" + + t = time.time() + q = q_fill.format( + tier=tier, used_clauses=used_clauses, + duration=duration, + table=table, + min_del_distance=min_del_distance) + self.c.execute(q) + + q_fix_null = "update {table}_{tier} set used_later = 0 where used_later is NULL".format( + tier=tier, table=table) + self.c.execute(q_fix_null) + + + q_num = "select count(*) from {table}_{tier}".format(tier=tier, table=table) + self.c.execute(q_num) + rows = self.c.fetchall() + for row in rows: + num = row[0] + + if table == "used_later" and num == 0: + print("ERROR: number of rows in {table}_{tier} is 0!".format(tier=tier, table=table)) + print("Query was: %s" % q) + exit(-1) + + + print("%s_%s filled T: %-3.2f s -- num rows: %d" % + (table, tier, time.time() - t, num)) + + def fill_used_later_X_perc_fit(self, tier, table): + print("Filling percentile_fit for {table}_{tier}".format(tier=tier, table=table)) + + q = """ + update {table}_{tier} + set percentile_fit = ( + select max({table}_percentiles.percentile) + from {table}_percentiles + where + {table}_percentiles.type_of_dat="{tier}" + and {table}_percentiles.percentile_descr="top_non_zero" + and {table}_percentiles.val >= {table}_{tier}.used_later); + """ + t = time.time() + self.c.execute(q.format(tier=tier, table=table)) + print("used_later_%s percentile filled T: %-3.2f s" % (tier, time.time() - t)) + + + +def write_mit_header(f): + f.write("""/****************************************** +Copyright (C) 2009-2020 Authors of CryptoMiniSat, see AUTHORS file + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. +***********************************************/\n\n""") + +def parse_configs(confs): + match = re.match(r"^([0-9]*)-([0-9]*)$", confs) + if not match: + print("ERROR: we cannot parse your config options: '%s'" % confs) + exit(-1) + + conf_from = int(match.group(1)) + conf_to = int(match.group(2))+1 + if conf_to <= conf_from: + print("ERROR: Conf range is not increasing") + exit(-1) + + print("Running configs:", range(conf_from, conf_to)) + return conf_from, conf_to + + +def get_features(fname): + best_features = [] + check_file_exists(fname) + with open(fname, "r") as f: + for l in f: + l = l.strip() + if len(l) == 0: + continue + + if l[0] == "#": + continue + + best_features.append(l) + + return best_features + + +def helper_divide(dividend, divisor, df, features, verb, name=None): + """ + to be used like: + import functools + divide = functools.partial(helper.divide, df=df, features=features, verb=options.verbose) + """ + + # dividend feature not present + #if dividend not in features: + #return None + + # divisorfeature not present + #if divisor not in features: + #return None + + # divide + if verb: + print("Dividing. dividend: '%s' divisor: '%s' " % (dividend, divisor)) + + if name is None: + name = "(%s/%s)" % (dividend, divisor) + + df[name] = df[dividend].div(df[divisor]) + return name + +def helper_larger_than(lhs, rhs, df, features, verb): + """ + to be used like: + import functools + larger_than = functools.partial(helper.larger_than, df=df, features=features, verb=options.verbose) + """ + + # divide + if verb: + print("Calulating '%s' >: '%s' " % (lhs, rhs)) + + name = "(" + lhs + ">" + rhs + ")" + df[name] = (df[lhs] > df[rhs]).astype(int) + return name + +def helper_add(toadd, df, features, verb): + """ + to be used like: + import functools + larger_than = functools.partial(helper.larger_than, df=df, features=features, verb=options.verbose) + """ + + # add + if verb: + print("Calulating: the feature addition of: %s", toadd) + + name = "(" + for i in range(1, len(toadd)): + name = toadd[i] + if i < len(toadd)-1: + name+="+" + name += ")" + + df[name] = df[toadd[0]] + for i in range(1, len(toadd)): + df[name] += df[toadd[i]] + return name + + +def dangerous(conn): + conn.execute("PRAGMA journal_mode = MEMORY") + conn.execute("PRAGMA synchronous = OFF") + + +def drop_idxs(conn): + q = """ + SELECT name FROM sqlite_master WHERE type == 'index' + """ + conn.execute(q) + rows = conn.fetchall() + queries = "" + for row in rows: + #print("Will delete index:", row[0]) + queries += "drop index if exists `%s`;\n" % row[0] + + t = time.time() + for q in queries.split("\n"): + conn.execute(q) + + print("Removed indexes: T: %-3.2f s"% (time.time() - t)) + + +def get_columns(tablename, verbose, conn): + q = "pragma table_info(%s);" % tablename + conn.execute(q) + rows = conn.fetchall() + columns = [] + for row in rows: + if verbose: + print("Using column in table {tablename}: {col}".format( + tablename=tablename, col=row[1])) + columns.append(row[1]) + + return columns + +def query_fragment(tablename, not_cols, short_name, verbose, conn): + cols = get_columns(tablename, verbose, conn) + filtered_cols = list(set(cols).difference(not_cols)) + ret = "" + for col in filtered_cols: + ret += ", {short_name}.`{col}` as `{short_name}.{col}`\n".format( + col=col, short_name=short_name) + + if verbose: + print("query for short name {short_name}: {ret}".format( + short_name=short_name, ret=ret)) + + return ret + + +def not_inside(not_these, inside_here): + for not_this in not_these: + if not_this in inside_here: + return False + + return True + + +# to check for too large or NaN values: +def check_too_large_or_nan_values(df, features=None): + print("Checking for too large or NaN values...") + if features is None: + features = df.columns.values.flatten().tolist() + + index = 0 + for index, row in df[features].iterrows(): + print("-------------") + print("At row index: ", index) + for val, name in zip(row, features): + print("Name: '%s', val: %s" % (name, val)) + if type(val) == str: + continue + + if math.isnan(val) or not np.isfinite(val) or val > np.finfo(np.float32).max: + print("issue with feature '%s' Value: '%s' Type: '%s" % ( + name, val, type(val))) + index += 1 + + print("Checking finished.") + + +def print_confusion_matrix(cm, + normalize=False, + title='Confusion matrix'): + """ + This function prints and plots the confusion matrix. + Normalization can be applied by setting `normalize=True`. + """ + if normalize: + cm = cm.astype('float') / cm.sum(axis=1)[:, np.newaxis] + + print(title) + if mlflow_avail: + mlflow.log_metric(title, cm[0][0]) + np.set_printoptions(precision=2) + print(cm) + + +def calc_min_split_point(df, min_samples_split): + split_point = int(float(df.shape[0])*min_samples_split) + if split_point < 10: + split_point = 10 + print("Minimum split point: ", split_point) + return split_point + + +def error_format(error): + if error is None: + return "XXX" + else: + return "{0:<2.2E}".format(error) + + +def calc_regression_error(data, features, to_predict, clf, toprint, + average="binary", highlight=False): + X_data = data[features] + y_data = data[to_predict] + print("Number of elements:", X_data.shape) + if data.shape[0] <= 1: + print("Cannot calculate regression error, too few elements") + return None + y_pred = clf.predict(X_data) + main_error = sklearn.metrics.mean_squared_error(y_data, y_pred) + print("Mean squared error is: %9s" % error_format(main_error)) + median_absolute_error = sklearn.metrics.median_absolute_error(y_data, y_pred) + print("Median abs error is : %9s" % error_format(median_absolute_error)) + + # use distrib + for start,end in [(0,10), (1,10), (10, 100), (100, 1000), (1000,10000), (10000, 1000000)]: + x = "--> Strata %6d <= %21s < %8d " % (start, to_predict, end) + myfilt = data[(data[to_predict] >= start) & (data[to_predict] < end)] + X_data = myfilt[features] + y_data = myfilt[to_predict] + y = " -- elems: {:12}".format(str(X_data.shape)) + if myfilt.shape[0] <= 1: + msqe = None + med_abs_err = None + mean_err = None + else: + y_pred = clf.predict(X_data) + msqe = sklearn.metrics.mean_squared_error(y_data, y_pred) + med_abs_err = sklearn.metrics.median_absolute_error(y_data, y_pred) + mean_err = (y_data - y_pred).sum()/len(y_data) + print("{} {} msqe: {:9s} mabse: {:9s} abs: {:9s}".format( + x, y, error_format(msqe), error_format(med_abs_err), error_format(mean_err))) + + # glue distrib + for start,end in [(0,3), (3,8), (8, 15), (15, 25), (25,50), (50, 100), (100, 1000000)]: + x = "--> Strata %6d <= %21s < %8d " % (start, "rdb0.glue", end) + myfilt = data[(data["rdb0.glue"] >= start) & (data["rdb0.glue"] < end)] + X_data = myfilt[features] + y_data = myfilt[to_predict] + y = " -- elems: {:12}".format(str(X_data.shape)) + if myfilt.shape[0] <= 1: + msqe = None + med_abs_err = None + mean_err = None + else: + y_pred = clf.predict(X_data) + msqe = sklearn.metrics.mean_squared_error(y_data, y_pred) + med_abs_err = sklearn.metrics.median_absolute_error(y_data, y_pred) + mean_err = (y_data - y_pred).sum()/len(y_data) + print("{} {} msqe: {:9s} mabse: {:9s} abs: {:9s}".format( + x, y, error_format(msqe), error_format(med_abs_err), error_format(mean_err))) + + return main_error + + +def conf_matrixes(data, features, to_predict, clf, toprint, + average="binary", highlight=False): + # get data + X_data = data[features] + y_data = data[to_predict] + print("Number of elements:", X_data.shape) + if data.shape[0] <= 1: + print("Cannot calculate confusion matrix, too few elements") + return None, None, None, None + + # Preform prediction + def f(x): + if x > 0.5: + return 1 + else: + return 0 + + y_pred = clf.predict(X_data) + #print("type(y_pred[0]): ", type(y_pred[0])) + if type(y_pred[0]) == np.float32: + y_pred = np.array([f(x) for x in y_pred]) + + # calc acc, precision, recall + accuracy = sklearn.metrics.accuracy_score( + y_data, y_pred) + + precision = sklearn.metrics.precision_score( + y_data, y_pred, pos_label=1, average=average) + + + recall = sklearn.metrics.recall_score( + y_data, y_pred, pos_label=1, average=average) + + # ROC AUC + predsi = np.array(y_pred) + y_testi = pd.DataFrame(y_data)["x.class"].squeeze() + try: + roc_auc = sklearn.metrics.roc_auc_score(y_testi, predsi) + except: + print("NOTE: ROC AUC is set to 0 because of completely one-sided OK/BAD") + roc_auc = 0 + + # record to mlflow + if mlflow_avail: + mlflow.log_metric(toprint + " -- accuracy", accuracy) + mlflow.log_metric(toprint + " -- precision", precision) + mlflow.log_metric(toprint + " -- recall", recall) + mlflow.log_metric(toprint + " -- roc_auc", roc_auc) + + color = "white" + bckgrnd = "on_grey" + if highlight: + color="green" + bckgrnd = "on_grey" + + txt = "%s prec : %-3.4f recall: %-3.4f accuracy: %-3.4f roc_auc: %-3.4f" + vals = (toprint, precision, recall, accuracy, roc_auc) + if termcolor_avail: + cprint(txt % vals , color, bckgrnd) + else: + cprint(txt % vals) + + # Plot confusion matrix + cnf_matrix = sklearn.metrics.confusion_matrix( + y_true=y_data, y_pred=y_pred) + print_confusion_matrix( + cnf_matrix, + title='Confusion matrix without normalization -- %s' % toprint) + print_confusion_matrix( + cnf_matrix, normalize=True, + title='Normalized confusion matrix -- %s' % toprint) + + return roc_auc + + +def check_file_exists(fname): + try: + f = open(fname) + except IOError: + print("File '%s' not accessible" % fname) + exit(-1) + finally: + f.close() + + +def output_to_classical_dot(clf, features, fname): + + feat_tmp = [] + for f in features: + x = str(f) + x = x.replace("rdb0.", "") + x = x.replace("cl.", "") + x = x.replace("HistLT.", "History_Long_Term") + x = x.replace("rdb0_common.", "all_learnts") + feat_tmp.append(x) + + sklearn.tree.export_graphviz(clf, out_file=fname, + feature_names=feat_tmp, + #class_names=clf.classes_, + filled=True, rounded=True, + special_characters=True, + proportion=True) + print("Run dot:") + print("dot -Tpng {fname} -o {fname}.png".format(fname=fname)) + print("gwenview {fname}.png".format(fname=fname)) + + +def print_feature_ranking(clf, X_train, top_num_features, features, plot=False): + best_features = [] + importances = clf.feature_importances_ + std = np.std( + [tree.feature_importances_ for tree in clf.estimators_], axis=0) + indices = np.argsort(importances)[::-1] + indices = indices[:top_num_features] + myrange = min(X_train.shape[1], top_num_features) + + # Print the feature ranking + print("Feature ranking:") + + for f in range(myrange): + print("%-3d %-55s -- %8.4f" % + (f + 1, features[indices[f]], importances[indices[f]])) + best_features.append(features[indices[f]]) + + # Plot the feature importances of the clf + if plot: + plot_feature_importances(importances, indices, myrange, std, features) + + return best_features + + +def plot_feature_importances(importances, indices, myrange, std, features): + plt.figure() + plt.title("Feature importances") + plt.bar(range(myrange), importances[indices], + color="r", align="center", + yerr=std[indices]) + plt.xticks(range(myrange), [features[x] + for x in indices], rotation=45) + plt.xlim([-1, myrange]) + + +def add_features_from_fname(df, features_fname, verbose=False): + print("Adding features...") + if not os.path.exists(features_fname): + print("ERROR: Feature file '%s' does not exist" % features_fname) + exit(-1) + + cldata_add_minimum_computed_features(df, verbose) + best_features = get_features(features_fname) + for feat in best_features: + toeval = ccg.to_source(ast.parse(feat)) + print("Adding feature %s as eval %s" % (feat, toeval)) + df[feat] = eval(toeval) + + +def add_features_from_list(df, best_features, verbose=False): + print("Adding features...") + cldata_add_minimum_computed_features(df, verbose) + for feat in best_features: + toeval = ccg.to_source(ast.parse(feat)) + print("Adding feature %s as eval %s" % (feat, toeval)) + df[feat] = eval(toeval) + + +def make_missing_into_nan(df): + print("Making None into NaN...") + def make_none_into_nan(x): + if x is None: + return np.nan + else: + return x + + for col in list(df): + if type(None) in df[col].apply(type).unique(): + df[col] = df[col].apply(make_none_into_nan) + print("Done.") + +def cldata_add_minimum_computed_features(df, verbose): + divide = functools.partial(helper_divide, df=df, features=list(df), verb=verbose) + divide("rdb0.act_ranking", "rdb0_common.tot_cls_in_db", name="rdb0.act_ranking_rel") + divide("rdb0.prop_ranking", "rdb0_common.tot_cls_in_db", name="rdb0.prop_ranking_rel") + divide("rdb0.uip1_ranking", "rdb0_common.tot_cls_in_db", name="rdb0.uip1_ranking_rel") + divide("rdb0.sum_uip1_per_time_ranking", "rdb0_common.tot_cls_in_db", + name="rdb0.sum_uip1_per_time_ranking_rel") + divide("rdb0.sum_props_per_time_ranking", "rdb0_common.tot_cls_in_db", + name="rdb0.sum_props_per_time_ranking_rel") + + df["rdb0_common.tot_irred_cls"] = df["rdb0_common.num_bin_irred_cls"] + df["rdb0_common.num_long_irred_cls"] + divide("rdb0_common.tot_irred_cls", "rdb0_common.num_vars") + divide("rdb0_common.num_long_irred_cls", "rdb0_common.num_long_irred_cls_lits") + divide("rdb0_common.num_long_irred_cls_lits", "rdb0_common.num_vars") + divide("rdb0_common.num_long_irred_cls", "rdb0_common.num_vars") + + +def cldata_add_computed_features(df, verbose): + print("Adding computed features...") + cldata_add_minimum_computed_features(df, verbose) + + del df["cl.conflicts"] + del df["cl.restartID"] + del df["rdb0.introduced_at_conflict"] + + divide = functools.partial(helper_divide, df=df, features=list(df), verb=verbose) + larger_than = functools.partial(helper_larger_than, df=df, features=list(df), verb=verbose) + add = functools.partial(helper_add, df=df, features=list(df), verb=verbose) + + # ************ + # TODO decision level and branch depth are the same, right??? + # ************ + print("size/glue/trail rel...") + divide("cl.trail_depth_level", "cl.trailDepthHistLT_avg") + divide("cl.trail_depth_level", "cl.trailDepthHist_avg") + + divide("cl.num_total_lits_antecedents", "cl.num_antecedents") + + del df["rdb0.uip1_ranking"] + del df["rdb0.prop_ranking"] + del df["rdb0.act_ranking"] + del df["rdb0.sum_uip1_per_time_ranking"] + del df["rdb0.sum_props_per_time_ranking"] + del df["rdb0_common.tot_cls_in_db"] + + # divide by avg and median + divide("rdb0.uip1_used", "rdb0_common.avg_uip1_used") + divide("rdb0.props_made", "rdb0_common.avg_props") + divide("rdb0.glue", "rdb0_common.avg_glue") + + divide("rdb0.uip1_used", "rdb0_common.median_uip1_used") + divide("rdb0.props_made", "rdb0_common.median_props") + + time_in_solver = "cl.time_inside_solver" + sum_props_per_time = divide("rdb0.sum_props_made", time_in_solver) + sum_uip1_per_time = divide("rdb0.sum_uip1_used", time_in_solver) + divide(sum_props_per_time, "rdb0_common.median_sum_uip1_per_time") + divide(sum_uip1_per_time, "rdb0_common.median_sum_props_per_time") + divide(sum_props_per_time, "rdb0_common.avg_sum_uip1_per_time") + divide(sum_uip1_per_time, "rdb0_common.avg_sum_props_per_time") + #del df[time_in_solver] + + divisors = [ + "cl.conflSizeHistlt_avg" + , "cl.glueHistLT_avg" + , "rdb0.glue" + , "rdb0.size" + # , "cl.orig_connects_num_communities" + # , "rdb0.connects_num_communities" + , "cl.orig_glue" + , "cl.glue_before_minim" + , "cl.glueHist_avg" + , "cl.glueHist_longterm_avg" + # , "cl.decision_level_hist" + , "cl.numResolutionsHistLT_avg" + , "cl.trailDepthHistLT_avg" + , "cl.trailDepthHist_avg" + , "cl.branchDepthHistQueue_avg" + , "cl.overlapHistLT_avg" + , "(cl.num_total_lits_antecedents/cl.num_antecedents)" + , "cl.num_antecedents" + , "rdb0.act_ranking_rel" + , "rdb0.prop_ranking_rel" + , "rdb0.uip1_ranking_rel" + , "rdb0.sum_uip1_per_time_ranking_rel" + , "rdb0.sum_props_per_time_ranking_rel" + , "cl.time_inside_solver" + # , "cl.num_overlap_literals" + ] + + # discounted stuff + divide("rdb0.discounted_uip1_used", "rdb0_common.avg_uip1_used") + divide("rdb0.discounted_props_made", "rdb0_common.avg_props") + divide("rdb0.discounted_uip1_used", "rdb0_common.median_uip1_used") + divide("rdb0.discounted_props_made", "rdb0_common.median_props") + #== + divide("rdb0.discounted_uip1_used2", "rdb0_common.avg_uip1_used") + divide("rdb0.discounted_props_made2", "rdb0_common.avg_props") + divide("rdb0.discounted_uip1_used2", "rdb0_common.median_uip1_used") + divide("rdb0.discounted_props_made2", "rdb0_common.median_props") + + sum_uip1_per_time = divide("rdb0.sum_uip1_used", "cl.time_inside_solver") + sum_props_per_time = divide("rdb0.sum_props_made", "cl.time_inside_solver") + antec_rel = divide("cl.num_total_lits_antecedents", "cl.antec_data_sum_sizeHistLT_avg") + divisors.append(sum_uip1_per_time) + divisors.append(sum_props_per_time) + divisors.append("rdb0.discounted_uip1_used") + divisors.append("rdb0.discounted_props_made") + divisors.append(antec_rel) + + orig_cols = list(df) + + # Thanks to Chai Kian Ming Adam for the idea of using LOG instead of SQRT + # add LOG + if False: + toadd = [] + for divisor in divisors: + x = "log2("+divisor+")" + df[x] = df[divisor].apply(np.log2) + toadd.append(x) + divisors.extend(toadd) + + # relative data + cols = list(df) + for col in cols: + if ("rdb" in col or "cl." in col) and "restart_type" not in col and "tot_cls_in" not in col: + for divisor in divisors: + divide(divisor, col) + divide(col, divisor) + + # smaller/larger than + print("smaller-or-greater comparisons...") + if False: + for col in cols: + if "avg" in col or "median" in col: + for divisor in divisors: + larger_than(col, divisor) + + # smaller-or-greater comparisons + #if not short: + #larger_than("cl.antec_data_sum_sizeHistLT_avg", "cl.num_total_lits_antecedents") + #larger_than("cl.overlapHistLT_avg", "cl.num_overlap_literals") + + # print("flatten/list...") + #old = set(df.columns.values.flatten().tolist()) + #df = df.dropna(how="all") + #new = set(df.columns.values.flatten().tolist()) + #if len(old - new) > 0: + #print("ERROR: a NaN number turned up") + #print("columns: ", (old - new)) + #assert(False) + #exit(-1) + +def print_datatypes(df): + pd.set_option('display.max_rows', len(df.dtypes)) + print(df.dtypes) + pd.reset_option('display.max_rows') diff --git a/cryptominisat/cppsrc/scripts/crystal/learn-kissat.sh b/cryptominisat/cppsrc/scripts/crystal/learn-kissat.sh new file mode 100755 index 00000000..59e9929b --- /dev/null +++ b/cryptominisat/cppsrc/scripts/crystal/learn-kissat.sh @@ -0,0 +1,129 @@ +#!/bin/bash + +# Copyright (C) 2020 Mate Soos +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; version 2 +# of the License. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +# 02110-1301, USA. + +# This file wraps CMake invocation for TravisCI +# so we can set different configurations via environment variables. + +#set -x +set -e + +function generate() { + dirname="${basename}-cut1-${cut1}-cut2-${cut2}-limit-${limit}-est${est}-xbmin${xgboostminchild}-xbmd${xboostmaxdepth}-reg${regressor}-subs${xgboostsubsample}" + + mkdir -p ${dirname} + rm -f ${dirname}/out_* + rm -f ${dirname}/predictor*.json + rm -f dirname.tar.gz + git rev-parse HEAD > ${dirname}/out_git + cat learn.sh >> ${dirname}/out_git + md5sum *.dat >> ${dirname}/out_git + + tiers=("short" "long" "forever") + tables=("used_later" "used_later_anc") + for tier in "${tiers[@]}"; do + mypids=() + for table in "${tables[@]}"; do + # check if DAT file exists + INFILE="comb-${table}-${tier}-cut1-${cut1}-cut2-${cut2}-limit-${limit}.dat" + if test -f "$INFILE"; then + echo "$INFILE exists, OK" + else + echo "ERROR: $INFILE does not exist!!" + exit -1 + fi + + /usr/bin/time --verbose -o "${dirname}/out_${tier}.timeout" \ + ../cldata_predict.py \ + $INFILE \ + --tier ${tier} --regressor $regressor \ + --xgboostest ${est} \ + --xgboostminchild $xgboostminchild --xboostmaxdepth=${xboostmaxdepth} \ + --basedir "${dirname}" \ + --features "best_only" \ + --table ${table} \ + --xgboostsubsample "$xgboostsubsample" \ + --bestfeatfile ${bestf} 2>&1 | tee "${dirname}/out-${table}-${tier}" & + pid=$! + echo "PID here is $pid" + mypids+=("$pid") + done + + # wait for PIDs now + echo "PIDS to wait for are: ${mypids[*]}" + for pid2 in "${mypids[@]}" + do + echo "Waiting for $pid2 ..." + wait $pid2 + done + done + + tar czvf ${dirname}.tar.gz ${dirname} +} + + +# best was: 8march-2020-3acd81dc55df3-cut1-5.0-cut2-30.0-limit-2000-est10-w0-xbmin300-xbmd4 + +#xboostmaxdepth=4 +#xboostminchild=300 +#est=10 + +# bestf="../../scripts/crystal/best_features-correlation2.txt" +bestf="../../scripts/crystal/best_features-kissat.txt" + +w=0 +xgboostsubsample="1.0" +#basename="15-dec-b1bd8f74bc2b42" +basename="15-dec-b1bd8f74bc2b42-kissat-2" +#basename="14-april-2021-69bad529f962c" +#basename="8march-2020-3acd81dc55df3-36feats" +#basename="aes-30-march-2020-a1e0e19be0c1" +#basename="orig" +limit=1000 +cut1="3.0" +cut2="25.0" +xboostmaxdepth=4 +xgboostminchild=300 +est=10 + +for xgboostsubsample in 1.0 +do +for limit in 10000 #1000 +do + for regressor in "xgb" #"lgbm" + do + for xboostmaxdepth in 4 #6 #8 10 12 + do + for xgboostminchild in 10 #300 + do + for est in 10 + do + generate + done + done + done + done +done +done + +exit 0 + + +# simple run: + +# ./cryptominisat5 goldb-heqc-i10mul.cnf --simdrat 1 --printsol 0 --predloc ./data/15-dec-b1bd8f74bc2b42-cut1-3.0-cut2-25.0-limit-10000-est10-xbmin10-xbmd4-regxgb-subs1.0/ --predtype py --predbestfeats ../scripts/crystal/best_features-correlation2.txt --predtables 000 diff --git a/cryptominisat/cppsrc/scripts/crystal/learn.sh b/cryptominisat/cppsrc/scripts/crystal/learn.sh new file mode 100755 index 00000000..4dabd490 --- /dev/null +++ b/cryptominisat/cppsrc/scripts/crystal/learn.sh @@ -0,0 +1,126 @@ +#!/bin/bash + +# Copyright (C) 2020 Mate Soos +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; version 2 +# of the License. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +# 02110-1301, USA. + +# This file wraps CMake invocation for TravisCI +# so we can set different configurations via environment variables. + +#set -x +set -e + +function generate() { + dirname="${basename}-cut1-${cut1}-cut2-${cut2}-limit-${limit}-est${est}-xbmin${xgboostminchild}-xbmd${xboostmaxdepth}-reg${regressor}-subs${xgboostsubsample}" + + mkdir -p ${dirname} + rm -f ${dirname}/out_* + rm -f ${dirname}/predictor*.json + rm -f dirname.tar.gz + git rev-parse HEAD > ${dirname}/out_git + cat learn.sh >> ${dirname}/out_git + md5sum *.dat >> ${dirname}/out_git + + tiers=("short" "long" "forever") + tables=("used_later" "used_later_anc") + for tier in "${tiers[@]}"; do + mypids=() + for table in "${tables[@]}"; do + # check if DAT file exists + INFILE="comb-${table}-${tier}-cut1-${cut1}-cut2-${cut2}-limit-${limit}.dat" + if test -f "$INFILE"; then + echo "$INFILE exists, OK" + else + echo "ERROR: $INFILE does not exist!!" + exit -1 + fi + + /usr/bin/time --verbose -o "${dirname}/out_${tier}.timeout" \ + ../cldata_predict.py \ + $INFILE \ + --tier ${tier} --regressor $regressor \ + --xgboostest ${est} \ + --xgboostminchild $xgboostminchild --xboostmaxdepth=${xboostmaxdepth} \ + --basedir "${dirname}" \ + --features "best_only" \ + --table ${table} \ + --xgboostsubsample "$xgboostsubsample" \ + --bestfeatfile ${bestf} 2>&1 | tee "${dirname}/out-${table}-${tier}" & + pid=$! + echo "PID here is $pid" + mypids+=("$pid") + done + + # wait for PIDs now + echo "PIDS to wait for are: ${mypids[*]}" + for pid2 in "${mypids[@]}" + do + echo "Waiting for $pid2 ..." + wait $pid2 + done + done + + tar czvf ${dirname}.tar.gz ${dirname} +} + + +# best was: 8march-2020-3acd81dc55df3-cut1-5.0-cut2-30.0-limit-2000-est10-w0-xbmin300-xbmd4 + +#xboostmaxdepth=4 +#xboostminchild=300 +#est=10 + +bestf="../../scripts/crystal/best_features-correlation2.txt" +w=0 +xgboostsubsample="1.0" +basename="15-dec-b1bd8f74bc2b42" +#basename="14-april-2021-69bad529f962c" +#basename="8march-2020-3acd81dc55df3-36feats" +#basename="aes-30-march-2020-a1e0e19be0c1" +#basename="orig" +limit=1000 +cut1="3.0" +cut2="25.0" +xboostmaxdepth=4 +xgboostminchild=300 +est=10 + +for xgboostsubsample in 1.0 +do +for limit in 10000 #1000 +do + for regressor in "xgb" #"lgbm" + do + for xboostmaxdepth in 4 6 #8 10 12 + do + for xgboostminchild in 10 #300 + do + for est in 10 + do + generate + done + done + done + done +done +done + +exit 0 + + +# simple run: + +# ./cryptominisat5 goldb-heqc-i10mul.cnf --simdrat 1 --printsol 0 --predloc ./data/15-dec-b1bd8f74bc2b42-cut1-3.0-cut2-25.0-limit-10000-est10-xbmin10-xbmd4-regxgb-subs1.0/ --predtype py --predbestfeats ../scripts/crystal/best_features-correlation2.txt --predtables 000 diff --git a/cryptominisat/cppsrc/scripts/crystal/ml_module.py b/cryptominisat/cppsrc/scripts/crystal/ml_module.py new file mode 100644 index 00000000..38584516 --- /dev/null +++ b/cryptominisat/cppsrc/scripts/crystal/ml_module.py @@ -0,0 +1,234 @@ +#!/usr/bin/python3 +# -*- coding: utf-8 -*- + +# Copyright (C) 2009-2020 Authors of CryptoMiniSat, see AUTHORS file +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; version 2 +# of the License. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +# 02110-1301, USA. + + +import numpy as np +import pandas as pd +import xgboost as xgb +import os +from ccg import * + +# to test memory safety +#import gc +# to test memory usage +#from memory_profiler import * + +MISSING=np.NaN + +raw_data = [ + "is_ternary_resolvent", + "rdb0.which_red_array", + "rdb0.last_touched", + "rdb0.act_ranking_rel", + "rdb0.uip1_ranking_rel", + "rdb0.prop_ranking_rel", + "rdb0.last_touched_diff", + "cl.time_inside_solver", + "rdb0.props_made", + "rdb0_common.avg_props", + #"rdb0_common.avg_glue", CANNOT DO, ternaries have no glue! + "rdb0_common.avg_uip1_used", + "rdb0_common.conflSizeHistLT_avg", + "rdb0_common.glueHistLT_avg", + "rdb0.sum_props_made", + "rdb0.discounted_props_made", + "rdb0.discounted_props_made2", + "rdb0.discounted_props_made3", + "rdb0.discounted_uip1_used", + "rdb0.discounted_uip1_used2", + "rdb0.discounted_uip1_used3", + "rdb0.sum_uip1_used", + "rdb0.uip1_used", + "rdb0.size", + "rdb0.sum_uip1_per_time_ranking", + "rdb0.sum_props_per_time_ranking", + "rdb0.sum_uip1_per_time_ranking_rel", + "rdb0.sum_props_per_time_ranking_rel", + "rdb0.is_distilled", + "cl.glueHist_avg", + "cl.atedecents_binIrred", + "cl.glueHistLT_avg", + "cl.glueHist_longterm_avg", + "cl.num_antecedents", + "cl.overlapHistLT_avg", + "cl.conflSizeHist_avg", + "cl.atedecents_binRed", + "cl.num_total_lits_antecedents", + "cl.numResolutionsHistLT_avg", + "rdb0.glue", + "cl.orig_glue", + "cl.glue_before_minim", + "cl.trail_depth_level", + #"sum_uip1_per_time_ranking_rel", + #"sum_props_per_time_ranking_rel", +] + +# check reproducibility by dumping and checking against previous run's dump +def dump_or_check(fname, df): + if check_file_exists(fname): + df_saved = pd.read_pickle(fname) + print("Checking equals...", fname) + if not df.equals(df_saved): + print("df.shape :", df.shape) + print("df_saved.shape :", df_saved.shape) + assert df.shape == df_saved.shape + for i in range(df): + if df[i] != df_saved[i]: + print("Not equal:") + print(df[i]) + print(df_saved[i]) + exit(-1) + + else: + df.to_pickle(fname) + print("Not checking, writing: ", fname) + + +def check_file_exists(fname): + return os.path.exists(fname) + +def get_features(fname): + best_features = [] + if not check_file_exists(fname): + print("File '%s' not accessible" % fname) + exit(-1) + + with open(fname, "r") as f: + for l in f: + l = l.strip() + if len(l) == 0: + continue + + if l[0] == "#": + continue + + best_features.append(l) + + return best_features + + +def check_against_binary_dat(fname, df, df_raw): + global best_features + check_file_exists(fname) + df2 = pd.read_csv(fname, sep=",", names=best_features) + print("Checking binary vs python:", fname) + + for f in best_features: + for i in range(df.shape[0]): + s_pyt = float(df[f][i]) + s_bin = float(df2[f][i]) + if np.isnan(s_pyt) and np.isnan(s_bin): + continue + if np.isnan(s_pyt) and not np.isnan(s_bin): + assert False + if not np.isnan(s_pyt) and np.isnan(s_bin): + assert False + diff = abs(s_pyt - s_bin) + + if diff > 10e-5: + for f_raw in list(df_raw): + print("pyt_raw:", df_raw[f_raw][i], " feat: ", f_raw) + print("pyt:", s_pyt, " feat: ", f) + print("bin:", s_bin, " feat: ", f) + print("diff for feat ", f, ": ", diff) + else: + #print("OK for feat", f) + pass + assert diff < 10e-5 + + #assert df.equals(df2) + + +models = [] +best_features = [] +feat_gen_exprs = [] +feat_gen_funcs = [] + +def add_features(df, df2): + for i, feat_gen_func in zip(range(len(best_features)), feat_gen_funcs): + df2[:, i] = feat_gen_func(df) + +def set_up_features(features_fname): + global best_features + global feat_gen_exprs + global feat_gen_funcs + best_features = get_features(features_fname) + for i, feat in zip(range(len(best_features)), best_features): + feat_gen_expr = ccg.to_source(ast.parse(feat)) + feat_gen_exprs.append(feat_gen_expr) + create_function = "def a%d(df): return %s" % (i, feat_gen_expr) + exec(create_function) + exec("feat_gen_funcs.append(a%d)" % i) + #print(feat_gen_funcs) + + +def load_models(short_fname, long_fname, forever_fname): + global models + for fname in [short_fname, long_fname, forever_fname]: + clf_xgboost = xgb.XGBRegressor(n_jobs=1) + new_fname = fname.replace("-py.", "-xgb.") + if not os.path.exists(new_fname): + new_fname = fname.replace("-py.", ".") + clf_xgboost.load_model(new_fname) + models.append(clf_xgboost) + + +num_called = 0 + +# to test memory usage +#@profile +def predict(data, check=False, dump=False): + global num_called + ret = [] + + df = pd.DataFrame(data, columns=raw_data) + transformed_data = np.empty((df.shape[0], len(best_features)), dtype=float) + if check: + dump_or_check('df_check'+str(num_called), df) + + add_features(df, transformed_data) + df_final = pd.DataFrame(transformed_data, columns=best_features) + df_final.replace([np.inf, np.NaN, np.inf, np.NINF, np.Infinity], MISSING, inplace=True) + + if check: + check_against_binary_dat('bin_dump'+str(num_called)+".csv", df_final, df) + + for i in range(3): + #x = models[i].predict(df_final) + x = models[i].get_booster().inplace_predict(df_final) + if check: + dump_or_check('x-%d-%d' % (num_called, i), pd.DataFrame(x)) + ret.append(x) + + if dump: + for i,name in zip(range(3), ["short", "long", "forever"]): + df["x.used_later_%s" % name] = ret[i] + + df.to_pickle('df_dump_%s' % num_called) + + if check: + dump_or_check('df_pred'+str(num_called), df_final) + + num_called += 1 + del df + del df_final + del transformed_data + # gc.collect() # to test memory safety + return ret diff --git a/cryptominisat/cppsrc/scripts/crystal/perc_sql_fixer.py b/cryptominisat/cppsrc/scripts/crystal/perc_sql_fixer.py new file mode 100755 index 00000000..19910c13 --- /dev/null +++ b/cryptominisat/cppsrc/scripts/crystal/perc_sql_fixer.py @@ -0,0 +1,160 @@ +#!/usr/bin/env python3 +# -*- coding: utf-8 -*- + +# Copyright (C) 2017 Mate Soos +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; version 2 +# of the License. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +# 02110-1301, USA. + + +import helper +import optparse +import time + +class QueryFixPerc (helper.QueryHelper): + def __init__(self, dbfname): + super(QueryFixPerc, self).__init__(dbfname) + + def check_table_exists(self): + q = "SELECT name FROM sqlite_master WHERE type='table' AND name='{table_name}';".format( + table_name="used_later_percentiles_backup") + self.c.execute(q) + rows = self.c.fetchall() + if len(rows) == 1: + print("Already fixed") + return True + + return False + + def copy_db(self): + # Drop table + q_drop = """ + DROP TABLE IF EXISTS `used_later_percentiles_backup`; + """ + self.c.execute(q_drop) + + # Create and fill used_later_X tables + q_create = """ + CREATE TABLE used_later_percentiles_backup AS + SELECT * + FROM used_later_percentiles;""" + self.c.execute(q_create) + + def create_percentiles_table(self): + # Drop table + q_drop = """ + DROP TABLE IF EXISTS `used_later_percentiles`; + """ + self.c.execute(q_drop) + + # Create and fill used_later_X tables + q_create = """ + create table `used_later_percentiles` ( + `type_of_dat` string NOT NULL, + `percentile_descr` string NOT NULL, + `percentile` float DEFAULT NULL, + `val` float NOT NULL + );""" + self.c.execute(q_create) + + idxs = """ + create index `used_later_percentiles_idx3` on `used_later_percentiles` (`type_of_dat`, `percentile_descr`, `percentile`, `val`); + create index `used_later_percentiles_idx2` on `used_later_percentiles` (`type_of_dat`, `percentile_descr`, `val`);""" + for q in idxs.split("\n"): + self.c.execute(q) + + def fix(self): + q2 = """ + insert into used_later_percentiles (type_of_dat, percentile_descr, percentile, val) + {q} + """ + + t = time.time() + q = "select * from used_later_percentiles_backup" + self.c.execute(q) + rows = self.c.fetchall() + fixed = 0 + for i in range(len(rows)): + if options.verbose: + print("row: ", rows[i]) + row = rows[i] + a = row[0][1:] + c = None + if row[1][:13] == "top_also_zero": + b = "top_also_zero" + c = row[1][13:] + elif row[1][:12] == "top_non_zero": + b = "top_non_zero" + c = row[1][12:] + elif row[1] == "avg": + b = "avg" + c = None + else: + print("c ? ", row[1]) + assert False, "What?" + + if c is not None: + c = float(c.rstrip("_perc").strip("_")) + else: + c = "NULL" + d = row[2] + + if a == "": + # this was removed + continue + + if options.verbose: + print("a: ", a) + print("b: ", b) + print("c: ", c) + print("d: ", d) + self.c.execute(q2.format(q="select '{a}', '{b}', {c}, {d};".format( + a=a, b=b, c=c, d=d))) + fixed+=1 + + print("Fixed:", fixed) + + # fix 100 + for name in ["short", "long", "forever"]: + self.c.execute(q2.format(name=name, q="select '{name}', 'top_non_zero', 100.0, 0.0;".format(name=name))) + self.c.execute(q2.format(name=name, q="select '{name}', 'top_also_zero', 100.0, 0.0;".format(name=name))) + + print("Fixed top 100 too") + +if __name__ == "__main__": + usage = "usage: %prog [options] file1.sqlite [file2.sqlite ...]" + parser = optparse.OptionParser(usage=usage) + + # verbosity level + parser.add_option("--verbose", "-v", action="store_true", default=False, + dest="verbose", help="Print more output") + parser.add_option("--sql", action="store_true", default=False, + dest="dump_sql", help="Dump SQL queries") + + (options, args) = parser.parse_args() + + if len(args) < 1: + print("ERROR: You must give at least one file") + exit(-1) + + + for f in args: + print("Doing file:" , f) + with QueryFixPerc(f) as q: + if q.check_table_exists(): + continue + q.copy_db() + q.create_percentiles_table() + q.fix() diff --git a/cryptominisat/cppsrc/scripts/crystal/process_all_dats.sh b/cryptominisat/cppsrc/scripts/crystal/process_all_dats.sh new file mode 100755 index 00000000..80abfed7 --- /dev/null +++ b/cryptominisat/cppsrc/scripts/crystal/process_all_dats.sh @@ -0,0 +1,111 @@ +#!/bin/bash + +# Copyright (C) 2020 Mate Soos +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; version 2 +# of the License. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +# 02110-1301, USA. + +# This file wraps CMake invocation for TravisCI +# so we can set different configurations via environment variables. + +set -e +set -x + +numconfs=1 + +function wait_threads { + FAIL=0 + for job in $(jobs -p) + do + echo "waiting for job '$job' ..." + wait "${job}" || FAIL=$((FAIL+=1)) + done +} + +function check_fails { + if [ "$FAIL" == "0" ]; + then + echo "All went well!" + else + echo "FAIL of one of the threads! ($FAIL)" + exit 255 + fi +} + +function check_error { + # exit in case of errors + if [[ -s error ]]; then + echo "ERROR: Issues occurred!" + exit 255 + else + echo "OK, no errors" + fi +} + +function populate_error { + rm -f error + touch error + for (( CONF = 0; CONF < numconfs; CONF++)) + do + grep -E --color -i -e "assert.*fail" -e "signal" -e "error" -e "kill" -e "terminate" "${1}_${CONF}" 2>&1 | tee -a error + grep -E --color -i -e "assert.*fail" -e "signal" -e "error" -e "kill" -e "terminate" "${2}_${CONF}" 2>&1 | tee -a error + done +} + +function combine { + rm -f out_combine_short_* + rm -f comb-short-conf-*.dat + rm -f out_combine_long_* + rm -f comb-long-conf-*.dat + for (( CONF = 0; CONF < numconfs; CONF++)) + do + rm -f "comb-short-conf-${CONF}.dat" + rm -f "comb-long-conf-${CONF}.dat" + + ./combine_dats.py -o "comb-short-conf-${CONF}.dat" $1/*-short-conf-${CONF}.dat > "out${2}_combine_short_${CONF}" 2>&1 & + ./combine_dats.py -o "comb-long-conf-${CONF}.dat" $1/*-long-conf-${CONF}.dat > "out${2}_combine_long_${CONF}" 2>&1 & + + wait_threads + check_fails + done + + populate_error "out_combine_short" "out_combine_long" + check_error +} + +function predict { + mkdir -p ../src/predict + rm -f ../src/predict/*.h + rm -f out_pred_short_* + rm -f out_pred_long_* + for (( CONF = 0; CONF < numconfs; CONF++)) + do + ./predict.py "comb-long-conf-${CONF}.dat" --scale --name long --basedir "../src/predict/" --final --forest --clusters 1 --split 0.005 --conf "${CONF}" --clustmin 0.10 --mindump 19 --prefok 1 > "out_pred_long_${CONF}" 2>&1 & + ./predict.py "comb-short-conf-${CONF}.dat" --scale --name short --basedir "../src/predict/" --final --forest --clusters 1 --split 0.005 --conf "${CONF}" --clustmin 0.10 --mindump 19 --prefok 1 > "out_pred_short_${CONF}" 2>&1 & + wait_threads + check_fails + done + + populate_error "out_pred_long" "out_pred_short" + check_error +} + +################ +# running +################ + +combine out-dats-8145576.wlm01 noclean +combine out-dats-8160767.wlm01 normal +predict diff --git a/cryptominisat/cppsrc/scripts/crystal/sample_data.py b/cryptominisat/cppsrc/scripts/crystal/sample_data.py new file mode 100755 index 00000000..e1c455a2 --- /dev/null +++ b/cryptominisat/cppsrc/scripts/crystal/sample_data.py @@ -0,0 +1,718 @@ +#!/usr/bin/env python3 +# -*- coding: utf-8 -*- + +# Copyright (C) 2009-2020 Authors of CryptoMiniSat, see AUTHORS file +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; version 2 +# of the License. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +# 02110-1301, USA. + +from __future__ import print_function +import sqlite3 +import optparse +import time +import os.path +import helper + + +class QueryDatRem(helper.QueryHelper): + def __init__(self, dbfname): + super(QueryDatRem, self).__init__(dbfname) + + def create_percentiles_table(self): + for table in ["used_later", "used_later_anc"]: + # drop table + q_drop = """ + DROP TABLE IF EXISTS `{table}_percentiles`; + """ + self.c.execute(q_drop.format(table=table)) + + # Create percentiles table + q_create = """ + create table `{table}_percentiles` ( + `type_of_dat` string NOT NULL, + `percentile_descr` string NOT NULL, + `percentile` float DEFAULT NULL, + `val` float NOT NULL + );""" + self.c.execute(q_create.format(table=table)) + + idxs = """ + create index `{table}_percentiles_idx3` on `{table}_percentiles` (`type_of_dat`, `percentile_descr`, `percentile`, `val`); + create index `{table}_percentiles_idx2` on `{table}_percentiles` (`type_of_dat`, `percentile_descr`, `val`);""" + for q in idxs.split("\n"): + self.c.execute(q.format(table=table)) + + + # "tier" here is "short", "long", or "forever" + def get_all_percentile_X(self, tier): + t = time.time() + for table in ["used_later", "used_later_anc"]: + print("Calculating percentiles now for table {table} and tier {tier} ...".format( + tier=tier, table=table)) + + q2 = """ + insert into {table}_percentiles (type_of_dat, percentile_descr, percentile, val) + {q} + """ + + q = "select '{tier}', 'avg', NULL, avg(used_later) from {table}_{tier};".format( + tier=tier, table=table) + self.c.execute(q2.format(tier=tier, table=table, q=q)) + + q = """ + SELECT + '{tier}', 'top_non_zero', {perc}, used_later + FROM {table}_{tier} + WHERE used_later>0 + ORDER BY used_later ASC + LIMIT 1 + OFFSET round((SELECT + COUNT(*) + FROM {table}_{tier} + WHERE used_later>0) * ((100-{perc}) / 100.0)) - 1; + """ + for perc in list(range(0,30,1))+list(range(30,100, 5)): + myq = q.format(tier=tier, table=table, perc=perc) + self.c.execute(q2.format(tier=tier, table=table, q=myq)) + # the 100% perecentile is not 0 (remember, this is "non-zero"), but let's cheat and add it in + self.c.execute(q2.format( + tier=tier, table=table, q="select '{tier}', 'top_non_zero', 100.0, 0.0;".format( + tier=tier, table=table))) + + q = """ + SELECT + '{tier}', 'top_also_zero', {perc}, used_later + FROM {table}_{tier} + ORDER BY used_later ASC + LIMIT 1 + OFFSET round((SELECT + COUNT(*) + FROM {table}_{tier}) * ((100.0-{perc}) / 100.0)) - 1; + """ + for perc in range(0,100, 10): + myq = q.format(tier=tier, table=table, perc=perc) + self.c.execute(q2.format(tier=tier, table=table, q=myq)) + self.c.execute( + q2.format(tier=tier, table=table, + q="select '{tier}', 'top_also_zero', 100.0, 0.0;".format(tier=tier, table=table))) + + print("Calculated percentiles/averages, T:", time.time()-t) + + def print_percentiles(self): + q_check = "select * from used_later_percentiles" + cur = self.conn.cursor() + cur.execute(q_check) + rows = cur.fetchall() + print("Percentiles/average for used_later_percentiles:") + for row in rows: + print(" -> %s %s -- %s : %s" %(row[0], row[1], row[2], row[3])) + + + def create_indexes1(self): + print("Recreating indexes...") + t = time.time() + queries = """ + create index `idxclid31` on `clause_stats` (`clauseID`); + create index `idxclid32` on `reduceDB` (`clauseID`); + create index `idxclid33` on `sum_cl_use` (`clauseID`); + create index `idxclid34` on `used_clauses` (`clauseID`); + create index `idxclid44` on `restart_dat_for_cl` (`clauseID`); + create index `idxclid35` on `var_data_fintime` (`var`, `sumConflicts_at_picktime`); + create index `idxclid36` on `var_data_picktime` (`var`, `sumConflicts_at_picktime`); + create index `idxclid37` on `dec_var_clid` (`var`, `sumConflicts_at_picktime`); + create index `idxclid40` on `restart_dat_for_var` (`conflicts`); + """ + + for q in queries.split("\n"): + self.c.execute(q) + + print("Created indexes needed T: %-3.2f s"% (time.time() - t)) + + def recreate_used_ID_table(self): + q = """ + DROP TABLE IF EXISTS `used_cl_ids`; + """ + self.c.execute(q) + + q = """ + CREATE TABLE `used_cl_ids` ( + `clauseID` int(20) NOT NULL + ); + """ + self.c.execute(q) + + q = """ + create index `idxclid30` on `used_cl_ids` (`clauseID`); + """ + self.c.execute(q) + + def remove_too_many_vardata(self): + t = time.time() + q = """ + select count() + from var_data_picktime + """ + ret = self.c.execute(q) + rows = self.c.fetchall() + assert len(rows) == 1 + num_vardata = rows[0][0] + print("Current number of elements in var_data: %d" % num_vardata) + + if num_vardata < options.goal_vardata: + print("Not too many in var_data, skipping removal.") + return + + q = """ + DROP TABLE IF EXISTS `used_vardat`; + """ + self.c.execute(q) + + q = """ + CREATE TABLE `used_vardat` ( + `var` bigint(20) NOT NULL + , `sumConflicts_at_picktime` bigint(20) NOT NULL + ); + """ + self.c.execute(q) + + q = """ + create index `idxclidxx` on `used_vardat` + (`var`, `sumConflicts_at_picktime`); + """ + self.c.execute(q) + + q = """ + insert into `used_vardat` + SELECT + var, sumConflicts_at_picktime + FROM var_data_picktime + order by random() + limit {limit} + """.format(limit=options.goal_vardata) + self.c.execute(q) + print("Added {limit} to `used_vardat`".format(limit=options.goal_vardata)) + print("--> T: %-3.2f s"% (time.time() - t)) + + t = time.time() + del_from = ["var_data_picktime", "var_data_fintime", "dec_var_clid"] + for table in del_from: + + q = """ + DROP TABLE IF EXISTS `myrows`; + """ + self.c.execute(q) + + q = """ + CREATE TABLE `myrows` ( + `myrowid` bigint(20) NOT NULL + ); + """ + self.c.execute(q) + + q = """ + INSERT INTO `myrows` + SELECT `rowid` + FROM `{table}` WHERE (`var`, `sumConflicts_at_picktime`) + in (SELECT `var`, `sumConflicts_at_picktime` from `used_vardat`); + """ + self.c.execute(q.format(table=table)) + + q = """ + create index `myidx111` on `myrows` (`myrowid`); + """ + + q = """ + DELETE FROM `{table}` WHERE (rowid) NOT IN + (SELECT `myrowid` from `myrows` );""" + self.c.execute(q.format(table=table)) + print("Deleted unused data from %s" % table) + + # cleanup + q = """ + DROP TABLE IF EXISTS `myrows`; + """ + self.c.execute(q) + + # sample restart_dat_for_var + q = """ + DELETE FROM restart_dat_for_var WHERE `conflicts` NOT IN + (SELECT `sumConflicts_at_picktime` from `used_vardat` group by sumConflicts_at_picktime);""" + self.c.execute(q) + print("Deleted unused data from restart_dat_for_var") + + # cleanup + q = """ + DROP TABLE IF EXISTS `used_vardat`; + """ + self.c.execute(q) + print("Cleaned up var_data_x & restart_dat_for_var tables T: %-3.2f s" + % (time.time() - t)) + + def insert_into_used_cls_ids_from_clstats(self, min_used, limit, table): + min_used = int(min_used) + + t = time.time() + val = int() + q = """ + insert into used_cl_ids + select + clauseID from {table} + where + num_used >= {min_used} + order by random() limit {limit} + """.format( + min_used=min_used, + limit=int(limit), + table=table) + + self.c.execute(q) + print("Added num_used >= %d from sum_cl_use to used_cls_ids T: %-3.2f s" + % (min_used, time.time() - t)) + + # inserts ratio that's slanted towards >=1 use + def fill_used_cl_ids_table(self, fair, limit): + t = time.time() + for table in ["sum_cl_use"]: + if not fair: + self.insert_into_used_cls_ids_from_clstats(min_used=100000, limit=limit/20, table=table) + self.insert_into_used_cls_ids_from_clstats(min_used=50000, limit=limit/10, table=table) + self.insert_into_used_cls_ids_from_clstats(min_used=10000, limit=limit/10, table=table) + self.insert_into_used_cls_ids_from_clstats(min_used=1000, limit=limit/10, table=table) + self.insert_into_used_cls_ids_from_clstats(min_used=100, limit=limit/10, table=table) + self.insert_into_used_cls_ids_from_clstats(min_used=30, limit=limit/5, table=table) + self.insert_into_used_cls_ids_from_clstats(min_used=20, limit=limit/4, table=table) + self.insert_into_used_cls_ids_from_clstats(min_used=5, limit=limit/3, table=table) + self.insert_into_used_cls_ids_from_clstats(min_used=1, limit=limit/2, table=table) + self.insert_into_used_cls_ids_from_clstats(min_used=0, limit=limit/2, table=table) + + q = """ + select count() + from used_cl_ids, sum_cl_use + where + used_cl_ids.clauseID = sum_cl_use.clauseID + and sum_cl_use.num_used > 0 + """ + ret = self.c.execute(q) + rows = self.c.fetchall() + assert len(rows) == 1 + good_ids = rows[0][0] + + q = """ + select count() + from used_cl_ids, sum_cl_use + where + used_cl_ids.clauseID = sum_cl_use.clauseID + and sum_cl_use.num_used = 0 + """ + ret = self.c.execute(q) + rows = self.c.fetchall() + assert len(rows) == 1 + bad_ids = rows[0][0] + + print("IDs in used_cl_ids that are 'good' (sum_cl_use.num_used > 0) : %d" % good_ids) + print("IDs in used_cl_ids that are 'bad' (sum_cl_use.num_used = 0) : %d" % bad_ids) + print(" T: %-3.2f s" % (time.time() - t)) + + def print_idxs(self): + + q = """ + SELECT * FROM sqlite_master WHERE type == 'index' + """ + self.c.execute(q) + rows = self.c.fetchall() + queries = "" + + if options.verbose: + print("Using indexes: ") + for row in rows: + print("-> index:", row) + + def create_used_clauses_red(self): + t = time.time() + q = """ + CREATE TABLE used_clauses_red AS + SELECT * FROM used_clauses WHERE clauseID IN (SELECT clauseID from used_cl_ids ); + """ + + self.c.execute(q) + print("Filtered into used_clauses_red T: %-3.2f s" % (time.time() - t)) + + def drop_used_clauses_red(self): + q = """ + drop TABLE if exists used_clauses_red; + """ + self.c.execute(q) + + def filter_tables_of_ids(self): + + queries = """ + drop index if exists idxclid34; + drop index if exists idxclid32; + """ + for q in queries.split("\n"): + self.c.execute(q) + + self.print_idxs() + + tables = ["clause_stats", "reduceDB", "sum_cl_use", "used_clauses_anc", + "used_clauses", "restart_dat_for_cl", "cl_last_in_solver"] + q = """ + DELETE FROM {table} WHERE clauseID NOT IN + (SELECT clauseID from used_cl_ids );""" + + for table in tables: + t = time.time() + self.c.execute(q.format(table=table)) + print("Filtered table '%s' T: %-3.2f s" % (table, time.time() - t)) + + def print_sum_cl_use_distrib(self): + q = """ + select c, num_used from ( + select count(*) as c, num_used + from sum_cl_use + group by num_used) order by num_used + """ + self.c.execute(q) + rows = self.c.fetchall() + print("Distribution of clause uses:") + total = 0 + zero_use = 0 + for i in range(len(rows)): + cnt = int(rows[i][0]) + numuse = int(rows[i][1]) + if numuse == 0: + zero_use = cnt + total += cnt + + i = 0 + while i < len(rows): + cnt = int(rows[i][0]) + numuse = int(rows[i][1]) + + this_cnt_tot = 0 + this_numuse_tot = 0 + for x in range(100000): + if i+x >= len(rows): + i+=x + break + + this_cnt = int(rows[i+x][0]) + this_numuse = int(rows[i+x][1]) + this_cnt_tot += this_cnt + this_numuse_tot += this_numuse + if this_cnt_tot > 300: + i+=x + i+=1 + break + print(" -> {cnt:-8d} of sum_cl_use: {numuse:-7d}-{this_numuse:-7d} -- {percent:-3.5f} ratio".format( + cnt=this_cnt_tot, numuse=numuse, this_numuse=this_numuse, percent=(this_cnt_tot/total))) + + + print("Total: %d of which zero_use: %d" % (total, zero_use)) + # grain-53-80-0s0-seed-125-4-init-35.cnf.out actually has only 0.0098 use (i.e. 0.98%) + if zero_use == 0 or zero_use/total < 0.009: + print("ERROR: Zero use is very low, this is almost surely a bug!") + exit(-1) + + def check_db_sanity(self): + print("Checking tables in DB...") + q = """ + SELECT name FROM sqlite_master WHERE type == 'table' + """ + found_sum_cl_use = False + self.c.execute(q) + rows = self.c.fetchall() + for row in rows: + if row[0] == "sum_cl_use": + found_sum_cl_use = True + + print("-> We have table: ", row[0]) + if row[0] == "used_later_short" or row[0] == "used_later_long": + print("ERROR: 'gen_pandas.py' has been already ran on this DB") + print(" this will be a mess. We cannot run. ") + print(" Exiting.") + exit(-1) + + if not found_sum_cl_use: + print("ERROR: Did not find sum_cl_use table. You probably didn't run") + print(" the 'clean_update_data.py' on this database") + print(" Exiting.") + exit(-1) + + q = """ + SELECT count() FROM sum_cl_use where num_used = 0 + """ + self.c.execute(q) + rows = self.c.fetchall() + assert len(rows) == 1 + num = int(rows[0][0]) + print("Unused clauses in sum_cl_use: ", num) + if num == 0: + print("ERROR: You most likely didn't run 'clean_data.py' on this database") + print(" Exiting.") + exit(-1) + + print("Tables seem OK") + + def insert_into_only_keep_rdb(self, min_used_later, limit, tier, table): + limit = int(limit) + t = time.time() + q = """ + insert into only_keep_rdb (id) + select + rdb0.rowid + + FROM + reduceDB as rdb0, + {table}_{tier} + + WHERE + {table}_{tier}.clauseID=rdb0.clauseID + and {table}_{tier}.rdb0conflicts=rdb0.conflicts + and {table}_{tier}.used_later >= {min_used_later} + order by random() + limit {limit}""".format(min_used_later=min_used_later, limit=limit, + tier=tier, table=table) + self.c.execute(q) + + ret = self.c.execute("""select count() from only_keep_rdb""") + rows = self.c.fetchall() + rdb_rows = rows[0][0] + + print("Insert only_keep_rdb where %s_%s >= %d T: %-3.2f s. Now size: %s" % + (table, tier, min_used_later, time.time() - t, rdb_rows)) + + def delete_too_many_rdb_rows(self): + t = time.time() + val = int(options.limit) + ret = self.c.execute("select count() from reduceDB") + rows = self.c.fetchall() + rdb_rows = rows[0][0] + print("Have %d lines of RDB, let's do non-fair selection" % (rdb_rows)) + + q = """ + drop table if exists only_keep_rdb; + """ + self.c.execute(q) + + t = time.time() + q = """create table only_keep_rdb ( + id bigint(20) not null + );""" + self.c.execute(q) + print("Created only_keep_rdb T: %-3.2f s" % (time.time() - t)) + + mygoal = options.goal_rdb/13 + table="used_later" # we could iterate with "used_later_anc", but not doing that + for tier in ["short", "long", "forever"]: + mygoal*=3 # this gives 8%, 23%, 70% distribution (total 100% if not rounded) + if not options.fair: + self.insert_into_only_keep_rdb(100000, mygoal/20, tier=tier, table=table) + self.insert_into_only_keep_rdb(10000, mygoal/20, tier=tier, table=table) + self.insert_into_only_keep_rdb(1000, mygoal/20, tier=tier, table=table) + self.insert_into_only_keep_rdb(100, mygoal/10, tier=tier, table=table) + self.insert_into_only_keep_rdb(20, mygoal/5, tier=tier, table=table) + self.insert_into_only_keep_rdb(10, mygoal/5, tier=tier, table=table) + self.insert_into_only_keep_rdb(5, mygoal/3, tier=tier, table=table) + self.insert_into_only_keep_rdb(1, mygoal/2, tier=tier, table=table) + self.insert_into_only_keep_rdb(0, mygoal, tier=tier, table=table) + + t = time.time() + ret = self.c.execute("select count() from only_keep_rdb") + rows = self.c.fetchall() + rdb_rows = rows[0][0] + print("We now have %d lines only_keep_rdb" % (rdb_rows)) + + + t = time.time() + q = """ + drop index if exists `idxclid6-4`; -- the other index on reduceDB + create index `idx_bbb` on `only_keep_rdb` (`id`); + """ + for l in q.split('\n'): + self.c.execute(l) + print("only_keep_rdb indexes added T: %-3.2f s" % (time.time() - t)) + + q = """ + delete from reduceDB + where reduceDB.rowid not in (select id from only_keep_rdb) + """ + self.c.execute(q) + print("Delete from reduceDB T: %-3.2f s" % (time.time() - t)) + + t = time.time() + val = int(options.limit) + ret = self.c.execute("select count() from reduceDB") + rows = self.c.fetchall() + rdb_rows = rows[0][0] + print("Finally have %d lines of RDB" % (rdb_rows)) + + + def del_table_and_vacuum(self): + helper.drop_idxs(self.c) + + t = time.time() + queries = """ + DROP TABLE IF EXISTS `used_later`; + DROP TABLE IF EXISTS `only_keep_rdb`; + DROP TABLE IF EXISTS `used_cl_ids`; + """ + for q in queries.split("\n"): + self.c.execute(q) + print("Deleted tables T: %-3.2f s" % (time.time() - t)) + + q = """ + vacuum; + """ + + t = time.time() + lev = self.conn.isolation_level + self.conn.isolation_level = None + self.c.execute(q) + self.conn.isolation_level = lev + print("Vacuumed database T: %-3.2f s" % (time.time() - t)) + + +if __name__ == "__main__": + usage = "usage: %prog [options] sqlitedb" + parser = optparse.OptionParser(usage=usage) + + parser.add_option("--limit", default=20000, type=int, + dest="limit", help="Number of clauses to limit ourselves to") + parser.add_option("--goalrdb", default=200000, type=int, + dest="goal_rdb", help="Number of RDB neeeded") + parser.add_option("--goalvardata", default=50000, type=int, + dest="goal_vardata", help="Number of varData points neeeded") + parser.add_option("--verbose", "-v", action="store_true", default=False, + dest="verbose", help="Print more output") + parser.add_option("--noidx", action="store_true", default=False, + dest="noidx", help="Don't recreate indexes") + parser.add_option("--fair", "-f", action="store_true", default=False, + dest="fair", help="Fair sampling. NOT DEFAULT.") + + # lengths of short/long + parser.add_option("--short", default=10*1000, type=int, + dest="short", help="Short duration. Default: %default") + parser.add_option("--long", default=30*1000, type=int, + dest="long", help="Long duration. Default: %default") + parser.add_option("--forever", default=120*1000, type=int, + dest="forever", help="Forever duration. Default: %default") + + (options, args) = parser.parse_args() + + if len(args) < 1: + print("ERROR: You must give the sqlite file!") + exit(-1) + + if not options.fair: + print("NOTE: Sampling will NOT be fair.") + print(" This is because otherwise, DB will be huge") + print(" and we need lots of positive datapoints") + print(" most of which will be from clauses that are more used") + + with QueryDatRem(args[0]) as q: + q.check_db_sanity() + helper.dangerous(q.c) + helper.drop_idxs(q.c) + q.create_indexes1() + q.remove_too_many_vardata() + + # this is the SLOW way of doing it -- without pre-sampling it + if False: + print("This is good for verifying that the fast ones are close") + # slower percentiles + t = time.time() + with helper.QueryFill(args[0]) as q: + helper.dangerous(q.c) + q.delete_and_create_used_laters() + q.create_indexes(verbose=options.verbose) + for tier in ["short", "long", "forever"]: + q.fill_used_later_X(tier, getattr(options, tier)) + with QueryDatRem(args[0]) as q: + helper.dangerous(q.c) + q.create_percentiles_table() + for tier in ["short", "long", "forever"]: + q.get_all_percentile_X(tier) + q.print_percentiles() + with helper.QueryFill(args[0]) as q: + q.delete_and_create_used_laters() + print("SLOWER percentiles:", time.time()-t) + + # Percentile generation + t = time.time() + + # first, we create "used_clauses_red" that contains a reduced + # list of clauseIDs we want to do this over. Here we sample FAIRLY!!!! + with QueryDatRem(args[0]) as q: + helper.dangerous(q.c) + q.recreate_used_ID_table() + q.fill_used_cl_ids_table(True, limit=4*options.limit) # notice the FAIR sampling! + q.drop_used_clauses_red() + q.create_used_clauses_red() + + # now we generate the used_later data + with helper.QueryFill(args[0]) as q: + helper.dangerous(q.c) + q.delete_and_create_used_laters() + q.create_indexes(verbose=options.verbose, used_clauses="used_clauses_red") + for table in ["used_later", "used_later_anc"]: + for tier in ["short", "long", "forever"]: + q.fill_used_later_X(tier, duration=getattr(options, tier), + used_clauses="used_clauses_red", + table=table) + + # now we calculate the distributions and save them + with QueryDatRem(args[0]) as q: + helper.dangerous(q.c) + q.create_percentiles_table() + for tier in ["short", "long", "forever"]: + q.get_all_percentile_X(tier) + q.print_percentiles() + q.drop_used_clauses_red() + with helper.QueryFill(args[0]) as q: + helper.drop_idxs(q.c) + q.delete_and_create_used_laters() + print("FASTER percentiles:", time.time()-t) + + # Filtering for clauseIDs in tables: + # ["clause_stats", "reduceDB", "sum_cl_use", + # "used_clauses", "restart_dat_for_cl", "cl_last_in_solver"] + # here we sample NON-FAIRLY (options.fair) by default! + with QueryDatRem(args[0]) as q: + helper.dangerous(q.c) + q.recreate_used_ID_table() + q.fill_used_cl_ids_table(options.fair, limit=options.limit) + q.filter_tables_of_ids() + q.print_sum_cl_use_distrib() + print("-------------") + + # RDB filtering + with helper.QueryFill(args[0]) as q: + helper.dangerous(q.c) + helper.drop_idxs(q.c) + q.delete_and_create_used_laters() + q.create_indexes(verbose=options.verbose) + + # this is is needed for RDB row deletion below (since it's not fair) + table = "used_later" # we could also do used_later_anc (for RDB) + for tier in ["short", "long", "forever"]: + q.fill_used_later_X(tier=tier, table=table, duration=getattr(options, tier)) + + with QueryDatRem(args[0]) as q: + print("-------------") + q.delete_too_many_rdb_rows() # NOTE: NOT FAIR!!! + + helper.drop_idxs(q.c) + q.del_table_and_vacuum() diff --git a/cryptominisat/cppsrc/scripts/crystal/setparams_ballofcrystal.sh b/cryptominisat/cppsrc/scripts/crystal/setparams_ballofcrystal.sh new file mode 100755 index 00000000..2bdf4da1 --- /dev/null +++ b/cryptominisat/cppsrc/scripts/crystal/setparams_ballofcrystal.sh @@ -0,0 +1,34 @@ +#!/bin/bash + +# Copyright (C) 2009-2020 Authors of CryptoMiniSat, see AUTHORS file +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; version 2 +# of the License. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +# 02110-1301, USA. + +# This file wraps CMake invocation for TravisCI +# so we can set different configurations via environment variables. + +export FNAMEOUT="mydata" +export FIXED="3000" +export DUMPRATIO="0.1" +export CLLOCK="0.3" +export EXTRA_GEN_PANDAS_OPTS="" +export cut1="3.0" +export cut2="25.0" +export SANITIZE=0 +export bestf="../../scripts/crystal/best_features-correlation2.txt" +export NOBUF="" +export NOBUF="stdbuf -oL -eL " +#export bestf="../../scripts/crystal/best_features-ext.txt" diff --git a/cryptominisat/cppsrc/scripts/crystal/vardata_gen_pandas.py b/cryptominisat/cppsrc/scripts/crystal/vardata_gen_pandas.py new file mode 100755 index 00000000..25225c7f --- /dev/null +++ b/cryptominisat/cppsrc/scripts/crystal/vardata_gen_pandas.py @@ -0,0 +1,304 @@ +#!/usr/bin/env python3 +# -*- coding: utf-8 -*- + +# Copyright (C) 2009-2020 Authors of CryptoMiniSat, see AUTHORS file +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; version 2 +# of the License. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +# 02110-1301, USA. + +from __future__ import print_function +import sqlite3 +import argparse +import time +import pickle +import re +import pandas as pd +import numpy as np +import os.path +import sys +import helper + + +def dump_df(df): + # rename columns if we have to: + cleanname = re.sub(r'\.cnf.gz.sqlite$', '', options.fname) + cleanname = re.sub(r'\.db$', '', options.fname) + cleanname = re.sub(r'\.sqlitedb$', '', options.fname) + cleanname = "{cleanname}-vardata".format( + cleanname=cleanname) + dump_dataframe(df, cleanname) + + +def dump_dataframe(df, name): + if options.dump_csv: + fname = "%s.csv" % name + print("Dumping CSV data to:", fname) + df.to_csv(fname, index=False, columns=sorted(list(df))) + + fname = "%s.dat" % name + print("Dumping pandas data to:", fname) + with open(fname, "wb") as f: + pickle.dump(df, f) + + +class QueryVar (helper.QueryHelper): + def __init__(self, dbfname): + super(QueryVar, self).__init__(dbfname) + + def create_indexes(self): + helper.drop_idxs(self.c) + + print("Recreating indexes...") + t = time.time() + queries = """ + create index `idxclid8` on `var_data_picktime` ( `var`, `sumConflicts_at_picktime`, `latest_vardist_feature_calc`); + create index `idxclid81` on `var_data_picktime` ( `var`, `sumConflicts_at_picktime`); + create index `idxclid82` on `var_dist` ( `var`, `latest_vardist_feature_calc`); + create index `idxclid9` on `var_data_fintime` ( `var`, `sumConflicts_at_picktime`); + + create index `idxclid10` on `dec_var_clid` ( `var`, `sumConflicts_at_picktime`, `clauseID`); + + create index `idxclid-s2` on `restart_dat_for_var` (`conflicts`, `latest_satzilla_feature_calc`, `branch_strategy`); + create index `idxclid-s4` on `satzilla_features` (`latest_satzilla_feature_calc`); + + create index `idxclid-s1` on `sum_cl_use` ( `clauseID`, `num_used`); + """ + + for l in queries.split('\n'): + t2 = time.time() + + if options.verbose: + print("Creating/dropping index: ", l) + self.c.execute(l) + if options.verbose: + print("Index dropping&creation T: %-3.2f s" % + (time.time() - t2)) + + print("indexes dropped&created T: %-3.2f s" % (time.time() - t)) + + def fill_var_data_use(self): + print("Filling var data use...") + + t = time.time() + q = "delete from `var_data_use`;" + self.c.execute(q) + print("var_data_use cleared T: %-3.2f s" % (time.time() - t)) + + t = time.time() + q = """ + insert into var_data_use + + (`var` + , `sumConflicts_at_picktime` + + , `cls_marked` + , `useful_clauses_used`) + + select + dvclid.var + , dvclid.sumConflicts_at_picktime + + -- measures for good + , count(cls.num_used) as cls_marked + , sum(cls.num_used) as useful_clauses_used + + FROM dec_var_clid as dvclid join sum_cl_use as cls + on cls.clauseID = dvclid.clauseID + + -- avoid division by zero below + + group by dvclid.var, dvclid.sumConflicts_at_picktime + ; + """ + if options.verbose: + print("query:", q) + self.c.execute(q) + + print("var_data_use filled T: %-3.2f s" % (time.time() - t)) + + t = time.time() + q = """ + UPDATE var_data_use SET useful_clauses_used = 0 + WHERE useful_clauses_used IS NULL + """ + self.c.execute(q) + + print("var_data_use updated T: %-3.2f s" % (time.time() - t)) + + def create_vardata_df(self, min_val, max_val, branch_str = None): + not_cols = [ + "clid_start_incl" + , "clid_end_notincl" + , "decided_pos" + , "propagated_pos" + , "restarts" + , "var" + , "cls_marked"] + var_data_picktime = helper.query_fragment( + "var_data_picktime", not_cols, "var_data_picktime", options.verbose, self.c) + var_data_fintime = helper.query_fragment( + "var_data_fintime", not_cols, "var_data_fintime", options.verbose, self.c) + + not_cols =[ + "var" + , "latest_vardist_feature_calc" + , "conflicts" + ] + var_dist = helper.query_fragment( + "var_dist", not_cols, "var_dist", options.verbose, self.c) + + not_cols =[ + "simplifications" + , "restarts" + , "conflicts" + , "latest_satzilla_feature_calc" + , "runtime" + , "propagations" + , "decisions" + , "flipped" + , "replaced" + , "eliminated" + , "set"] + rst = helper.query_fragment( + "restart_dat_for_var", not_cols, "rst", options.verbose, self.c) + + not_cols =[ + ""] + szfeat = helper.query_fragment( + "satzilla_features", not_cols, "szfeat", options.verbose, self.c) + + not_cols =[ + "useful_clauses" + , "sumConflicts_at_picktime" + , "var"] + var_data_use = helper.query_fragment( + "var_data_use", not_cols, "var_data_use", options.verbose, self.c) + + not_cols =[ + "clauseID" + , "first_confl_used" + , "last_confl_used"] + sum_cl_use = helper.query_fragment( + "sum_cl_use", not_cols, "sum_cl_use", options.verbose, self.c) + + + my_branch_str = "" + if branch_str is not None: + my_branch_str = "and rst.branch_strategy = {branch_str}".format( + branch_str=branch_str) + + q = """ + select + sum_cl_use.num_used as `x.num_used` + {rst} + {var_dist} + {var_data_picktime} + {var_data_fintime} + {szfeat} + {sum_cl_use} + + FROM + var_data_picktime + , var_data_fintime + , sum_cl_use + , dec_var_clid + , var_dist + , restart_dat_for_var as rst + , satzilla_features as szfeat + + WHERE + var_data_picktime.sumConflicts_at_picktime > 15000 + and sum_cl_use.clauseID = dec_var_clid.clauseID + + and var_data_picktime.var = dec_var_clid.var + and var_data_picktime.sumConflicts_at_picktime = dec_var_clid.sumConflicts_at_picktime + + and var_data_fintime.var = dec_var_clid.var + and var_data_fintime.sumConflicts_at_picktime = dec_var_clid.sumConflicts_at_picktime + + and var_dist.var = dec_var_clid.var + and var_dist.latest_vardist_feature_calc = var_data_picktime.latest_vardist_feature_calc + + and rst.conflicts = var_data_picktime.sumConflicts_at_picktime + and rst.latest_satzilla_feature_calc = szfeat.latest_satzilla_feature_calc + + and sum_cl_use.num_used >= {min_val} + and sum_cl_use.num_used <= {max_val} + + {my_branch_str} + + order by random() + limit {limit} + """.format( + rst=rst, + var_data_use=var_data_use, + var_data_picktime=var_data_picktime, + var_data_fintime=var_data_fintime, + var_dist=var_dist, + sum_cl_use=sum_cl_use, + szfeat=szfeat, + limit=options.limit, + min_val=min_val, + max_val=max_val, + my_branch_str=my_branch_str, + min_cls_below=options.min_cls_below) + + df = pd.read_sql_query(q, self.conn) + print("DF dimensions:", df.shape) + return df + + +if __name__ == "__main__": + usage = "usage: %(prog)s [options] file.sqlite" + parser = argparse.ArgumentParser(usage=usage) + + parser.add_argument("fname", type=str, metavar='SQLITEFILE') + parser.add_argument("--verbose", "-v", action="store_true", + default=False, dest="verbose", help="Print more output") + parser.add_argument("--csv", action="store_true", default=False, + dest="dump_csv", help="Dump CSV (for weka)") + parser.add_argument("--limit", type=int, default=10000, + dest="limit", help="How many data points") + parser.add_argument("--minclsbelow", type=int, default=1, + dest="min_cls_below", help="Minimum number of clauses below to generate data point") + parser.add_argument("--unbalanced", action="store_true", + default=False, dest="unbalanced", help="Get unbalanced output") + + options = parser.parse_args() + + if options.fname is None: + print("ERROR: You must give exactly one file") + exit(-1) + + np.random.seed(2097483) + with QueryVar(options.fname) as q: + q.create_indexes() + q.fill_var_data_use() + + if not options.unbalanced: + dfs = [] + for branch_str in range(4): + print("Doing == 0 use:") + dfs.append(q.create_vardata_df(0, 0, branch_str)) + print("Doing >0 use:") + dfs.append(q.create_vardata_df(1, 200000, branch_str)) + print("Finished branch_str: ", branch_str) + df_full = pd.concat(dfs, sort=False) + else: + df_full = q.create_vardata_df(0, 2000000000) + + print("Final DF dimensions:", df_full.shape) + + dump_df(df_full) diff --git a/cryptominisat/cppsrc/scripts/crystal/vardata_predict.py b/cryptominisat/cppsrc/scripts/crystal/vardata_predict.py new file mode 100755 index 00000000..fa1db496 --- /dev/null +++ b/cryptominisat/cppsrc/scripts/crystal/vardata_predict.py @@ -0,0 +1,530 @@ +#!/usr/bin/env python3 +# -*- coding: utf-8 -*- + +# Copyright (C) 2009-2020 Authors of CryptoMiniSat, see AUTHORS file +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; version 2 +# of the License. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +# 02110-1301, USA. + +from __future__ import print_function +import sklearn.ensemble +import sklearn.tree +import sqlite3 +import argparse +import time +import pickle +import re +import pandas as pd +import numpy as np +import os.path +import sys +import helper +import sklearn +import functools +ver = sklearn.__version__.split(".") +if int(ver[1]) < 20: + from sklearn.cross_validation import train_test_split +else: + from sklearn.model_selection import train_test_split + + +def add_computed_features(df): + print("Original number of features:", len(list(df))) + print("Adding computed features...") + cols = list(df) + divide = functools.partial(helper.divide, df=df, features=cols, verb=options.verbose) + + if not options.picktime_only: + # create "during" + for col in cols: + if "_at_fintime" in col: + during_name = col.replace("_at_fintime", "_during") + at_picktime_name = col.replace("_at_fintime", "_at_picktime") + at_fintime_name = col + if options.verbose: + print("fintime name: ", at_fintime_name) + print("picktime name: ", at_picktime_name) + df[during_name] = df[at_fintime_name]-df[at_picktime_name] + + # remove picktime & fintime, only use "during" + cols = list(df) + for c in cols: + if "at_picktime" in c or "at_fintime" in c: + del df[c] + + else: + # remove everything to do with "clauses_below" and "at_fintime" + cols = list(df) + for c in cols: + if "var_data_fintime" in c: + del df[c] + + if False: + # per-conflicts, per-decisions, per-lits + divisors = [ + "var_data_picktime.sumConflicts_at_picktime" + , "var_data_picktime.sumClLBD_at_picktime" + , "var_data_picktime.sumClSize_at_picktime" + , "var_data_picktime.sumConflictClauseLits_at_picktime" + # neutral below + , "var_data_picktime.dec_depth" + # below during + , "var_data_picktime.inside_conflict_clause_antecedents_at_picktime" + , "var_data_picktime.sumDecisions_below_during" + , "var_data_picktime.sumPropagations_below_during" + , "var_data_picktime.sumConflicts_below_during" + , "var_data_picktime.sumAntecedents_below_during" + , "var_data_picktime.sumConflictClauseLits_below_during" + , "var_data_picktime.sumAntecedentsLits_below_during" + , "var_data_picktime.sumClSize_below_during" + , "var_data_picktime.sumClLBD_below_during" + ] + + cols = list(df) + for col in cols: + if "x." not in col and "var_data_use" not in col: + for divisor in divisors: + divide(col, divisor) + + # divide var_dist by szfeat, all-by-all + if False: + for c in cols: + if "szfeat" in c: + for c2 in cols: + if "var_dist" in c2: + divide(c2, c) + + # divide during by during, all-by-all + if True: + for c in cols: + if "during" in c: + for c2 in cols: + if "during" in c2: + divide(c2, c) + + df["var_dist.num_irred_cls"] = df["var_dist.num_irred_long_cls"] + df["var_dist.num_irred_bin_cls"] + df["var_dist.num_red_cls"] = df["var_dist.num_red_long_cls"] + df["var_dist.num_red_bin_cls"] + + for red in ["red", "irred"]: + divide("var_dist.{red}_num_times_in_bin_clause".format(red=red), "var_dist.num_{red}_bin_cls".format(red=red)) + divide("var_dist.{red}_num_times_in_long_clause".format(red=red), "var_dist.num_{red}_long_cls".format(red=red)) + divide("var_dist.{red}_satisfies_cl".format(red=red), "var_dist.num_{red}_cls".format(red=red)) + divide("var_dist.{red}_tot_num_lit_of_bin_it_appears_in".format(red=red), "var_dist.num_{red}_bin_cls".format(red=red)) + divide("var_dist.{red}_tot_num_lit_of_long_cls_it_appears_in".format(red=red), "var_dist.num_{red}_long_cls".format(red=red)) + divide("var_dist.{red}_sum_var_act_of_cls".format(red=red), "var_dist.num_{red}_long_cls".format(red=red)) + divide("var_dist.{red}_satisfies_cl".format(red=red), "var_dist.num_{red}_cls".format(red=red)) + divide("var_dist.{red}_falsifies_cl".format(red=red), "var_dist.num_{red}_cls".format(red=red)) + divide("var_dist.{red}_tot_num_lit_of_long_cls_it_appears_in".format(red=red), "var_dist.num_{red}_long_cls".format(red=red)) + divide("var_dist.{red}_sum_var_act_of_cls".format(red=red), "var_dist.num_{red}_long_cls".format(red=red)) + divide("var_dist.{red}_satisfies_cl".format(red=red), "var_dist.num_{red}_cls".format(red=red)) + divide("var_dist.{red}_sum_var_act_of_cls".format(red=red), "var_dist.num_{red}_long_cls".format(red=red)) + + divide("var_dist.tot_act_long_red_cls", "var_dist.num_red_long_cls") + + divide("var_data_picktime.inside_conflict_clause_antecedents_during_at_picktime", + "var_data_picktime.sumAntecedentsLits_at_picktime") + + divide("var_data_picktime.sumAntecedentsLits_below_during", + "var_data_picktime.sumAntecedentsLits_at_picktime") + + + + + + + divide("var_data_picktime.inside_conflict_clause_during_at_picktime", + "var_data_picktime.sumConflicts_at_picktime") + divide("var_data_picktime.inside_conflict_clause_antecedents_at_picktime", + "var_data_picktime.sumAntecedentsLits_at_picktime") + + divide("var_data_picktime.num_decided", "var_data_picktime.sumDecisions_at_picktime") + divide("var_data_picktime.num_decided_pos", "var_data_picktime.sumDecisions_at_picktime") + divide("var_data_picktime.num_decided", "var_data_picktime.num_decided_pos") + + divide("var_data_picktime.num_propagated", "var_data_picktime.sumPropagations_at_picktime") + divide("var_data_picktime.num_propagated_pos", "var_data_picktime.sumPropagations_at_picktime") + divide("var_data_picktime.num_propagated", "var_data_picktime.num_propagated_pos") + + + for c in cols: + if "var_dist.num_" in c: + del df[c] + del df["var_dist.num_irred_cls"] + del df["var_dist.num_red_cls"] + + # we divide these and then delete + xs = [ + "var_dist.red_num_times_in_long_clause", + "var_data_picktime.inside_conflict_clause_at_picktime", + "var_data_picktime.sumClSize_at_picktime", + "var_data_picktime.sumClLBD_at_picktime", + "var_data_picktime.sumAntecedents_at_picktime", + "var_data_picktime.sumAntecedentsLits_at_picktime", + "var_data_picktime.sumConflictClauseLits_at_picktime", + "var_data_picktime.inside_conflict_clause_antecedents_at_picktime", + "var_data_picktime.inside_conflict_clause_antecedents_during_at_picktime", + "var_data_picktime.sumAntecedentsLits_below_during", + "var_data_picktime.inside_conflict_clause_glue_at_picktime", + "var_data_picktime.inside_conflict_clause_glue_during_at_picktime" + ] + ys = [ + "var_data_picktime.sumConflicts_at_picktime", + "var_data_picktime.num_decided", + "var_data_picktime.num_propagated" + ] + for x in xs: + for y in ys: + divide(x, y) + del df[x] + + + + todel = [ + "var_data_picktime.latest_vardist_feature_calc", + + "var_dist.red_falsifies_cl", + "var_dist.irred_falsifies_cl", + "var_dist.red_satisfies_cl", + "var_dist.irred_satisfies_cl", + + "var_data_picktime.dec_depth", + "var_dist.red_num_times_in_bin_clause", + "var_dist.irred_sum_var_act_of_cls", + "var_dist.tot_act_long_red_cls", + "var_dist.red_tot_num_lit_of_long_cls_it_appears_in", + "var_dist.red_sum_var_act_of_cls", + #"rst.branch_strategy", + + "var_data_picktime.num_decided", + "var_data_picktime.num_decided_pos", + "var_data_picktime.num_propagated", + "var_data_picktime.num_propagated_pos", + "var_data_picktime.sumPropagations_at_picktime", + "var_data_picktime.sumDecisions_at_picktime", + + "var_data_picktime.inside_conflict_clause_during_at_picktime" + ] + for d in todel: + del df[d] + + for c in cols: + if "rst." in c and "strategy" not in c and "restart_type" not in c: + if c in list(df): + del df[c] + + print("Done adding computed features. New number of features: ", len(list(df))) + + +def rem_useless_features(df): + col = list(df) + for c in col: + if "restart_type" in c or "szfeat" in c: + del df[c] + + # remove hidden data + del df["sum_cl_use.num_used"] + pass + + +class Learner: + def __init__(self, df, funcname, fname, cluster_no): + self.df = df + self.func_name = funcname + self.fname = fname + self.cluster_no = cluster_no + + def cut_into_chunks(self): + df["x.class"] = pd.qcut( + df["x.num_used"], + q=options.quantiles, + duplicates='drop', + labels=False) + + df['x.class'] = df['x.class'].astype(str) + + @staticmethod + def fix_feat_name(x): + if "during" in x or "clauses_below" in x: + x = x.replace("var_data_", "") + + return x + + def one_classifier(self, features, to_predict, final, write_code=False): + print("-> Number of features :", len(features)) + print("-> Number of datapoints:", self.df.shape) + print("-> Predicting :", to_predict) + + # get smaller part to work on + # also, copy it so we don't get warning about setting a slice of a DF + if options.only_pecr >= 0.98: + df = self.df.copy() + else: + _, df_tmp = train_test_split(self.df, test_size=options.only_pecr) + df = df_tmp.copy() + print("-> Number of datapoints after applying '--only':", df.shape) + + if options.dump_csv: + fname = "mydump.csv" + print("Dumping CSV data to:", fname) + df.to_csv(fname, index=False, columns=sorted(list(df))) + + if options.check_row_data: + helper.check_too_large_or_nan_values(df, features+["x.class"]) + print("Checked, all good!") + + train, test = train_test_split(df, test_size=0.33) + X_train = train[features] + y_train = train[to_predict] + + t = time.time() + clf = None + if final: + split_point = helper.calc_min_split_point( + df, options.min_samples_split) + clf = sklearn.tree.DecisionTreeClassifier( + max_depth=options.tree_depth, + min_samples_split=split_point) + else: + clf = sklearn.ensemble.RandomForestClassifier( + n_estimators=1000, + max_features="sqrt") + + del df + clf.fit(X_train, y_train) + print("Training finished. T: %-3.2f" % (time.time() - t)) + + if not final: + best_features = helper.print_feature_ranking( + clf, X_train, + top_num_features=options.top_num_features, + features=features, + plot=options.show) + else: + if options.dot is not None: + if not options.final_is_tree: + print("ERROR: You cannot use the DOT function on non-trees") + exit(-1) + + helper.output_to_classical_dot( + clf, features, + fname=options.dot + "-" + self.func_name) + + if options.basedir and write_code: + c = helper.CodeWriter(clf, features, self.func_name, self.fname, options.verbose) + c.func_signature = """ + const Solver* solver + , const VarData& varData + , uint64_t sumConflicts_during + , uint64_t sumDecisions_during + , uint64_t sumPropagations_during + , uint64_t sumAntecedents_during + , uint64_t sumAntecedentsLits_during + , uint64_t sumConflictClauseLits_during + , uint64_t sumDecisionBasedCl_during + , uint64_t sumClLBD_during + , uint64_t sumClSize_during + , uint64_t clauses_below + """ + c.func_call = """ + solver + , varData + , sumConflicts_during + , sumDecisions_during + , sumPropagations_during + , sumAntecedents_during + , sumAntecedentsLits_during + , sumConflictClauseLits_during + , sumDecisionBasedCl_during + , sumClLBD_during + , sumClSize_during + , clauses_below + """ + c.per_func_defines = """""" + c.file_header = """ + #include "clause.h" + #include "vardata.h" + #include "solver.h" + #include + + namespace CMSat { + """ + c.fix_feat_name = self.fix_feat_name + c.clean_up() + c.print_full_code() + + precision, recall, accuracy = helper.conf_matrixes( + test, features, to_predict, clf, + toprint="test", average="micro") + helper.conf_matrixes( + train, features, to_predict, clf, + toprint="train", average="micro") + + # TODO do L1 regularization + # TODO do principal component analysis + + if not final: + return best_features + else: + return prec+recall+acc + + def learn(self): + self.cut_into_chunks() + features = list(self.df) + features.remove("clust") + features.remove("x.class") + features.remove("x.num_used") + + if options.raw_data_plots: + pd.options.display.mpl_style = "default" + self.df.hist() + self.df.boxplot() + + if not options.only_final: + top_n_feats = self.one_classifier(features, "x.class", final=False) + if options.show: + plt.show() + + if options.get_best_topn_feats is not None: + greedy_features = helper.calc_greedy_best_features( + top_n_feats, options.get_best_topn_feats, + self) + + return + + best_features = [ + 'var_data_picktime.flipped_confs_ago', + '(var_dist.tot_act_long_red_cls/var_dist.num_red_long_cls)', + 'var_data_picktime.conflicts_since_decided', + '(var_data_picktime.num_decided/var_data_picktime.num_decided_pos)', + '(var_dist.red_num_times_in_long_clause/var_data_picktime.num_propagated)', + '(var_dist.red_num_times_in_long_clause/var_data_picktime.num_decided)', + 'var_data_picktime.rel_activity_at_picktime', + '(var_data_picktime.sumAntecedentsLits_below_during/var_data_picktime.sumAntecedentsLits_at_picktime)', + '(var_data_picktime.num_propagated/var_data_picktime.num_propagated_pos)', + 'var_data_picktime.conflicts_since_propagated', + ] + + self.one_classifier(best_features, "x.class", + final=True, + write_code=True) + + if options.show: + plt.show() + + +if __name__ == "__main__": + usage = "usage: %(prog)s [options] file.sqlite" + parser = argparse.ArgumentParser(usage=usage) + + # dataframe + parser.add_argument("fname", type=str, metavar='PANDASFILE') + parser.add_argument("--verbose", "-v", action="store_true", default=False, + dest="verbose", help="Print more output") + parser.add_argument("--top", default=40, type=int, metavar="TOPN", + dest="top_num_features", help="Candidates are top N features for greedy selector") + parser.add_argument("--printfeat", action="store_true", default=False, + dest="print_features", help="Print features") + parser.add_argument("--check", action="store_true", default=False, + dest="check_row_data", help="Check row data for NaN or float overflow") + parser.add_argument("--greedy", default=None, type=int, metavar="TOPN", + dest="get_best_topn_feats", help="Greedy Best K top features from the top N features given by '--top N'") + parser.add_argument("--show", default=False, action="store_true", + dest="show", help="Show graphs") + parser.add_argument("--final", default=False, action="store_true", + dest="only_final", help="Only generate final predictor") + parser.add_argument("--rawplots", action="store_true", default=False, + dest="raw_data_plots", help="Display raw data plots") + parser.add_argument("--dot", type=str, default=None, + dest="dot", help="Create DOT file") + parser.add_argument("--basedir", type=str, + dest="basedir", help="The base directory of where the CryptoMiniSat source code is") + parser.add_argument("--clust", default=False, action="store_true", + dest="use_clusters", help="Use clusters") + parser.add_argument("--conf", default=0, type=int, + dest="conf_num", help="Which predict configuration this is") + parser.add_argument("--picktimeonly", default=False, action="store_true", + dest="picktime_only", help="Only use and generate pictime data") + + # tree/forest options + parser.add_argument("--depth", default=None, type=int, + dest="tree_depth", help="Depth of the tree to create") + parser.add_argument("--split", default=0.01, type=float, metavar="RATIO", + dest="min_samples_split", help="Split in tree if this many samples or above. Used as a percentage of datapoints") + parser.add_argument("--numtrees", default=5, type=int, + dest="num_trees", help="How many trees to generate for the forest") + + # data filtering + parser.add_argument("--only", default=0.99, type=float, + dest="only_pecr", help="Only use this percentage of data") + parser.add_argument("-q", default=2, type=int, metavar="QUANTS", + dest="quantiles", help="Number of quantiles we want") + parser.add_argument("--nocomputed", default=False, action="store_true", + dest="no_computed", help="Don't add computed features") + parser.add_argument("--csv", action="store_true", default=False, + dest="dump_csv", help="Dump CSV (for weka)") + + # type of classifier + parser.add_argument("--tree", default=False, action="store_true", + dest="final_is_tree", help="Final classifier should be a tree") + parser.add_argument("--svm", default=False, action="store_true", + dest="final_is_svm", help="Final classifier should be an svm") + parser.add_argument("--lreg", default=False, action="store_true", + dest="final_is_logreg", help="Final classifier should be a logistic regression") + parser.add_argument("--forest", default=False, action="store_true", + dest="final_is_forest", help="Final classifier should be a forest") + parser.add_argument("--voting", default=False, action="store_true", + dest="final_is_voting", help="Final classifier should be a voting of all of: forest, svm, logreg") + + options = parser.parse_args() + + if options.fname is None: + print("ERROR: You must give the pandas file!") + exit(-1) + + df = pd.read_pickle(options.fname) + + rem_useless_features(df) + if not options.no_computed: + add_computed_features(df) + + # cluster setup + if options.use_clusters: + used_clusters = df.groupby("clust").nunique() + clusters = [] + for clust, _ in used_clusters["clust"].iteritems(): + clusters.append(clust) + else: + clusters = [0] + df["clust"] = 0 + + # generation + for clno in clusters: + funcname = "maple_reward_conf{conf_num}_cluster{clno}".format( + clno=clno, conf_num=options.conf_num) + + fname = "maple_predictor_conf{conf_num}_cluster{clno}.h".format( + clno=clno, conf_num=options.conf_num) + + if options.basedir is not None: + f = options.basedir+"/"+fname + else: + f = None + + p = Learner( + df, + funcname=funcname, + fname=f, + cluster_no=clno) + p.learn() diff --git a/cryptominisat/cppsrc/scripts/drat-proof.py b/cryptominisat/cppsrc/scripts/drat-proof.py new file mode 100755 index 00000000..979c0b7a --- /dev/null +++ b/cryptominisat/cppsrc/scripts/drat-proof.py @@ -0,0 +1,243 @@ +#!/usr/bin/python3 +# -*- coding: utf-8 -*- + +# Copyright (C) 2009-2020 Authors of CryptoMiniSat, see AUTHORS file +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; version 2 +# of the License. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +# 02110-1301, USA. + +import unittest + +def inv(l): + assert len(l) > 0 + if l[0] == "-": + return l[1:] + else: + return "-"+l + +def check_clause_sanity(c): + for i1 in range(len(c)): + l1 = c[i1] + for i2 in range(i1+1, len(c)): + l2 = c[i2] + if l1 == l2: + print("ERROR: Same literal twice in clause: %s", l1) + assert False + + if l1 == inv(l2): + print("ERROR: Inverted literal in clause: %s ", l1) + assert False + + return True + + +def can_resolve(c1, c2): + check_clause_sanity(c1) + check_clause_sanity(c2) + + # find inverted + resolve_on = None + for a in c1: + for b in c2: + if a==inv(b): + if resolve_on is not None: + return None + resolve_on = a + + return resolve_on + +def resolve(c1, c2): + resolve_on = can_resolve(c1,c2) + assert resolve_on is not None, "Cannot resolve the two clauses!" + + ret = [] + for a in c1: + if a != resolve_on: + ret.append(a) + + for b in c2: + if b != inv(resolve_on) and b not in ret: + ret.append(b) + + ret = sorted(ret) + return ret + + +def ham_w(num): + w = 0 + for i in range(16): + w += (num>>i)&1 + + return w + + +def gen_cls(x): + check_clause_sanity(x) + + ret = [] + for i in range(1<>i2&1 == 1: + cl.append(inv(l)) + else: + cl.append(l) + + ret.append(cl) + + return ret + + +class TestMethods(unittest.TestCase): + + def test_inv(self): + self.assertEqual(inv("a"), "-a") + self.assertEqual(inv("-a"), "a") + self.assertEqual(inv("x1"), "-x1") + self.assertEqual(inv("-x1"), "x1") + + def test_sanity_good(self): + self.assertTrue(check_clause_sanity(["a"])) + self.assertTrue(check_clause_sanity(["a", "b"])) + self.assertTrue(check_clause_sanity(["a", "-b"])) + + def test_sanity(self): + with self.assertRaises(AssertionError): + check_clause_sanity(["a", "a"]) + with self.assertRaises(AssertionError): + check_clause_sanity(["a", "-a"]) + + def tets_gen_cls(self): + self.assertEqual(gen_cls(["a"]), [["a"]]) + self.assertEqual(gen_cls(["-a"]), [["-a"]]) + self.assertEqual(gen_cls(["a", "b"]), [["a", "b"], ["-a", "-b"]]) + self.assertEqual(gen_cls(["a", "-b"]), [["a", "-b"], ["-a", "b"]]) + self.assertEqual( + gen_cls(["a", "b", "c"]), + [["a", "b", "c"], ["-a", "-b", "c"], ["-a", "b", "-c"], ["a", "-b", "-c"]]) + + def test_ham_w(self): + self.assertEqual(ham_w(1), 1) + self.assertEqual(ham_w(0), 0) + self.assertEqual(ham_w(2), 1) + self.assertEqual(ham_w(3), 2) + self.assertEqual(ham_w(9), 2) + self.assertEqual(ham_w(8), 1) + self.assertEqual(ham_w(11), 3) + + def test_resolve(self): + with self.assertRaises(AssertionError): + resolve(["-a", "b"], ["-a", "c"]) + + with self.assertRaises(AssertionError): + resolve(["-a", "-b"], ["a", "b"]) + + self.assertEqual(resolve(["a", "b", "c"], ["-a", "b"]), ["b", "c"]) + +def num_inside(cl,lits): + num = 0 + for l in cl: + for l2 in lits: + if l == l2: + num+=1 + + return num + + +def find_most_inside(xors, to_prove): + most_inside = 0 + most_inside_cl = None + for i_x in range(len(xors)): + x = xors[i_x] + cls = gen_cls(x) + for i_c in range(len(cls)): + cl = cls[i_c] + n = num_inside(cl, to_prove) + if n > most_inside: + most_inside = n + most_inside_cl = cl + most_inside_at = i_x + + return most_inside, most_inside_cl, most_inside_at + + +def find_resolvent_most_inside(xors, cl_other, to_prove): + most_inside = 0 + most_inside_cl = None + for i_x in range(len(xors)): + x = xors[i_x] + cls = gen_cls(x) + for i in range(len(cls)): + cl = cls[i] + if can_resolve(cl,cl_other) is None: + continue + + n = num_inside(cl, to_prove) + if n > most_inside: + most_inside = n + most_inside_cl = cl + most_inside_at = i_x + + return most_inside, most_inside_cl, most_inside_at + +def prove(xors, to_prove): + to_prove = sorted(to_prove) + + ret = [] + most_inside, cl, most_inside_at = find_most_inside(xors, to_prove) + assert most_inside > 0 + print("cl picked:", cl) + xors.remove(xors[most_inside_at]) + + while cl != to_prove: + most_inside, cl2, most_inside_at = find_resolvent_most_inside(xors, cl, to_prove) + assert most_inside > 0 + print("cl picked:", cl2) + + cl = resolve(cl, cl2) + cl = sorted(cl) + print("resolvent:", cl) + +if __name__ == '__main__': + # XORs to add together (we know this) + xors = [ + ["a", "b", "c"], + ["a", "b", "d"] + ] + + # so c+d = 0 + # so c=1 d=0 must be banned + # generate clause + to_prove = ["-c", "d"] + + + print("xors:", xors) + print("to_prove:", to_prove) + prove(xors, to_prove) + print("----------------") + print("----------------") + + + print(gen_cls(["v1", "-v2"])) + print(gen_cls(["v1", "v2", "v3"])) + print("----------------") + print("----------------") + + unittest.main() + diff --git a/cryptominisat/cppsrc/scripts/fuzz/CMakeLists.txt b/cryptominisat/cppsrc/scripts/fuzz/CMakeLists.txt new file mode 100644 index 00000000..7868396a --- /dev/null +++ b/cryptominisat/cppsrc/scripts/fuzz/CMakeLists.txt @@ -0,0 +1,29 @@ +# Copyright (C) 2009-2020 Authors of CryptoMiniSat, see AUTHORS file +# +# Permission is hereby granted, free of charge, to any person obtaining a copy +# of this software and associated documentation files (the "Software"), to deal +# in the Software without restriction, including without limitation the rights +# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +# copies of the Software, and to permit persons to whom the Software is +# furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in +# all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +# THE SOFTWARE. + + +# resource limiting is not available on Windows, so skip +if (ENABLE_TESTING AND NOT MSVC AND NOT ONLY_SIMPLE) + add_test ( + NAME verifier_test + COMMAND ${PYTHON_EXECUTABLE} ${CMAKE_CURRENT_SOURCE_DIR}/verifier_test.py + WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} + ) +endif() diff --git a/cryptominisat/cppsrc/scripts/fuzz/debuglib.py b/cryptominisat/cppsrc/scripts/fuzz/debuglib.py new file mode 100644 index 00000000..f129d074 --- /dev/null +++ b/cryptominisat/cppsrc/scripts/fuzz/debuglib.py @@ -0,0 +1,168 @@ +#!/usr/bin/env python3 +# -*- coding: utf-8 -*- + +# Copyright (C) 2009-2020 Authors of CryptoMiniSat, see AUTHORS file +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; version 2 +# of the License. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +# 02110-1301, USA. + +from __future__ import with_statement # Required in 2.5 +from __future__ import print_function +import random + +def shuffle_cnf(fname1, fname2, seed): + random.seed(int(seed)) + + with open(fname1, "r") as f1: + headers = [] + lines = [] + for line in f1: + line = line.strip() + if len(line) > 1 and line[0] == 'p': + headers.append(line) + else: + lines.append(line) + + random.shuffle(lines) + + with open(fname2, "w") as f2: + for line in headers: + f2.write(line+"\n") + for line in lines: + f2.write(line+"\n") + +def get_max_var_from_clause(line): + maxvar = 0 + # strip leading 'x' + line2 = line.strip() + if len(line2) > 0 and line2[0] == 'x': + line2 = line2[1:] + + for lit in line2.split(): + num = 0 + try: + num = int(lit) + except ValueError: + print("line '%s' contains a non-integer variable" % line2) + + maxvar = max(maxvar, abs(num)) + + return maxvar + + +class debuglib: + @staticmethod + def generate_random_assumps(maxvar): + assumps = "" + num = 0 + varsInside = set() + + # Half of the time, no assumptions at all + if random.randint(0, 1) == 1: + return assumps + + # use a distribution so that few will be in assumps + while (num < maxvar and random.randint(0, 4) > 0): + + # get a var that is not already inside the assumps + thisVar = random.randint(1, maxvar) + tries = 0 + while (thisVar in varsInside): + thisVar = random.randint(1, maxvar) + tries += 1 + + # too many tries, don't waste time + if tries > 100: + return assumps + + varsInside.add(thisVar) + + # random sign + num += 1 + if random.randint(0, 1): + thisVar *= -1 + + assumps += "%d " % thisVar + + return assumps + + @staticmethod + def file_len_no_comment(fname): + i = 0 + with open(fname) as f: + for l in f: + # ignore comments and empty lines and header + if not l or l[0] == "c" or l[0] == "p": + continue + i += 1 + + return i + + @staticmethod + def main(fname1, fname2): + + # approx number of solve()-s to add + if random.randint(0, 1) == 1: + num_to_add = random.randint(0, 10) + else: + num_to_add = 0 + + # based on length and number of solve()-s to add, intersperse + # file with ::solve() + file_len = debuglib.file_len_no_comment(fname1) + if num_to_add > 0: + nextToAdd = random.randint(1, int(file_len / num_to_add) + 1) + else: + nextToAdd = file_len + 1 + + fin = open(fname1, "r") + fout = open(fname2, "w") + at = 0 + maxvar = 0 + for line in fin: + line = line.strip() + + # ignore comments (but write them out) + if not line or line[0] == "c" or line[0] == 'p': + fout.write(line + '\n') + continue + + at += 1 + if at >= nextToAdd: + assumps = debuglib.generate_random_assumps(maxvar) + if random.choice([True, False]): + fout.write("c Solver::solve( %s )\n" % assumps) + elif random.choice([True, False]): + fout.write("c Solver::simplify( %s )\n" % assumps) + else: + fout.write("c Solver::simplify( %s )\n" % assumps) + fout.write("c Solver::solve( %s )\n" % assumps) + + nextToAdd = at + \ + random.randint(1, int(file_len / num_to_add) + 1) + + # calculate max variable + maxvar = max(maxvar, get_max_var_from_clause(line)) + + # copy line over + fout.write(line + '\n') + fout.close() + fin.close() + + +def intersperse(fname1, fname2, seed): + random.seed(int(seed)) + debuglib.main(fname1, fname2) + diff --git a/cryptominisat/cppsrc/scripts/fuzz/fuzz_test.py b/cryptominisat/cppsrc/scripts/fuzz/fuzz_test.py new file mode 100755 index 00000000..614459d6 --- /dev/null +++ b/cryptominisat/cppsrc/scripts/fuzz/fuzz_test.py @@ -0,0 +1,762 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- + +# Copyright (C) 2009-2020 Authors of CryptoMiniSat, see AUTHORS file +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; version 2 +# of the License. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +# 02110-1301, USA. + +from __future__ import with_statement # Required in 2.5 +from __future__ import print_function +import subprocess +import os +import sys +import time +import random +from random import choice +import optparse +import glob +import resource +from verifier import * +from functools import partial + +print("our CWD is: %s files here: %s" % (os.getcwd(), glob.glob("*"))) +sys.path.append(os.getcwd()) +print("our sys.path is", sys.path) + +from debuglib import * + + +class PlainHelpFormatter(optparse.IndentedHelpFormatter): + + def format_description(self, description): + if description: + return description + "\n" + else: + return "" + + +usage = "usage: %prog [options] --fuzz/--regtest/--checkdir/filetocheck" +desc = """Fuzz the solver with fuzz-generator: ./fuzz_test.py +""" + + +def set_up_parser(): + parser = optparse.OptionParser(usage=usage, description=desc, + formatter=PlainHelpFormatter()) + parser.add_option("--exec", metavar="SOLVER", dest="solver", + default="../../build/cryptominisat5", + help="SAT solver executable. Default: %default") + + parser.add_option("--extraopts", "-e", metavar="OPTS", + dest="extra_options", default="", + help="Extra options to give to SAT solver") + + parser.add_option("--verbose", "-v", action="store_true", default=False, + dest="verbose", help="Print more output") + + # for fuzz-testing + parser.add_option("--seed", dest="fuzz_seed_start", + help="Fuzz test start seed. Otherwise, random seed is picked" + " (printed to console)", type=int) + + parser.add_option("--fuzzlim", dest="fuzz_test_lim", type=int, + help="Number of fuzz tests to run" + ) + parser.add_option("--dovalgrind", dest="novalgrind", default=True, + action="store_false", help="Use valgrind installed -- NOT recommended, compile with SANTIZE instead!") + + parser.add_option("--valgrindfreq", dest="valgrind_freq", type=int, + default=10, help="1 out of X times valgrind will be used. Default: %default in 1") + + parser.add_option("--gauss", dest="gauss", default=False, + action="store_true", + help="Concentrate fuzzing gauss") + parser.add_option("--sampling", dest="only_sampling", default=False, + action="store_true", + help="Concentrate fuzzing sampling variables") + parser.add_option("--maxth", "-m", dest="max_threads", default=20, + type=int, help="Max number of threads") + + parser.add_option("--tout", "-t", dest="maxtime", type=int, default=25, + help="Max time to run. Default: %default") + + parser.add_option("--textra", dest="maxtimediff", type=int, default=5, + help="Extra time on top of timeout for processing." + " Default: %default") + + return parser + + +def fuzzer_call_failed(fname): + print("OOps, fuzzer executable call failed!") + print("Did you build with cmake -DENABLE_TESTING=ON? Did you do git submodules init & update?") + print("Here is the output:") + + print("**** ----- ****") + with open(fname, "r") as a: + for x in a: + print(x.strip()) + print("**** ----- ****") + exit(-1) + + +class create_fuzz: + + def call_from_fuzzer(self, fuzzer, fname): + seed = random.randint(0, 1000000) + if len(fuzzer) == 1: + call = "{0} {1} > {2}".format(fuzzer[0], seed, fname) + elif len(fuzzer) == 2: + call = "{0} {1} {2} > {3}".format( + fuzzer[0], fuzzer[1], seed, fname) + elif len(fuzzer) == 3: + hashbits = (random.getrandbits(20) % 80) + 1 + call = "%s %s %d %s %d > %s" % ( + fuzzer[0], fuzzer[1], hashbits, fuzzer[2], seed, fname) + else: + assert False, "Fuzzer must have at most 2 arguments" + + return call + + def create_fuzz_file(self, fuzzer, fuzzers, fname): + # handle special fuzzer + fnames_multi = [] + if len(fuzzer) == 2 and fuzzer[1] == "special": + + # sometimes just fuzz with all SAT problems + fixed = random.getrandbits(1) == 1 + + for _ in range(random.randrange(2, 4)): + fname2 = unique_file("fuzzTest-multipart") + fnames_multi.append(fname2) + + # chose a ranom fuzzer, not multipart + fuzzer2 = ["multipart.py", "special"] + while os.path.basename(fuzzer2[0]) == "multipart.py": + fuzzer2 = choice(fuzzers) + + # sometimes fuzz with SAT problems only + if (fixed): + fuzzer2 = fuzzers[0] + + print("fuzzer2 used: %s" % fuzzer2) + call = self.call_from_fuzzer(fuzzer2, fname2) + print("calling sub-fuzzer: %s" % call) + status = subprocess.call(call, shell=True) + if status != 0: + fuzzer_call_failed(fname2) + + # construct multi-fuzzer call + call = "" + call += fuzzer[0] + call += " " + for name in fnames_multi: + call += " " + name + call += " > " + fname + + return call, fnames_multi + + # handle normal fuzzer + else: + return self.call_from_fuzzer(fuzzer, fname), [] + + +def file_exists(fname): + try: + with open(fname): + return True + except IOError: + return False + + +def print_version(): + command = options.solver + " --version" + if options.verbose: + print("Executing: %s" % command) + p = subprocess.Popen(command.rsplit(), stderr=subprocess.STDOUT, + stdout=subprocess.PIPE, universal_newlines=True) + + consoleOutput, err = p.communicate() + print("Version values: %s" % consoleOutput.strip()) + + +class Tester: + + def __init__(self): + self.ignoreNoSolution = False + self.extra_opts_supported = self.list_options_if_supported( + ["xor", "autodisablegauss", "sql", "breakid", "predshort"]) + self.sol_parser = solution_parser(options) + self.sqlitedbfname = None + self.only_sampling = False + self.sampling_vars = [] + self.this_gauss_on = False + self.num_threads = 1 + self.novalgrind = options.novalgrind + + def list_options_if_supported(self, tocheck): + ret = [] + for elem in tocheck: + if self.option_supported(elem): + ret.append(elem) + + return ret + + def option_supported(self, option_name): + command = options.solver + command += " --hhelp" + p = subprocess.Popen( + command.rsplit(), stderr=subprocess.STDOUT, + stdout=subprocess.PIPE, + universal_newlines=True) + + consoleOutput, err = p.communicate() + + for l in consoleOutput.split("\n"): + tmp_option_name = "--" + option_name + if tmp_option_name in l: + return True + + return False + + def create_rnd_sched(self, string_list): + opts = string_list.split(",") + opts = [a.strip(" ") for a in opts] + opts = sorted(list(set(opts))) + if options.verbose: + print("available schedule options: %s" % opts) + + sched = [] + for _ in range(int(random.gammavariate(12, 0.7))): + sched.append(random.choice(opts)) + + # just so that XOR is really found and used, so we can fuzz it + if "autodisablegauss" in self.extra_opts_supported: + sched.append("occ-xor") + + return sched + + def rnd_schedule_all(self): + sched_opts = "scc-vrepl," + sched_opts += "sub-impl, intree-probe," + sched_opts += "sub-str-cls-with-bin, distill-cls, scc-vrepl, sub-impl," + sched_opts += "sub-cls-with-bin," + sched_opts += "str-impl, sub-str-cls-with-bin, distill-cls, scc-vrepl," + sched_opts += "occ-backw-sub-str, occ-backw-sub, occ-xor, occ-clean-implicit, occ-bve, occ-bva," + sched_opts += "renumber, must-renumber," + sched_opts += "card-find, breakid," + sched_opts += "occ-lit-rem, distill-bins, occ-resolv-subs,occ-rem-with-orgates" + + # type of schedule + cmd = "" + sched = self.create_rnd_sched(sched_opts) + sched = ",".join(sched) + + if sched != "": + cmd += "--schedule %s " % sched + + sched = ",".join(self.create_rnd_sched(sched_opts)) + if sched != "": + cmd += "--preschedule %s " % sched + + return cmd + + def random_options(self): + self.sqlitedbfname = None + cmd = " --zero-exit-status " + + # disable gauss when gauss is compiled in but asked not to be used + #if not self.this_gauss_on and "autodisablegauss" in self.extra_opts_supported: + #cmd += "--gauss 0 " + + cmd += "--presimp %d " % random.choice([1]*10+[0]) + if not options.gauss: + cmd += "--confbtwsimp %d " % random.choice([100, 1000]) + cmd += "--nextm %f " % random.choice([0.1, 0.01, 0.001]) + cmd += "--everylev1 %d " % random.choice([122, 1222, 12222]) + cmd += "--everylev2 %d " % random.choice([133, 1333, 14444]) + + if "breakid" in self.extra_opts_supported: + cmd += "--breakid %d " % random.choice([1]*10+[0]) + cmd += "--breakideveryn %d " % random.choice([1]*10+[3]) + cmd += "--breakidcls %d " % random.choice([0, 1, 2, 3, 10]+[50]*4) + cmd += "--breakidtime %d " % random.choice([10000]*5+[1]) + + if options.gauss: + sls = 0 + cmd += "--autodisablegauss %s " % random.choice([0]*15+[1]) + + # "Maximum number of matrixes to treat.") + cmd += "--maxnummatrices %s " % int(random.gammavariate(1.5, 20.0)) + + # SLS + cmd += "--sls %d " % random.choice([0, 1]) + cmd += "--slsgetphase %d " % random.choice([0, 0, 0, 1]) + cmd += "--yalsatmems %d " % random.choice([1, 2, 5]) + cmd += "--walksatruns %d " % random.choice([2, 15, 20]) + + # polarities + cmd += "--polar %s " % random.choice(["true", "false", "rnd", "auto"]) + + cmd += "--mustrenumber %d " % random.choice([0, 1]) + cmd += "--diffdeclevelchrono %d " % random.choice([1, random.randint(1, 1000), -1]) + cmd += "--bva %d " % random.choice([1, 1, 1, 0]) + cmd += "--bvaeveryn %d " % random.choice([1, random.randint(1, 20)]) + + if self.only_sampling: + cmd += "--onlysampling " + cmd += "--sampling " + cmd += ",".join(["%s" % x for x in self.sampling_vars]) + " " + + if random.choice([True, False]): + cmd += "--varsperxorcut %d " % random.randint(4, 6) + cmd += "--tern %d " % random.choice([0, 1]) + cmd += "--terntimelim %d " % random.choice([1, 10, 100]) + cmd += "--ternkeep %d " % random.choice([0, 0.001, 0.5, 300]) + cmd += "--terncreate %d " % random.choice([0, 0.001, 0.5, 300]) + cmd += "--locgmult %.12f " % random.gammavariate(0.5, 0.7) + cmd += "--varelimover %d " % random.gammavariate(1, 20) + cmd += "--memoutmult %0.12f " % random.gammavariate(0.05, 10) + cmd += "--verb %d " % random.choice([0, 0, 0, 0, 1, 2]) + cmd += "--detachxor %d " % random.choice([0, 1, 1, 1, 1]) + cmd += "--restart %s " % random.choice( + ["geom", "glue", "luby"]) + cmd += "--adjustglue %f " % random.choice([0, 0.5, 0.7, 1.0]) + cmd += "--gluehist %s " % random.randint(1, 500) + cmd += "--updateglueonanalysis %s " % random.randint(0, 1) + # cmd += "--clean %s " % random.choice(["size", "glue", "activity", + # "prconf"]) + cmd += "--occredmax %s " % random.randint(0, 100) + cmd += "--distill %s " % random.randint(0, 1) + cmd += "--recur %s " % random.randint(0, 1) + cmd += "--varelimcheckres %s " % random.randint(0, 1) + cmd += "--implicitmanip %s " % random.randint(0, 1) + cmd += "--occsimp %s " % random.randint(0, 1) + cmd += "--occirredmaxmb %s " % random.gammavariate(0.2, 5) + cmd += "--occredmaxmb %s " % random.gammavariate(0.2, 5) + cmd += "--implsubsto %s " % random.choice([0, 10, 1000]) + cmd += "--sync %d " % random.choice([100, 1000, 6000, 100000]) + cmd += "-m %0.12f " % random.gammavariate(0.1, 5.0) + cmd += "--maxsccdepth %d " % random.choice([0, 1, 100, 100000]) + + # more more minim + cmd += "--moremoreminim %d " % random.choice([1, 1, 1, 0]) + cmd += "--moremorealways %d " % random.choice([1, 1, 1, 0]) + + if self.this_gauss_on: + if random.randint(0,1000) < 10: + # Set maximum no. of rows for gaussian matrix." + cmd += "--maxmatrixrows %s " % int(random.gammavariate(1, 15.0)) + + # "Set minimum no. of rows for gaussian matrix. + cmd += "--minmatrixrows %s " % int(random.gammavariate(1, 15.0)) + + if "sql" in self.extra_opts_supported and random.randint(0, 3) > 0 and self.num_threads == 1: + cmd += "--sql 2 " + self.sqlitedbfname = unique_file("fuzz", ".sqlitedb") + cmd += "--sqlitedb %s " % self.sqlitedbfname + cmd += "--sqlitedboverwrite 1 " + cmd += "--cldatadumpratio %0.3f " % random.choice([0.9, 0.1, 0.7]) + + # the most buggy ones, don't turn them off much, please + if random.choice([1, 0, 0]): + opts = ["scc", "varelim", "strengthen", "intree", + "renumber", "savemem", "moreminim", "gates", + "schedsimp", "otfhyper"] + + if "xor" in self.extra_opts_supported: + opts.append("xor") + + for opt in opts: + if opt == "xor" and self.this_gauss_on: + continue + + cmd += "--%s %d " % (opt, random.choice([0, 1, 1, 1, 1])) + + cmd += self.rnd_schedule_all() + + return cmd + + def execute(self, fname, fname_frat=None, fixed_opts="", rnd_opts=None): + if os.path.isfile(options.solver) is not True: + print("Error: Cannot find CryptoMiniSat executable.Searched in: '%s'" % + options.solver) + print("Error code 300") + exit(300) + + for f in glob.glob("%s-debugLibPart*.output" % fname): + os.unlink(f) + + # construct command + command = "" + if not self.novalgrind and random.randint(1, options.valgrind_freq) == 1: + command += "valgrind -q --leak-check=full --error-exitcode=9 " + command += options.solver + if rnd_opts is None: + rnd_opts = self.random_options() + command += rnd_opts + if self.needDebugLib: + command += "--debuglib %s " % fname + command += "--threads %d " % self.num_threads + command += options.extra_options + " " + command += fixed_opts + " " + if fname is not None: + command += " %s " % fname + if fname_frat: + command += " %s " % fname_frat + + if options.verbose: + print("Executing before doalarm/pipes: %s " % command) + + # print time limit + if options.verbose: + print("CPU limit of parent (pid %d)" % os.getpid(), resource.getrlimit(resource.RLIMIT_CPU)) + + # if need time limit, then limit + err_fname = unique_file("err", ".out") + out_fname = unique_file("out", ".out") + + if self.num_threads == 1: + time_limit = partial(setlimits, options.maxtime) + else: + time_limit = None + + myalarm = "./doalarm -t real %d "% options.maxtime + toexec = myalarm + command + " 1>" + out_fname + " 2> " + err_fname + print("Executing: " + toexec) + retcode = os.system(toexec) + + # print time limit after child startup + #if options.verbose: + #print("CPU limit of parent (pid %d) after startup of child: %s secs" % + #(os.getpid(), resource.getrlimit(resource.RLIMIT_CPU))) + + # Get solver output + consoleOutput = "" + with open(out_fname, "r") as f: + for line in f: + consoleOutput += line + #retcode = p.returncode + #err_file.close() + with open(err_fname, "r") as err_file: + found_something = False + for line in err_file: + line = line.strip() + if line == "": + continue + + if options.verbose: + print("ERR line: ", line) + + # let's not care about leaks for the moment + if "LeakSanitizer: detected memory leaks" in line: + break + + # don't error out on issues related to UBSAN/ASAN + # of clang of other projects + noprob = ["std::_Ios_Fmtflags", "mzd.h", "lexical_cast.hpp", + "MersenneTwister.h", "boost::any::holder", "~~~~~", + "SUMMARY", "process memory map", "==========="] + + ok = False + for x in noprob: + if x in line: + ok = True + + if not ok: + found_something = True + errline = line + + if found_something: + print("Error line while executing: %s" % errline.strip()) + exit(-1) + + os.unlink(err_fname) + if self.sqlitedbfname is not None: + os.unlink(self.sqlitedbfname) + + if options.verbose: + print("CPU limit of parent (pid %d) after child finished executing: %s" % + (os.getpid(), resource.getrlimit(resource.RLIMIT_CPU))) + + os.unlink(out_fname) + return consoleOutput, retcode + + def check(self, fname, fname_frat=None, + checkAgainst=None, + fixed_opts="", + rnd_opts=None): + + consoleOutput = "" + if checkAgainst is None: + checkAgainst = fname + curr_time = time.time() + + # Do we need to solve the problem, or is it already solved? + consoleOutput, retcode = self.execute( + fname, fname_frat=fname_frat, + fixed_opts=fixed_opts, rnd_opts=rnd_opts) + + # if time was limited, we need to know if we were over the time limit + # and that is why there is no solution + diff_time = time.time() - curr_time + if diff_time > (options.maxtime - options.maxtimediff): + print("Too much time to solve, aborted!") + return None + + print("Within time limit: %.2f s" % diff_time) + print("filename: %s" % fname) + + if options.verbose: + print(consoleOutput) + + if retcode != 0: + print("Return code of CryptoMiniSat is not 0, it is: %d -- error!" % retcode) + exit(-1) + + # if library debug is set, check it + if (self.needDebugLib): + must_check_unsat = True + if options.gauss: + must_check_unsat = random.choice([False]*15+[True]) + self.sol_parser.check_debug_lib(checkAgainst, must_check_unsat) + + print("Checking console output...") + unsat, solution, _ = self.sol_parser.parse_solution_from_output( + consoleOutput.split("\n"), self.ignoreNoSolution) + + if not unsat: + if len(self.sampling_vars) != 0: + self.sol_parser.sampling_vars_solution_check(fname, self.sampling_vars, solution) + else: + self.sol_parser.test_found_solution(solution, checkAgainst) + + return + + # it's UNSAT, let's check with FRAT + if fname_frat: + toexec = "./frat-rs elab {fname_frat} {cnf} -v" + toexec = toexec.format(cnf=fname, fname_frat=fname_frat) + print("Checking with FRAT.. ", toexec) + p = subprocess.Popen(toexec.rsplit(), + stdout=subprocess.PIPE, + universal_newlines=True) + + consoleOutput2 = p.communicate()[0] + diff_time = time.time() - curr_time + + # find verification code + foundVerif = False + fratLine = "" + for line in consoleOutput2.split('\n'): + if len(line) >= 8: + if line[0:8] == "VERIFIED": + fratLine = line + foundVerif = True + + # Check whether we have found a verification code + if foundVerif is False: + print("verifier error! It says: %s" % consoleOutput2) + assert foundVerif, "Cannot find FRAT verification code!" + else: + print("OK, FRAT says: %s" % fratLine) + + if options.gauss: + if random.choice([True, True, True, True, False]): + print("NOT verifying with other solver, it's Gauss so too expensive") + return + + # check with other solver + ret = self.sol_parser.check_unsat(checkAgainst) + if ret is None: + print("Other solver time-outed, cannot check") + elif ret is True: + print("UNSAT verified by other solver") + else: + print("Grave bug: SAT-> UNSAT : Other solver found solution!!") + exit() + + def fuzz_test_one(self): + print("--- NORMAL TESTING ---") + self.num_threads = random.choice([1]+[random.randint(2,4)]) + self.num_threads = min(options.max_threads, self.num_threads) + self.this_gauss_on = "autodisablegauss" in self.extra_opts_supported + + # frat turns off a bunch of systems, like symmetry breaking so use it about 50% of time + self.frat = self.num_threads == 1 and (random.randint(0, 10) < 5) + + self.sqlitedbfname = None + self.only_sampling = random.choice([True, False, False, False, False]) and not self.frat + + if options.only_sampling: + self.frat = False + self.only_sampling = True + + if self.frat: + fuzzers = fuzzers_frat + elif options.gauss: + fuzzers = fuzzers_xor + else: + fuzzers = fuzzers_nofrat + fuzzer = random.choice(fuzzers) + + fname = unique_file("fuzzTest") + fname_frat = None + if self.frat: + fname_frat = unique_file("fuzzTest-frat") + + # create the fuzz file + cf = create_fuzz() + call, todel = cf.create_fuzz_file(fuzzer, fuzzers, fname) + print("calling %s" % call) + status = subprocess.call(call, shell=True) + if status != 0: + fuzzer_call_failed(fname) + + shuf_seed = random.randint(1, 100000) + fname_shuffled = unique_file("fuzzTest") + print("calling ./shuffle.py %s %s %s" % (fname, fname_shuffled, shuf_seed)) + shuffle_cnf(fname, fname_shuffled, shuf_seed) + os.unlink(fname) + fname = fname_shuffled + + if not self.frat and not self.only_sampling: + print("->Multipart test") + self.needDebugLib = True + interspersed_fname = unique_file("fuzzTest-interspersed") + seed_for_inters = random.randint(0, 1000000) + intersperse(fname, interspersed_fname, seed_for_inters) + print("Interspersed: ./intersperse.py %s %s %d" % (fname, + interspersed_fname, + seed_for_inters)) + os.unlink(fname) + else: + self.needDebugLib = False + interspersed_fname = fname + + # calculate sampling vars + self.sampling_vars = [] + if self.only_sampling: + max_vars = self.sol_parser.max_vars_in_file(fname) + assert max_vars > 0 + + self.sampling_vars = [] + myset = {} + for _ in range(random.randint(1, 50)): + x = random.randint(1, max_vars) + if x not in myset: + self.sampling_vars.append(x) + myset[x] = 1 + + # don't do it for 0-length sampling vars + if len(self.sampling_vars) == 0: + self.only_sampling = False + + self.check(fname=interspersed_fname, fname_frat=fname_frat) + + # remove temporary filenames + os.unlink(interspersed_fname) + if fname_frat: + os.unlink(fname_frat) + for name in todel: + os.unlink(name) + + def delete_file_no_matter_what(self, fname): + try: + os.unlink(fname) + except: + pass + +fuzzers_noxor = [ + ["../../build/tests/sha1-sat/sha1-gen --nocomment --attack preimage --rounds 20", + "--hash-bits", "--seed"], + ["../../build/tests/sha1-sat/sha1-gen --nocomment --attack preimage --zero " + "--message-bits 400 --rounds 8 --hash-bits 60", + "--seed"], + # ["build/cnf-fuzz-nossum"], + ["../../build/tests/cnf-utils/cnf-fuzz-biere"], + ["../../build/tests/cnf-utils/cnf-fuzz-biere"], + ["../../build/tests/cnf-utils/cnf-fuzz-biere"], + ["../../build/tests/cnf-utils/cnf-fuzz-biere"], + ["../../build/tests/cnf-utils/makewff -cnf 3 250 1080", "-seed"], + ["../../build/tests/cnf-utils/sgen4 -unsat -n 50", "-s"], + ["../../build/tests/cnf-utils//sgen4 -sat -n 50", "-s"], + ["../../utils/cnf-utils/cnf-fuzz-brummayer.py", "-s"], + ["../../utils/cnf-utils/cnf-fuzz-xor.py", "--seed"], + ["../../utils/cnf-utils/cnf-fuzz-xor.py", "--seed"], + ["../../utils/cnf-utils/cnf-fuzz-xor.py", "--seed"], + ["../../utils/cnf-utils/cnf-fuzz-xor.py", "--seed"], + ["../../utils/cnf-utils/multipart.py", "special"] +] + +fuzzers_xor = [ + ["../../utils/cnf-utils/xortester.py --varsmin 40", "--seed"], + ["../../utils/cnf-utils/xortester.py --varsmin 60", "--seed"], + ["../../utils/cnf-utils/xortester.py --varsmin 80", "--seed"], + ["../../utils/cnf-utils/xortester.py --varsmin 100", "--seed"], + ["../../utils/cnf-utils/xortester.py --varsmin 200", "--seed"], + ["../../utils/cnf-utils/spacer_test.py", "--seed"], + ["../../build/tests/sha1-sat/sha1-gen --xor --attack preimage --rounds 21", + "--hash-bits", "--seed"], +] + + +if __name__ == "__main__": + if not os.path.isdir("out"): + print("Directory for outputs, 'out' not present, creating it.") + os.mkdir("out") + + # parse options + parser = set_up_parser() + (options, args) = parser.parse_args() + if options.valgrind_freq <= 0: + print("Valgrind Frequency must be at least 1") + exit(-1) + + fuzzers_frat = fuzzers_noxor + fuzzers_nofrat = fuzzers_noxor + fuzzers_xor + + print_version() + tester = Tester() + tester.needDebugLib = False + num = 0 + rnd_seed = options.fuzz_seed_start + if rnd_seed is None: + rnd_seed = random.randint(0, 1000*1000*100) + + while True: + toexec = "./fuzz_test.py --fuzzlim 1 --seed %d " % rnd_seed + if not options.novalgrind: + toexec += "--dovalgrind " + if options.valgrind_freq: + toexec += "--valgrindfreq %d " % options.valgrind_freq + if options.gauss: + toexec += "--gauss " + if options.only_sampling: + toexec += "--sampling " + toexec += "-m %d " % options.max_threads + toexec += "-t %d " % options.maxtime + + print("") + print("") + print("--> To re-create fuzz-test below: %s" % toexec) + + random.seed(rnd_seed) + tester.fuzz_test_one() + rnd_seed += 1 + num += 1 + if options.fuzz_test_lim is not None and num >= options.fuzz_test_lim: + exit(0) diff --git a/cryptominisat/cppsrc/scripts/fuzz/intersperse.py b/cryptominisat/cppsrc/scripts/fuzz/intersperse.py new file mode 100755 index 00000000..eabb76d8 --- /dev/null +++ b/cryptominisat/cppsrc/scripts/fuzz/intersperse.py @@ -0,0 +1,31 @@ +#!/usr/bin/env python3 +# -*- coding: utf-8 -*- + +# Copyright (C) 2009-2020 Authors of CryptoMiniSat, see AUTHORS file +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; version 2 +# of the License. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +# 02110-1301, USA. + +from __future__ import with_statement # Required in 2.5 +from __future__ import print_function +import debuglib +import sys + +if len(sys.argv) != 4: + print("You must give 3 arguments: input file, output file, seed") + + +debuglib.intersperse(sys.argv[1], sys.argv[2], sys.argv[3]) +print("OK, output in %s" % sys.argv[2]) diff --git a/cryptominisat/cppsrc/scripts/fuzz/shuffle.py b/cryptominisat/cppsrc/scripts/fuzz/shuffle.py new file mode 100755 index 00000000..0bc980be --- /dev/null +++ b/cryptominisat/cppsrc/scripts/fuzz/shuffle.py @@ -0,0 +1,31 @@ +#!/usr/bin/env python3 +# -*- coding: utf-8 -*- + +# Copyright (C) 2009-2020 Authors of CryptoMiniSat, see AUTHORS file +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; version 2 +# of the License. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +# 02110-1301, USA. + +from __future__ import with_statement # Required in 2.5 +from __future__ import print_function +import debuglib +import sys + +if len(sys.argv) != 4: + print("You must give 3 arguments: input file, output file, seed") + + +debuglib.shuffle(sys.argv[1], sys.argv[2], sys.argv[3]) +print("OK, output in %s" % sys.argv[2]) diff --git a/cryptominisat/cppsrc/scripts/fuzz/verifier.py b/cryptominisat/cppsrc/scripts/fuzz/verifier.py new file mode 100755 index 00000000..407a394f --- /dev/null +++ b/cryptominisat/cppsrc/scripts/fuzz/verifier.py @@ -0,0 +1,593 @@ +#!/usr/bin/env python3 +# -*- coding: utf-8 -*- + +# Copyright (C) 2009-2020 Authors of CryptoMiniSat, see AUTHORS file +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; version 2 +# of the License. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + +from __future__ import with_statement # Required in 2.5 +from __future__ import print_function +import optparse +import gzip +import re +import fnmatch +from xor_to_cnf_class import * +from debuglib import * +import subprocess +import os +import stat +import time +import resource +from functools import partial + + +def unique_file(fname_begin, fname_end=".cnf"): + counter = 1 + while 1: + fname = "out/" + fname_begin + '_' + str(counter) + fname_end + try: + fd = os.open( + fname, os.O_CREAT | os.O_EXCL, stat.S_IREAD | stat.S_IWRITE) + os.fdopen(fd).close() + return fname + except OSError: + pass + + counter += 1 + if counter > 300: + print("Cannot create unique_file, last try was: %s" % fname) + exit(-1) + + +def setlimits(maxtime): + # sys.stdout.write("Setting resource limit in child (pid %d): %d s\n" % + # (os.getpid(), maxtime)) + resource.setrlimit(resource.RLIMIT_CPU, (maxtime, maxtime)) + + +class solution_parser: + def __init__(self, options): + self.options = options + + @staticmethod + def test_found_solution(solution, fname, debugLibPart=None): + if debugLibPart is None: + print("Verifying solution for CNF file %s" % fname) + else: + print("Verifying solution for CNF file %s, part %d" % + (fname, debugLibPart)) + + if fnmatch.fnmatch(fname, '*.gz'): + f = gzip.open(fname, "r") + else: + f = open(fname, "r") + clauses = 0 + thisDebugLibPart = 0 + + for line in f: + line = line.rstrip() + + # skip empty lines + if len(line) == 0: + continue + + # count debug lib parts + if line[0] == 'c' and "Solver::solve" in line: + thisDebugLibPart += 1 + + # if we are over debugLibPart, exit + if debugLibPart is not None and thisDebugLibPart >= debugLibPart: + f.close() + return + + # check solution against clause + try: + if line[0] != 'c' and line[0] != 'p': + if line[0] != 'x': + solution_parser._check_regular_clause(line, solution) + else: + assert line[0] == 'x', "Line must start with p, c, v or x" + solution_parser._check_xor_clause(line, solution) + + clauses += 1 + except: + if debugLibPart is not None: + print("--> Error in part: %s. We are reading up to and including part: %s" + % (thisDebugLibPart, debugLibPart-1)) + raise + + f.close() + print("Verified %d original xor®ular clauses" % clauses) + + def sampling_vars_solution_check(self, fname, sampling_vars, solution): + assert len(sampling_vars) > 0 + a = XorToCNF() + tmpfname = unique_file("tmp_for_xor_to_cnf_convert") + a.convert(fname, tmpfname, len(sampling_vars)) + + with open(tmpfname, "a") as f: + # NOTE: the "p cnf..." header will be wrong + for i in sampling_vars: + if i not in solution: + print("ERROR: solution does not contain sampling var %d" % i) + print("Sampling vars were: %s" % sampling_vars) + exit(-1) + + if solution[i]: + f.write("%d 0\n" % i) + else: + f.write("-%d 0\n" % i) + + print("-> added partial solution to temporary CNF file %s" % tmpfname) + + # execute with the other solver + toexec = "../../build/utils/lingeling-ala/lingeling %s" % tmpfname + print("sampling check -- solving with other solver: %s" % toexec) + curr_time = time.time() + try: + p = subprocess.Popen(toexec.rsplit(), + stdout=subprocess.PIPE, + preexec_fn=partial(setlimits, self.options.maxtime), + universal_newlines=True) + except OSError: + print("ERROR: Lingeing didn't run... did you install it? It should be in the path as `lingeling`") + raise + + consoleOutput2 = p.communicate()[0] + os.unlink(tmpfname) + + # if other solver was out of time, then we can't say anything + diff_time = time.time() - curr_time + if diff_time > self.options.maxtime - self.options.maxtimediff: + print("Other solver: too much time to solve, aborted!") + return None + + # extract output from the other solver + print("Checking other solver output...") + otherSolverUNSAT, _, _ = self.parse_solution_from_output( + consoleOutput2.split("\n")) + + # check if the other solver finds a solution with the sampling vars + # set as per partial solution returned + if otherSolverUNSAT is True: + print("ERROR; The other solver did NOT find a solution with the partial solution given") + exit(-1) + return False + + print("OK, other solver found a solution using the partial solution") + + return True + + def check_unsat(self, fname): + a = XorToCNF() + tmpfname = unique_file("tmp_for_xor_to_cnf_convert") + a.convert(fname, tmpfname) + + # execute with the other solver + toexec = "../../build/utils/lingeling-ala/lingeling %s" % tmpfname + print("UNSAT check -- solving with other solver: %s" % toexec) + curr_time = time.time() + try: + p = subprocess.Popen(toexec.rsplit(), + stdout=subprocess.PIPE, + preexec_fn=partial(setlimits, self.options.maxtime), + universal_newlines=True) + except OSError: + print("ERROR: Lingeling didn't run... did you install it? It should be in the path as `lingeling`") + raise + + consoleOutput2 = p.communicate()[0] + os.unlink(tmpfname) + + # if other solver was out of time, then we can't say anything + diff_time = time.time() - curr_time + if diff_time > self.options.maxtime - self.options.maxtimediff: + print("Other solver: too much time to solve, aborted!") + return None + + # extract output from the other solver + print("Checking other solver output...") + otherSolverUNSAT, otherSolverSolution, _ = self.parse_solution_from_output( + consoleOutput2.split("\n")) + + # check if the other solver agrees with us + return otherSolverUNSAT + + def check_debug_lib(self, fname, must_check_unsat=True): + largestPart = self._find_largest_debuglib_part(fname) + for debugLibPart in range(1, largestPart + 1): + fname_debug = "%s-debugLibPart%d.output" % (fname, debugLibPart) + print("Checking debug lib part %s -- %s " % (debugLibPart, fname_debug)) + + if (os.path.isfile(fname_debug) is False): + print("Error: Filename to be read '%s' is not a file!" % fname_debug) + exit(-1) + + # take file into mem + f = open(fname_debug, "r") + text = f.read() + output_lines = text.splitlines() + f.close() + + unsat, solution, conflict = self.parse_solution_from_output(output_lines) + assumps = self._get_assumps(fname, debugLibPart) + if unsat is False: + print("debugLib is SAT") + self._check_assumps_inside_solution(assumps, solution) + self.test_found_solution(solution, fname, debugLibPart) + else: + print("debugLib is UNSAT") + if must_check_unsat: + assert conflict is not None, "debugLibPart must create a conflict in case of UNSAT" + self._check_assumps_inside_conflict(assumps, conflict) + tmpfname = unique_file("tmp_for_extract_libpart") + self._extract_lib_part(fname, debugLibPart, assumps, tmpfname) + + # check with other solver + ret = self.check_unsat(tmpfname) + if ret is None: + print("Cannot check, other solver took too much time") + elif ret is True: + print("UNSAT verified by other solver") + else: + print("Grave bug: SAT-> UNSAT : Other solver found solution!!") + exit(-1) + os.unlink(tmpfname) + + self.remove_debuglib_files(fname) + + def remove_debuglib_files(self, fname): + #removing debuglib files + largestPart = self._find_largest_debuglib_part(fname) + for debugLibPart in range(1, largestPart + 1): + fname_debug = "%s-debugLibPart%d.output" % (fname, debugLibPart) + os.unlink(fname_debug) + + @staticmethod + def parse_solution_from_output(output_lines, ignoreNoSolution=False): + if len(output_lines) == 0: + print("Error! SAT solver output is empty!") + print("output lines: %s" % output_lines) + exit(-1) + + # solution will be put here + satunsatfound = False + vlinefound = False + solution = {} + conflict = None + + # parse in solution + for line in output_lines: + # skip comment + if re.match('^conflict ', line): + line = line.strip().split()[1:] + conflict = [int(elem) for elem in line] + continue + + if (re.match('^c ', line)): + continue + + # solution + if (re.match('^s ', line)): + if (satunsatfound): + print("ERROR: solution twice in solver output!") + exit(400) + + if 'UNSAT' in line: + unsat = True + satunsatfound = True + continue + + if 'SAT' in line: + unsat = False + satunsatfound = True + continue + + print("ERROR: line starts with 's' but no SAT/UNSAT on line") + exit(400) + + # parse in solution + if (re.match('^v ', line)): + vlinefound = True + myvars = line.split(' ') + for var in myvars: + var = var.strip() + if var == "" or var == 'v': + continue + if (int(var) == 0): + break + intvar = int(var) + solution[abs(intvar)] = (intvar >= 0) + continue + + if (line.strip() == ""): + continue + + print("Error! SAT solver output contains a line that is neither 'v' nor 'c' nor 's'!") + print("Line is:", line.strip()) + exit(-1) + + # print("Parsed values:", solution) + + if (ignoreNoSolution is False and + (satunsatfound is False or ( + unsat is False and vlinefound is False))): + print("Error: Cannot find line starting with 's' or 'v' in output!") + print(output_lines) + print("Error code 500") + exit(-1) + + if (ignoreNoSolution is True and + (satunsatfound is False or ( + unsat is False and vlinefound is False))): + print("Probably timeout, since no solution printed. Could, of course, be segfault/assert fault, etc.") + print("Making it look like an UNSAT, so no checks!") + return (True, []) + + if (satunsatfound is False): + print("Error: Cannot find if SAT or UNSAT. Maybe didn't finish running?") + print(output_lines) + print("Error code 500") + exit(-1) + + if (unsat is False and vlinefound is False): + print("Error: Solution is SAT, but no 'v' line") + print (output_lines) + print("Error code 500") + exit(-1) + + return unsat, solution, conflict + + def _extract_lib_part(self, fname, debug_num, assumps, tofile): + fromf = open(fname, "r") + thisDebugLibPart = 0 + maxvar = 0 + numcls = 0 + for line in fromf: + line = line.strip() + + # ignore empty strings and headers + if not line or line[0] == "p": + continue + + # process (potentially special) comments + if line[0] == "c": + if "Solver::solve" in line: + thisDebugLibPart += 1 + + continue + + # break out if we reached the debug lib part + if thisDebugLibPart >= debug_num: + break + + # count clauses and get max var number + numcls += 1 + maxvar = max(maxvar, get_max_var_from_clause(line)) + + fromf.close() + + # now we can create the new CNF file + fromf = open(fname, "r") + tof = open(tofile, "w") + tof.write("p cnf %d %d\n" % (maxvar, numcls + len(assumps))) + + thisDebugLibPart = 0 + for line in fromf: + line = line.strip() + # skip empty lines and headers + if not line or line[0] == "p": + continue + + # parse up special header + if line[0] == "c": + if "Solver::solve" in line: + thisDebugLibPart += 1 + + continue + + # break out if we reached the debug lib part + if thisDebugLibPart >= debug_num: + break + + tof.write(line + '\n') + + # add assumptions + for lit in assumps: + tof.write("%d 0\n" % lit) + + fromf.close() + tof.close() + + def _get_assumps(self, fname, debugLibPart): + f = open(fname, "r") + + thispart = 0 + solveline = None + for line in f: + if "Solver::solve" in line: + thispart += 1 + if thispart == debugLibPart: + solveline = line + break + f.close() + + assert solveline is not None + ret = re.match("c.*Solver::solve\((.*)\)", solveline) + assert ret is not None + assumps = ret.group(1).strip().split() + assumps = [int(x) for x in assumps] + + print("Assumptions: ", assumps) + return assumps + + def _check_assumps_inside_conflict(self, assumps, conflict): + for lit in conflict: + if -1 * lit not in assumps: + print("ERROR: Final conflict contains %s but assumps is %s" %(conflict, assumps)) + print("ERROR: lit ", lit, " is in conflict but its inverse is not is assumps!") + exit(-100) + + print("OK, final conflict only contains elements from assumptions") + + def _check_assumps_inside_solution(self, assumps, solution): + for lit in assumps: + var = abs(lit) + val = lit > 0 + if var in solution: + if solution[var] != val: + print("Solution pinted has literal %s but assumptions contained the inverse: '%s'" % (-1 * lit, assumps)) + exit(-100) + + print("OK, all assumptions inside solution") + + def _find_largest_debuglib_part(self, fname): + largestPart = 0 + dirList2 = os.listdir("out/.") + fname_no_out = fname.replace("out/", "") + for fname_debug in dirList2: + if fnmatch.fnmatch(fname_debug, "%s-debugLibPart*.output" % fname_no_out): + largestPart += 1 + + return largestPart + + @staticmethod + def max_vars_in_file(fname): + maxvar = 0 + with open(fname, "r") as f: + for line in f: + line = line.strip() + + # ignore comments + if not line or line[0] == "c" or line[0] == 'p': + continue + + # calculate max variable + maxvar = max(maxvar, get_max_var_from_clause(line)) + + return maxvar + + @staticmethod + def _check_regular_clause(line, solution): + lits = line.split() + for lit in lits: + numlit = int(lit) + if numlit == 0: + break + + if abs(numlit) not in solution: + continue + + if solution[abs(numlit)] ^ (numlit < 0): + return True + + # print not set vars + for lit in lits: + numlit = int(lit) + if numlit == 0: + break + + if abs(numlit) not in solution: + print("var %d in XOR clause not set" % abs(numlit)) + + #print("Every other var set to FALSE") + #print("Orig clause in DIMACS: ", lits) + print("Error: clause '%s' not satisfied." % line.strip()) + raise NameError("Error: clause '%s' not satisfied." % line) + return False + + @staticmethod + def _check_xor_clause(line, solution): + line = line.lstrip('x') + lits = line.split() + final = False + for lit in lits: + numlit = int(lit) + if numlit != 0: + if abs(numlit) not in solution: + raise NameError("Error: var %d not solved, but referred to in a xor-clause of the CNF" % abs(numlit)) + final ^= solution[abs(numlit)] + final ^= numlit < 0 + if final is False: + print("Error: xor-clause '%s' not satisfied." % line.strip()) + raise NameError("Error: xor-clause '%s' not satisfied." % line) + + return final + + +def parse_arguments(): + class PlainHelpFormatter(optparse.IndentedHelpFormatter): + + def format_description(self, description): + if description: + return description + "\n" + else: + return "" + + usage = """usage: %prog solution cnf + +For example: +%prog my_solution_file.out my_problem.cnf.gz""" + parser = optparse.OptionParser(usage=usage, formatter=PlainHelpFormatter()) + parser.add_option("--verbose", "-v", action="store_true", + default=False, dest="verbose", help="Be more verbose") + parser.add_option("--tout", "-t", dest="maxtime", type=int, default=100, + help="Max time to run. Default: %default") + parser.add_option("--textra", dest="maxtimediff", type=int, default=10, + help="Extra time on top of timeout for processing." + " Default: %default") + # parse options + options, args = parser.parse_args() + return options, args + +if __name__ == "__main__": + options, args = parse_arguments() + print("Options are:", options) + print("args are:", args) + if len(args) != 2: + print("ERROR: You must give exactly two parameters, " + "one SOLUTION and one CNF") + print("You gave {n} parameters".format(**{"n": len(args)})) + exit(-1) + + sol_file = args[0] + cnf_file = args[1] + print("Verifying CNF file '{cnf}' against solution in file '{sol}'".format( + **{"cnf": cnf_file, "sol": sol_file})) + + print("Checking debug libs...") + sol_parser = solution_parser(options) + sol_parser.check_debug_lib(cnf_file) + + print("Checking console output...") + sol = {} + with open(sol_file) as f: + dat = f.read() + + dat = dat.split("\n") + unsat, solution, _ = sol_parser.parse_solution_from_output(dat) + if not unsat: + sol_parser.test_found_solution(solution, cnf_file) + exit(0) + + # check with other solver + ret = sol_parser.check_unsat(cnf_file) + if ret is None: + print("Other solver time-outed, cannot check") + elif ret is True: + print("UNSAT verified by other solver") + else: + print("Grave bug: SAT-> UNSAT : Other solver found solution!!") + exit(-1) diff --git a/cryptominisat/cppsrc/scripts/fuzz/verifier_test.py b/cryptominisat/cppsrc/scripts/fuzz/verifier_test.py new file mode 100755 index 00000000..fc6b4d5f --- /dev/null +++ b/cryptominisat/cppsrc/scripts/fuzz/verifier_test.py @@ -0,0 +1,83 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- + +# Copyright (C) 2009-2020 Authors of CryptoMiniSat, see AUTHORS file +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; version 2 +# of the License. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + +from __future__ import with_statement # Required in 2.5 +from __future__ import print_function + +from verifier import * +import unittest + + +class Map(dict): + """ + Example: + m = Map({'first_name': 'Eduardo'}, last_name='Pool', age=24, sports=['Soccer']) + """ + def __init__(self, *args, **kwargs): + super(Map, self).__init__(*args, **kwargs) + for arg in args: + if isinstance(arg, dict): + for k, v in arg.items(): + self[k] = v + + if kwargs: + for k, v in kwargs.iteritems(): + self[k] = v + + def __getattr__(self, attr): + return self.get(attr) + + +class TestVerifier(unittest.TestCase): + def setUp(self): + options = Map({"verbose": False, "maxtime": 60, "maxtimediff": 160}) + self.s = solution_parser(options) + + def test_sat_cl(self): + self.assertTrue(self.s._check_regular_clause("1 2 3", {1: True})) + self.assertTrue(self.s._check_regular_clause("1 2 3", {2: True})) + self.assertTrue(self.s._check_regular_clause("1 2 -3", {3: False})) + + def test_unsat_cl(self): + self.assertRaises(NameError, self.s._check_regular_clause, "-1 2 3", {1: True}) + self.assertRaises(NameError, self.s._check_regular_clause, "-1 2 3", {}) + self.assertRaises(NameError, self.s._check_regular_clause, "-1 2 3 0", {}) + self.assertRaises(NameError, self.s._check_regular_clause, "1 2 -3 0", {0: True}) + self.assertRaises(NameError, self.s._check_regular_clause, "1 2 3", {1: False, 2: False, 3: False}) + self.assertRaises(NameError, self.s._check_regular_clause, "-1 -2 -3", {1: True, 2: True, 3: True}) + + def test_sat_xcl(self): + self.assertTrue(NameError, self.s._check_xor_clause("x1 2 3", {1: True, 2: False, 3: False})) + self.assertTrue(NameError, self.s._check_xor_clause("x1 2 3 0", {1: True, 2: False, 3: False})) + + def test_unsat_xcl(self): + self.assertRaises(NameError, self.s._check_xor_clause, "x1 2 3", {1: True}) + self.assertRaises(NameError, self.s._check_xor_clause, "x1 2 3", {1: False, 2: False, 3: False}) + + def test_sol_parse_sat(self): + unsat, s, _ = self.s.parse_solution_from_output(["s SAT", "v 1 2 3 0"]) + self.assertEqual(s, {1: True, 2: True, 3: True}) + + def test_sol_parse_unsat(self): + unsat, _, _ = self.s.parse_solution_from_output(["s UNSAT\n"]) + self.assertTrue(unsat) + + +if __name__ == '__main__': + unittest.main() diff --git a/cryptominisat/cppsrc/scripts/fuzz/xor_to_cnf_class.py b/cryptominisat/cppsrc/scripts/fuzz/xor_to_cnf_class.py new file mode 100644 index 00000000..4475b110 --- /dev/null +++ b/cryptominisat/cppsrc/scripts/fuzz/xor_to_cnf_class.py @@ -0,0 +1,240 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- + +# Copyright (C) 2009-2020 Authors of CryptoMiniSat, see AUTHORS file +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; version 2 +# of the License. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + +from __future__ import print_function +import re + + +class XorToCNF: + def __init__(self): + self.cutsize = 4 + + def get_max_var(self, clause): + maxvar = 0 + + tmp = clause.strip() + if len(tmp) == 0: + return 0 + + assert re.search(r'^x? *-?\d+', tmp) + + if tmp[0] == 'x': + tmp = tmp[1:] + + for lit in tmp.split(): + var = abs(int(lit)) + maxvar = max(var, maxvar) + + return maxvar + + def convert(self, infilename, outfilename, num_extra_cls=0): + assert isinstance(self.cutsize, int) + if self.cutsize <= 2: + print("ERROR: The cut size MUST be larger or equal to 3") + exit(-1) + + maxvar, numcls, extravars_needed, extracls_needed = self.get_stats(infilename) + fout = open(outfilename, "w") + fout.write("p cnf %d %d\n" % + (maxvar + extravars_needed, + numcls + extracls_needed + num_extra_cls)) + fin = open(infilename, "r") + atvar = maxvar + for line in fin: + line = line.strip() + + # skip empty line + if len(line) == 0: + continue + + # skip header and comments + if line[0] == 'c' or line[0] == 'p': + continue + + if line[0] == 'x': + # convert XOR to normal(s) + xorclauses, atvar = self.cut_up_xor_to_n(line, atvar) + for xorcl in xorclauses: + cls = self.xor_to_cnf_simple(xorcl) + for cl in cls: + fout.write(cl + "\n") + else: + # simply print normal clause + fout.write(line + "\n") + + assert atvar == maxvar + extravars_needed + fout.close() + fin.close() + + def popcount(self, x): + return bin(x).count('1') + + def parse_xor(self, xorclause): + assert re.search(r'^x( *-?\d+ )*0$', xorclause) + + tmp = xorclause[1:] + lits = [int(elem) for elem in tmp.split()] + assert lits[len(lits)-1] == 0 + + # remove last element, the 0 + lits = lits[:len(lits)-1] + + return lits + + def xor_to_cnf_simple(self, xorclause, equals=True): + assert equals is True or equals is False + if equals is True: + equals = 1 + else: + equals = 0 + + lits = self.parse_xor(xorclause) + + # empty XOR clause is TRUE, so is NOT an empty clause (i.e. UNSAT) + if len(lits) == 0: + return [] + + ret = [] + for i in range(2**(len(lits))): + # only the ones we need + cls = "" + if self.popcount(i) % 2 == equals: + continue + + for at in range(len(lits)): + if ((i >> at) & 1) == 0: + cls += "%d " % lits[at] + else: + cls += "%d " % (-1*lits[at]) + + cls += "0" + ret.append(cls) + + return ret + + def cut_up_xor_to_n(self, xorclause, oldmaxvar): + assert self.cutsize > 2 + + lits = self.parse_xor(xorclause) + xors = [] + + # xor clause that doesn't need to be cut up + if len(lits) <= self.cutsize: + retcl = "x" + for lit in lits: + retcl += "%d " % lit + retcl += "0" + return [[retcl], oldmaxvar] + + at = 0 + newmaxvar = oldmaxvar + while(at < len(lits)): + + # until when should we cut? + until = min(at + self.cutsize-1, len(lits)) + + # if in the middle, don't add so much + if at > 0 and until < len(lits): + until -= 1 + + thisxor = "x" + for i2 in range(at, until): + thisxor += "%d " % lits[i2] + + # add the extra variables + if at == 0: + # beginning, add only one + thisxor += "%d 0" % (newmaxvar+1) + newmaxvar += 1 + elif until == len(lits): + # end, only add the one we already made + thisxor += "-%d 0" % (newmaxvar) + else: + thisxor += "-%d %d 0" % (newmaxvar, newmaxvar+1) + newmaxvar += 1 + + xors.append(thisxor) + + # move along where we are at + at = until + + return [xors, newmaxvar] + + def num_extra_vars_cls_needed(self, numlits): + def cls_for_plain_xor(numlits): + return 2**(numlits-1) + + varsneeded = 0 + clsneeded = 0 + + at = 0 + while(at < numlits): + # at the beginning + if at == 0: + if numlits > self.cutsize: + at += self.cutsize-1 + varsneeded += 1 + clsneeded += cls_for_plain_xor(self.cutsize) + else: + at = numlits + clsneeded += cls_for_plain_xor(numlits) + + # in the middle + elif at + (self.cutsize-1) < numlits: + at += self.cutsize-2 + varsneeded += 1 + clsneeded += cls_for_plain_xor(self.cutsize) + # at the end + else: + clsneeded += cls_for_plain_xor(numlits-at+1) + at = numlits + + return [varsneeded, clsneeded] + + def get_stats(self, infilename): + infile = open(infilename, "r") + + maxvar = 0 + numcls = 0 + extravars_needed = 0 + extracls_needed = 0 + for line in infile: + line = line.strip() + + # empty line, skip + if len(line) == 0: + continue + + # header or comment + if line[0] == 'p' or line[0] == 'c': + continue + + # get max var + maxvar = max(self.get_max_var(line), maxvar) + + if line[0] == 'x': + e_var, e_clause = self.num_extra_vars_cls_needed(len(self.parse_xor(line))) + extravars_needed += e_var + extracls_needed += e_clause + else: + numcls += 1 + + infile.close() + + return [maxvar, numcls, extravars_needed, extracls_needed] diff --git a/cryptominisat/cppsrc/scripts/gen_xor_pb.py b/cryptominisat/cppsrc/scripts/gen_xor_pb.py new file mode 100755 index 00000000..5d0a1dc9 --- /dev/null +++ b/cryptominisat/cppsrc/scripts/gen_xor_pb.py @@ -0,0 +1,50 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- + +# Copyright (C) 2009-2020 Authors of CryptoMiniSat, see AUTHORS file +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; version 2 +# of the License. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +# 02110-1301, USA. + + +from __future__ import with_statement # Required in 2.5 +from __future__ import print_function +import sys +import random + +if len(sys.argv) !=4: + print("ERROR: You must give 3 arguments: vars, Numxors and K") + exit(-1) + +vs = int(sys.argv[1]) +numxors = int(sys.argv[2]) +k = int(sys.argv[3]) + +print("c Will generate %d variable, %d XORs and then all variables's values sum will be at least %d" % (vs, numxors, k)) + +for i in range(numxors): + thisxor = [] + for x in range(vs): + if random.choice([True, False]): + thisxor.append(x) + print("c XOR:", thisxor) + + out = "x" + if random.choice([True, False]): + out += "-" + for x in thisxor: + out += "%d " % (x+1) + out+="0\nc " + print(out) diff --git a/cryptominisat/cppsrc/scripts/lpn-gen.py b/cryptominisat/cppsrc/scripts/lpn-gen.py new file mode 100755 index 00000000..4648ccb8 --- /dev/null +++ b/cryptominisat/cppsrc/scripts/lpn-gen.py @@ -0,0 +1,233 @@ +#!/usr/bin/env python3 +# -*- coding: utf-8 -*- + +# Copyright (C) 2009-2020 Authors of CryptoMiniSat, see AUTHORS file +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; version 2 +# of the License. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +# 02110-1301, USA. + +import optparse +import random +import os + +class PlainHelpFormatter(optparse.IndentedHelpFormatter): + + def format_description(self, description): + if description: + return description + "\n" + else: + return "" + + +usage = "usage: %prog [options] " +desc = """Generates an LPN problem +""" + + +def set_up_parser(): + parser = optparse.OptionParser(usage=usage, description=desc, + formatter=PlainHelpFormatter()) + + parser.add_option("--verbose", "-v", action="store_true", default=False, + dest="verbose", help="Print more output") + + # for fuzz-testing + parser.add_option("--seed", "-s", dest="seed", default=None, + help="Genereate with this seed", type=int) + parser.add_option("-n", dest="n", default=None, type=int, + help="Functiion width") + parser.add_option("--pb", dest="pb", default=False, action="store_true", + help="Functiion width") + parser.add_option("-m", dest="samples", default=None, type=int, + help="Number of samples") + parser.add_option("--noise", dest="noise", default=0.1, type=float, + help="Ratio of noise") + parser.add_option("--tolerance", "-t", dest="tolerance", default=None, type=int, + help="Tolerance for error. It is set AUTOMATICALLY if you don't set it here. It will be set to EXACTLY the actual error, so you will get a SAT instance.") + #parser.add_option("--autotolerance", dest="autotolerance", action="store_true", default=False, + #help="Set tolerance automatically to PERFECT match. Default.") + + return parser + + + +if __name__ == "__main__": + # parse opts + parser = set_up_parser() + (opts, args) = parser.parse_args() + + if opts.seed is None or opts.n is None or opts.samples is None or opts.noise is None: + print("ERROR: You MUST give all of: --seed, -n, -m") + exit(-1) + + print("c Seed: %3d" % opts.seed) + print("c n: %3d" % opts.n) + print("c Samples: %3d" % opts.samples) + print("c Noise: %-3.2f" % opts.noise) + random.seed(opts.seed) + + # y[i] = set randomly [[output]] + # x[i] = data that SAT solver can manipulate + # val[x][y] = x[i]*y[i] + + + fun = [] + for i in range(opts.n): + fun.append(random.randint(0, 1)) + + inputs = [] + for i in range(opts.samples): + inp = [] + for i2 in range(opts.n): + inp.append(random.randint(0, 1)) + inputs.append(inp) + + real_outputs = [] + for i in range(opts.samples): + out = 0 + for a,b in zip(fun, inputs[i]): + out ^= a*b + real_outputs.append(out) + + num_incorrect_eqs = 0 + correct_eqs = [] + outputs = [] + for i in range(opts.samples): + out = real_outputs[i] + if random.random() < opts.noise: + out = out ^ 1 + num_incorrect_eqs+=1 + correct_eqs.append(False) + else: + correct_eqs.append(True) + outputs.append(out) + + print("c Tncorrect eqs: %3d" %num_incorrect_eqs) + tolerance=None + if opts.tolerance is None: + tolerance = num_incorrect_eqs + print("c -------------------- setting tolerance AUTOMATICALLY, since '--tolerance' was not set") + else: + tolerance = opts.tolerance + print("c Tolerance: %3d" % tolerance) + + # print + print("c equations. FUN[i2]*INPUT[i][i2]") + for i in range(opts.samples): + toprint = "" + for i2 in range(opts.n): + toprint += "c %d" % fun[i2] + toprint += "*" + toprint += "%d" % inputs[i][i2] + if i2 != opts.n-1: + toprint += " + " + toprint += " = %d" % outputs[i] + toprint += " -- correct: %s" % correct_eqs[i] + print(toprint) + + + # variable table (sequential): + # n: function we need to figure out + # inputs -- n+n+n...n exactly opts.samples times. Total: opts.samples*opts.n + # outputs -- opts.samples + # helper functions come here + + v = 1 + vars_fun = [] + for _ in range(opts.n): + vars_fun.append(v) + v+=1 + + #vars_inputs = [] + #for _ in range(opts.samples): + #tmp = [] + #for _ in range(opts.n): + #tmp.append(v) + #v+=1 + #vars_inputs.append(tmp) + + vars_noise = [] + for _ in range(opts.samples): + vars_noise.append(v) + v+=1 + + #################### + ####### Generate CNF + #################### + + if opts.pb: + print("* #variable= %d #constraint= 1" % (opts.n+opts.samples)) + + # compute outputs + for i in range(opts.samples): + vs = [] + for i2 in range(opts.n): + # v = inputs[i][i2] * fun[i] + if inputs[i][i2] == 1: + vs.append(vars_fun[i2]) + + out = "x " + out_pb = "* xor " + for x in vs: + out += "%d " % x + out_pb += "x%d " % x + + out_pb += "x%d " % vars_noise[i] + if outputs[i]: + out+="%d " % vars_noise[i] + out_pb+=" 1" + else: + out+="-%d " % vars_noise[i] + out_pb+=" 0" + + out +="0" + if opts.pb: + print(out_pb) + else: + print(out) + + # get noise + print("c Num equations: ", opts.samples) + print("c Incorrect equations: ", num_incorrect_eqs) + print("c Tolerance: ", tolerance) + if num_incorrect_eqs > tolerance: + print("c this will be UNSAT for sure. Tolerance is smaller than the number of Incorrect euqations.") + + if opts.pb: + out = "" + for i in range(opts.samples): + out +="-1 x%d " % vars_noise[i] + out += " >= %d" % (-tolerance) + print(out) + else: + out = "b " + for i in range(opts.samples): + out +="-%d " % vars_noise[i] + out += "0 %d" % (opts.samples-tolerance) + print(out) + + # print correct output + out = "c correct output is: " + if num_incorrect_eqs <= tolerance: + out += "SAT " + for i in range(opts.n): + val = fun[i] + if val: + out+= "%d " % vars_fun[i] + else: + out+= "-%d " % vars_fun[i] + else: + out += "UNSAT " + print(out) diff --git a/cryptominisat/cppsrc/scripts/lpn-test.sh b/cryptominisat/cppsrc/scripts/lpn-test.sh new file mode 100755 index 00000000..30864330 --- /dev/null +++ b/cryptominisat/cppsrc/scripts/lpn-test.sh @@ -0,0 +1,56 @@ +#!/bin/bash + +echo "Usage: ./todo.sh OUTPUTS FUNLEN NOISE" + +outputs=$1 +funlen=$2 +noise=$3 +cont=$4 +mkdir -p "lpn-out" + +echo "outputs: $outputs" +echo "funlen : $funlen" +echo "noise : $noise" + +for seed in {1..20}; do + tmpfname="tmp-$1-$2-$3" + ./lpn-gen.py -m $outputs -n $funlen --noise $noise -s $seed > "lpn-out/$tmpfname-$seed" + /usr/bin/time --verbose ./cryptominisat5 "lpn-out/$tmpfname-$seed" > "lpn-out/$tmpfname-$seed-out" + ./check_lpn_solution.py "lpn-out/$tmpfname-$seed" "lpn-out/$tmpfname-$seed-out" + out=$? + + if [[ "$out" -eq "0" ]]; then + echo "OK, test: $seed" + else + echo "NOT OK!!" + if [[ "$cont" -eq "1" ]]; then + echo "continuing, as requested" + else + exit -1 + fi + fi +done +echo "Finished" + +for seed in {1..20}; do + tmpfname="tmp-$1-$2-$3" + ./lpn-gen.py -m $outputs -n $funlen --noise $noise -s $seed --pb > "lpn-out/$tmpfname-$seed-pb" + sed "s/^c.*//" "lpn-out/$tmpfname-$seed-pb" > "lpn-out/$tmpfname-$seed-pb-cleaned" + /usr/bin/time --verbose ./linpb --print-sol=1 "lpn-out/$tmpfname-$seed-pb-cleaned" > "lpn-out/$tmpfname-$seed-out" + egrep "(^s )|(^v )" "lpn-out/$tmpfname-$seed-out" > "lpn-out/$tmpfname-$seed-out-filt" + sed "s/x//g" -i "lpn-out/$tmpfname-$seed-out-filt" + ./check_lpn_solution.py "lpn-out/$tmpfname-$seed-pb" "lpn-out/$tmpfname-$seed-out-filt" + out=$? + + if [[ "$out" -eq "0" ]]; then + echo "OK, test: $seed" + else + echo "NOT OK!!" + if [[ "$cont" -eq "1" ]]; then + echo "continuing, as requested" + else + exit -1 + fi + fi +done +echo "Finished" diff --git a/cryptominisat/cppsrc/scripts/output_parser/concat_files.py b/cryptominisat/cppsrc/scripts/output_parser/concat_files.py new file mode 100755 index 00000000..1dd7b7f9 --- /dev/null +++ b/cryptominisat/cppsrc/scripts/output_parser/concat_files.py @@ -0,0 +1,111 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- + +# Copyright (C) 2009-2020 Authors of CryptoMiniSat, see AUTHORS file +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; version 2 +# of the License. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +# 02110-1301, USA. + +import collections +import sys + +toaddheader = [] +toaddval = [] +for x in range(1, len(sys.argv)): + if x % 2 == 1: + toaddheader.append(sys.argv[x]) + else: + toaddval.append(sys.argv[x]) + + +infilenames = [] +infilenames.append("signals.csv") +infilenames.append("solveTimes_rev.csv") + +# main data +files = {} + + +############### +# Fill file names +############### +allfiles = open("allFiles.csv", "r") +for l in allfiles: + l = l.strip() + files[l] = {"SAT":"?"} + +############### +# Fill times, signals +############### +infiles = [] +for x in infilenames: + infiles.append(open(x, "r")) +for f,fname in zip(infiles, infilenames): + for l in f: + l = l.strip() + l = l.split(" ") + + # print("appending to %s : %s" % (l[0], l[1])) + files[l[0]][fname] = l[1] + + +############### +# Fill SAT/UNSAT +############### +with open("solvedUNSAT.csv") as f: + for l in f: + l = l.strip() + files[l]["SAT"] = "UNSAT" + +with open("solvedSAT.csv") as f: + for l in f: + l = l.strip() + files[l]["SAT"] = "SAT" + + +############### +# Print header +############### +toprint = "fname," +for x in range(len(infilenames)): + toprint += infilenames[x].replace(".csv", "") + if x+1 < len(infilenames): + toprint += "," + +for x in toaddheader: + toprint+=","+x +toprint+=",SAT" + +print(toprint) + + + +############### +# Print lines, in order +############### +od = collections.OrderedDict(sorted(files.items())) +for k, v in od.items(): + toprint = "" + for fname in infilenames+["SAT"]: + if fname in v: + toprint += "%s," % v[fname] + else: + toprint += "?," + + for x in toaddval: + toprint+= x + "," + + toprint = toprint.rstrip(",") + print("%s,%s" % (k, toprint)) diff --git a/cryptominisat/cppsrc/scripts/output_parser/convert_to_cactusplot.py b/cryptominisat/cppsrc/scripts/output_parser/convert_to_cactusplot.py new file mode 100755 index 00000000..369a81cc --- /dev/null +++ b/cryptominisat/cppsrc/scripts/output_parser/convert_to_cactusplot.py @@ -0,0 +1,29 @@ +#!/usr/bin/env python + +import sys +of = sys.argv[1] +f = open(of, "r") +text = f.read() +mylines = text.splitlines() +i = 0; +time = [] +for line in mylines : + #print("line:", line) + time.append(float(line.split()[0])) + #print "t:%f" %(time[i]) + i += 1 + +lastnum = -1 +for a in range(0, 4999, 1): + num = 0 + for t in time: + #print "t: %f a: %d" %(t, a) + if (t < a) : + num += 1 + + if (lastnum != num) : + print("%d \t%d" %(num, a)) + lastnum = num + +f.close(); +exit(0) diff --git a/cryptominisat/cppsrc/scripts/output_parser/create_solvetimes.sh b/cryptominisat/cppsrc/scripts/output_parser/create_solvetimes.sh new file mode 100755 index 00000000..2d22354d --- /dev/null +++ b/cryptominisat/cppsrc/scripts/output_parser/create_solvetimes.sh @@ -0,0 +1,25 @@ +#!/bin/bash + +module unload gcc/4.9.3 +module load anaconda/3 +module load openmpi/intel/1.10.2 +mypids=() +for x in `ls | grep $1`; do + cd $x + echo At $x + pwd + ../solvetimes_from_output.sh & + pid=$! + echo "PID here is $pid" + mypids+=("$pid") + cd .. +done + +echo "PIDS to wait for are: ${mypids[*]}" +for pid2 in "${mypids[@]}" +do + echo "Waiting for $pid2 ..." + wait $pid2 +done + + diff --git a/cryptominisat/cppsrc/scripts/output_parser/plotit b/cryptominisat/cppsrc/scripts/output_parser/plotit new file mode 100644 index 00000000..128bda49 --- /dev/null +++ b/cryptominisat/cppsrc/scripts/output_parser/plotit @@ -0,0 +1,45 @@ +#set term epslatex color rounded size 4.9,2.2 +#set term postscript size 8,4 +set term png rounded size 800,600 + +set pointsize 1 +set tics scale 2 + +#set ytics 4e+8 +#set output "only-vs-congl.eps" +set xlabel "No. solved instances from SAT Comp'09" +set ylabel "Time (s)" +#unset key +set xtics 20 +#set key inside b +#set logscale x +#set xtics (10,40,160,640,2560,5000) +set style line 1 lt 1 lw 1 pt 4 ps 0.3 linecolor rgbcolor "red" +set style line 2 lt 2 lw 1 pt 8 ps 0.3 linecolor rgbcolor "orange" +set style line 3 lt 3 lw 1 pt 12 ps 0.3 linecolor rgbcolor "blue" + +########################################## + +#set key lmargin +set key left top +#set output "CryptoMiniSat2.5.0_vs_CryptoMiniSat2.6.0.png" +#plot "./solveTimes56Graph" w lp title "CryptoMiniSat 2.5.0 (SAT Race version)" ls 1, "solveTimes82-learntminimGraph" w lp title "CryptoMiniSat 2.6.0" ls 2 + +#set output "Ligeling_vs_CryptoMiniSat2.6.1.png" +#plot [80:] "./solveTimes97Graph" w lp title "CryptoMiniSat 2.6.1", "./solveTimesLingelingGraph" w lp title "Lingeling" + +#set output "CryptoMiniSat2.7.1-compare.png" +#plot [80:] "./solveTimesMiniSatGraph" w lp title "MiniSat 2.2", "./solveTimesLingelingGraph" w lp title "lingeling", "./solveTimesPrecoSat465Graph" w lp title "PrecoSat465", "./solveTimes97Graph" w lp title "CryptoMiniSat2.7.1" + +#set output "With-without-tans-strong-minim.png" +#plot [80:] "./solveTimes97Graph" w lp title "With transitive strong minimisation", "./solveTimes97-nolfminimGraph" w lp title "Without transitive strong minimisation" + +set output "CryptoMiniSat3Beta-compare.eps" +plot [80:] "./solveTimesMiniSatGraph" w lp title "MiniSat 2.2", "./solveTimesLingelingGraph" w lp title "lingeling", "./solveTimesPrecoSat465Graph" w lp title "PrecoSat465", "./solveTimes129Graph" w lp title "CryptoMiniSat3Beta" + + +#set term png rounded size 700,400 +set term postscript eps color lw 1.5 "Helvetica" 29 size 7,3 +set output "CryptoMiniSat-Competition.eps" +plot [80:] "./solveTimesMiniSatGraph" w lp title "MiniSat 2.2", "./solveTimesLingelingGraph" w lp title "lingeling", "./solveTimesPrecoSat465Graph" w lp title "PrecoSat465", "./solveTimes129Graph" w lp title "CryptoMiniSat SAT Comp'11" + diff --git a/cryptominisat/cppsrc/scripts/output_parser/solved_with_options.sh b/cryptominisat/cppsrc/scripts/output_parser/solved_with_options.sh new file mode 100755 index 00000000..022121b8 --- /dev/null +++ b/cryptominisat/cppsrc/scripts/output_parser/solved_with_options.sh @@ -0,0 +1,38 @@ +#!/bin/bash + +check="$1" +FILE="20180321_110706599_p_cnf_320_1120.cnf" +FILE="001-80-12-sc2014.cnf" + +rm -f out +for d in `ls | grep $check`; do + echo $d; + FILE=`ls $d/*.out.xz | head -n1 | sed "s/.out.xz//"` + echo "FILE: $FILE" + PAR2=`cat $d/PAR2score | awk '{printf "%7.f", $1}'` + PAR2score_1500=`cat $d/PAR2score_1500 | awk '{printf "%7.f", $1}'` + name=`xzgrep "Command being" ${FILE}.timeout.xz` + numsolved=`wc -l $d/solved.csv | awk '{printf "%3d", $1}'` + numALL=`wc -l $d/allFiles.csv | awk '{printf "%3d", $1}'` + numUNSAT=`wc -l $d/solvedUNSAT.csv | awk '{printf "%3d", $1}'` + numSAT=`wc -l $d/solvedSAT.csv | awk '{printf "%3d", $1}'` + rev=`xzgrep -i "revision" ${FILE}.out.xz | awk '{print $5}' | cut -c1-7` + reducedb_percent_time=`awk '{printf "%-3.1f", $1}' $d/reducedb_percent_time.percent` + distill_bin_percent_time=`awk '{printf "%-3.1f", $1}' $d/distill_bin_percent_time.percent` + distill_long_percent_time=`awk '{printf "%-3.1f", $1}' $d/distill_long_percent_time.percent` + occsimp_percent_time=`awk '{printf "%-3.1f", $1}' $d/occsimp_percent_time.percent` + avgtime_SAT=`cat $d/avgtime_SAT | awk '{printf "%5.0f", $1}'` + avgtime_UNSAT=`cat $d/avgtime_UNSAT | awk '{printf "%5.0f", $1}'` + numsls=`wc -l $d/sls_sat.csv | awk '{printf "%2d", $1}'` + memout_or_issue=`wc -l $d/memout_or_issue.csv | awk '{printf "%3d", $1}'` + formatteddir=`echo $d | awk '{printf "%27s", $1}'` + mediantime_SAT=`cat $d/mediantime_SAT | awk '{printf "%4.0f", $1}'` + mediantime_UNSAT=`cat $d/mediantime_UNSAT | awk '{printf "%4.0f", $1}'` + avg_tier0_size=`cat $d/avg_tier0_size | awk '{printf "%4.1f", $1}'` + avg_tier1_size=`cat $d/avg_tier1_size | awk '{printf "%4.1f", $1}'` + avg_tier2_size=`cat $d/avg_tier2_size | awk '{printf "%4.1f", $1}'` + name=`echo $name | sed "s/ 001-80-12-sc2014.cnf.*//"` + #echo "${PAR2} ${PAR2score_1500} $formatteddir $numsolved $numSAT $numUNSAT $numALL ${memout_or_issue}MO ${numsls}SLS ${avg_tier0_size}-T0 ${avg_tier1_size}-T1 ${avg_tier2_size}-T2 ${mediantime_SAT}MedS ${mediantime_UNSAT}MedU $rev $reducedb_percent_time%RDB $distill_percent_time%DIST $occsimp_percent_time%OCC $name" >> out + echo "${PAR2} ${PAR2score_1500} $formatteddir $numsolved $numSAT $numUNSAT $numALL ${memout_or_issue}MO ${numsls}SLS ${avg_tier0_size}-T0 ${avg_tier1_size}-T1 ${avg_tier2_size}-T2 ${mediantime_SAT}MedS ${mediantime_UNSAT}MedU $rev $reducedb_percent_time%RDB $distill_long_percent_time%DISTL $distill_bin_percent_time%DISTILLB $occsimp_percent_time%OCC $name" >> out +done +sed "s/20180321_110706.*//" out | sed "s/Command.*time.*cryptominisat5//" | sed "s/-drat0.solved.csv//" | sed "s/ *Command being timed.*cryptominisat5//" | sed "s/\t/ /g" | sed "s/\t/ /g" | sort -n diff --git a/cryptominisat/cppsrc/scripts/output_parser/solvetimes_from_output.sh b/cryptominisat/cppsrc/scripts/output_parser/solvetimes_from_output.sh new file mode 100755 index 00000000..589fe4e1 --- /dev/null +++ b/cryptominisat/cppsrc/scripts/output_parser/solvetimes_from_output.sh @@ -0,0 +1,119 @@ +#!/bin/sh + +rm -f memout.csv + +# checking for assert/signal/error/terminate fail +xzgrep --color -i -e "assert.*fail" -e "floating" -e "signal" -e "error" -e "terminate" `ls *.out.xz` | tee issues.csv +xzgrep "signal 4" issues.csv + +# Getting SAT & UNSAT +xzgrep "^s .*SATISFIABLE" *.out.xz | sed 's/:s.*$//' > solved_xz.csv +sed 's/.gz.*/.gz/' solved_xz.csv > solved.csv +xzgrep "^s UNSATISFIABLE" $(cat solved_xz.csv) | sed 's/:s.*$//' | sed 's/.gz.*/.gz/' | sort > solvedUNSAT.csv +xzgrep "^s SATISFIABLE" $(cat solved_xz.csv) | sed 's/:s.*$//' | sed 's/.gz.*/.gz/' | sort > solvedSAT.csv + + +# All files +ls -- *.out.xz > allFiles_xz.csv +ls -- *.out.xz | sed "s/.gz.*/.gz/" > allFiles.csv + +# Getting solveTimes +xzgrep "Total" $(cat solved_xz.csv) | awk '{print $7 " "$1}' | sed 's/:c.*$//' > solveTimes_xz.csv +sed 's/.gz.*/.gz/' solveTimes_xz.csv | sort -n > solveTimes.csv + + +# adjusting/getting solved.csv, solveTimes.csv, solveTimes_rev.csv +sed "s/^/\^/" solved.csv | sed "s/$/\$/" > solved_filtering.csv +grep -v -f solved_filtering.csv allFiles.csv | sed "s/.gz.*/.gz/" > unsolved.csv +rm solved_filtering.csv +grep -v -f solved_xz.csv allFiles_xz.csv > unsolved_xz.csv +cat unsolved.csv | awk '{print "5000.00 " $1}' >> solveTimes.csv +awk '{print $2 " " $1}' solveTimes.csv | sort > solveTimes_rev.csv + + +# 1500 cutoff +awk '{if ($1 < 1500) {print $2}}' solveTimes_xz.csv | sort > solved_under_1500_full_list_xz.csv +grep -f solvedUNSAT.csv solved_under_1500_full_list_xz.csv | sed 's/:s.*$//' | sed 's/.gz.*/.gz/' | sort > solvedUNSAT1500.csv +grep -f solvedSAT.csv solved_under_1500_full_list_xz.csv | sed 's/:s.*$//' | sed 's/.gz.*/.gz/' | sort > solvedSAT1500.csv + +# Getting "file SAT/UNSAT/UNKN" list +cat solvedSAT.csv | awk '{print $1 " SAT"}' > solved_sol.csv +cat solvedUNSAT.csv | awk '{print $1 " UNSAT"}' >> solved_sol.csv +cat unsolved.csv | awk '{print $1 " UNKN"}' >> solved_sol.csv +sort solved_sol.csv > solved_sol2.csv +rm -f solved_sol.csv +mv solved_sol2.csv solved_sol.csv + +# user times +xzgrep "User time" *.timeout.xz | awk '{print $5 " " $1}' | sed "s/.timeout.xz://" > user_times.csv + +#Memout or issue +grep -f unsolved.csv user_times.csv | sort -n -r | awk '{if ($1 < 4950) {print $0}}' | sort > memout_or_issue.csv + +# ReduceDB time for solved instances +xzgrep -i "ReduceDB time" $(cat solved_xz.csv) | awk '{print $1 " " $5}' | sed "s/.out.xz:c//" | sort > reducedb_times.csv +reducedb_time=$(awk '{a+=$2} END {print a}' reducedb_times.csv) +solved_total_time=$(awk '{if ($1=="5000.00") {x+=0} else {x += $1};} END {printf "%d\n", x}' solveTimes.csv) +bc <<< "scale=4; ($reducedb_time/$solved_total_time)*100.0" > reducedb_percent_time.percent + +# Distill long time for solved instances +xzgrep -i "distill long time" $(cat solved_xz.csv) | awk '{print $1 " " $6}' | sed "s/.out.xz:c//" | sort > distill_long_times.csv +distill_long_time=$(awk '{a+=$2} END {print a}' distill_long_times.csv) +solved_total_time=$(awk '{if ($1=="5000.00") {x+=0} else {x += $1};} END {printf "%d\n", x}' solveTimes.csv) +bc <<< "scale=4; ($distill_long_time/$solved_total_time)*100.0" > distill_long_percent_time.percent + +# Distill bin time for solved instances +xzgrep -i "distill bin time" $(cat solved_xz.csv) | awk '{print $1 " " $6}' | sed "s/.out.xz:c//" | sort > distill_bin_times.csv +distill_bin_time=$(awk '{a+=$2} END {print a}' distill_bin_times.csv) +solved_total_time=$(awk '{if ($1=="5000.00") {x+=0} else {x += $1};} END {printf "%d\n", x}' solveTimes.csv) +bc <<< "scale=4; ($distill_bin_time/$solved_total_time)*100.0" > distill_bin_percent_time.percent + +# Occsimp time for solved instances +xzgrep -i "OccSimplifier time " $(cat solved_xz.csv) | awk '{print $1 " " $5}' | sed "s/.out.xz:c//" | sort > occsimp_times.csv +occsimp_time=$(awk '{a+=$2} END {print a}' occsimp_times.csv) +solved_total_time=$(awk '{if ($1=="5000.00") {x+=0} else {x += $1};} END {printf "%d\n", x}' solveTimes.csv) +bc <<< "scale=4; ($occsimp_time/$solved_total_time)*100.0" > occsimp_percent_time.percent + +xzgrep signal *.timeout.xz | sed -E "s/.timeout.*signal (.*)/ \1/" > signals.csv +xzgrep signal *.timeout.xz | sed -E "s/.timeout.*signal (.*)//" > signals_files.csv +sed "s/^/\^/" signals_files.csv | sed "s/$/\$/" > signals_files_filtering.csv +grep -v -f signals_files_filtering.csv allFiles.csv | awk '{print $1 " -1"}' >> signals.csv +rm -f signals_files_filtering.csv +sort signals.csv > signals_sorted.csv +rm -f signals.csv signals_files.csv +mv signals_sorted.csv signals.csv +grep " 11" signals.csv + +# PAR 2 score 5000s timeout +awk '{if ($1=="5000.00") {x+=10000} else {x += $1};} END {printf "%7.0f\n", x}' solveTimes.csv > PAR2score +mypwd=`pwd` +echo "$mypwd PAR2 score is: " `cat PAR2score` +awk '{if ($1 >= 1500) {x+=3000} else {x += $1};} END {printf "%6.0f\n", x}' solveTimes.csv > PAR2score_1500 +echo "$mypwd PAR2_1500 score is: " `cat PAR2score_1500` +xzgrep "avg cls in red 0" $(cat solved_xz.csv) | awk '{k+=$8;x+=1} END {printf "%3.1fK", (k/(x*1000))}' > avg_tier0_size +xzgrep "avg cls in red 1" $(cat solved_xz.csv) | awk '{k+=$8;x+=1} END {printf "%3.1fK", (k/(x*1000))}' > avg_tier1_size +xzgrep "avg cls in red 2" $(cat solved_xz.csv) | awk '{k+=$8;x+=1} END {printf "%3.1fK", (k/(x*1000))}' > avg_tier2_size + +# avg times SAT/UNSAT +grep -f solvedSAT.csv solveTimes.csv | sort -n | awk -f ../median.awk > mediantime_SAT +grep -f solvedUNSAT.csv solveTimes.csv | sort -n | awk -f ../median.awk > mediantime_UNSAT +grep -f solvedSAT.csv solveTimes.csv | awk '{{x+=$1; y+=1}} END {printf "%-7.2f\n", (x/y)}' > avgtime_SAT +grep -f solvedUNSAT.csv solveTimes.csv | awk '{{x+=$1; y+=1}} END {printf "%-7.2f\n", (x/y)}' > avgtime_UNSAT + +xzgrep "ASSIGNMENT FOUND" $(cat solved_xz.csv | grep -f solvedSAT.csv) | sed 's/:s.*$//' | sed 's/.gz.*/.gz/' | sort > sls_sat.csv + + + +../concat_files.py > combined.csv + + +################ + +# xzgrep "total elapsed seconds" *.out.xz | awk '{if ($7 > 5) {print $1 " - " $7;}; a+=$7;} END {print a}' +# 9093.88 + +# expensive ones make up HALF of the time used: +# xzgrep "total elapsed seconds" *.out.xz | awk '{if ($7 > 5) {print $1 " - " $7; a+=$7;}} END {print a}' +# 5417.6 + + diff --git a/cryptominisat/cppsrc/scripts/output_parser/solvetimes_from_output_cadical.sh b/cryptominisat/cppsrc/scripts/output_parser/solvetimes_from_output_cadical.sh new file mode 100755 index 00000000..1edabdc3 --- /dev/null +++ b/cryptominisat/cppsrc/scripts/output_parser/solvetimes_from_output_cadical.sh @@ -0,0 +1,68 @@ +xzgrep --color -i -e "assert.*fail" -e "floating" -e "signal" -e "error" -e "terminate" *.out.xz | tee issues.csv +echo "checking for signal 4" +xzgrep "signal 4" issues.csv + +# 1500 cutoff +echo "Getting solveTimes" +xzgrep "total real" *.out.xz | awk '{print $7 " "$1}' | sed 's/:c.*$//' > solveTimes_xz.csv +echo "Getting problems solved under 1500" +awk '{if ($1 < 1500) {print $2}}' solveTimes_xz.csv | sort > solved_under_1500_full_list_xz.csv +awk '{print $2}' solveTimes_xz.csv | sort > solved_xz.csv +sed 's/.gz.*/.gz/' solved_xz.csv > solved.csv +sed 's/.gz.*/.gz/' solveTimes_xz.csv | sort -n > solveTimes.csv +ls -- *.out.xz > allFiles_xz.csv +ls -- *.out.xz | sed "s/.gz.*/.gz/" > allFiles.csv + +# for normal +echo "Getting SAT & UNSAT" +xzgrep "^s UNSATISFIABLE" $(cat solved_xz.csv) | sed 's/:s.*$//' | sed 's/.gz.*/.gz/' | sort > solvedUNSAT.csv +xzgrep "^s SATISFIABLE" $(cat solved_xz.csv) | sed 's/:s.*$//' | sed 's/.gz.*/.gz/' | sort > solvedSAT.csv + +# adjusting solved.csv, solveTimes.csv, solveTimes_rev.csv +echo "Getting solveTimes_rev.csv" +sed "s/^/\^/" solved.csv | sed "s/$/\$/" > solved_filtering.csv +grep -v -f solved_filtering.csv allFiles.csv | sed "s/.gz.*/.gz/" > unsolved.csv +rm solved_filtering.csv +grep -v -f solved_xz.csv allFiles_xz.csv > unsolved_xz.csv +cat unsolved.csv | awk '{print "5000.00 " $1}' >> solveTimes.csv +awk '{print $2 " " $1}' solveTimes.csv | sort > solveTimes_rev.csv + +# memory out +echo "Getting memout..." +xzgrep "what.*bad.*alloc" $(cat unsolved_xz.csv) | sed "s/.gz.*/.gz/" | sort > memout.csv +sed "s/^/\^/" memout.csv | sed "s/$/\$/" > memout_filtering.csv +grep -v -f memout_filtering.csv allFiles.csv | sed "s/.gz/.gz OK/" > memout2.csv +rm memout_filtering.csv +cat memout.csv | sed "s/.gz/.gz BAD/" >> memout2.csv +sort memout2.csv > memout3.csv +rm memout.csv memout2.csv +mv memout3.csv memout.csv + +# 1500 cutoff +echo "Getting 1500 UNSAT" +xzgrep "^s UNSATISFIABLE" $(cat solved_under_1500_full_list_xz.csv) | sed 's/:s.*$//' | sed 's/.gz.*/.gz/' | sort > solvedUNSAT1500.csv +echo "Getting 1500 SAT" +xzgrep "^s SATISFIABLE" $(cat solved_under_1500_full_list_xz.csv) | sed 's/:s.*$//' | sed 's/.gz.*/.gz/' | sort > solvedSAT1500.csv +rm -f solved1500.csv +cat solvedUNSAT1500.csv > solved1500.csv +cat solvedSAT1500.csv >> solved1500.csv + +cat solvedSAT.csv | awk '{print $1 " SAT"}' > solved_sol.csv +cat solvedUNSAT.csv | awk '{print $1 " UNSAT"}' >> solved_sol.csv +cat unsolved.csv | awk '{print $1 " UNKN"}' >> solved_sol.csv +sort solved_sol.csv > solved_sol2.csv +rm solved_sol.csv +mv solved_sol2.csv solved_sol.csv + + +xzgrep signal *.timeout.xz | sed -E "s/.timeout.*signal (.*)/ \1/" > signals.csv +xzgrep signal *.timeout.xz | sed -E "s/.timeout.*signal (.*)//" > signals_files.csv +sed "s/^/\^/" signals_files.csv | sed "s/$/\$/" > signals_files_filtering.csv +grep -v -f signals_files_filtering.csv allFiles.csv | awk '{print $1 " -1"}' >> signals.csv +rm signals_files_filtering.csv +sort signals.csv > signals_sorted.csv +rm signals.csv signals_files.csv +mv signals_sorted.csv signals.csv +grep " 11" signals.csv +awk '{if ($1=="5000.00") {x+=10000} else {x += $1};} END {printf "%d\n", x}' solveTimes.csv > PAR2score +echo "PAR2 score is: " `cat PAR2score` diff --git a/cryptominisat/cppsrc/scripts/output_parser/solvetimes_from_output_glucose.sh b/cryptominisat/cppsrc/scripts/output_parser/solvetimes_from_output_glucose.sh new file mode 100755 index 00000000..4525b438 --- /dev/null +++ b/cryptominisat/cppsrc/scripts/output_parser/solvetimes_from_output_glucose.sh @@ -0,0 +1,80 @@ +#!/bin/sh + +echo "checking for assert/signal/error/terminate fail" +xzgrep --color -i -e "assert.*fail" -e "floating" -e "signal" -e "error" -e "terminate" *.out.xz | tee issues.csv +echo "checking for signal 4" +xzgrep "signal 4" issues.csv + +# 1500 cutoff +echo "Getting solveTimes" +xzgrep "CPU time" *.out.xz | awk '{print $5 " "$1}' | sed 's/:c.*$//' > solveTimes_xz.csv +echo "Getting problems solved under 1500" +awk '{if ($1 < 1500) {print $2}}' solveTimes_xz.csv | sort > solved_under_1500_full_list_xz.csv +awk '{print $2}' solveTimes_xz.csv | sort > solved_xz.csv +sed 's/.gz.*/.gz/' solved_xz.csv > solved.csv +sed 's/.gz.*/.gz/' solveTimes_xz.csv | sort -n > solveTimes.csv +ls -- *.out.xz > allFiles_xz.csv +ls -- *.out.xz | sed "s/.gz.*/.gz/" > allFiles.csv + +# for normal +echo "Getting SAT & UNSAT" +xzgrep "^s UNSATISFIABLE" $(cat solved_xz.csv) | sed 's/:s.*$//' | sed 's/.gz.*/.gz/' | sort > solvedUNSAT.csv +xzgrep "^s SATISFIABLE" $(cat solved_xz.csv) | sed 's/:s.*$//' | sed 's/.gz.*/.gz/' | sort > solvedSAT.csv + +# adjusting solved.csv, solveTimes.csv, solveTimes_rev.csv +echo "Getting solveTimes_rev.csv" +sed "s/^/\^/" solved.csv | sed "s/$/\$/" > solved_filtering.csv +grep -v -f solved_filtering.csv allFiles.csv | sed "s/.gz.*/.gz/" > unsolved.csv +rm solved_filtering.csv +grep -v -f solved_xz.csv allFiles_xz.csv > unsolved_xz.csv +cat unsolved.csv | awk '{print "5000.00 " $1}' >> solveTimes.csv +awk '{print $2 " " $1}' solveTimes.csv | sort > solveTimes_rev.csv + +# memory out +echo "Getting memout..." +xzgrep "what.*bad.*alloc" $(cat unsolved_xz.csv) | sed "s/.gz.*/.gz/" | sort > memout.csv +sed "s/^/\^/" memout.csv | sed "s/$/\$/" > memout_filtering.csv +grep -v -f memout_filtering.csv allFiles.csv | sed "s/.gz/.gz OK/" > memout2.csv +rm memout_filtering.csv +cat memout.csv | sed "s/.gz/.gz BAD/" >> memout2.csv +sort memout2.csv > memout3.csv +rm memout.csv memout2.csv +mv memout3.csv memout.csv + +# 1500 cutoff +echo "Getting 1500 UNSAT" +xzgrep "^s UNSATISFIABLE" $(cat solved_under_1500_full_list_xz.csv) | sed 's/:s.*$//' | sed 's/.gz.*/.gz/' | sort > solvedUNSAT1500.csv +echo "Getting 1500 SAT" +xzgrep "^s SATISFIABLE" $(cat solved_under_1500_full_list_xz.csv) | sed 's/:s.*$//' | sed 's/.gz.*/.gz/' | sort > solvedSAT1500.csv +rm -f solved1500.csv +cat solvedUNSAT1500.csv > solved1500.csv +cat solvedSAT1500.csv >> solved1500.csv + +cat solvedSAT.csv | awk '{print $1 " SAT"}' > solved_sol.csv +cat solvedUNSAT.csv | awk '{print $1 " UNSAT"}' >> solved_sol.csv +cat unsolved.csv | awk '{print $1 " UNKN"}' >> solved_sol.csv +sort solved_sol.csv > solved_sol2.csv +rm solved_sol.csv +mv solved_sol2.csv solved_sol.csv + + +xzgrep signal *.timeout.xz | sed -E "s/.timeout.*signal (.*)/ \1/" > signals.csv +xzgrep signal *.timeout.xz | sed -E "s/.timeout.*signal (.*)//" > signals_files.csv +sed "s/^/\^/" signals_files.csv | sed "s/$/\$/" > signals_files_filtering.csv +grep -v -f signals_files_filtering.csv allFiles.csv | awk '{print $1 " -1"}' >> signals.csv +rm signals_files_filtering.csv +sort signals.csv > signals_sorted.csv +rm signals.csv signals_files.csv +mv signals_sorted.csv signals.csv +grep " 11" signals.csv +awk '{if ($1=="5000.00") {x+=10000} else {x += $1};} END {printf "%d\n", x}' solveTimes.csv > PAR2score +echo "PAR2 score is: " `cat PAR2score` + +xzgrep "ASSIGNMENT FOUND" *.out.xz | sed "s/.out.*//" > walksat_sat.csv +grep -v -f walksat_sat.csv allFiles.csv | sed "s/.gz/.gz FALL/" > walksat_nosat.csv +sed "s/$/ WALK/" walksat_sat.csv > walksat_sat2.csv +cat walksat_sat2.csv walksat_nosat.csv | sort > walksat.csv + + + +../concat_files.py > combined.csv diff --git a/cryptominisat/cppsrc/scripts/output_parser/solvetimes_from_output_lingeling.sh b/cryptominisat/cppsrc/scripts/output_parser/solvetimes_from_output_lingeling.sh new file mode 100755 index 00000000..ef017d40 --- /dev/null +++ b/cryptominisat/cppsrc/scripts/output_parser/solvetimes_from_output_lingeling.sh @@ -0,0 +1,7 @@ +#!/bin/sh + +zgrep "\%.*all" -- *out.gz | awk '{print $2}' > solveTimes +zgrep "\% *all" -- *out.gz | awk '{print $1}' | sed 's/:c$//' | sed 's/gz.*/gz/' | sort > solved +ls -- *out.gz | sed 's/gz.*/gz/' | sort > allFiles +zgrep "s UNSATISFIABLE" -- *out.gz | sed 's/:s.*$//' | sed 's/gz.*/gz/' | sort > solvedUNSAT +zgrep "s SATISFIABLE" -- *out.gz | sed 's/:s.*$//' | sed 's/gz.*/gz/' | sort > solvedSAT diff --git a/cryptominisat/cppsrc/scripts/output_parser/solvetimes_from_output_yalsat.sh b/cryptominisat/cppsrc/scripts/output_parser/solvetimes_from_output_yalsat.sh new file mode 100755 index 00000000..8bd9fe64 --- /dev/null +++ b/cryptominisat/cppsrc/scripts/output_parser/solvetimes_from_output_yalsat.sh @@ -0,0 +1,11 @@ +#!/usr/bin/bash +set -x + +#xzgrep "s SATIS" *.out.xz > solved +cat solved | sed "s/.out.*//" > solved_files +rm -f solveTimes.csv +for f in `cat solved_files`; do + xzgrep "time" "$f.out.xz" | awk '{print $6 " x"}' | sed "s/x/$f/" >> solveTimes_unsorted +done +sort -n solveTimes_unsorted > solveTimes.csv +rm solveTimes_unsorted diff --git a/cryptominisat/cppsrc/scripts/output_parser/sqlite3_checks.py b/cryptominisat/cppsrc/scripts/output_parser/sqlite3_checks.py new file mode 100755 index 00000000..c1d16248 --- /dev/null +++ b/cryptominisat/cppsrc/scripts/output_parser/sqlite3_checks.py @@ -0,0 +1,330 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- + +from __future__ import print_function +import sqlite3 +import optparse +import operator +import time +import helper + + +class Query: + def __init__(self, dbfname): + self.conn = sqlite3.connect(dbfname) + self.c = self.conn.cursor() + + def __enter__(self): + return self + + def __exit__(self, exc_type, exc_value, traceback): + self.conn.close() + + def create_indexes(self): + helper.drop_idxs(self.c) + + print("Recreating indexes...") + queries = """ + create index `idx1` on `tags` (`runid`, `name`); + create index `idx2` on `timepassed` (`runid`, `elapsed`); + create index `idx3` on `timepassed` (`runid`, `elapsed`, `name`); + create index `idx4` on `memused` (`runid`, `MB`, `name`); + + """ + for l in queries.split('\n'): + t2 = time.time() + + if options.verbose: + print("Creating index: ", l) + self.c.execute(l) + if options.verbose: + print("Index creation T: %-3.2f s" % (time.time() - t2)) + + print("indexes created T: %-3.2f s" % (time.time() - t)) + + def find_time_outliers(self): + print("----------- TIME OUTLIERS --------------") + query = """ + select tags.val, timepassed.name, timepassed.elapsed + from timepassed,tags + where + timepassed.name != 'search' + and timepassed.elapsed > %d + and tags.name="filename" + and tags.runid = timepassed.runid + + order by elapsed desc; + """ % (options.maxtime) + + for row in self.c.execute(query): + operation = row[1] + t = row[2] + fname = self.get_fname(row[0]) + print("%-32s %-20s %.1fs" % (fname, operation, t)) + + def check_memory(self): + print("----------- MEMORY OUTLIERS --------------") + + query = """ + select tags.val, memused.name, max(memused.MB) + from memused,tags + where + tags.name="filename" + and memused.MB > %d + and memused.name != 'vm' + and memused.name != 'rss' + and memused.name != 'longclauses' + and tags.runid = memused.runid + + group by tags.val, memused.name + order by MB desc; + """ % (options.maxmemory) + + for row in self.c.execute(query): + subsystem = row[1] + gigs = row[2]/1000.0 + fname = self.get_fname(row[0]) + print("%-32s %-20s %.1f GB" % (fname, subsystem, gigs)) + + def check_memory_rss(self): + print("----------- MEMORY OUTLIERS RSS --------------") + + query = """ + select tags.val, memused.name, max(memused.MB) + from memused,tags + where + tags.name="filename" + and memused.MB > %d + and memused.name == 'rss' + and tags.runid = memused.runid + + group by tags.val, memused.name + order by MB desc; + """ % (options.maxmemory*2) + + for row in self.c.execute(query): + subsystem = row[1] + gigs = row[2]/1000.0 + fname = self.get_fname(row[0]) + print("%-32s %-20s %.1f GB" % (fname, subsystem, gigs)) + + def find_worst_unaccounted_memory(self): + print("----------- Largest RSS vs counted differences --------------") + query = """ + select tags.val, a.`runtime`, abs((b.rss-a.mysum)/b.rss) as differperc, + a.mysum as counted, b.rss as total + from tags, + + (select runid, `runtime`, sum(MB) as mysum + from memused + where name != 'rss' + and name != 'vm' + group by `runtime`) as a, + + (select runid, name, `runtime`, MB as rss + from memused + where name = 'rss') as b + + where + tags.name="filename" + and a.`runtime` = b.`runtime` + and total > %d + and a.runid = tags.runid + and b.runid = tags.runid + + order by differperc desc + """ % (options.minmemory) + + for row,_ in zip(self.c.execute(query), range(10)): + t = row[1] + diff_perc = row[2] + counted = row[3] + total = row[4] + fname = self.get_fname(row[0]) + print("%-32s at: %-8.1fs counted: %3.2f GB rss: %3.2f GB" % (fname, t, counted/1000.0, total/1000.0)) + + def memory_distrib(self): + print("----------- MEMORY DISTRIBUTION --------------") + print("all divided by RSS -- resident size") + + query = """ + select sum(MB) + from memused + where name != 'vm' + and name != 'rss'; + """ + for row in self.c.execute(query): + recorded_mem = float(row[0]) + + query = """ + select sum(MB) + from memused + where name = 'rss'; + """ + for row in self.c.execute(query): + rss_mem = float(row[0]) + + unaccounted = rss_mem - recorded_mem; + print("%-20s %.1f%%" % ("unaccounted", unaccounted/rss_mem*100.0)) + + query = """ + select name, sum(MB) as memsum + from memused + where name != 'vm' + and name != 'rss' + group by name + order by memsum desc; + """ + + for row in self.c.execute(query): + subsystem = row[0] + mbs = float(row[1]) + print("%-20s %.1f%%" % (subsystem, mbs/rss_mem*100.0)) + + def get_fname(self, val) : + fname = val.split("/") + fname = fname[len(fname)-1] + fname = fname.rstrip(".cnf.gz") + #if len(fname) > 40: + # fname = fname[:30] + "..." + fname[len(fname)-10:] + + return fname + + def calc_time_spent(self): + print("----------- TIME DISTRIBUTION --------------") + + query = """ + select sum(elapsed) + from timepassed + where name='search'; + """ + for row in self.c.execute(query): + search_time = float(row[0]) + + query = """ + select sum(elapsed) + from timepassed + where name!='search'; + """ + for row in self.c.execute(query): + other_time = float(row[0]) + + total = search_time + other_time + print("Total: %10.1fh Search: %3.1f%%, Other: %3.1f%%" % + (total/3600, search_time/total*100, other_time/total*100)) + + query = """ + select name, sum(elapsed) + from timepassed + group by name; + """ + times = {} + for row in self.c.execute(query): + times[row[0]] = float(row[1]) + + # print("Names: %s" % times) + sorted_t = sorted(times.items(), key=operator.itemgetter(1), reverse=True) + for (name, t) in sorted_t: + name = name[:40] + print("%-40s %3.1f%%" % (name, t/total*100)) + + def find_intersting_problems(self): + print("----------- Interesting problems for learning --------------") + + #Find CNFs that are interesting: + #* solved in under 500s + #* UNSAT + #* more conflicts than 60'000 + + #last conflict > 60000, UNSAT, solvetime under 500s + query = """ + select tags.val, a.maxtime, a.maxconfl, mems.maxmem + + from + (select runid, max(conflicts) as maxconfl, max(`runtime`) as maxtime + from timepassed + ) as a + + , (select * + from finishup + where status = "l_False" + ) as b + + , (select runid, max(MB) as maxmem + from memused + ) as mems + + , tags + + where a.maxconfl > 20000 + and a.maxconfl < 400000 + and a.maxtime < 400 + and a.maxtime > 10 + and tags.name = "filename" + and tags.runid = a.runid + and tags.runid = b.runid + + + order by maxtime desc + """ + + for row in self.c.execute(query): + fname = row[1].split("/") + fname = fname[len(fname)-1] + t = row[1] + confl = row[2] + mb = row[3] + print("t(mins): %-6.1f confl(K): %-6.1f mem(GB): %-6.1f fname: %s" % + (t/60.0, confl/(1000.0), mb/1024.0, fname)) + + +if __name__ == "__main__": + usage = "usage: %prog [options] sqlitedb" + parser = optparse.OptionParser(usage=usage) + + parser.add_option("--createind", action="store_true", default=False, + dest="create_indexes", help="Create indexes") + + parser.add_option("--maxtime", metavar="CUTOFF", + dest="maxtime", default=20, type=int, + help="Max time for an operation") + + parser.add_option("--maxmemory", metavar="CUTOFF", + dest="maxmemory", default=500, type=int, + help="Max memory for a subsystem") + + parser.add_option("--minmemory", metavar="MINMEM", + dest="minmemory", default=800, type=int, + help="Minimum memory to be checked for RSS vs counted check") + + parser.add_option("--verbose", "-v", action="store_true", default=False, + dest="verbose", help="Print more output") + + (options, args) = parser.parse_args() + + if len(args) != 1: + print("ERROR: You must give exactly one argument, the sqlite3 database file") + exit(-1) + + dbfname = args[0] + print("Using sqlite3db file %s" % dbfname) + + #peform queries + with Query(dbfname) as q: + if options.create_indexes: + q.create_indexes() + q.find_intersting_problems() + q.find_worst_unaccounted_memory() + q.check_memory_rss() + q.check_memory() + q.memory_distrib() + q.find_time_outliers() + q.calc_time_spent() + + + +#select timepassed.runID, tag,elapsed from timepassed,tags where name like 'shorten and str red%' and elapsed > 2 and tags.runID = timepassed.runID; + +#select * from timepassed where elapsed > 20 and name not like 'search'; + +#select * from startup, solverRun, finishup where finishup.runID = solverRun.runID and (finishup.endTime - startup.startTime) < 30 and solverRun.version = "618b5e79fdd8a15918e19fb76ca08aa069f14b54" and solverRun.runID = startup.runID; diff --git a/cryptominisat/cppsrc/scripts/output_parser/update_concat_sqlite_files.py b/cryptominisat/cppsrc/scripts/output_parser/update_concat_sqlite_files.py new file mode 100755 index 00000000..d083a5dc --- /dev/null +++ b/cryptominisat/cppsrc/scripts/output_parser/update_concat_sqlite_files.py @@ -0,0 +1,137 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- + +from __future__ import print_function +import sqlite3 +import optparse +import random + +tables = ["tags", "timepassed", "memused" + , "solverRun", "startup", "finishup"] + +class Query: + def __init__(self, dbfname): + self.dbfname = dbfname + self.conn = sqlite3.connect(self.dbfname) + self.c = self.conn.cursor() + + def __enter__(self): + return self + + def __exit__(self, exc_type, exc_value, traceback): + self.conn.close() + + def add_ids(self): + print("----------- adding IDs to db %s --------------" % self.dbfname) + runid = random.randint(0, 2**32-1) + + query = """ + alter table `{tablename}` add column runid bigint(2) default null; + update `{tablename}` set runid={runid}; + """ + + for table in tables: + print("adding runid {runid} to table {tablename}" + .format(runid=runid, tablename=table)) + for q in query.split("\n"): + self.c.execute(q.format(runid=runid, tablename=table)) + + print("Finished adding IDs to tables") + self.c.execute("commit;") + + + def create_empty_tables(self): + query=""" + DROP TABLE IF EXISTS `tags`; + CREATE TABLE `tags` ( + `name` varchar(500) NOT NULL, + `val` varchar(500) NOT NULL + , runid bigint(2) default null + ); + + DROP TABLE IF EXISTS `timepassed`; + CREATE TABLE `timepassed` ( + `simplifications` bigint(20) NOT NULL, + `conflicts` bigint(20) NOT NULL, + `runtime` float NOT NULL, + `name` varchar(200) NOT NULL, + `elapsed` float NOT NULL, + `timeout` int(20) DEFAULT NULL, + `percenttimeremain` float DEFAULT NULL + , runid bigint(2) default null + ); + + DROP TABLE IF EXISTS `memused`; + CREATE TABLE `memused` ( + `simplifications` bigint(20) NOT NULL, + `conflicts` bigint(20) NOT NULL, + `runtime` float NOT NULL, + `name` varchar(200) NOT NULL, + `MB` int(20) NOT NULL + , runid bigint(2) default null + ); + + DROP TABLE IF EXISTS `solverRun`; + CREATE TABLE `solverRun` ( + `runtime` float NOT NULL, + `gitrev` varchar(100) NOT NULL + , runid bigint(2) default null + ); + + DROP TABLE IF EXISTS `startup`; + CREATE TABLE `startup` ( + `startTime` datetime NOT NULL + , runid bigint(2) default null + ); + + DROP TABLE IF EXISTS `finishup`; + CREATE TABLE `finishup` ( + `endTime` datetime NOT NULL, + `status` varchar(255) NOT NULL + , runid bigint(2) default null + );""" + self.c.executescript(query) + + def merge_data(self, files): + query = """ + attach '{fname}' as toMerge; + BEGIN; + insert into {table} select * from toMerge.{table}; + COMMIT; + detach toMerge; + """ + + for f in files: + print("Merging file %s" % f) + for table in tables: + print("-> Merging table %s" % table) + self.c.executescript(query.format(fname=f, table=table)) + +if __name__ == "__main__": + usage = "usage: %prog [options] sqlitedb" + parser = optparse.OptionParser(usage=usage) + parser.add_option("--verbose", "-v", action="store_true", default=False, + dest="verbose", help="Print more output") + parser.add_option("--onlyconcat", action="store_true", default=False, + dest="onlyconcat", help="Only concatenate") + + (options, args) = parser.parse_args() + + if len(args) < 2: + print("ERROR: You must give at least two arguments, the sqlite3 database files") + exit(-1) + + if not options.onlyconcat: + for fname in args: + print("Using sqlite3db file %s" % fname) + + #peform queries + with Query(fname) as q: + q.add_ids() + + print("Finished adding IDs to all tables in all files") + + print("Merging tables...") + with Query("merged.sqlitedb") as q: + q.create_empty_tables() + q.merge_data(args) diff --git a/cryptominisat/cppsrc/scripts/reconf/count_plus_minus.sh b/cryptominisat/cppsrc/scripts/reconf/count_plus_minus.sh new file mode 100755 index 00000000..495a006c --- /dev/null +++ b/cryptominisat/cppsrc/scripts/reconf/count_plus_minus.sh @@ -0,0 +1,46 @@ +#!/usr/bin/bash + +#rm outfile*.data +#rm outs/*.data +#./reconf.py -n 18 -i 1,2,8,9,10,11,15,5,14,13,3 -f outs/out /home/soos/media/sat/out/new/out-reconf-6776906.wlm01-*/*.out + + +for f in `ls outs/*.data`; do + echo "$f:" + grep ",+" $f | wc -l; + grep ",-" $f | wc -l; + echo "---" +done + + +echo "this is solved by everyone:" +grep "total-10-13-u.cnf" outs/*.data + +echo "this is solved by nobody:" +grep "partial-10-13-u.cnf" outs/*.data + +echo "this is solved by some only -8-==rec15 and -10-=rec17 and -9-=rec16), small diff:" +grep "mp1-22.5.cnf.gz" outs/*.data + +echo "this is solved by everyone except 7, large diff:" +grep "mp1-klieber2017s-1000-024-eq.cnf" outs/*.data + +echo "given neg : rec17, rec7, rec16" +echo "which is eqiv: 10, 4, 9, (note: 8-drat = 15, which is ignored)" + +echo "to check:" +echo 'grep -i "User time" */mp1-klieber2017s-1000-024-eq.cnf*.timeout | awk '{print $5 " -- " $1}' | sort -n' + +echo 'mapping: +num -> reconf +0 0 +1 3 +2 4 +3 6 +4 7 +5 12 +6 13 +7 14 +8 15 +9 16 +10 17' diff --git a/cryptominisat/cppsrc/scripts/reconf/generate_reconf.py b/cryptominisat/cppsrc/scripts/reconf/generate_reconf.py new file mode 100755 index 00000000..8d96519e --- /dev/null +++ b/cryptominisat/cppsrc/scripts/reconf/generate_reconf.py @@ -0,0 +1,108 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- + +# Copyright (C) 2009-2020 Authors of CryptoMiniSat, see AUTHORS file +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; version 2 +# of the License. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +# 02110-1301, USA. + +from __future__ import with_statement # Required in 2.5 +from __future__ import print_function +import sys +import subprocess + + +def query_yes_no(question, default="no"): + """Ask a yes/no question via input() and return their answer. + + "question" is a string that is presented to the user. + "default" is the presumed answer if the user just hits . + It must be "yes" (the default), "no" or None (meaning + an answer is required of the user). + + The "answer" return value is True for "yes" or False for "no". + """ + valid = {"yes": True, "y": True, "ye": True, + "no": False, "n": False} + if default is None: + prompt = " [y/n] " + elif default == "yes": + prompt = " [Y/n] " + elif default == "no": + prompt = " [y/N] " + else: + raise ValueError("invalid default answer: '%s'" % default) + + while True: + sys.stdout.write(question + prompt) + choice = input().lower() + if default is not None and choice == '': + return valid[default] + elif choice in valid: + return valid[choice] + else: + sys.stdout.write("Please respond with 'yes' or 'no' " + "(or 'y' or 'n').\n") + + +num = 18 +ignore = "1,2,8,9,10,11,15,5,14,13,3" +files = "/home/soos/media/sat/out/new/out-reconf-6776906.wlm01-*/*.out" + +# for testing +#num = 8 +#ignore = "0,1,2,3,5,6" +#files = "/home/soos/media/sat/out/new2/out-reconf-6776906.wlm01-*/*.out" + +ignore_elems = {} +for x in ignore.split(","): + x = x.strip() + if x == "": + continue + + x = int(x) + ignore_elems[x] = True + +subprocess.call("rm outs/*", shell=True) +toexec = "./reconf.py -n %d -i %s -f outs/out %s" % (num, ignore, files) +f = open("output", "w") +ret = subprocess.call(toexec, shell=True, stdout=f) +f.close() +if ret != 0: + print("ERROR: reconf call exited non-zero: %s" % toexec) + exit(-1) + +for i in range(num): + if i in ignore_elems: + continue + + print("reconf with %d" % i) + subprocess.call("cp outs/reconf.names outs/out%d.names" % i, shell=True) + subprocess.call("c5.0 -u 20 -f outs/out%d -r > outs/out%d.c50.out" % (i, i), shell=True) + +subprocess.call("./tocpp.py -i %s -n %d > ../../src/satzilla_features_to_reconf.cpp" % (ignore, num), + shell=True) + +subprocess.call("sed -i 's/red-/red_cl_distrib./g' ../../src/satzilla_features_to_reconf.cpp", + shell=True) + +upload = query_yes_no("Upload to AWS?") +if upload: + subprocess.call("aws s3 cp ../../src/satzilla_features_to_reconf.cpp s3://msoos-solve-data/solvers/", shell=True) + print("Uploded to AWS") +else: + print("Not uploaded to AWS") + + diff --git a/cryptominisat/cppsrc/scripts/reconf/reconf.py b/cryptominisat/cppsrc/scripts/reconf/reconf.py new file mode 100755 index 00000000..b6722161 --- /dev/null +++ b/cryptominisat/cppsrc/scripts/reconf/reconf.py @@ -0,0 +1,334 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- + +# Copyright (C) 2009-2020 Authors of CryptoMiniSat, see AUTHORS file +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; version 2 +# of the License. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +# 02110-1301, USA. + +import sys +import re +import ntpath +import os + +from optparse import OptionParser +usage = """ +./reconf.py -n 15 ~/media/sat/out/satcomp091113/reconf0-09113-23-July-2015-mark-XZGKC-78499d3f2-tout-5000-mout-1600/*.stdout* ~/media/sat/out/satcomp091113/reconf14-091113-28-August-2015-mark-O5T8F-169dfc802-tout-5000-mout-1600/*.stdout* + +NOTE: you *must* have reconf14 in there or a lot of data will be missing +in particular avg_confl_size, which will make the system error out on you. +""" +parser = OptionParser(usage=usage) +parser.add_option("-f", "--file", + dest="outfname", type=str, default="outfile", + help="print final values to this file") +parser.add_option("-n", "--num", + dest="num", type=int, + help="Number of reconfs") +parser.add_option("--dropdown", + dest="dropdown", type=float, default=0.02, + help="From traget 1.0 this is subtracted no matter what") +parser.add_option("--cutoff", + dest="cutoff", type=float, default=0.50, + help="At least this much or higher is needed for +") +parser.add_option("--divisor", + dest="divisor", type=float, default=1500.0, + help="Time difference is divided by this much and subtracted") +parser.add_option("--ignorethresh", + dest="ignore_threshold", type=float, default=4000.0, + help="If all solved above this score, ignore") +parser.add_option("--maxscore", + dest="maxscore", type=int, default=5000.0, + help="Scores go down from here") +parser.add_option("--ignore", "-i", + dest="ignore", type=str, + help="Ignore these reconfs") +parser.add_option("--verbose", "-r", dest="verbose", default=False, + action="store_true", help="More verbose") + +(options, args) = parser.parse_args() +# print("files to parse are:", args) + +ignore = {} +if options.ignore: + for r in options.ignore.split(","): + r = r.strip() + r = int(r) + ignore[r] = True + +satzilla_feat_order = ["numClauses", "binary", "horn", "horn_mean", "horn_std", "horn_min", "horn_max", "horn_spread", "vcg_var_mean", "vcg_var_std", "vcg_var_min", "vcg_var_max", "vcg_var_spread", "vcg_cls_mean", "vcg_cls_std", "vcg_cls_min", "vcg_cls_max", "vcg_cls_spread", "pnr_var_mean", "pnr_var_std", "pnr_var_min", "pnr_var_max", "pnr_var_spread", "pnr_cls_mean", "pnr_cls_std", "pnr_cls_min", "pnr_cls_max", "pnr_cls_spread", "avg_confl_size", "confl_size_min", "confl_size_max", "avg_confl_glue", "confl_glue_min", "confl_glue_max", "avg_num_resolutions", "num_resolutions_min", "num_resolutions_max", "learnt_bins_per_confl", "avg_branch_depth", "branch_depth_min", "branch_depth_max", "avg_trail_depth_delta", "trail_depth_delta_min", "trail_depth_delta_max", "avg_branch_depth_delta", "props_per_confl", "confl_per_restart", "decisions_per_conflict", "irred_cl_distrib.glue_distr_mean", "irred_cl_distrib.glue_distr_var", "irred_cl_distrib.size_distr_mean", "irred_cl_distrib.size_distr_var", "irred_cl_distrib.uip_use_distr_mean", "irred_cl_distrib.uip_use_distr_var", "irred_cl_distrib.activity_distr_mean", "irred_cl_distrib.activity_distr_var", "red_cl_distrib.glue_distr_mean", "red_cl_distrib.glue_distr_var", "red_cl_distrib.size_distr_mean", "red_cl_distrib.size_distr_var", "red_cl_distrib.uip_use_distr_mean", "red_cl_distrib.uip_use_distr_var", "red_cl_distrib.activity_distr_mean", "red_cl_distrib.activity_distr_var"] + +f = open("outs/reconf.names", "w") +f.write("reconf. | the target attribute\n\n") +f.write("name: label.\n") +for o in satzilla_feat_order: + f.write("%s: continuous.\n" % o) +f.write("\nreconf: +,-.\n") +f.close() + +if options.num is None: + print("ERROR: You must give the number of reconfs") + exit(-1) + + +def parse_satzilla_features_line(line): + line = re.sub("c.*satzilla_features. ", "", line) + line = line.strip().split(" ") + dat = {} + + name = "" + for elem, i in zip(line, range(1000)): + elem = elem.strip(":").strip(",") + if i % 2 == 0: + name = elem + continue + + dat[name] = elem + name = "" + return dat + + +def nobody_could_solve_it(reconf_score): + for r_s_elem in reconf_score: + if r_s_elem[1] != 0: + return False + + return True + + +def all_above_fixed_score(reconf_score): + for x in reconf_score: + if x[0] in ignore: + continue + + if x[1] < options.ignore_threshold: + print("-> not ignoring, reconf %d is below ignore threshold" % x[0]) + return False + + return True + + +def print_satzilla_features_and_scores(fname, satzilla_features, reconfs_scores): + r_s = sorted(reconfs_scores, key=lambda x: x[1])[::-1] + best_reconf = r_s[0][0] + best_reconf_score = r_s[0][1] + print("r_s: ", r_s) + + if nobody_could_solve_it(r_s): + print("Nobody could solve: %s" % fname) + return -1, False + + if all_above_fixed_score(r_s): + print("All above score: %s" % (fname)) + return -2, False + + print("Calculating +/- for %s" % fname) + + # calculate final array + final_array = [0.0]*options.num + val = 1.0 + best_score = r_s[0][1] + for conf_score, i in zip(r_s, range(100)): + diff = abs(conf_score[1]-best_score) + best_score = conf_score[1] + val -= float(diff)/options.divisor + if diff > 0: + val -= options.dropdown + + if val < 0.0 or conf_score[1] == 0: + val = 0.0 + + if conf_score[1] > 0: + final_array[conf_score[0]] = val + + # assemble final string + string = "" + string += "%s," % fname + for name in satzilla_feat_order: + string += "%s," % satzilla_features[name] + + # print to console + if True: + string2 = str(string) + string2 += "||" + for a in final_array: + string2 += "%.1f " % a + + print(string2) + + # print to files + origstring = str(string) + for i in range(options.num): + # skip files we don't need to write to + if i in ignore: + continue + + string = str(origstring) + if final_array[i] >= options.cutoff: + string += "+" + else: + string += "-" + + outf[i].write(string + "\n") + + only_this_could_solve_it = r_s[1][1] == 0 + return best_reconf, only_this_could_solve_it + + +def parse_file(fname): + f = open(fname, 'r') + # print("fname orig:", fname) + fname_clean = re.sub("cnf.gz-.*", "cnf.gz", fname) + fname_clean = ntpath.split(fname_clean)[1] + reconf = 0 + + satisfiable = None + satzilla_features = None + score = 0 + for line in f: + line = line.strip() + #print("parsing line:", line) + if satzilla_features is None and "satzilla_features" in line and "numClauses" in line: + satzilla_features = parse_satzilla_features_line(line) + + if "Total time" in line: + time_used = line.strip().split(":")[1].strip() + score = int(round(float(time_used))) + score = options.maxscore-score + + if "reconfigured" in line: + reconf = line.split("to config")[1].strip() + reconf = int(reconf) + + if "s SATIS" in line: + satisfiable = True + + if "s UNSATIS" in line: + satisfiable = False + + #if satisfiable == True: + # score = 0 + + if reconf in ignore: + score = 0 + + # print("satzilla_features:", satzilla_features) + return fname_clean, reconf, satzilla_features, score + + +all_files = set() +all_files_scores = {} +all_files_satzilla_features = {} +max_num_satzilla_features = 0 +for x in args: + print("# parsing infile:", x) + fname, reconf, satzilla_features, score = parse_file(x) + if fname in all_files: + if all_files_satzilla_features[fname] != satzilla_features: + print("different satzilla_features extracted for fname", fname) + print("orig:", all_files_satzilla_features[fname]) + print("new: ", satzilla_features) + print("Keeping the longer one!") + + if all_files_satzilla_features[fname] is None: + num_satzilla_features = 0 + else: + num_satzilla_features = len(all_files_satzilla_features[fname]) + + if satzilla_features is not None and num_satzilla_features < len(satzilla_features): + all_files_satzilla_features[fname] = satzilla_features + else: + all_files.add(fname) + all_files_satzilla_features[fname] = satzilla_features + all_files_scores[fname] = [] + + #print("fname:", fname) + all_files_scores[fname].append([reconf, score]) + + sys.stdout.write(".") + sys.stdout.flush() + +print("END--------") +print("all files:", all_files) +print("") + +outf = [] +outfnames = [] +for i in range(options.num): + fname = options.outfname + str(i) + ".data" + outfnames.append(fname) + try: + os.unlink(fname) + except: + pass + + if i not in ignore: + outf.append(open(fname, "w")) + else: + outf.append(None) + +best_reconf = {'all_above_fixed_score': 0, 'nobody_could_solve_it': 0} +for x in range(options.num): + best_reconf[x] = 0 +only_this = dict(best_reconf) + + +for fname in all_files: + print("") + print("calculating final DATs for CNF ", fname) + if all_files_satzilla_features[fname] is None: + print("-> solved too early, no satzilla_features, skipping") + continue + + if options.verbose: + print("-> all_files_satzilla_features[fname]:", all_files_satzilla_features[fname]) + if "avg_confl_size" not in all_files_satzilla_features[fname]: + print("-> WARNING This is weird, probably not solved by one (different satzilla_features than everything else), skipping") + continue + + if all_files_satzilla_features[fname] is None: + print("-> satzilla_features for file is None: %s" % fname) + + if all_files_satzilla_features[fname] is not None: + best, only_this_could_solve_it = print_satzilla_features_and_scores(fname, all_files_satzilla_features[fname], all_files_scores[fname]) + + if best == -2: + best = "all_above_fixed_score" + + if best == -1: + best = "nobody_could_solve_it" + + print("-> best here:", best) + best_reconf[best] = best_reconf[best] + 1 + if only_this_could_solve_it: + only_this[best] = only_this[best] + 1 + +print("") +print("Wrote data files: %s\n" % outfnames) +print("\n-----------------------------") +print("best reconfs: ") +for a, b in best_reconf.items(): + if a not in ignore: + print("%-20s : %-3d" % (a, b)) + +print("\n-----------------------------") +print("uniquely solved by: ") +for a, b in only_this.items(): + if a not in ignore: + print("%-20s : %-3d" % (a, b)) + +for i in range(options.num): + if outf[i] is not None: + outf[i].close() diff --git a/cryptominisat/cppsrc/scripts/reconf/tocpp.py b/cryptominisat/cppsrc/scripts/reconf/tocpp.py new file mode 100755 index 00000000..6849528c --- /dev/null +++ b/cryptominisat/cppsrc/scripts/reconf/tocpp.py @@ -0,0 +1,208 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- + +# Copyright (C) 2009-2020 Authors of CryptoMiniSat, see AUTHORS file +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; version 2 +# of the License. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +# 02110-1301, USA. + + +from __future__ import print_function +import sys + +from optparse import OptionParser +parser = OptionParser() +parser.add_option("-n", "--num", + dest="num", type=int, + help="Number of reconfs") +parser.add_option("--ignore", "-i", + dest="ignore", type=str, + help="Ignore these reconfs") + +(options, args) = parser.parse_args() + +ignore = {} +if options.ignore: + for r in options.ignore.split(","): + r = r.strip() + r = int(r) + ignore[r] = True + +if options.num is None: + print("ERROR: You must give the number of reconfs") + exit(-1) + +print("""/****************************************** +Copyright (C) 2009-2020 Authors of CryptoMiniSat, see AUTHORS file + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. +***********************************************/ + +#include "satzilla_features.h" +#include +using std::cout; +using std::endl; + +namespace CMSat { +""") + +for i in range(options.num): + if i not in ignore: + print("double get_score%d(const SatZillaFeatures& satzilla_feat, const int verb);" % i) + +print(""" +int get_reconf_from_satzilla_features(const SatZillaFeatures& satzilla_feat, const int verb) +{ +\tdouble best_score = 0.0; +\tint best_val = 0; +\tdouble score; +""") + +for i in range(options.num): + if i in ignore: + continue + + print(""" +\tscore = get_score%d(satzilla_feat, verb); +\tif (verb >= 2) +\t\tcout << "c Score for reconf %d is " << score << endl; +\tif (best_score < score) { +\t\tbest_score = score; +\t\tbest_val = %d; +\t} +""" % (i, i, i)) + +print(""" +\tif (verb >= 2) +\t\tcout << "c Winning reconf is " << best_val << endl; +\treturn best_val; +} + +""") + + +def read_one_reconf(reconf_num): + sys.stderr.write("Parsing reconf num %d\n" % reconf_num) + f = open("outs/out%d.rules" % reconf_num) + num_conds = 0 + cond_no = 0 + num_rules = 0 + rule_no = 0 + string = "" + + print(""" +double get_score%d(const SatZillaFeatures& satzilla_feat, const int verb) +{""" % reconf_num) + for line in f: + if "id=" in line: + continue + + line = line.strip() + line = line.split(" ") + dat = {} + for elem in line: + elems = elem.split("=") + elems = [e.strip("\"") for e in elems] + dat[elems[0]] = elems[1] + + if "conds" in dat: + assert num_conds == cond_no + num_conds = int(dat["conds"]) + rule_class = dat["class"] + cond_no = 0 + confidence = float(dat["confidence"]) + continue + + if "entries" in dat: + continue + + if "rules" in dat: + num_rules = int(dat["rules"]) + + if "default" in dat: + default = dat["default"] + if default == "+": + print("\tdouble default_val = %.2f;\n" % (1.0)) + else: + print("\tdouble default_val = %.2f;\n" % (0.0)) + + print("\tdouble total_plus = 0.0;") + print("\tdouble total_neg = 0.0;") + continue + + # process rules + if cond_no == 0: + string = "\tif (" + else: + string += " &&\n\t\t" + + string += "(satzilla_feat.%s %s %.5f)" % (dat["att"], dat["result"], + float(dat["cut"])) + cond_no += 1 + + # end rules + if cond_no == num_conds: + string += ")\n\t{" + print(string) + + string = "" + if rule_class == "+": + string += "\t\ttotal_plus += %.3f;" % confidence + else: + string += "\t\ttotal_neg += %.3f;" % confidence + + print(string) + print("\t}") + rule_no += 1 + + print("\t// num_rules:", num_rules) + print("\t// rule_no:", rule_no) + sys.stderr.write("num rules: %s rule_no: %s\n" % (num_rules, rule_no)) + assert num_rules == rule_no + print("\t// default is:", default) + print(""" +\tif (total_plus == 0.0 && total_neg == 0.0) { +\t\treturn default_val; +\t} +\tif (verb >= 2) { +\t\t//cout << "c plus: " << total_plus << " , neg: " << total_neg << endl; +\t} +\treturn total_plus - total_neg; +} +""") + + +for i in range(options.num): + if i not in ignore: + read_one_reconf(i) + +print(""" +} //end namespace""") diff --git a/cryptominisat/cppsrc/scripts/speed-check/addclause.py b/cryptominisat/cppsrc/scripts/speed-check/addclause.py new file mode 100755 index 00000000..caa7df5e --- /dev/null +++ b/cryptominisat/cppsrc/scripts/speed-check/addclause.py @@ -0,0 +1,79 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- + +# Copyright (c) 2018, Marcel Bargull, Mate Soos +# +# Permission is hereby granted, free of charge, to any person obtaining a copy +# of this software and associated documentation files (the "Software"), to deal +# in the Software without restriction, including without limitation the rights +# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +# copies of the Software, and to permit persons to whom the Software is +# furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in +# all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +# THE SOFTWARE. + +from array import array +from collections import defaultdict +from itertools import chain +from time import time +import pycryptosat +import pycosat + + +def cms_setup(clauses, m): + solver = pycryptosat.Solver() + solver.add_clauses(clauses, max_var=m) + return solver + + +def cms_solve(solver): + return solver.solve() + + +def ps_setup(clauses, m): + return pycosat.itersolve(clauses, vars=m) + + +def ps_solve(iter_sol): + return next(iter_sol) + + +if __name__ == "__main__": + n = 550*1000 + clause_list = list(chain.from_iterable( + [(-x, x + n, x + int(n/2)), (-x, x + n, x + int(n/2))] for x in range(1, n+1) + )) + clause_array = array("i", chain.from_iterable(c + (0,) for c in clause_list)) + m = max(clause_array) + + all_times = defaultdict(list) + my_list = ("CMS", cms_setup, cms_solve), ("Pycosat", ps_setup, ps_solve) + #my_list = ("CMS", cms_setup, cms_solve), (None, None, None) + for solver_type, setup, solve in list(my_list): + if solver_type is None: + continue + + my_type_list = ("list", clause_list), ("array", clause_array) + #my_type_list = ("list", clause_list), (None, None) + for clauses_type, clauses in (my_type_list): + if clauses is None: + continue + + for _ in range(5): + t = time() + solver = setup(clauses, m) + all_times["setup {:<7} {:<5}".format(solver_type, clauses_type)].append(time() - t) + t = time() + solve(solver) + all_times["solve {:<7} {:<5}".format(solver_type, clauses_type)].append(time() - t) + for text, times in sorted(all_times.items()): + print(text, *map("{:5.3f}".format, sorted(times))) diff --git a/cryptominisat/cppsrc/scripts/starexec/job.xml b/cryptominisat/cppsrc/scripts/starexec/job.xml new file mode 100644 index 00000000..c6a79492 --- /dev/null +++ b/cryptominisat/cppsrc/scripts/starexec/job.xml @@ -0,0 +1,36 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/cryptominisat/cppsrc/scripts/tbuddy_fuzzer.sh b/cryptominisat/cppsrc/scripts/tbuddy_fuzzer.sh new file mode 100755 index 00000000..77df0a29 --- /dev/null +++ b/cryptominisat/cppsrc/scripts/tbuddy_fuzzer.sh @@ -0,0 +1,40 @@ +#!/bin/bash +set -x + +from=$1 +to=$((from+1000)) +i=$1 +while [[ ${to} -gt ${i} ]]; do + echo "Doing $i" + rm -f test_FRAT-${i} + rm -f test_FRAT-${i}.cnf + + # ../utils/cnf-utils/cnf-fuzz-brummayer.py > test_FRAT-${i}.cnf + # timeout 5s ./cryptominisat5 test_FRAT-${i}.cnf b --distill 0 --scc 0 --varelim 0 --presimp 0 --xor 0 --confbtwsimp 10000000 --occsimp 0 --sls 0 --bva 0 --intree 0 > out_test + # timeout 5s ./cryptominisat5 test_FRAT-${i}.cnf b --distill 1 --scc 1 --varelim 1 --presimp 1 --xor 0 --confbtwsimp 100 --occsimp 1 --sls 0 --bva 0 --intree 0 > out_test + + ../utils/cnf-utils/xortester.py -s $i --varsmin 35 > test_FRAT-${i}.cnf + # ../utils/cnf-utils/xortester.py -s $i --varsmin 35 > test_FRAT-${i}.cnf + # timeout 30s ./cryptominisat5 test_FRAT-${i}.cnf b-${i} --distill 1 --scc 1 --varelim 1 --presimp 1 --xor 1 --confbtwsimp 100 --occsimp 1 --sls 1 --bva 1 --intree 1 --maxmatrixcols 10000 --maxmatrixrows 10000 --strmaxt 0 --mustconsolidate 1 > out_test-${i} + + timeout 30s ./cryptominisat5 test_FRAT-${i}.cnf b-${i} --presimp 1 --maxmatrixcols 10000 --maxmatrixrows 10000 > out_test-${i} + + a=`grep "UNSATIS" out_test-${i}` + if [[ $? -eq 0 ]]; then + ./frat-rs stat b-${i} + ./frat-rs elab b-${i} -m test_FRAT-${i}.cnf -v + if [[ $? == 0 ]]; then + echo "OK, verification good" + else + echo "Verification error" + exit -1 + fi + else + echo "not UNSAT" + fi + rm -f b-${i} + rm -f out_test-${i} + rm -f ELAB-${i} + rm -f test_FRAT-${i} + i=$((i+1)) +done diff --git a/cryptominisat/cppsrc/scripts/translate_opb.py b/cryptominisat/cppsrc/scripts/translate_opb.py new file mode 100755 index 00000000..57b15fe6 --- /dev/null +++ b/cryptominisat/cppsrc/scripts/translate_opb.py @@ -0,0 +1,305 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- + +# Copyright (C) 2022 Authors of CryptoMiniSat, see AUTHORS file +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; version 2 +# of the License. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +# 02110-1301, USA. + +import sys +import subprocess + +def parse_lit(x): + inv = 1 + if x[0] == '~': + inv = -1 + x = x[1:] + + assert x[0] == 'x' + v = int(x[1:]) + return v*inv + +def leq_translate(c): + #if len(c.lhs) == 1 and c.lhs[0][0] == 1 and c.cutoff == 0: + #print("%d %d 0" % (-c.lhs[0][1], c.rhs)) + #print("%d %d 0" % (c.lhs[0][1], -c.rhs)) + #return + #if len(c.lhs) == 1 and c.lhs[0][0] == -1 and c.cutoff == 1: + #print("%d %d 0" % (-c.lhs[0][1], c.rhs)) + #print("%d %d 0" % (c.lhs[0][1], -c.rhs)) + #return + + #if len(c.lhs) == 1 and c.rhs == None and c.cutoff == 1: + #if c.lhs[0][0] == 1: + #print("%d 0" % c.lhs[0][1]) + #return + #sys.stderr.write("ERRROOOR\n") + #exit(-1) + + ins = [] + for l in c.lhs: + if l[0] == 1: + ins.append(l[1]) + continue + else: + ins.append(-l[1]) + c.cutoff+=1 + + pr = "b " + for l in ins: + pr += "%d " % l + + pr += "0 " + pr += "%d " % c.cutoff + + if c.rhs is not None: + pr += "%d " % c.rhs + print("%s" % pr) + +class Constr: + def __init__(self, lhs, cutoff, rhs, sign): + self.lhs = lhs + self.cutoff = cutoff + self.rhs = rhs + self.sign = sign + + def __repr__(self): + return "lhs: %s cutoff: %s sign: %s rhs: %s" % (self.lhs, self.cutoff, self.sign, self.rhs) + + def simple(self): + if self.sign != "=" and self.sign != ">=": + return + + for l in self.lhs: + if l[0] == 1 or l[0] == -1: + continue + else: + return False + + return True + + def translate(self): + print("c Doing simple:", self) + assert self.simple() + if self.sign == ">=": + leq_translate(self) + elif self.sign == "=": + leq_translate(self) + c = Constr(self.lhs, self.cutoff, self.rhs, self.sign) + c.cutoff = len(c.lhs) - c.cutoff + for i in range(len(c.lhs)): + c.lhs[i][0] = -c.lhs[i][0] + leq_translate(c) + else: + print("ERRROR") + exit(-1) + + + + + +def parse_constr(line): + lhs = [] + cutoff = None + rhs = None + sign = "" + + at_lhs = True + at_cutoff = False + at_rhs = False + done = False + line = line.split(' ') + i = 0 + #print("line:", line) + while i < len(line): + #print("SO FAR -- lhs: ", lhs, "cutoff: ", cutoff, "rhs: ", rhs, "at_lhs:", at_lhs, "at_cutoff:", at_cutoff, "at_rhs:", at_rhs) + + k = line[i].strip() + if k == '': + i+=1 + continue + + if at_lhs: + if k == ">=" or k == "=": + sign = k + at_lhs = False + at_cutoff= True + i+=1 + continue + #else: + #sys.stderr.write("ERRROOOR: input has:" + k) + #exit(-1) + coeff = int(k) + assert i+1 < len(line) + i+=1 + k = line[i].strip() + lit = parse_lit(k) + lhs.append([coeff, lit]) + i+=1 + continue + + if at_cutoff: + if k == "<->": + at_cutoff= False + at_rhs = True + i+=1 + continue + if k == ";": + done = True + break + cutoff = int(k) + i+=1 + continue + + if at_rhs: + if k == ";": + done = True + break + assert k[0] == 'x' + rhs = parse_lit(k) + i+=1 + continue + + assert False + + assert done + + #if rhs is not None: + #print("lhs: ", lhs, "cutoff: ", cutoff, "rhs: ", rhs) + #else: + #print("lhs: ", lhs, "cutoff: ", cutoff) + + return Constr(lhs, cutoff, rhs, sign) + + +def do_pbsugar(constr, maxvar): + with open("sugarin", "w") as f: + f.write("* #variable= %d #constraint= 1\n" % maxvar) + for i in constr.lhs: + f.write("%d x%d " % (i[0],i[1])) + f.write(" >= %d ;\n" % constr.cutoff) + assert constr.rhs is None + + args = ("./pbsugar", "-map", "x", "-n", "sugarin", "-sat", "sugarout") + popen = subprocess.Popen(args, stdout=subprocess.PIPE) + popen.wait() + output = popen.stdout.read() + #print("c pbsugar output: ", output) + + # get map + varmap_end = 0 + varmap = {} + with open("x", "r") as f: + first = True + for line in f: + if first: + num_max = int(line.strip()) + assert num_max == maxvar # or it had to use some extra vars + first = False + continue + line=line.strip().split(' ') + assert line[0][0] == 'x' + new = int(line[1]) + orig = int(line[0][1:]) + varmap[new] = orig + if new > varmap_end: + varmap_end = new + + towrite = "" + with open("sugarout", "r") as f: + for line in f: + if "p cnf" in line: + continue + line = line.strip().split() + for lit in line: + lit = int(lit) + sign = lit < 0 + var = abs(lit) + if var == 0: + towrite+= '0' + print(towrite) + towrite = "" + continue + + if var in varmap: + # part of original formula + var2 = varmap[var] + else: + # fresh variable by pbsugar + assert var > varmap_end + maxvar+=1 + var2 = maxvar + + if sign: + lit2 = -var2 + else: + lit2 = var2 + towrite+="%d " % lit2 + + return maxvar + + +if __name__ == "__main__": + if len(sys.argv) != 2: + print("ERROR: must give ONE input, the OPB file") + exit(-1) + + fname = sys.argv[1] + + # parse input + ind = [] + constr = [] + maxvar = None + with open(fname, "r") as f: + # parse ind + for line in f: + line = line.strip() + if len(line) == 0: + continue + + if "#variable" in line: + maxvar = int(line.split()[2]) + print("c maxvar: ", maxvar) + continue + + if "* ind" in line: + line = line[5:] + for k in line.split(' '): + k = k.strip() + if k != "0" and k != '': + ind.append(int(k)) + continue + + if line[0] == '*': + continue + + constr.append(parse_constr(line)) + + # deal with independent + pr = "c ind " + for i in ind: + pr += "%d " % i + print("%s 0" % pr) + + # create output + for c in constr: + print("c doing constraint: ", c) + if c.simple(): + c.translate() + else: + print("c Using pbsugar to deal with: ", c) + maxvar = do_pbsugar(c, maxvar) + + diff --git a/cryptominisat/cppsrc/scripts/xxd-alike.py b/cryptominisat/cppsrc/scripts/xxd-alike.py new file mode 100755 index 00000000..9001ee52 --- /dev/null +++ b/cryptominisat/cppsrc/scripts/xxd-alike.py @@ -0,0 +1,67 @@ +#!/usr/bin/env python + +# Copyright (c) 2017, Martin Horenovsky +# Copyright (C) 2009-2020 Authors of CryptoMiniSat, see AUTHORS file + +# Permission is hereby granted, free of charge, to any person obtaining a copy +# of this software and associated documentation files (the "Software"), to deal +# in the Software without restriction, including without limitation the rights +# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +# copies of the Software, and to permit persons to whom the Software is +# furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in +# all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +# THE SOFTWARE. + +import sys +import hashlib + +PY3 = sys.version_info.major == 3 + +input_name = sys.argv[1] +output_path = sys.argv[2] +last_dash = input_name.rfind("/") +if last_dash != -1: + output_name = input_name[last_dash+1:].replace('.', '_') +else: + output_name = input_name.replace('.', '_') + + +# In python 3, opening file as rb will return bytes and iteration is per byte +# In python 2, opening file as rb will return string and iteration is per char +# and char need to be converted to bytes. +# This function papers over the differences +def convert(c): + if PY3: + return c + return ord(c) + + +with open(input_name, 'rb') as file: + contents = file.read() + + +with open(output_path, 'w') as out: + out.write('unsigned char {}[] = {{'.format(output_name)) + first = True + for i, byte in enumerate(contents): + if not first: + out.write(', ') + first = False + if i % 12 == 0: + out.write('\n ') + out.write('0x{:02x}'.format(convert(byte))) + + out.write(', 0x00') + out.write('\n};\n') + + out.write('unsigned int {}_len = {};\n'.format(output_name, len(contents))) + out.write('const char* {}_hash = "{}";\n'.format(output_name, hashlib.sha1(contents).hexdigest())) diff --git a/cryptominisat/cppsrc/setup.cfg b/cryptominisat/cppsrc/setup.cfg new file mode 100644 index 00000000..1a5e8a3b --- /dev/null +++ b/cryptominisat/cppsrc/setup.cfg @@ -0,0 +1,6 @@ +[metadata] +url = https://github.com/msoos/cryptominisat +long_description_content_type = "text/markdown" + +[options] +python_requires = >=3.5 diff --git a/cryptominisat/cppsrc/setup.py b/cryptominisat/cppsrc/setup.py new file mode 100644 index 00000000..27d7fa4f --- /dev/null +++ b/cryptominisat/cppsrc/setup.py @@ -0,0 +1,118 @@ +# +# CryptoMiniSat +# +# Copyright (c) 2009-2017, Mate Soos. All rights reserved. +# Copyright (c) 2017, Pierre Vignet +# +# Permission is hereby granted, free of charge, to any person obtaining a copy +# of this software and associated documentation files (the "Software"), to deal +# in the Software without restriction, including without limitation the rights +# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +# copies of the Software, and to permit persons to whom the Software is +# furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in +# all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +# THE SOFTWARE. + + +import sys +import os +from setuptools import Extension, setup +import sysconfig +import toml +import pathlib +from sys import platform + +def _parse_toml(pyproject_path): + pyproject_text = pyproject_path.read_text() + pyproject_data = toml.loads(pyproject_text) + return pyproject_data['project']['version'] + +picosatlib = ('picosatlib', { + 'sources': [ + "src/picosat/picosat.c", + "src/picosat/version.c"], + 'language' : "c", + 'define_macros' : [("TRACE", "ON")], + 'include_dirs' : ["src/picosat/"] + }) + + +def gen_modules(version): + + if platform == "win32" or platform == "cygwin": + extra_compile_args_val = ['-I../', '-Isrc/', '/std:c++17', "/DCMS_FULL_VERSION=\""+version+"\""] + define_macros_val = [("TRACE", "")] + + else: + extra_compile_args_val = ['-I../', '-Isrc/', '-std=c++17'] + define_macros_val = [("TRACE", ""), ("CMS_FULL_VERSION", "\""+version+"\"")] + + modules = Extension( + name = "pycryptosat", + include_dirs = ["src/"], + sources = ["python/src/pycryptosat.cpp", + "python/src/GitSHA1.cpp", + "src/bva.cpp", + "src/cardfinder.cpp", + "src/ccnr_cms.cpp", + "src/ccnr.cpp", + "src/clauseallocator.cpp", + "src/clausecleaner.cpp", + "src/cnf.cpp", + "src/completedetachreattacher.cpp", + "src/cryptominisat_c.cpp", + "src/cryptominisat.cpp", + "src/datasync.cpp", + "src/distillerbin.cpp", + "src/distillerlitrem.cpp", + "src/distillerlong.cpp", + "src/distillerlongwithimpl.cpp", + "src/frat.cpp", + "src/gatefinder.cpp", + "src/gaussian.cpp", + "src/get_clause_query.cpp", + "src/hyperengine.cpp", + "src/intree.cpp", + "src/lucky.cpp", + "src/matrixfinder.cpp", + "src/occsimplifier.cpp", + "src/packedrow.cpp", + "src/propengine.cpp", + "src/reducedb.cpp", + "src/sccfinder.cpp", + "src/searcher.cpp", + "src/searchstats.cpp", + "src/sls.cpp", + "src/solutionextender.cpp", + "src/solverconf.cpp", + "src/solver.cpp", + "src/str_impl_w_impl.cpp", + "src/subsumeimplicit.cpp", + "src/subsumestrengthen.cpp", + "src/varreplacer.cpp", + "src/xorfinder.cpp", + "src/oracle/oracle.cpp", + ], + extra_compile_args = extra_compile_args_val, + define_macros=define_macros_val, + language = "c++", + ) + return modules + +if __name__ == '__main__': + pyproject_path = pathlib.Path('pyproject.toml') + version = _parse_toml(pyproject_path) + modules = gen_modules(version) + setup( + ext_modules = [modules], + libraries = [picosatlib], + ) diff --git a/cryptominisat/cppsrc/sonar-project.properties b/cryptominisat/cppsrc/sonar-project.properties new file mode 100644 index 00000000..d36d9c47 --- /dev/null +++ b/cryptominisat/cppsrc/sonar-project.properties @@ -0,0 +1,14 @@ +# must be unique in a given SonarQube instance +sonar.projectKey=msoos_cryptominisat +# this is the name and version displayed in the SonarQube UI. Was mandatory prior to SonarQube 6.1. +sonar.projectName=CryptoMiniSat +sonar.projectVersion=1.0 + +# Path is relative to the sonar-project.properties file. Replace "\" by "/" on Windows. +# This property is optional if sonar.modules is set. +sonar.sources=src,build/cmsat5-src + +# Encoding of the source code. Default is default system encoding +#sonar.sourceEncoding=UTF-8 + +sonar.cfamily.build-wrapper-output=build/bw-output diff --git a/cryptominisat/cppsrc/src/.color_coded b/cryptominisat/cppsrc/src/.color_coded new file mode 100644 index 00000000..61956f76 --- /dev/null +++ b/cryptominisat/cppsrc/src/.color_coded @@ -0,0 +1 @@ +-I../build/cmsat5-src/ diff --git a/cryptominisat/cppsrc/src/.kdev_include_paths b/cryptominisat/cppsrc/src/.kdev_include_paths new file mode 100644 index 00000000..7111dba3 --- /dev/null +++ b/cryptominisat/cppsrc/src/.kdev_include_paths @@ -0,0 +1 @@ +/home/soos/development/sat_solvers/cryptominisat/build/include/ diff --git a/cryptominisat/cppsrc/src/CMakeLists.txt b/cryptominisat/cppsrc/src/CMakeLists.txt new file mode 100644 index 00000000..987328b9 --- /dev/null +++ b/cryptominisat/cppsrc/src/CMakeLists.txt @@ -0,0 +1,450 @@ +# Copyright (C) 2009-2020 Authors of CryptoMiniSat, see AUTHORS file +# +# Permission is hereby granted, free of charge, to any person obtaining a copy +# of this software and associated documentation files (the "Software"), to deal +# in the Software without restriction, including without limitation the rights +# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +# copies of the Software, and to permit persons to whom the Software is +# furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in +# all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +# THE SOFTWARE. + +include_directories( ${PROJECT_SOURCE_DIR} ) +include_directories( ${BOSPHORUS_INCLUDE_DIRS} ) +include_directories( ${TBUDDY_INCLUDE_DIRS} ) +include_directories( ${LOUVAIN_COMMUNITIES_INCLUDE_DIRS} ) +include_directories( SYSTEM ${MPI_INCLUDE_PATH} ) + +if (NOT WIN32) + add_cxx_flag_if_supported("-Wno-bitfield-constant-conversion") + #add_cxx_flag_if_supported("-Wduplicated-cond") + #add_cxx_flag_if_supported("-Wduplicated-branches") + add_cxx_flag_if_supported("-Wlogical-op") + add_cxx_flag_if_supported("-Wrestrict") + add_cxx_flag_if_supported("-Wnull-dereference") + add_cxx_flag_if_supported("-Wdouble-promotion") + add_cxx_flag_if_supported("-Wshadow") + add_cxx_flag_if_supported("-Wformat=2") + add_cxx_flag_if_supported("-Wextra-semi") + add_cxx_flag_if_supported("-pedantic") + #add_cxx_flag_if_supported("-Wdeprecated") + + if (FINAL_PREDICTOR) + add_cxx_flag_if_supported("-Wno-unused-parameter") + add_cxx_flag_if_supported("-Wno-unused-but-set-variable") + endif() +endif() +add_sanitize_flags() + +include_directories(${CMAKE_CURRENT_BINARY_DIR}) +include_directories(${CMAKE_CURRENT_SOURCE_DIR}) + +if (ENABLE_TESTING) + add_definitions( -DCMS_TESTING_ENABLED ) + set(GTEST_PREFIX ${PROJECT_SOURCE_DIR}/utils/gtest) + include_directories(${GTEST_PREFIX}/include) +endif() + +configure_file("${CMAKE_CURRENT_SOURCE_DIR}/GitSHA1.cpp.in" "${CMAKE_CURRENT_BINARY_DIR}/GitSHA1.cpp" @ONLY) + +if (STATS OR FINAL_PREDICTOR) + if (NOT Python3_EXECUTABLE) + MESSAGE(FATAL_ERROR "Unfortunately, the python interpreter is needed for statistics because of SQL text generation") + endif() + + add_custom_command( + OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/sql_tablestructure.cpp + WORKING_DIRECTORY ${CMAKE_SOURCE_DIR} + COMMAND ${Python3_EXECUTABLE} ${CRYPTOMS_SCRIPTS_DIR}/xxd-alike.py cmsat_tablestructure.sql ${CMAKE_CURRENT_BINARY_DIR}/sql_tablestructure.cpp + DEPENDS ${CMAKE_SOURCE_DIR}/cmsat_tablestructure.sql ${CRYPTOMS_SCRIPTS_DIR}/xxd-alike.py + ) + add_custom_target(tablestruct ALL DEPENDS ${CMAKE_CURRENT_BINARY_DIR}/sql_tablestructure.cpp) +endif() + +if (FINAL_PREDICTOR) + include_directories(${Python3_INCLUDE_DIRS}) + include_directories(${Python3_NumPy_INCLUDE_DIRS}) + add_custom_command( + OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/pred_short.cpp + WORKING_DIRECTORY ${CMAKE_SOURCE_DIR} + COMMAND ${Python3_EXECUTABLE} ${CRYPTOMS_SCRIPTS_DIR}/xxd-alike.py src/predict/predictor_short.json ${CMAKE_CURRENT_BINARY_DIR}/pred_short.cpp + DEPENDS ${CMAKE_SOURCE_DIR}/src/predict/predictor_short.json ${CRYPTOMS_SCRIPTS_DIR}/xxd-alike.py + ) + add_custom_target(pred_short ALL DEPENDS ${CMAKE_CURRENT_BINARY_DIR}/pred_short.cpp) + + add_custom_command( + OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/pred_long.cpp + WORKING_DIRECTORY ${CMAKE_SOURCE_DIR} + COMMAND ${Python3_EXECUTABLE} ${CRYPTOMS_SCRIPTS_DIR}/xxd-alike.py src/predict/predictor_long.json ${CMAKE_CURRENT_BINARY_DIR}/pred_long.cpp + DEPENDS ${CMAKE_SOURCE_DIR}/src/predict/predictor_long.json ${CRYPTOMS_SCRIPTS_DIR}/xxd-alike.py + ) + add_custom_target(pred_long ALL DEPENDS ${CMAKE_CURRENT_BINARY_DIR}/pred_long.cpp) + + add_custom_command( + OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/pred_forever.cpp + WORKING_DIRECTORY ${CMAKE_SOURCE_DIR} + COMMAND ${Python3_EXECUTABLE} ${CRYPTOMS_SCRIPTS_DIR}/xxd-alike.py src/predict/predictor_forever.json ${CMAKE_CURRENT_BINARY_DIR}/pred_forever.cpp + DEPENDS ${CMAKE_SOURCE_DIR}/src/predict/predictor_forever.json ${CRYPTOMS_SCRIPTS_DIR}/xxd-alike.py + ) + add_custom_target(pred_forever ALL DEPENDS ${CMAKE_CURRENT_BINARY_DIR}/pred_forever.cpp) +endif() + +# Needed for PicoSAT trace generation +add_definitions( -DTRACE ) + +set(cryptoms_lib_files + cnf.cpp + frat.cpp + propengine.cpp + varreplacer.cpp + clausecleaner.cpp + occsimplifier.cpp + gatefinder.cpp + subsumestrengthen.cpp + clauseallocator.cpp + sccfinder.cpp + solverconf.cpp + distillerlong.cpp + distillerlitrem.cpp + distillerbin.cpp + distillerlongwithimpl.cpp + str_impl_w_impl.cpp + solutionextender.cpp + completedetachreattacher.cpp + searcher.cpp + solver.cpp + hyperengine.cpp + subsumeimplicit.cpp + datasync.cpp + reducedb.cpp + bva.cpp + intree.cpp + searchstats.cpp + xorfinder.cpp + cardfinder.cpp + cryptominisat_c.cpp + sls.cpp + sqlstats.cpp + vardistgen.cpp + ccnr.cpp + ccnr_cms.cpp + lucky.cpp + get_clause_query.cpp + gaussian.cpp + packedrow.cpp + matrixfinder.cpp + picosat/picosat.c + picosat/version.c + oracle/oracle.cpp + ${CMAKE_CURRENT_BINARY_DIR}/GitSHA1.cpp +) + +if (GPU) + set(cryptoms_lib_files + ${cryptoms_lib_files} + gpuShareLib/Utils.cc + gpuShareLib/Assigs.cu + gpuShareLib/BaseTypes.cu + gpuShareLib/Clauses.cu + gpuShareLib/ClauseUpdates.cu + gpuShareLib/CorrespArr.cu + gpuShareLib/GpuClauseSharerImpl.cu + gpuShareLib/GpuRunner.cu + gpuShareLib/GpuUtils.cu + gpuShareLib/Helper.cu + gpuShareLib/Reported.cu + gpuShareLib/Reporter.cu + ) +endif() + +set(cryptoms_lib_link_libs "") + +set(cryptoms_lib_link_libs + ${cryptoms_lib_link_libs} +) + +if (tbuddy_FOUND) + set(cryptoms_lib_link_libs ${cryptoms_lib_link_libs} tbuddy) +endif() + +if (FINAL_PREDICTOR) + set(cryptoms_lib_files + ${cryptoms_lib_files} +# predict/clustering_imp.cpp + cl_predictors_xgb.cpp + cl_predictors_py.cpp + cl_predictors_lgbm.cpp + cl_predictors_abs.cpp + ) + SET(cryptoms_lib_link_libs ${cryptoms_lib_link_libs} + _lightgbm xgboost dmlc rabit rt ${Python3_LIBRARIES}) +endif() + +if (STATS_NEEDED) + set(cryptoms_lib_files + ${cryptoms_lib_files} + community_finder.cpp + satzilla_features_calc.cpp + satzilla_features.cpp + ) +endif() + +if (MPI_FOUND) + SET(cryptoms_lib_link_libs ${cryptoms_lib_link_libs} ${MPI_CXX_LIBRARIES}) +endif() + +if (BOSPHORUS_LIBRARIES) + include_directories( ${BOSPHORUS_INCLUDE_DIRS} ) + + SET(cryptoms_lib_files ${cryptoms_lib_files} cms_bosphorus.cpp) + SET(cryptoms_lib_link_libs ${cryptoms_lib_link_libs} ${BOSPHORUS_LIBRARIES}) +endif() + +if (BREAKID_LIBRARIES) + include_directories( ${BREAKID_INCLUDE_DIRS} ) + + SET(cryptoms_lib_files ${cryptoms_lib_files} cms_breakid.cpp) + SET(cryptoms_lib_link_libs ${cryptoms_lib_link_libs} ${BREAKID_LIBRARIES}) +endif() + +if (STATS) + SET(cryptoms_lib_files ${cryptoms_lib_files} + sqlitestats.cpp + ${CMAKE_CURRENT_BINARY_DIR}/sql_tablestructure.cpp + ) + SET(cryptoms_lib_link_libs ${cryptoms_lib_link_libs} ${SQLITE3_LIBRARIES}) +endif () + +if (FINAL_PREDICTOR) + SET(cryptoms_lib_files ${cryptoms_lib_files} + ${CMAKE_CURRENT_BINARY_DIR}/pred_short.cpp + ${CMAKE_CURRENT_BINARY_DIR}/pred_long.cpp + ${CMAKE_CURRENT_BINARY_DIR}/pred_forever.cpp + ) +endif() + +add_library(cryptominisat5 + ${cryptoms_lib_files} + cryptominisat.cpp +) +# Make sure the exported target has the include directory set +target_include_directories(cryptominisat5 PUBLIC + $ + $ +) + +set_target_properties(cryptominisat5 + PROPERTIES CUDA_SEPARABLE_COMPILATION ON) +set_property(TARGET cryptominisat5 + PROPERTY CUDA_ARCHITECTURES 35 50 72 +) + +GENERATE_EXPORT_HEADER(cryptominisat5 + BASE_NAME cryptominisat5 + #EXPORT_MACRO_NAME cryptominisat5_EXPORT + #EXPORT_FILE_NAME MyLibrary_Export.h + #STATIC_DEFINE MyLibrary_BUILT_AS_STATIC +) + +if (SQLITE3_FOUND AND STATS) + add_dependencies(cryptominisat5 + tablestruct + ) +endif() + +if (FINAL_PREDICTOR) + add_dependencies(cryptominisat5 + pred_short + pred_long + pred_forever + ) +endif() + +# indicate that we depend on pthread, and compile in the actual library +target_link_libraries(cryptominisat5 + LINK_PUBLIC ${cryptoms_lib_link_libs} + LINK_PUBLIC ${LOUVAIN_COMMUNITIES_LIBRARIES} + LINK_PUBLIC ${CMAKE_THREAD_LIBS_INIT} +) + +if (NOT WIN32) + set_target_properties(cryptominisat5 PROPERTIES + PUBLIC_HEADER "${cryptominisat5_public_headers}" + VERSION ${PROJECT_VERSION_MAJOR}.${PROJECT_VERSION_MINOR} + SOVERSION ${PROJECT_VERSION_MAJOR}.${PROJECT_VERSION_MINOR} + ) +else() + set_target_properties(cryptominisat5 PROPERTIES + OUTPUT_NAME cryptominisat5win + PUBLIC_HEADER "${cryptominisat5_public_headers}" + VERSION ${PROJECT_VERSION_MAJOR}.${PROJECT_VERSION_MINOR} + SOVERSION ${PROJECT_VERSION_MAJOR}.${PROJECT_VERSION_MINOR} + ) +endif() + +if (IPASIR) + add_library(ipasircryptominisat5 + ipasir.cpp + ${cryptoms_lib_files} + cryptominisat.cpp + ) + target_link_libraries(ipasircryptominisat5 + LINK_PUBLIC ${cryptoms_lib_link_libs} + LINK_PUBLIC ${CMAKE_THREAD_LIBS_INIT} + ) + set_target_properties(ipasircryptominisat5 PROPERTIES + OUTPUT_NAME ipasircryptominisat5 + PUBLIC_HEADER "${cryptominisat5_public_headers}" + VERSION ${PROJECT_VERSION_MAJOR}.${PROJECT_VERSION_MINOR} + SOVERSION ${PROJECT_VERSION_MAJOR}.${PROJECT_VERSION_MINOR} + ) + GENERATE_EXPORT_HEADER(ipasircryptominisat5) + install(TARGETS ipasircryptominisat5 + EXPORT ${CRYPTOMINISAT5_EXPORT_NAME} + LIBRARY DESTINATION "${CMAKE_INSTALL_LIBDIR}" + ARCHIVE DESTINATION "${CMAKE_INSTALL_LIBDIR}" + RUNTIME DESTINATION "${CMAKE_INSTALL_BINDIR}" + PUBLIC_HEADER DESTINATION "${CMAKE_INSTALL_INCLUDEDIR}/cryptominisat5" + ) +endif() + +cmsat_add_public_header(cryptominisat5 ${CMAKE_CURRENT_SOURCE_DIR}/cryptominisat_c.h ) +cmsat_add_public_header(cryptominisat5 ${CMAKE_CURRENT_SOURCE_DIR}/cryptominisat.h ) +cmsat_add_public_header(cryptominisat5 ${CMAKE_CURRENT_SOURCE_DIR}/solvertypesmini.h ) +cmsat_add_public_header(cryptominisat5 ${CMAKE_CURRENT_SOURCE_DIR}/dimacsparser.h ) +cmsat_add_public_header(cryptominisat5 ${CMAKE_CURRENT_SOURCE_DIR}/streambuffer.h ) + +# ----------------------------------------------------------------------------- +# Copy public headers into build directory include directory. +# The cryptominisat5Config.cmake we generate in the build directory depends on +# this. +# ----------------------------------------------------------------------------- +set(HEADER_DEST "${PROJECT_BINARY_DIR}/include/cryptominisat5") +add_custom_target(CopyPublicHeaders ALL) +get_target_property(cryptominisat5_public_headers cryptominisat5 PUBLIC_HEADER) +foreach(public_header ${cryptominisat5_public_headers}) + get_filename_component(HEADER_NAME ${public_header} NAME) + add_custom_command(TARGET CopyPublicHeaders PRE_BUILD + COMMAND ${CMAKE_COMMAND} -E make_directory + "${HEADER_DEST}" + COMMAND ${CMAKE_COMMAND} -E echo + "Copying ${HEADER_NAME} to ${HEADER_DEST}" + COMMAND ${CMAKE_COMMAND} -E + copy_if_different + ${public_header} + "${HEADER_DEST}" + ) +endforeach() + +GENERATE_EXPORT_HEADER(cryptominisat5) +install(TARGETS cryptominisat5 + EXPORT ${CRYPTOMINISAT5_EXPORT_NAME} + LIBRARY DESTINATION "${CMAKE_INSTALL_LIBDIR}" + ARCHIVE DESTINATION "${CMAKE_INSTALL_LIBDIR}" + RUNTIME DESTINATION "${CMAKE_INSTALL_BINDIR}" + PUBLIC_HEADER DESTINATION "${CMAKE_INSTALL_INCLUDEDIR}/cryptominisat5" +) + +add_executable(cryptominisat5-bin + main.cpp + main_common.cpp + main_exe.cpp + signalcode.cpp +) + +if (EMSCRIPTEN) + add_executable(cryptominisat5-bin + main_emscripten.cpp + main_common.cpp + ) + + set_target_properties(cryptominisat5-bin + PROPERTIES + OUTPUT_NAME cryptominisat5 + LINK_FLAGS "-s WASM=1 -s ALLOW_MEMORY_GROWTH=1 -s EXTRA_EXPORTED_RUNTIME_METHODS='[\"ccall\", \"cwrap\"]' -s LINKABLE=1 -s EXPORT_ALL=1 --pre-js ${CMAKE_CURRENT_SOURCE_DIR}/pre.js" + ) + + SET_SOURCE_FILES_PROPERTIES(main_emscripten.cpp + PROPERTIES COMPILE_FLAGS "-s WASM=1 -s ALLOW_MEMORY_GROWTH=1 -s EXTRA_EXPORTED_RUNTIME_METHODS='[\"ccall\", \"cwrap\"]' -s LINKABLE=1 -s EXPORT_ALL=1" + ) +endif() + +if (MPI_FOUND) + add_executable(cryptominisat5_mpi-bin + main_mpi.cpp + datasyncserver.cpp + ) +endif() + +set(cryptoms_exec_link_libs + cryptominisat5 +) + +IF (ZLIB_FOUND) + SET(cryptoms_exec_link_libs ${cryptoms_exec_link_libs} ${ZLIB_LIBRARY}) +ENDIF() + + +########################## +### Deal with binaries +########################## +if (MPI_FOUND) + set_target_properties(cryptominisat5_mpi-bin PROPERTIES + OUTPUT_NAME cryptominisat5_mpi + RUNTIME_OUTPUT_DIRECTORY ${PROJECT_BINARY_DIR} + INSTALL_RPATH_USE_LINK_PATH TRUE + ) + target_link_libraries(cryptominisat5_mpi-bin + ${cryptoms_exec_link_libs} + ${MPI_C_LIBRARIES} + ) + install(TARGETS cryptominisat5_mpi-bin + # EXPORT ${CRYPTOMINISAT5_EXPORT_NAME} + RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR} + ) + SET(CPACK_PACKAGE_EXECUTABLES "cryptominisat5_mpi") +endif() + +set_target_properties(cryptominisat5-bin PROPERTIES + OUTPUT_NAME cryptominisat5 + RUNTIME_OUTPUT_DIRECTORY ${PROJECT_BINARY_DIR} + INSTALL_RPATH_USE_LINK_PATH TRUE) +target_link_libraries(cryptominisat5-bin + ${cryptoms_exec_link_libs} +) +install(TARGETS cryptominisat5-bin + # EXPORT ${CRYPTOMINISAT5_EXPORT_NAME} + RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR} +) +SET(CPACK_PACKAGE_EXECUTABLES "cryptominisat5") + +if (FEEDBACKFUZZ) + add_executable(cms_feedback_fuzz + fuzz.cpp + libfuzz/FuzzerCrossOver.cpp + libfuzz/FuzzerDriver.cpp + libfuzz/FuzzerInterface.cpp + libfuzz/FuzzerIO.cpp + libfuzz/FuzzerLoop.cpp + libfuzz/FuzzerMain.cpp + libfuzz/FuzzerMutate.cpp + libfuzz/FuzzerSanitizerOptions.cpp + libfuzz/FuzzerSHA1.cpp + libfuzz/FuzzerTraceState.cpp + libfuzz/FuzzerUtil.cpp + ) + target_link_libraries(cms_feedback_fuzz + ${cryptoms_exec_link_libs} + ) + + set_target_properties(cms_feedback_fuzz PROPERTIES RUNTIME_OUTPUT_DIRECTORY ${PROJECT_BINARY_DIR}) +endif() diff --git a/cryptominisat/cppsrc/src/GitSHA1.cpp.in b/cryptominisat/cppsrc/src/GitSHA1.cpp.in new file mode 100644 index 00000000..8ce96b11 --- /dev/null +++ b/cryptominisat/cppsrc/src/GitSHA1.cpp.in @@ -0,0 +1,66 @@ +/****************************************** +Copyright (c) 2017, Mate Soos + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. +***********************************************/ + +#include "src/GitSHA1.h" + +const char* CMSat::get_version_sha1() +{ + static const char myversion_sha1[] = "@GIT_SHA1@"; + return myversion_sha1; +} + +const char* CMSat::get_version_tag() +{ + static const char myversion_tag[] = "@PROJECT_VERSION@"; + return myversion_tag; +} + +const char* CMSat::get_compilation_env() +{ + static const char compilation_env[] = + "CMAKE_CXX_COMPILER = @CMAKE_CXX_COMPILER@ | " + "CMAKE_CXX_FLAGS = @CMAKE_CXX_FLAGS@ | " + "COMPILE_DEFINES = @COMPILE_DEFINES@ | " + "STATICCOMPILE = @STATICCOMPILE@ | " + "ONLY_SIMPLE = @ONLY_SIMPLE@ | " + "STATS = @STATS@ | " + "SQLITE3_FOUND = @SQLITE3_FOUND@ | " + "ZLIB_FOUND = @ZLIB_FOUND@ | " + "VALGRIND_FOUND = @VALGRIND_FOUND@ | " + "ENABLE_TESTING = @ENABLE_TESTING@ | " + "SLOW_DEBUG = @SLOW_DEBUG@ | " + "ENABLE_ASSERTIONS = @ENABLE_ASSERTIONS@ | " + "PYTHON_EXECUTABLE = @PYTHON_EXECUTABLE@ | " + "PYTHON_LIBRARY = @PYTHON_LIBRARY@ | " + "PYTHON_INCLUDE_DIRS = @PYTHON_INCLUDE_DIRS@ | " + "MY_TARGETS = @MY_TARGETS@ | " + "LARGEMEM = @LARGEMEM@ | " + "LIMITMEM = @LIMITMEM@ | " + "BREAKID_LIBRARIES = @BREAKID_LIBRARIES@ | " + "BREAKID-VER = @BREAKID_VERSION_MAJOR@.@BREAKID_VERSION_MINOR@ | " + "BOSPHORUS_LIBRARIES = @BOSPHORUS_LIBRARIES@ | " + "BOSPH-VER = @BOSPHORUS_VERSION_MAJOR@.@BOSPHORUS_VERSION_MINOR@ | " + "compilation date time = " __DATE__ " " __TIME__ + "" + ; + return compilation_env; +} diff --git a/cryptominisat/cppsrc/src/GitSHA1.h b/cryptominisat/cppsrc/src/GitSHA1.h new file mode 100644 index 00000000..6f3c2126 --- /dev/null +++ b/cryptominisat/cppsrc/src/GitSHA1.h @@ -0,0 +1,29 @@ +/****************************************** +Copyright (C) 2009-2020 Authors of CryptoMiniSat, see AUTHORS file + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. +***********************************************/ + +namespace CMSat { + +const char* get_version_sha1(); +const char* get_version_tag(); +const char* get_compilation_env(); + +} diff --git a/cryptominisat/cppsrc/src/Vec.h b/cryptominisat/cppsrc/src/Vec.h new file mode 100644 index 00000000..3c58641b --- /dev/null +++ b/cryptominisat/cppsrc/src/Vec.h @@ -0,0 +1,330 @@ +/*******************************************************************************************[Vec.h] +Copyright (c) 2003-2007, Niklas Een, Niklas Sorensson +Copyright (c) 2007-2010, Niklas Sorensson + +Permission is hereby granted, free of charge, to any person obtaining a copy of this software and +associated documentation files (the "Software"), to deal in the Software without restriction, +including without limitation the rights to use, copy, modify, merge, publish, distribute, +sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all copies or +substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT +NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, +DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT +OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +**************************************************************************************************/ + +#ifndef Vec_h +#define Vec_h + +#include +#include +#include +#include +#include + +#include "constants.h" +#include "XAlloc.h" + +using std::numeric_limits; + +namespace CMSat { + +class Watched; + +//================================================================================================= +// Automatically resizable arrays +// +// NOTE! Don't use this vector on datatypes that cannot be re-located in memory (with realloc) + +template +class vec { +public: + T* data; + T* begin() + { + return data; + } + T* end() + { + return data + sz; + } + + const T* begin() const + { + return data; + } + const T* end() const + { + return data + sz; + } +private: + uint32_t sz; + uint32_t cap; + + // Don't allow copying (error prone): + vec& operator = (vec& /*other*/) + { + assert(0); + return *this; + } + vec (vec& /*other*/) + { + assert(0); + } + + // Helpers for calculating next capacity: + static inline uint32_t imax (int32_t x, int32_t y) + { + int32_t mask = (y - x) >> (sizeof(uint32_t) * 8 - 1); + return (x & mask) + (y & (~mask)); + } + +public: + // Constructors: + vec() : data(NULL) , sz(0) , cap(0) { } + explicit vec(uint32_t size) : data(NULL) , sz(0) , cap(0) + { + growTo(size); + } + vec(uint32_t size, const T& pad) : data(NULL) , sz(0) , cap(0) + { + growTo(size, pad); + } + ~vec() + { + clear(true); + } + + // Size operations: + uint32_t size() const + { + return sz; + } + void shrink (uint32_t nelems) + { + assert(nelems <= sz); + for (uint32_t i = 0; i < nelems; i++) { + sz--, data[sz].~T(); + } + } + void shrink_ (uint32_t nelems) + { + assert(nelems <= sz); + sz -= nelems; + } + uint32_t capacity () const + { + return cap; + } + void capacity (int32_t min_cap); + void growTo (uint32_t size); + void growTo (uint32_t size, const T& pad); + void clear (bool dealloc = false); + + // Stack interface: + void push () + { + if (sz == cap) { + capacity(sz + 1); + } + new (&data[sz]) T(); + sz++; + } + void push (const T& elem) + { + if (sz == cap) { + capacity(sz + 1); + } + data[sz++] = elem; + } + void push_ (const T& elem) + { + assert(sz < cap); + data[sz++] = elem; + } + void pop () + { + assert(sz > 0); + sz--, data[sz].~T(); + } + // NOTE: it seems possible that overflow can happen in the 'sz+1' expression of 'push()', but + // in fact it can not since it requires that 'cap' is equal to INT_MAX. This in turn can not + // happen given the way capacities are calculated (below). Essentially, all capacities are + // even, but INT_MAX is odd. + + const T& last () const + { + return data[sz - 1]; + } + T& last () + { + return data[sz - 1]; + } + + // Vector interface: + const T& operator [] (uint32_t index) const + { + return data[index]; + } + T& operator [] (uint32_t index) + { + return data[index]; + } + + // Duplicatation (preferred instead): + void copyTo(vec& copy) const + { + copy.clear(); + copy.growTo(sz); + for (uint32_t i = 0; i < sz; i++) { + copy[i] = data[i]; + } + } + void moveTo(vec& dest) + { + dest.clear(true); + dest.data = data; + dest.sz = sz; + dest.cap = cap; + data = NULL; + sz = 0; + cap = 0; + } + void swap(vec& dest) + { + std::swap(dest.data, data); + std::swap(dest.sz, sz); + std::swap(dest.cap, cap); + } + + void resize(uint32_t s) { + if (s < sz) { + shrink(sz - s); + } else { + growTo(s); + } + } + + void insert(uint32_t num) + { + growTo(sz+num); + } + + bool empty() const + { + return sz == 0; + } + + void shrink_to_fit() + { + if (sz == 0) { + free(data); + cap = 0; + data = NULL; + return; + } + + T* data2 = (T*)realloc(data, sz*sizeof(T)); + if (data2 == 0) { + //We just keep the size then + return; + } + data = data2; + cap = sz; + } +}; + + +// Fixes by @Topologist from GitHub. Thank you so much! +template +void vec::capacity(int32_t min_cap) +{ + if ((int32_t)cap >= min_cap) { + return; + } + + // NOTE: grow by approximately 3/2 + uint32_t add = imax((min_cap - (int32_t)cap + 1) & ~1, (((int32_t)cap >> 1) + 2) & ~1); + if (add > numeric_limits::max() - cap) { + throw std::bad_alloc(); + } + cap += (uint32_t)add; + + // This avoids memory fragmentation by many reallocations + uint32_t new_size = 2; + while (new_size < cap) { + new_size *= 2; + } + if (new_size * 2 / 3 > cap) { + new_size = new_size * 2 / 3; + } + cap = new_size; + + if (((data = (T*)::realloc(data, cap * sizeof(T))) == NULL) && errno == ENOMEM) { + throw std::bad_alloc(); + } +} + + +template +void vec::growTo(uint32_t size, const T& pad) +{ + if (sz >= size) { + return; + } + capacity(size); + for (uint32_t i = sz; i < size; i++) { + data[i] = pad; + } + sz = size; +} + + +template +void vec::growTo(uint32_t size) +{ + if (sz >= size) { + return; + } + capacity(size); + for (uint32_t i = sz; i < size; i++) { + new (&data[i]) T(); + } + sz = size; +} + + +template +void vec::clear(bool dealloc) +{ + if (data != NULL) { + for (uint32_t i = 0; i < sz; i++) { + data[i].~T(); + } + sz = 0; + if (dealloc) { + free(data), data = NULL, cap = 0; + } + } +} + +template<> +inline void vec::clear(bool dealloc) +{ + if (data != NULL) { + sz = 0; + if (dealloc) { + free(data), data = NULL, cap = 0; + } + } +} + +//================================================================================================= +} + +#endif diff --git a/cryptominisat/cppsrc/src/XAlloc.h b/cryptominisat/cppsrc/src/XAlloc.h new file mode 100644 index 00000000..1d64f5d0 --- /dev/null +++ b/cryptominisat/cppsrc/src/XAlloc.h @@ -0,0 +1,47 @@ +/****************************************************************************************[XAlloc.h] +Copyright (c) 2009-2010, Niklas Sorensson + +Permission is hereby granted, free of charge, to any person obtaining a copy of this software and +associated documentation files (the "Software"), to deal in the Software without restriction, +including without limitation the rights to use, copy, modify, merge, publish, distribute, +sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all copies or +substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT +NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, +DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT +OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +**************************************************************************************************/ + + +#ifndef Glucose_XAlloc_h +#define Glucose_XAlloc_h + +#include +#include +#include + +namespace Glucose { + +//================================================================================================= +// Simple layer on top of malloc/realloc to catch out-of-memory situtaions and provide some typing: + +class OutOfMemoryException {}; +static inline void* xrealloc(void* ptr, size_t size) +{ + void* mem = realloc(ptr, size); + if (mem == NULL && errno == ENOMEM) { + throw OutOfMemoryException(); + } else { + return mem; + } +} + +//================================================================================================= +} + +#endif diff --git a/cryptominisat/cppsrc/src/alg.h b/cryptominisat/cppsrc/src/alg.h new file mode 100644 index 00000000..741c1952 --- /dev/null +++ b/cryptominisat/cppsrc/src/alg.h @@ -0,0 +1,43 @@ +/******************************************************************************* +MiniSat -- Copyright (c) 2003-2006, Niklas Een, Niklas Sorensson + +Permission is hereby granted, free of charge, to any person obtaining a copy of this software and +associated documentation files (the "Software"), to deal in the Software without restriction, +including without limitation the rights to use, copy, modify, merge, publish, distribute, +sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all copies or +substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT +NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, +DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT +OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +*******************************************************************************/ + +#ifndef Alg_h +#define Alg_h + +#include +#include +#include "solvertypes.h" +#include "watched.h" +#include "constants.h" + +namespace CMSat { + +template +static inline void remove(V& ts, const T& t) +{ + uint32_t j = 0; + for (; j < ts.size() && ts[j] != t; j++); + assert(j < ts.size()); + for (; j < (uint32_t)(ts.size()-1); j++) ts[j] = ts[j+1]; + ts.resize(ts.size() -1); +} + +} //end namespace + +#endif diff --git a/cryptominisat/cppsrc/src/argparse.hpp b/cryptominisat/cppsrc/src/argparse.hpp new file mode 100644 index 00000000..c614b5ed --- /dev/null +++ b/cryptominisat/cppsrc/src/argparse.hpp @@ -0,0 +1,2183 @@ +/* + __ _ _ __ __ _ _ __ __ _ _ __ ___ ___ + / _` | '__/ _` | '_ \ / _` | '__/ __|/ _ \ Argument Parser for Modern C++ +| (_| | | | (_| | |_) | (_| | | \__ \ __/ http://github.com/p-ranav/argparse + \__,_|_| \__, | .__/ \__,_|_| |___/\___| + |___/|_| + +Licensed under the MIT License . +SPDX-License-Identifier: MIT +Copyright (c) 2019-2022 Pranav Srinivas Kumar +and other contributors. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. +*/ +#pragma once + +#ifndef ARGPARSE_MODULE_USE_STD_MODULE +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#endif + +namespace argparse { + +namespace details { // namespace for helper methods + +template +struct HasContainerTraits : std::false_type {}; + +template <> struct HasContainerTraits : std::false_type {}; + +template <> struct HasContainerTraits : std::false_type {}; + +template +struct HasContainerTraits< + T, std::void_t().begin()), + decltype(std::declval().end()), + decltype(std::declval().size())>> : std::true_type {}; + +template +inline constexpr bool IsContainer = HasContainerTraits::value; + +template +struct HasStreamableTraits : std::false_type {}; + +template +struct HasStreamableTraits< + T, + std::void_t() << std::declval())>> + : std::true_type {}; + +template +inline constexpr bool IsStreamable = HasStreamableTraits::value; + +constexpr std::size_t repr_max_container_size = 5; + +template std::string repr(T const &val) { + if constexpr (std::is_same_v) { + return val ? "true" : "false"; + } else if constexpr (std::is_convertible_v) { + return '"' + std::string{std::string_view{val}} + '"'; + } else if constexpr (IsContainer) { + std::stringstream out; + out << "{"; + const auto size = val.size(); + if (size > 1) { + out << repr(*val.begin()); + std::for_each( + std::next(val.begin()), + std::next( + val.begin(), + static_cast( + std::min(size, repr_max_container_size) - 1)), + [&out](const auto &v) { out << " " << repr(v); }); + if (size <= repr_max_container_size) { + out << " "; + } else { + out << "..."; + } + } + if (size > 0) { + out << repr(*std::prev(val.end())); + } + out << "}"; + return out.str(); + } else if constexpr (IsStreamable) { + std::stringstream out; + out << val; + return out.str(); + } else { + return ""; + } +} + +namespace { + +template constexpr bool standard_signed_integer = false; +template <> constexpr bool standard_signed_integer = true; +template <> constexpr bool standard_signed_integer = true; +template <> constexpr bool standard_signed_integer = true; +template <> constexpr bool standard_signed_integer = true; +template <> constexpr bool standard_signed_integer = true; + +template constexpr bool standard_unsigned_integer = false; +template <> constexpr bool standard_unsigned_integer = true; +template <> constexpr bool standard_unsigned_integer = true; +template <> constexpr bool standard_unsigned_integer = true; +template <> constexpr bool standard_unsigned_integer = true; +template <> +constexpr bool standard_unsigned_integer = true; + +} // namespace + +constexpr int radix_2 = 2; +constexpr int radix_8 = 8; +constexpr int radix_10 = 10; +constexpr int radix_16 = 16; + +template +constexpr bool standard_integer = + standard_signed_integer || standard_unsigned_integer; + +template +constexpr decltype(auto) +apply_plus_one_impl(F &&f, Tuple &&t, Extra &&x, + std::index_sequence /*unused*/) { + return std::invoke(std::forward(f), std::get(std::forward(t))..., + std::forward(x)); +} + +template +constexpr decltype(auto) apply_plus_one(F &&f, Tuple &&t, Extra &&x) { + return details::apply_plus_one_impl( + std::forward(f), std::forward(t), std::forward(x), + std::make_index_sequence< + std::tuple_size_v>>{}); +} + +constexpr auto pointer_range(std::string_view s) noexcept { + return std::tuple(s.data(), s.data() + s.size()); +} + +template +constexpr bool starts_with(std::basic_string_view prefix, + std::basic_string_view s) noexcept { + return s.substr(0, prefix.size()) == prefix; +} + +enum class chars_format { + scientific = 0xf1, + fixed = 0xf2, + hex = 0xf4, + binary = 0xf8, + general = fixed | scientific +}; + +struct ConsumeBinaryPrefixResult { + bool is_binary; + std::string_view rest; +}; + +constexpr auto consume_binary_prefix(std::string_view s) + -> ConsumeBinaryPrefixResult { + if (starts_with(std::string_view{"0b"}, s) || + starts_with(std::string_view{"0B"}, s)) { + s.remove_prefix(2); + return {true, s}; + } + return {false, s}; +} + +struct ConsumeHexPrefixResult { + bool is_hexadecimal; + std::string_view rest; +}; + +using namespace std::literals; + +constexpr auto consume_hex_prefix(std::string_view s) + -> ConsumeHexPrefixResult { + if (starts_with("0x"sv, s) || starts_with("0X"sv, s)) { + s.remove_prefix(2); + return {true, s}; + } + return {false, s}; +} + +template +inline auto do_from_chars(std::string_view s) -> T { + T x; + auto [first, last] = pointer_range(s); + auto [ptr, ec] = std::from_chars(first, last, x, Param); + if (ec == std::errc()) { + if (ptr == last) { + return x; + } + throw std::invalid_argument{"pattern '" + std::string(s) + + "' does not match to the end"}; + } + if (ec == std::errc::invalid_argument) { + throw std::invalid_argument{"pattern '" + std::string(s) + "' not found"}; + } + if (ec == std::errc::result_out_of_range) { + throw std::range_error{"'" + std::string(s) + "' not representable"}; + } + return x; // unreachable +} + +template struct parse_number { + auto operator()(std::string_view s) -> T { + return do_from_chars(s); + } +}; + +template struct parse_number { + auto operator()(std::string_view s) -> T { + if (auto [ok, rest] = consume_binary_prefix(s); ok) { + return do_from_chars(rest); + } + throw std::invalid_argument{"pattern not found"}; + } +}; + +template struct parse_number { + auto operator()(std::string_view s) -> T { + if (starts_with("0x"sv, s) || starts_with("0X"sv, s)) { + if (auto [ok, rest] = consume_hex_prefix(s); ok) { + try { + return do_from_chars(rest); + } catch (const std::invalid_argument &err) { + throw std::invalid_argument("Failed to parse '" + std::string(s) + + "' as hexadecimal: " + err.what()); + } catch (const std::range_error &err) { + throw std::range_error("Failed to parse '" + std::string(s) + + "' as hexadecimal: " + err.what()); + } + } + } else { + // Allow passing hex numbers without prefix + // Shape 'x' already has to be specified + try { + return do_from_chars(s); + } catch (const std::invalid_argument &err) { + throw std::invalid_argument("Failed to parse '" + std::string(s) + + "' as hexadecimal: " + err.what()); + } catch (const std::range_error &err) { + throw std::range_error("Failed to parse '" + std::string(s) + + "' as hexadecimal: " + err.what()); + } + } + + throw std::invalid_argument{"pattern '" + std::string(s) + + "' not identified as hexadecimal"}; + } +}; + +template struct parse_number { + auto operator()(std::string_view s) -> T { + auto [ok, rest] = consume_hex_prefix(s); + if (ok) { + try { + return do_from_chars(rest); + } catch (const std::invalid_argument &err) { + throw std::invalid_argument("Failed to parse '" + std::string(s) + + "' as hexadecimal: " + err.what()); + } catch (const std::range_error &err) { + throw std::range_error("Failed to parse '" + std::string(s) + + "' as hexadecimal: " + err.what()); + } + } + + auto [ok_binary, rest_binary] = consume_binary_prefix(s); + if (ok_binary) { + try { + return do_from_chars(rest_binary); + } catch (const std::invalid_argument &err) { + throw std::invalid_argument("Failed to parse '" + std::string(s) + + "' as binary: " + err.what()); + } catch (const std::range_error &err) { + throw std::range_error("Failed to parse '" + std::string(s) + + "' as binary: " + err.what()); + } + } + + if (starts_with("0"sv, s)) { + try { + return do_from_chars(rest); + } catch (const std::invalid_argument &err) { + throw std::invalid_argument("Failed to parse '" + std::string(s) + + "' as octal: " + err.what()); + } catch (const std::range_error &err) { + throw std::range_error("Failed to parse '" + std::string(s) + + "' as octal: " + err.what()); + } + } + + try { + return do_from_chars(rest); + } catch (const std::invalid_argument &err) { + throw std::invalid_argument("Failed to parse '" + std::string(s) + + "' as decimal integer: " + err.what()); + } catch (const std::range_error &err) { + throw std::range_error("Failed to parse '" + std::string(s) + + "' as decimal integer: " + err.what()); + } + } +}; + +namespace { + +template inline const auto generic_strtod = nullptr; +template <> inline const auto generic_strtod = strtof; +template <> inline const auto generic_strtod = strtod; +template <> inline const auto generic_strtod = strtold; + +} // namespace + +template inline auto do_strtod(std::string const &s) -> T { + if (isspace(static_cast(s[0])) || s[0] == '+') { + throw std::invalid_argument{"pattern '" + s + "' not found"}; + } + + auto [first, last] = pointer_range(s); + char *ptr; + + errno = 0; + auto x = generic_strtod(first, &ptr); + if (errno == 0) { + if (ptr == last) { + return x; + } + throw std::invalid_argument{"pattern '" + s + + "' does not match to the end"}; + } + if (errno == ERANGE) { + throw std::range_error{"'" + s + "' not representable"}; + } + return x; // unreachable +} + +template struct parse_number { + auto operator()(std::string const &s) -> T { + if (auto r = consume_hex_prefix(s); r.is_hexadecimal) { + throw std::invalid_argument{ + "chars_format::general does not parse hexfloat"}; + } + if (auto r = consume_binary_prefix(s); r.is_binary) { + throw std::invalid_argument{ + "chars_format::general does not parse binfloat"}; + } + + try { + return do_strtod(s); + } catch (const std::invalid_argument &err) { + throw std::invalid_argument("Failed to parse '" + s + + "' as number: " + err.what()); + } catch (const std::range_error &err) { + throw std::range_error("Failed to parse '" + s + + "' as number: " + err.what()); + } + } +}; + +template struct parse_number { + auto operator()(std::string const &s) -> T { + if (auto r = consume_hex_prefix(s); !r.is_hexadecimal) { + throw std::invalid_argument{"chars_format::hex parses hexfloat"}; + } + if (auto r = consume_binary_prefix(s); r.is_binary) { + throw std::invalid_argument{"chars_format::hex does not parse binfloat"}; + } + + try { + return do_strtod(s); + } catch (const std::invalid_argument &err) { + throw std::invalid_argument("Failed to parse '" + s + + "' as hexadecimal: " + err.what()); + } catch (const std::range_error &err) { + throw std::range_error("Failed to parse '" + s + + "' as hexadecimal: " + err.what()); + } + } +}; + +template struct parse_number { + auto operator()(std::string const &s) -> T { + if (auto r = consume_hex_prefix(s); r.is_hexadecimal) { + throw std::invalid_argument{ + "chars_format::binary does not parse hexfloat"}; + } + if (auto r = consume_binary_prefix(s); !r.is_binary) { + throw std::invalid_argument{"chars_format::binary parses binfloat"}; + } + + return do_strtod(s); + } +}; + +template struct parse_number { + auto operator()(std::string const &s) -> T { + if (auto r = consume_hex_prefix(s); r.is_hexadecimal) { + throw std::invalid_argument{ + "chars_format::scientific does not parse hexfloat"}; + } + if (auto r = consume_binary_prefix(s); r.is_binary) { + throw std::invalid_argument{ + "chars_format::scientific does not parse binfloat"}; + } + if (s.find_first_of("eE") == std::string::npos) { + throw std::invalid_argument{ + "chars_format::scientific requires exponent part"}; + } + + try { + return do_strtod(s); + } catch (const std::invalid_argument &err) { + throw std::invalid_argument("Failed to parse '" + s + + "' as scientific notation: " + err.what()); + } catch (const std::range_error &err) { + throw std::range_error("Failed to parse '" + s + + "' as scientific notation: " + err.what()); + } + } +}; + +template struct parse_number { + auto operator()(std::string const &s) -> T { + if (auto r = consume_hex_prefix(s); r.is_hexadecimal) { + throw std::invalid_argument{ + "chars_format::fixed does not parse hexfloat"}; + } + if (auto r = consume_binary_prefix(s); r.is_binary) { + throw std::invalid_argument{ + "chars_format::fixed does not parse binfloat"}; + } + if (s.find_first_of("eE") != std::string::npos) { + throw std::invalid_argument{ + "chars_format::fixed does not parse exponent part"}; + } + + try { + return do_strtod(s); + } catch (const std::invalid_argument &err) { + throw std::invalid_argument("Failed to parse '" + s + + "' as fixed notation: " + err.what()); + } catch (const std::range_error &err) { + throw std::range_error("Failed to parse '" + s + + "' as fixed notation: " + err.what()); + } + } +}; + +template +std::string join(StrIt first, StrIt last, const std::string &separator) { + if (first == last) { + return ""; + } + std::stringstream value; + value << *first; + ++first; + while (first != last) { + value << separator << *first; + ++first; + } + return value.str(); +} + +template struct can_invoke_to_string { + template + static auto test(int) + -> decltype(std::to_string(std::declval()), std::true_type{}); + + template static auto test(...) -> std::false_type; + + static constexpr bool value = decltype(test(0))::value; +}; + +template struct IsChoiceTypeSupported { + using CleanType = typename std::decay::type; + static const bool value = std::is_integral::value || + std::is_same::value || + std::is_same::value || + std::is_same::value; +}; + +template +std::size_t get_levenshtein_distance(const StringType &s1, + const StringType &s2) { + std::vector> dp( + s1.size() + 1, std::vector(s2.size() + 1, 0)); + + for (std::size_t i = 0; i <= s1.size(); ++i) { + for (std::size_t j = 0; j <= s2.size(); ++j) { + if (i == 0) { + dp[i][j] = j; + } else if (j == 0) { + dp[i][j] = i; + } else if (s1[i - 1] == s2[j - 1]) { + dp[i][j] = dp[i - 1][j - 1]; + } else { + dp[i][j] = 1 + std::min({dp[i - 1][j], dp[i][j - 1], dp[i - 1][j - 1]}); + } + } + } + + return dp[s1.size()][s2.size()]; +} + +template +std::string_view +get_most_similar_string(const std::map &map, + const std::string_view input) { + std::string_view most_similar{}; + std::size_t min_distance = std::numeric_limits::max(); + + for (const auto &entry : map) { + std::size_t distance = get_levenshtein_distance(entry.first, input); + if (distance < min_distance) { + min_distance = distance; + most_similar = entry.first; + } + } + + return most_similar; +} + +} // namespace details + +enum class nargs_pattern { optional, any, at_least_one }; + +enum class default_arguments : unsigned int { + none = 0, + help = 1, + version = 2, + all = help | version, +}; + +inline default_arguments operator&(const default_arguments &a, + const default_arguments &b) { + return static_cast( + static_cast::type>(a) & + static_cast::type>(b)); +} + +class ArgumentParser; + +class Argument { + friend class ArgumentParser; + friend auto operator<<(std::ostream &stream, const ArgumentParser &parser) + -> std::ostream &; + + template + explicit Argument(std::string_view prefix_chars, + std::array &&a, + std::index_sequence /*unused*/) + : m_accepts_optional_like_value(false), + m_is_optional((is_optional(a[I], prefix_chars) || ...)), + m_is_required(false), m_is_repeatable(false), m_is_used(false), + m_prefix_chars(prefix_chars) { + ((void)m_names.emplace_back(a[I]), ...); + std::sort( + m_names.begin(), m_names.end(), [](const auto &lhs, const auto &rhs) { + return lhs.size() == rhs.size() ? lhs < rhs : lhs.size() < rhs.size(); + }); + } + +public: + template + explicit Argument(std::string_view prefix_chars, + std::array &&a) + : Argument(prefix_chars, std::move(a), std::make_index_sequence{}) {} + + Argument &help(std::string help_text) { + m_help = std::move(help_text); + return *this; + } + + Argument &metavar(std::string metavar) { + m_metavar = std::move(metavar); + return *this; + } + + template Argument &default_value(T &&value) { + m_num_args_range = NArgsRange{0, m_num_args_range.get_max()}; + m_default_value_repr = details::repr(value); + + if constexpr (std::is_convertible_v) { + m_default_value_str = std::string{std::string_view{value}}; + } else if constexpr (details::can_invoke_to_string::value) { + m_default_value_str = std::to_string(value); + } + + m_default_value = std::forward(value); + return *this; + } + + Argument &default_value(const char *value) { + return default_value(std::string(value)); + } + + Argument &required() { + m_is_required = true; + return *this; + } + + Argument &implicit_value(std::any value) { + m_implicit_value = std::move(value); + m_num_args_range = NArgsRange{0, 0}; + return *this; + } + + // This is shorthand for: + // program.add_argument("foo") + // .default_value(false) + // .implicit_value(true) + Argument &flag() { + default_value(false); + implicit_value(true); + return *this; + } + + template + auto action(F &&callable, Args &&... bound_args) + -> std::enable_if_t, + Argument &> { + using action_type = std::conditional_t< + std::is_void_v>, + void_action, valued_action>; + if constexpr (sizeof...(Args) == 0) { + m_action.emplace(std::forward(callable)); + } else { + m_action.emplace( + [f = std::forward(callable), + tup = std::make_tuple(std::forward(bound_args)...)]( + std::string const &opt) mutable { + return details::apply_plus_one(f, tup, opt); + }); + } + return *this; + } + + auto &append() { + m_is_repeatable = true; + return *this; + } + + template + auto scan() -> std::enable_if_t, Argument &> { + static_assert(!(std::is_const_v || std::is_volatile_v), + "T should not be cv-qualified"); + auto is_one_of = [](char c, auto... x) constexpr { + return ((c == x) || ...); + }; + + if constexpr (is_one_of(Shape, 'd') && details::standard_integer) { + action(details::parse_number()); + } else if constexpr (is_one_of(Shape, 'i') && + details::standard_integer) { + action(details::parse_number()); + } else if constexpr (is_one_of(Shape, 'u') && + details::standard_unsigned_integer) { + action(details::parse_number()); + } else if constexpr (is_one_of(Shape, 'b') && + details::standard_unsigned_integer) { + action(details::parse_number()); + } else if constexpr (is_one_of(Shape, 'o') && + details::standard_unsigned_integer) { + action(details::parse_number()); + } else if constexpr (is_one_of(Shape, 'x', 'X') && + details::standard_unsigned_integer) { + action(details::parse_number()); + } else if constexpr (is_one_of(Shape, 'a', 'A') && + std::is_floating_point_v) { + action(details::parse_number()); + } else if constexpr (is_one_of(Shape, 'e', 'E') && + std::is_floating_point_v) { + action(details::parse_number()); + } else if constexpr (is_one_of(Shape, 'f', 'F') && + std::is_floating_point_v) { + action(details::parse_number()); + } else if constexpr (is_one_of(Shape, 'g', 'G') && + std::is_floating_point_v) { + action(details::parse_number()); + } else { + static_assert(alignof(T) == 0, "No scan specification for T"); + } + + return *this; + } + + Argument &nargs(std::size_t num_args) { + m_num_args_range = NArgsRange{num_args, num_args}; + return *this; + } + + Argument &nargs(std::size_t num_args_min, std::size_t num_args_max) { + m_num_args_range = NArgsRange{num_args_min, num_args_max}; + return *this; + } + + Argument &nargs(nargs_pattern pattern) { + switch (pattern) { + case nargs_pattern::optional: + m_num_args_range = NArgsRange{0, 1}; + break; + case nargs_pattern::any: + m_num_args_range = + NArgsRange{0, (std::numeric_limits::max)()}; + break; + case nargs_pattern::at_least_one: + m_num_args_range = + NArgsRange{1, (std::numeric_limits::max)()}; + break; + } + return *this; + } + + Argument &remaining() { + m_accepts_optional_like_value = true; + return nargs(nargs_pattern::any); + } + + template void add_choice(T &&choice) { + static_assert(details::IsChoiceTypeSupported::value, + "Only string or integer type supported for choice"); + static_assert(std::is_convertible_v || + details::can_invoke_to_string::value, + "Choice is not convertible to string_type"); + if (!m_choices.has_value()) { + m_choices = std::vector{}; + } + + if constexpr (std::is_convertible_v) { + m_choices.value().push_back( + std::string{std::string_view{std::forward(choice)}}); + } else if constexpr (details::can_invoke_to_string::value) { + m_choices.value().push_back(std::to_string(std::forward(choice))); + } + } + + Argument &choices() { + if (!m_choices.has_value()) { + throw std::runtime_error("Zero choices provided"); + } + return *this; + } + + template + Argument &choices(T &&first, U &&... rest) { + add_choice(std::forward(first)); + choices(std::forward(rest)...); + return *this; + } + + void find_default_value_in_choices_or_throw() const { + + const auto &choices = m_choices.value(); + + if (m_default_value.has_value()) { + if (std::find(choices.begin(), choices.end(), m_default_value_str) == + choices.end()) { + // provided arg not in list of allowed choices + // report error + + std::string choices_as_csv = + std::accumulate(choices.begin(), choices.end(), std::string(), + [](const std::string &a, const std::string &b) { + return a + (a.empty() ? "" : ", ") + b; + }); + + throw std::runtime_error( + std::string{"Invalid default value "} + m_default_value_repr + + " - allowed options: {" + choices_as_csv + "}"); + } + } + } + + template + void find_value_in_choices_or_throw(Iterator it) const { + + const auto &choices = m_choices.value(); + + if (std::find(choices.begin(), choices.end(), *it) == choices.end()) { + // provided arg not in list of allowed choices + // report error + + std::string choices_as_csv = + std::accumulate(choices.begin(), choices.end(), std::string(), + [](const std::string &a, const std::string &b) { + return a + (a.empty() ? "" : ", ") + b; + }); + + throw std::runtime_error(std::string{"Invalid argument "} + + details::repr(*it) + " - allowed options: {" + + choices_as_csv + "}"); + } + } + + template + Iterator consume(Iterator start, Iterator end, + std::string_view used_name = {}) { + if (!m_is_repeatable && m_is_used) { + throw std::runtime_error("Duplicate argument"); + } + m_is_used = true; + m_used_name = used_name; + + if (m_choices.has_value()) { + // Check each value in (start, end) and make sure + // it is in the list of allowed choices/options + std::size_t i = 0; + auto max_number_of_args = m_num_args_range.get_max(); + for (auto it = start; it != end; ++it) { + if (i == max_number_of_args) { + break; + } + find_value_in_choices_or_throw(it); + i += 1; + } + } + + const auto num_args_max = m_num_args_range.get_max(); + const auto num_args_min = m_num_args_range.get_min(); + std::size_t dist = 0; + if (num_args_max == 0) { + m_values.emplace_back(m_implicit_value); + std::visit([](const auto &f) { f({}); }, m_action); + return start; + } + if ((dist = static_cast(std::distance(start, end))) >= + num_args_min) { + if (num_args_max < dist) { + end = std::next(start, static_cast( + num_args_max)); + } + if (!m_accepts_optional_like_value) { + end = std::find_if( + start, end, + std::bind(is_optional, std::placeholders::_1, m_prefix_chars)); + dist = static_cast(std::distance(start, end)); + if (dist < num_args_min) { + throw std::runtime_error("Too few arguments"); + } + } + + struct ActionApply { + void operator()(valued_action &f) { + std::transform(first, last, std::back_inserter(self.m_values), f); + } + + void operator()(void_action &f) { + std::for_each(first, last, f); + if (!self.m_default_value.has_value()) { + if (!self.m_accepts_optional_like_value) { + self.m_values.resize( + static_cast(std::distance(first, last))); + } + } + } + + Iterator first, last; + Argument &self; + }; + std::visit(ActionApply{start, end, *this}, m_action); + return end; + } + if (m_default_value.has_value()) { + return start; + } + throw std::runtime_error("Too few arguments for '" + + std::string(m_used_name) + "'."); + } + + /* + * @throws std::runtime_error if argument values are not valid + */ + void validate() const { + if (m_is_optional) { + // TODO: check if an implicit value was programmed for this argument + if (!m_is_used && !m_default_value.has_value() && m_is_required) { + throw_required_arg_not_used_error(); + } + if (m_is_used && m_is_required && m_values.empty()) { + throw_required_arg_no_value_provided_error(); + } + } else { + if (!m_num_args_range.contains(m_values.size()) && + !m_default_value.has_value()) { + throw_nargs_range_validation_error(); + } + } + + if (m_choices.has_value()) { + // Make sure the default value (if provided) + // is in the list of choices + find_default_value_in_choices_or_throw(); + } + } + + std::string get_names_csv(char separator = ',') const { + return std::accumulate( + m_names.begin(), m_names.end(), std::string{""}, + [&](const std::string &result, const std::string &name) { + return result.empty() ? name : result + separator + name; + }); + } + + std::string get_usage_full() const { + std::stringstream usage; + + usage << get_names_csv('/'); + const std::string metavar = !m_metavar.empty() ? m_metavar : "VAR"; + if (m_num_args_range.get_max() > 0) { + usage << " " << metavar; + if (m_num_args_range.get_max() > 1) { + usage << "..."; + } + } + return usage.str(); + } + + std::string get_inline_usage() const { + std::stringstream usage; + // Find the longest variant to show in the usage string + std::string longest_name = m_names.front(); + for (const auto &s : m_names) { + if (s.size() > longest_name.size()) { + longest_name = s; + } + } + if (!m_is_required) { + usage << "["; + } + usage << longest_name; + const std::string metavar = !m_metavar.empty() ? m_metavar : "VAR"; + if (m_num_args_range.get_max() > 0) { + usage << " " << metavar; + if (m_num_args_range.get_max() > 1) { + usage << "..."; + } + } + if (!m_is_required) { + usage << "]"; + } + return usage.str(); + } + + std::size_t get_arguments_length() const { + + std::size_t names_size = std::accumulate( + std::begin(m_names), std::end(m_names), std::size_t(0), + [](const auto &sum, const auto &s) { return sum + s.size(); }); + + if (is_positional(m_names.front(), m_prefix_chars)) { + // A set metavar means this replaces the names + if (!m_metavar.empty()) { + // Indent and metavar + return 2 + m_metavar.size(); + } + + // Indent and space-separated + return 2 + names_size + (m_names.size() - 1); + } + // Is an option - include both names _and_ metavar + // size = text + (", " between names) + std::size_t size = names_size + 2 * (m_names.size() - 1); + if (!m_metavar.empty() && m_num_args_range == NArgsRange{1, 1}) { + size += m_metavar.size() + 1; + } + return size + 2; // indent + } + + friend std::ostream &operator<<(std::ostream &stream, + const Argument &argument) { + std::stringstream name_stream; + name_stream << " "; // indent + if (argument.is_positional(argument.m_names.front(), + argument.m_prefix_chars)) { + if (!argument.m_metavar.empty()) { + name_stream << argument.m_metavar; + } else { + name_stream << details::join(argument.m_names.begin(), + argument.m_names.end(), " "); + } + } else { + name_stream << details::join(argument.m_names.begin(), + argument.m_names.end(), ", "); + // If we have a metavar, and one narg - print the metavar + if (!argument.m_metavar.empty() && + argument.m_num_args_range == NArgsRange{1, 1}) { + name_stream << " " << argument.m_metavar; + } + } + + // align multiline help message + auto stream_width = stream.width(); + auto name_padding = std::string(name_stream.str().size(), ' '); + auto pos = std::string::size_type{}; + auto prev = std::string::size_type{}; + auto first_line = true; + auto hspace = " "; // minimal space between name and help message + stream << name_stream.str(); + std::string_view help_view(argument.m_help); + while ((pos = argument.m_help.find('\n', prev)) != std::string::npos) { + auto line = help_view.substr(prev, pos - prev + 1); + if (first_line) { + stream << hspace << line; + first_line = false; + } else { + stream.width(stream_width); + stream << name_padding << hspace << line; + } + prev += pos - prev + 1; + } + if (first_line) { + stream << hspace << argument.m_help; + } else { + auto leftover = help_view.substr(prev, argument.m_help.size() - prev); + if (!leftover.empty()) { + stream.width(stream_width); + stream << name_padding << hspace << leftover; + } + } + + // print nargs spec + if (!argument.m_help.empty()) { + stream << " "; + } + stream << argument.m_num_args_range; + + if (argument.m_default_value.has_value() && + argument.m_num_args_range != NArgsRange{0, 0}) { + stream << "[default: " << argument.m_default_value_repr << "]"; + } else if (argument.m_is_required) { + stream << "[required]"; + } + stream << "\n"; + return stream; + } + + template bool operator!=(const T &rhs) const { + return !(*this == rhs); + } + + /* + * Compare to an argument value of known type + * @throws std::logic_error in case of incompatible types + */ + template bool operator==(const T &rhs) const { + if constexpr (!details::IsContainer) { + return get() == rhs; + } else { + using ValueType = typename T::value_type; + auto lhs = get(); + return std::equal(std::begin(lhs), std::end(lhs), std::begin(rhs), + std::end(rhs), [](const auto &a, const auto &b) { + return std::any_cast(a) == b; + }); + } + } + +private: + class NArgsRange { + std::size_t m_min; + std::size_t m_max; + + public: + NArgsRange(std::size_t minimum, std::size_t maximum) + : m_min(minimum), m_max(maximum) { + if (minimum > maximum) { + throw std::logic_error("Range of number of arguments is invalid"); + } + } + + bool contains(std::size_t value) const { + return value >= m_min && value <= m_max; + } + + bool is_exact() const { return m_min == m_max; } + + bool is_right_bounded() const { + return m_max < (std::numeric_limits::max)(); + } + + std::size_t get_min() const { return m_min; } + + std::size_t get_max() const { return m_max; } + + // Print help message + friend auto operator<<(std::ostream &stream, const NArgsRange &range) + -> std::ostream & { + if (range.m_min == range.m_max) { + if (range.m_min != 0 && range.m_min != 1) { + stream << "[nargs: " << range.m_min << "] "; + } + } else { + if (range.m_max == (std::numeric_limits::max)()) { + stream << "[nargs: " << range.m_min << " or more] "; + } else { + stream << "[nargs=" << range.m_min << ".." << range.m_max << "] "; + } + } + return stream; + } + + bool operator==(const NArgsRange &rhs) const { + return rhs.m_min == m_min && rhs.m_max == m_max; + } + + bool operator!=(const NArgsRange &rhs) const { return !(*this == rhs); } + }; + + void throw_nargs_range_validation_error() const { + std::stringstream stream; + if (!m_used_name.empty()) { + stream << m_used_name << ": "; + } else { + stream << m_names.front() << ": "; + } + if (m_num_args_range.is_exact()) { + stream << m_num_args_range.get_min(); + } else if (m_num_args_range.is_right_bounded()) { + stream << m_num_args_range.get_min() << " to " + << m_num_args_range.get_max(); + } else { + stream << m_num_args_range.get_min() << " or more"; + } + stream << " argument(s) expected. " << m_values.size() << " provided."; + throw std::runtime_error(stream.str()); + } + + void throw_required_arg_not_used_error() const { + std::stringstream stream; + stream << m_names.front() << ": required."; + throw std::runtime_error(stream.str()); + } + + void throw_required_arg_no_value_provided_error() const { + std::stringstream stream; + stream << m_used_name << ": no value provided."; + throw std::runtime_error(stream.str()); + } + + static constexpr int eof = std::char_traits::eof(); + + static auto lookahead(std::string_view s) -> int { + if (s.empty()) { + return eof; + } + return static_cast(static_cast(s[0])); + } + + /* + * decimal-literal: + * '0' + * nonzero-digit digit-sequence_opt + * integer-part fractional-part + * fractional-part + * integer-part '.' exponent-part_opt + * integer-part exponent-part + * + * integer-part: + * digit-sequence + * + * fractional-part: + * '.' post-decimal-point + * + * post-decimal-point: + * digit-sequence exponent-part_opt + * + * exponent-part: + * 'e' post-e + * 'E' post-e + * + * post-e: + * sign_opt digit-sequence + * + * sign: one of + * '+' '-' + */ + static bool is_decimal_literal(std::string_view s) { + auto is_digit = [](auto c) constexpr { + switch (c) { + case '0': + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + case '8': + case '9': + return true; + default: + return false; + } + }; + + // precondition: we have consumed or will consume at least one digit + auto consume_digits = [=](std::string_view sd) { + // NOLINTNEXTLINE(readability-qualified-auto) + auto it = std::find_if_not(std::begin(sd), std::end(sd), is_digit); + return sd.substr(static_cast(it - std::begin(sd))); + }; + + switch (lookahead(s)) { + case '0': { + s.remove_prefix(1); + if (s.empty()) { + return true; + } + goto integer_part; + } + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + case '8': + case '9': { + s = consume_digits(s); + if (s.empty()) { + return true; + } + goto integer_part_consumed; + } + case '.': { + s.remove_prefix(1); + goto post_decimal_point; + } + default: + return false; + } + + integer_part: + s = consume_digits(s); + integer_part_consumed: + switch (lookahead(s)) { + case '.': { + s.remove_prefix(1); + if (is_digit(lookahead(s))) { + goto post_decimal_point; + } else { + goto exponent_part_opt; + } + } + case 'e': + case 'E': { + s.remove_prefix(1); + goto post_e; + } + default: + return false; + } + + post_decimal_point: + if (is_digit(lookahead(s))) { + s = consume_digits(s); + goto exponent_part_opt; + } + return false; + + exponent_part_opt: + switch (lookahead(s)) { + case eof: + return true; + case 'e': + case 'E': { + s.remove_prefix(1); + goto post_e; + } + default: + return false; + } + + post_e: + switch (lookahead(s)) { + case '-': + case '+': + s.remove_prefix(1); + } + if (is_digit(lookahead(s))) { + s = consume_digits(s); + return s.empty(); + } + return false; + } + + static bool is_optional(std::string_view name, + std::string_view prefix_chars) { + return !is_positional(name, prefix_chars); + } + + /* + * positional: + * _empty_ + * '-' + * '-' decimal-literal + * !'-' anything + */ + static bool is_positional(std::string_view name, + std::string_view prefix_chars) { + auto first = lookahead(name); + + if (first == eof) { + return true; + } else if (prefix_chars.find(static_cast(first)) != + std::string_view::npos) { + name.remove_prefix(1); + if (name.empty()) { + return true; + } + return is_decimal_literal(name); + } + return true; + } + + /* + * Get argument value given a type + * @throws std::logic_error in case of incompatible types + */ + template T get() const { + if (!m_values.empty()) { + if constexpr (details::IsContainer) { + return any_cast_container(m_values); + } else { + return std::any_cast(m_values.front()); + } + } + if (m_default_value.has_value()) { + return std::any_cast(m_default_value); + } + if constexpr (details::IsContainer) { + if (!m_accepts_optional_like_value) { + return any_cast_container(m_values); + } + } + + throw std::logic_error("No value provided for '" + m_names.back() + "'."); + } + + /* + * Get argument value given a type. + * @pre The object has no default value. + * @returns The stored value if any, std::nullopt otherwise. + */ + template auto present() const -> std::optional { + if (m_default_value.has_value()) { + throw std::logic_error("Argument with default value always presents"); + } + if (m_values.empty()) { + return std::nullopt; + } + if constexpr (details::IsContainer) { + return any_cast_container(m_values); + } + return std::any_cast(m_values.front()); + } + + template + static auto any_cast_container(const std::vector &operand) -> T { + using ValueType = typename T::value_type; + + T result; + std::transform( + std::begin(operand), std::end(operand), std::back_inserter(result), + [](const auto &value) { return std::any_cast(value); }); + return result; + } + + std::vector m_names; + std::string_view m_used_name; + std::string m_help; + std::string m_metavar; + std::any m_default_value; + std::string m_default_value_repr; + std::optional + m_default_value_str; // used for checking default_value against choices + std::any m_implicit_value; + std::optional> m_choices{std::nullopt}; + using valued_action = std::function; + using void_action = std::function; + std::variant m_action{ + std::in_place_type, + [](const std::string &value) { return value; }}; + std::vector m_values; + NArgsRange m_num_args_range{1, 1}; + // Bit field of bool values. Set default value in ctor. + bool m_accepts_optional_like_value : 1; + bool m_is_optional : 1; + bool m_is_required : 1; + bool m_is_repeatable : 1; + bool m_is_used : 1; + std::string_view m_prefix_chars; // ArgumentParser has the prefix_chars +}; + +class ArgumentParser { +public: + explicit ArgumentParser(std::string program_name = {}, + std::string version = "1.0", + default_arguments add_args = default_arguments::all, + bool exit_on_default_arguments = true, + std::ostream &os = std::cout) + : m_program_name(std::move(program_name)), m_version(std::move(version)), + m_exit_on_default_arguments(exit_on_default_arguments), + m_parser_path(m_program_name) { + if ((add_args & default_arguments::help) == default_arguments::help) { + add_argument("-h", "--help") + .action([&](const auto & /*unused*/) { + os << help().str(); + if (m_exit_on_default_arguments) { + std::exit(0); + } + }) + .default_value(false) + .help("shows help message and exits") + .implicit_value(true) + .nargs(0); + } + if ((add_args & default_arguments::version) == default_arguments::version) { + add_argument("-v", "--version") + .action([&](const auto & /*unused*/) { + os << m_version << std::endl; + if (m_exit_on_default_arguments) { + std::exit(0); + } + }) + .default_value(false) + .help("prints version information and exits") + .implicit_value(true) + .nargs(0); + } + } + + ~ArgumentParser() = default; + + // ArgumentParser is meant to be used in a single function. + // Setup everything and parse arguments in one place. + // + // ArgumentParser internally uses std::string_views, + // references, iterators, etc. + // Many of these elements become invalidated after a copy or move. + ArgumentParser(const ArgumentParser &other) = delete; + ArgumentParser &operator=(const ArgumentParser &other) = delete; + ArgumentParser(ArgumentParser &&) noexcept = delete; + ArgumentParser &operator=(ArgumentParser &&) = delete; + + explicit operator bool() const { + auto arg_used = std::any_of(m_argument_map.cbegin(), m_argument_map.cend(), + [](auto &it) { return it.second->m_is_used; }); + auto subparser_used = + std::any_of(m_subparser_used.cbegin(), m_subparser_used.cend(), + [](auto &it) { return it.second; }); + + return m_is_parsed && (arg_used || subparser_used); + } + + // Parameter packing + // Call add_argument with variadic number of string arguments + template Argument &add_argument(Targs... f_args) { + using array_of_sv = std::array; + auto argument = + m_optional_arguments.emplace(std::cend(m_optional_arguments), + m_prefix_chars, array_of_sv{f_args...}); + + if (!argument->m_is_optional) { + m_positional_arguments.splice(std::cend(m_positional_arguments), + m_optional_arguments, argument); + } + + index_argument(argument); + return *argument; + } + + class MutuallyExclusiveGroup { + friend class ArgumentParser; + + public: + MutuallyExclusiveGroup() = delete; + + explicit MutuallyExclusiveGroup(ArgumentParser &parent, + bool required = false) + : m_parent(parent), m_required(required), m_elements({}) {} + + MutuallyExclusiveGroup(const MutuallyExclusiveGroup &other) = delete; + MutuallyExclusiveGroup & + operator=(const MutuallyExclusiveGroup &other) = delete; + + MutuallyExclusiveGroup(MutuallyExclusiveGroup &&other) noexcept + : m_parent(other.m_parent), m_required(other.m_required), + m_elements(std::move(other.m_elements)) { + other.m_elements.clear(); + } + + template Argument &add_argument(Targs... f_args) { + auto &argument = m_parent.add_argument(std::forward(f_args)...); + m_elements.push_back(&argument); + return argument; + } + + private: + ArgumentParser &m_parent; + bool m_required{false}; + std::vector m_elements{}; + }; + + MutuallyExclusiveGroup &add_mutually_exclusive_group(bool required = false) { + m_mutually_exclusive_groups.emplace_back(*this, required); + return m_mutually_exclusive_groups.back(); + } + + // Parameter packed add_parents method + // Accepts a variadic number of ArgumentParser objects + template + ArgumentParser &add_parents(const Targs &... f_args) { + for (const ArgumentParser &parent_parser : {std::ref(f_args)...}) { + for (const auto &argument : parent_parser.m_positional_arguments) { + auto it = m_positional_arguments.insert( + std::cend(m_positional_arguments), argument); + index_argument(it); + } + for (const auto &argument : parent_parser.m_optional_arguments) { + auto it = m_optional_arguments.insert(std::cend(m_optional_arguments), + argument); + index_argument(it); + } + } + return *this; + } + + ArgumentParser &add_description(std::string description) { + m_description = std::move(description); + return *this; + } + + ArgumentParser &add_epilog(std::string epilog) { + m_epilog = std::move(epilog); + return *this; + } + + /* Getter for arguments and subparsers. + * @throws std::logic_error in case of an invalid argument or subparser name + */ + template T &at(std::string_view name) { + if constexpr (std::is_same_v) { + return (*this)[name]; + } else { + auto subparser_it = m_subparser_map.find(name); + if (subparser_it != m_subparser_map.end()) { + return subparser_it->second->get(); + } + throw std::logic_error("No such subparser: " + std::string(name)); + } + } + + ArgumentParser &set_prefix_chars(std::string prefix_chars) { + m_prefix_chars = std::move(prefix_chars); + return *this; + } + + ArgumentParser &set_assign_chars(std::string assign_chars) { + m_assign_chars = std::move(assign_chars); + return *this; + } + + /* Call parse_args_internal - which does all the work + * Then, validate the parsed arguments + * This variant is used mainly for testing + * @throws std::runtime_error in case of any invalid argument + */ + void parse_args(const std::vector &arguments) { + parse_args_internal(arguments); + // Check if all arguments are parsed + for ([[maybe_unused]] const auto &[unused, argument] : m_argument_map) { + argument->validate(); + } + + // Check each mutually exclusive group and make sure + // there are no constraint violations + for (const auto &group : m_mutually_exclusive_groups) { + auto mutex_argument_used{false}; + Argument *mutex_argument_it{nullptr}; + for (Argument *arg : group.m_elements) { + if (!mutex_argument_used && arg->m_is_used) { + mutex_argument_used = true; + mutex_argument_it = arg; + } else if (mutex_argument_used && arg->m_is_used) { + // Violation + throw std::runtime_error("Argument '" + arg->get_usage_full() + + "' not allowed with '" + + mutex_argument_it->get_usage_full() + "'"); + } + } + + if (!mutex_argument_used && group.m_required) { + // at least one argument from the group is + // required + std::string argument_names{}; + std::size_t i = 0; + std::size_t size = group.m_elements.size(); + for (Argument *arg : group.m_elements) { + if (i + 1 == size) { + // last + argument_names += "'" + arg->get_usage_full() + "' "; + } else { + argument_names += "'" + arg->get_usage_full() + "' or "; + } + i += 1; + } + throw std::runtime_error("One of the arguments " + argument_names + + "is required"); + } + } + } + + /* Call parse_known_args_internal - which does all the work + * Then, validate the parsed arguments + * This variant is used mainly for testing + * @throws std::runtime_error in case of any invalid argument + */ + std::vector + parse_known_args(const std::vector &arguments) { + auto unknown_arguments = parse_known_args_internal(arguments); + // Check if all arguments are parsed + for ([[maybe_unused]] const auto &[unused, argument] : m_argument_map) { + argument->validate(); + } + return unknown_arguments; + } + + /* Main entry point for parsing command-line arguments using this + * ArgumentParser + * @throws std::runtime_error in case of any invalid argument + */ + // NOLINTNEXTLINE(cppcoreguidelines-avoid-c-arrays) + void parse_args(int argc, const char *const argv[]) { + parse_args({argv, argv + argc}); + } + + /* Main entry point for parsing command-line arguments using this + * ArgumentParser + * @throws std::runtime_error in case of any invalid argument + */ + // NOLINTNEXTLINE(cppcoreguidelines-avoid-c-arrays) + auto parse_known_args(int argc, const char *const argv[]) { + return parse_known_args({argv, argv + argc}); + } + + /* Getter for options with default values. + * @throws std::logic_error if parse_args() has not been previously called + * @throws std::logic_error if there is no such option + * @throws std::logic_error if the option has no value + * @throws std::bad_any_cast if the option is not of type T + */ + template T get(std::string_view arg_name) const { + if (!m_is_parsed) { + throw std::logic_error("Nothing parsed, no arguments are available."); + } + return (*this)[arg_name].get(); + } + + /* Getter for options without default values. + * @pre The option has no default value. + * @throws std::logic_error if there is no such option + * @throws std::bad_any_cast if the option is not of type T + */ + template + auto present(std::string_view arg_name) const -> std::optional { + return (*this)[arg_name].present(); + } + + /* Getter that returns true for user-supplied options. Returns false if not + * user-supplied, even with a default value. + */ + auto is_used(std::string_view arg_name) const { + return (*this)[arg_name].m_is_used; + } + + /* Getter that returns true if a subcommand is used. + */ + auto is_subcommand_used(std::string_view subcommand_name) const { + return m_subparser_used.at(subcommand_name); + } + + /* Getter that returns true if a subcommand is used. + */ + auto is_subcommand_used(const ArgumentParser &subparser) const { + return is_subcommand_used(subparser.m_program_name); + } + + /* Indexing operator. Return a reference to an Argument object + * Used in conjunction with Argument.operator== e.g., parser["foo"] == true + * @throws std::logic_error in case of an invalid argument name + */ + Argument &operator[](std::string_view arg_name) const { + auto it = m_argument_map.find(arg_name); + if (it != m_argument_map.end()) { + return *(it->second); + } + if (!is_valid_prefix_char(arg_name.front())) { + std::string name(arg_name); + const auto legal_prefix_char = get_any_valid_prefix_char(); + const auto prefix = std::string(1, legal_prefix_char); + + // "-" + arg_name + name = prefix + name; + it = m_argument_map.find(name); + if (it != m_argument_map.end()) { + return *(it->second); + } + // "--" + arg_name + name = prefix + name; + it = m_argument_map.find(name); + if (it != m_argument_map.end()) { + return *(it->second); + } + } + throw std::logic_error("No such argument: " + std::string(arg_name)); + } + + // Print help message + friend auto operator<<(std::ostream &stream, const ArgumentParser &parser) + -> std::ostream & { + stream.setf(std::ios_base::left); + + auto longest_arg_length = parser.get_length_of_longest_argument(); + + stream << parser.usage() << "\n\n"; + + if (!parser.m_description.empty()) { + stream << parser.m_description << "\n\n"; + } + + if (!parser.m_positional_arguments.empty()) { + stream << "Positional arguments:\n"; + } + + for (const auto &argument : parser.m_positional_arguments) { + stream.width(static_cast(longest_arg_length)); + stream << argument; + } + + if (!parser.m_optional_arguments.empty()) { + stream << (parser.m_positional_arguments.empty() ? "" : "\n") + << "Optional arguments:\n"; + } + + for (const auto &argument : parser.m_optional_arguments) { + stream.width(static_cast(longest_arg_length)); + stream << argument; + } + + bool has_visible_subcommands = std::any_of( + parser.m_subparser_map.begin(), parser.m_subparser_map.end(), + [](auto &p) { return !p.second->get().m_suppress; }); + + if (has_visible_subcommands) { + stream << (parser.m_positional_arguments.empty() + ? (parser.m_optional_arguments.empty() ? "" : "\n") + : "\n") + << "Subcommands:\n"; + for (const auto &[command, subparser] : parser.m_subparser_map) { + if (subparser->get().m_suppress) { + continue; + } + + stream << std::setw(2) << " "; + stream << std::setw(static_cast(longest_arg_length - 2)) + << command; + stream << " " << subparser->get().m_description << "\n"; + } + } + + if (!parser.m_epilog.empty()) { + stream << '\n'; + stream << parser.m_epilog << "\n\n"; + } + + return stream; + } + + // Format help message + auto help() const -> std::stringstream { + std::stringstream out; + out << *this; + return out; + } + + // Format usage part of help only + auto usage() const -> std::string { + std::stringstream stream; + + stream << "Usage: " << this->m_program_name; + + // Add any options inline here + for (const auto &argument : this->m_optional_arguments) { + stream << " " << argument.get_inline_usage(); + } + // Put positional arguments after the optionals + for (const auto &argument : this->m_positional_arguments) { + if (!argument.m_metavar.empty()) { + stream << " " << argument.m_metavar; + } else { + stream << " " << argument.m_names.front(); + } + } + // Put subcommands after positional arguments + if (!m_subparser_map.empty()) { + stream << " {"; + std::size_t i{0}; + for (const auto &[command, subparser] : m_subparser_map) { + if (subparser->get().m_suppress) { + continue; + } + + if (i == 0) { + stream << command; + } else { + stream << "," << command; + } + ++i; + } + stream << "}"; + } + + return stream.str(); + } + + // Printing the one and only help message + // I've stuck with a simple message format, nothing fancy. + [[deprecated("Use cout << program; instead. See also help().")]] std::string + print_help() const { + auto out = help(); + std::cout << out.rdbuf(); + return out.str(); + } + + void add_subparser(ArgumentParser &parser) { + parser.m_parser_path = m_program_name + " " + parser.m_program_name; + auto it = m_subparsers.emplace(std::cend(m_subparsers), parser); + m_subparser_map.insert_or_assign(parser.m_program_name, it); + m_subparser_used.insert_or_assign(parser.m_program_name, false); + } + + void set_suppress(bool suppress) { m_suppress = suppress; } + +private: + bool is_valid_prefix_char(char c) const { + return m_prefix_chars.find(c) != std::string::npos; + } + + char get_any_valid_prefix_char() const { return m_prefix_chars[0]; } + + /* + * Pre-process this argument list. Anything starting with "--", that + * contains an =, where the prefix before the = has an entry in the + * options table, should be split. + */ + std::vector + preprocess_arguments(const std::vector &raw_arguments) const { + std::vector arguments{}; + for (const auto &arg : raw_arguments) { + + const auto argument_starts_with_prefix_chars = + [this](const std::string &a) -> bool { + if (!a.empty()) { + + const auto legal_prefix = [this](char c) -> bool { + return m_prefix_chars.find(c) != std::string::npos; + }; + + // Windows-style + // if '/' is a legal prefix char + // then allow single '/' followed by argument name, followed by an + // assign char, e.g., ':' e.g., 'test.exe /A:Foo' + const auto windows_style = legal_prefix('/'); + + if (windows_style) { + if (legal_prefix(a[0])) { + return true; + } + } else { + // Slash '/' is not a legal prefix char + // For all other characters, only support long arguments + // i.e., the argument must start with 2 prefix chars, e.g, + // '--foo' e,g, './test --foo=Bar -DARG=yes' + if (a.size() > 1) { + return (legal_prefix(a[0]) && legal_prefix(a[1])); + } + } + } + return false; + }; + + // Check that: + // - We don't have an argument named exactly this + // - The argument starts with a prefix char, e.g., "--" + // - The argument contains an assign char, e.g., "=" + auto assign_char_pos = arg.find_first_of(m_assign_chars); + + if (m_argument_map.find(arg) == m_argument_map.end() && + argument_starts_with_prefix_chars(arg) && + assign_char_pos != std::string::npos) { + // Get the name of the potential option, and check it exists + std::string opt_name = arg.substr(0, assign_char_pos); + if (m_argument_map.find(opt_name) != m_argument_map.end()) { + // This is the name of an option! Split it into two parts + arguments.push_back(std::move(opt_name)); + arguments.push_back(arg.substr(assign_char_pos + 1)); + continue; + } + } + // If we've fallen through to here, then it's a standard argument + arguments.push_back(arg); + } + return arguments; + } + + /* + * @throws std::runtime_error in case of any invalid argument + */ + void parse_args_internal(const std::vector &raw_arguments) { + auto arguments = preprocess_arguments(raw_arguments); + if (m_program_name.empty() && !arguments.empty()) { + m_program_name = arguments.front(); + } + auto end = std::end(arguments); + auto positional_argument_it = std::begin(m_positional_arguments); + for (auto it = std::next(std::begin(arguments)); it != end;) { + const auto ¤t_argument = *it; + if (Argument::is_positional(current_argument, m_prefix_chars)) { + if (positional_argument_it == std::end(m_positional_arguments)) { + + std::string_view maybe_command = current_argument; + + // Check sub-parsers + auto subparser_it = m_subparser_map.find(maybe_command); + if (subparser_it != m_subparser_map.end()) { + + // build list of remaining args + const auto unprocessed_arguments = + std::vector(it, end); + + // invoke subparser + m_is_parsed = true; + m_subparser_used[maybe_command] = true; + return subparser_it->second->get().parse_args( + unprocessed_arguments); + } + + if (m_positional_arguments.empty()) { + + // Ask the user if they argument they provided was a typo + // for some sub-parser, + // e.g., user provided `git totes` instead of `git notes` + if (!m_subparser_map.empty()) { + throw std::runtime_error( + "Failed to parse '" + current_argument + "', did you mean '" + + std::string{details::get_most_similar_string( + m_subparser_map, current_argument)} + + "'"); + } + + // Ask the user if they meant to use a specific optional argument + if (!m_optional_arguments.empty()) { + for (const auto &opt : m_optional_arguments) { + if (!opt.m_implicit_value.has_value()) { + // not a flag, requires a value + if (!opt.m_is_used) { + throw std::runtime_error( + "Zero positional arguments expected, did you mean " + + opt.get_usage_full()); + } + } + } + + throw std::runtime_error("Zero positional arguments expected"); + } else { + throw std::runtime_error("Zero positional arguments expected"); + } + } else { + throw std::runtime_error("Maximum number of positional arguments " + "exceeded, failed to parse '" + + current_argument + "'"); + } + } + auto argument = positional_argument_it++; + it = argument->consume(it, end); + continue; + } + + auto arg_map_it = m_argument_map.find(current_argument); + if (arg_map_it != m_argument_map.end()) { + auto argument = arg_map_it->second; + it = argument->consume(std::next(it), end, arg_map_it->first); + } else if (const auto &compound_arg = current_argument; + compound_arg.size() > 1 && + is_valid_prefix_char(compound_arg[0]) && + !is_valid_prefix_char(compound_arg[1])) { + ++it; + for (std::size_t j = 1; j < compound_arg.size(); j++) { + auto hypothetical_arg = std::string{'-', compound_arg[j]}; + auto arg_map_it2 = m_argument_map.find(hypothetical_arg); + if (arg_map_it2 != m_argument_map.end()) { + auto argument = arg_map_it2->second; + it = argument->consume(it, end, arg_map_it2->first); + } else { + throw std::runtime_error("Unknown argument: " + current_argument); + } + } + } else { + throw std::runtime_error("Unknown argument: " + current_argument); + } + } + m_is_parsed = true; + } + + /* + * Like parse_args_internal but collects unused args into a vector + */ + std::vector + parse_known_args_internal(const std::vector &raw_arguments) { + auto arguments = preprocess_arguments(raw_arguments); + + std::vector unknown_arguments{}; + + if (m_program_name.empty() && !arguments.empty()) { + m_program_name = arguments.front(); + } + auto end = std::end(arguments); + auto positional_argument_it = std::begin(m_positional_arguments); + for (auto it = std::next(std::begin(arguments)); it != end;) { + const auto ¤t_argument = *it; + if (Argument::is_positional(current_argument, m_prefix_chars)) { + if (positional_argument_it == std::end(m_positional_arguments)) { + + std::string_view maybe_command = current_argument; + + // Check sub-parsers + auto subparser_it = m_subparser_map.find(maybe_command); + if (subparser_it != m_subparser_map.end()) { + + // build list of remaining args + const auto unprocessed_arguments = + std::vector(it, end); + + // invoke subparser + m_is_parsed = true; + m_subparser_used[maybe_command] = true; + return subparser_it->second->get().parse_known_args_internal( + unprocessed_arguments); + } + + // save current argument as unknown and go to next argument + unknown_arguments.push_back(current_argument); + ++it; + } else { + // current argument is the value of a positional argument + // consume it + auto argument = positional_argument_it++; + it = argument->consume(it, end); + } + continue; + } + + auto arg_map_it = m_argument_map.find(current_argument); + if (arg_map_it != m_argument_map.end()) { + auto argument = arg_map_it->second; + it = argument->consume(std::next(it), end, arg_map_it->first); + } else if (const auto &compound_arg = current_argument; + compound_arg.size() > 1 && + is_valid_prefix_char(compound_arg[0]) && + !is_valid_prefix_char(compound_arg[1])) { + ++it; + for (std::size_t j = 1; j < compound_arg.size(); j++) { + auto hypothetical_arg = std::string{'-', compound_arg[j]}; + auto arg_map_it2 = m_argument_map.find(hypothetical_arg); + if (arg_map_it2 != m_argument_map.end()) { + auto argument = arg_map_it2->second; + it = argument->consume(it, end, arg_map_it2->first); + } else { + unknown_arguments.push_back(current_argument); + break; + } + } + } else { + // current argument is an optional-like argument that is unknown + // save it and move to next argument + unknown_arguments.push_back(current_argument); + ++it; + } + } + m_is_parsed = true; + return unknown_arguments; + } + + // Used by print_help. + std::size_t get_length_of_longest_argument() const { + if (m_argument_map.empty()) { + return 0; + } + std::size_t max_size = 0; + for ([[maybe_unused]] const auto &[unused, argument] : m_argument_map) { + max_size = + std::max(max_size, argument->get_arguments_length()); + } + for ([[maybe_unused]] const auto &[command, unused] : m_subparser_map) { + max_size = std::max(max_size, command.size()); + } + return max_size; + } + + using argument_it = std::list::iterator; + using mutex_group_it = std::vector::iterator; + using argument_parser_it = + std::list>::iterator; + + void index_argument(argument_it it) { + for (const auto &name : std::as_const(it->m_names)) { + m_argument_map.insert_or_assign(name, it); + } + } + + std::string m_program_name; + std::string m_version; + std::string m_description; + std::string m_epilog; + bool m_exit_on_default_arguments = true; + std::string m_prefix_chars{"-"}; + std::string m_assign_chars{"="}; + bool m_is_parsed = false; + std::list m_positional_arguments; + std::list m_optional_arguments; + std::map m_argument_map; + std::string m_parser_path; + std::list> m_subparsers; + std::map m_subparser_map; + std::map m_subparser_used; + std::vector m_mutually_exclusive_groups; + bool m_suppress = false; +}; + +} // namespace argparse diff --git a/cryptominisat/cppsrc/src/avgcalc.h b/cryptominisat/cppsrc/src/avgcalc.h new file mode 100644 index 00000000..9d10ebe1 --- /dev/null +++ b/cryptominisat/cppsrc/src/avgcalc.h @@ -0,0 +1,198 @@ +/****************************************** +Copyright (C) 2009-2020 Authors of CryptoMiniSat, see AUTHORS file + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. +***********************************************/ + +#pragma once + +#include "constants.h" +#include +#include +#include +#include +#include + +using std::numeric_limits; + +namespace CMSat { + +#define AVGCALC_NEED_MIN_MAX + +template +class AvgCalc { + T2 sum; + size_t num; + #if defined(STATS_NEEDED) + double sumSqare; + #endif + #ifdef AVGCALC_NEED_MIN_MAX + T min; + T max; + #endif + +public: + AvgCalc(void) : + sum(0) + , num(0) + #if defined(STATS_NEEDED) + , sumSqare(0) + #endif + #ifdef AVGCALC_NEED_MIN_MAX + , min(numeric_limits::max()) + , max(numeric_limits::min()) + #endif + {} + + AvgCalc& operator/=(const T2 val) + { + sum /= val; + min /= val; + max /= val; + #if defined(STATS_NEEDED) + sumSqare /= val*val; + #endif + + return *this; + } + + AvgCalc& operator+=(const AvgCalc& other) + { + sum += other.sum; + num += other.num; + min = std::min(min, other.min); + max = std::min(min, other.max); + #if defined(STATS_NEEDED) + sumSqare += other.sumSqare; + #endif + + return *this; + } + + AvgCalc& operator-=(const AvgCalc& other) + { + sum += other.sum; + num += other.num; + min = std::min(min, other.min); + max = std::min(min, other.max); + #if defined(STATS_NEEDED) + sumSqare += other.sumSqare; + #endif + + return *this; + } + + T2 get_sum() const + { + return sum; + } + + void push(const T x) { + sum += x; + num++; + + #if defined(STATS_NEEDED) + sumSqare += (double)x*(double)x; + #endif + #ifdef AVGCALC_NEED_MIN_MAX + max = std::max(max, x); + min = std::min(min, x); + #endif + } + + #ifdef AVGCALC_NEED_MIN_MAX + T getMin() const + { + if (min == numeric_limits::max()) + return 0; + + return min; + } + + T getMax() const + { + if (max == numeric_limits::min()) + return 0; + + return max; + } + #endif + #if defined(STATS_NEEDED) + double var() const + { + if (num == 0) + return 0; + + const double calcAvg = avg(); + return + (((double)sumSqare + - 2.0*calcAvg*(double)sum + ))/(double)num + + calcAvg*calcAvg; + } + #endif + + double avg() const + { + if (num == 0) + return 0; + + return (double)sum/(double)num; + } + + std::string avgPrint(size_t prec, size_t w) const + { + std::stringstream ss; + if (num > 0) { + ss << std::fixed << std::setprecision(prec) << std::setw(w) << std::left + << avg(); + } else { + ss << std::setw(w) << "?"; + } + + return ss.str(); + } + + void clear() + { + AvgCalc tmp; + *this = tmp; + } + + void addData(const AvgCalc& other) + { + sum += other.sum; + num += other.num; + + #if defined(STATS_NEEDED) + sumSqare += other.sumSqare; + #endif + #ifdef AVGCALC_NEED_MIN_MAX + min = std::min(min, other.min); + max = std::max(max, other.max); + #endif + } + + size_t num_data_elements() const + { + return num; + } +}; + +} //end namespace diff --git a/cryptominisat/cppsrc/src/bitarray.h b/cryptominisat/cppsrc/src/bitarray.h new file mode 100644 index 00000000..59e5052b --- /dev/null +++ b/cryptominisat/cppsrc/src/bitarray.h @@ -0,0 +1,141 @@ +/****************************************** +Copyright (C) 2009-2020 Authors of CryptoMiniSat, see AUTHORS file + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. +***********************************************/ + +#ifndef BITARRAY_H +#define BITARRAY_H + +//#define DEBUG_BITARRAY + +#include +#include +#include "constants.h" +#include + + +namespace CMSat { + +class BitArray +{ +public: + ~BitArray() + { + free(mp); + } + + BitArray() + {} + + BitArray(const BitArray& other) + { + *this = other; + } + + BitArray& operator=(const BitArray& b) + { + if (size != b.size) { + mp = (uint64_t*)realloc(mp, b.size*sizeof(uint64_t)); + assert(mp != NULL); + size = b.size; + } + memcpy(mp, b.mp, size*sizeof(uint64_t)); + + return *this; + } + + void resize(uint32_t _size, const bool fill) + { + _size = _size/64 + (bool)(_size%64); + if (size != _size) { + mp = (uint64_t*)realloc(mp, _size*sizeof(uint64_t)); + assert(mp != NULL); + size = _size; + } + if (fill) setOne(); + else setZero(); + } + + inline bool isZero() const + { + const uint64_t* mp2 = (const uint64_t*)mp; + + for (uint32_t i = 0; i < size; i++) { + if (mp2[i]) return false; + } + return true; + } + + inline void setZero() + { + if (size != 0) { + memset(mp, 0, size*sizeof(uint64_t)); + } + } + + inline void setOne() + { + if (size != 0) { + memset(mp, 0xff, size*sizeof(uint64_t)); + } + } + + inline void clearBit(const uint32_t i) + { + #ifdef DEBUG_BITARRAY + assert(size*64 > i); + #endif + + mp[i/64] &= ~((uint64_t)1 << (i%64)); + } + + inline void setBit(const uint32_t i) + { + #ifdef DEBUG_BITARRAY + assert(size*64 > i); + #endif + + mp[i/64] |= ((uint64_t)1 << (i%64)); + } + + inline bool operator[](const uint32_t& i) const + { + #ifdef DEBUG_BITARRAY + assert(size*64 > i); + #endif + + return (mp[i/64] >> (i%64)) & 1; + } + + inline uint32_t getSize() const + { + return size*64; + } + +private: + + uint32_t size = 0; + uint64_t* mp = NULL; +}; + +} //end namespace + +#endif //BITARRAY_H + diff --git a/cryptominisat/cppsrc/src/boundedqueue.h b/cryptominisat/cppsrc/src/boundedqueue.h new file mode 100644 index 00000000..903b8248 --- /dev/null +++ b/cryptominisat/cppsrc/src/boundedqueue.h @@ -0,0 +1,196 @@ +/*************************************************************************** +MiniSat -- Copyright (c) 2003-2006, Niklas Een, Niklas Sorensson +2008 - Gilles Audemard, Laurent Simon +CryptoMiniSat -- Copyright (C) 2009-2020 Authors of CryptoMiniSat, see AUTHORS file + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. +****************************************************************************/ + +#ifndef BOUNDEDQUEUE_H +#define BOUNDEDQUEUE_H + +#include "constants.h" +#include "avgcalc.h" +#include +#include +#include +#include +#include +#include + +namespace CMSat { +using std::vector; + +template +class bqueue { + //Only stores info for N elements + vector elems; + uint32_t first; + uint32_t last; + uint32_t maxsize; //max number of history elements + uint32_t queuesize; // Number of current elements (must be < maxsize !) + T2 sumofqueue; + #if defined(STATS_NEEDED) || defined(FINAL_PREDICTOR) + AvgCalc longTermAvg; + #endif + +public: + bqueue(void) : + first(0) + , last(0) + , maxsize(0) + , queuesize(0) + , sumofqueue(0) + {} + + size_t usedMem() const + { + return sizeof(size_t)*4 + elems.capacity()*sizeof(T) + sizeof(T2) + sizeof(AvgCalc); + } + + void push(const T x) { + if (queuesize == maxsize) { + // The queue is full, next value to enter will replace oldest one + + assert(last == first); + sumofqueue -= elems[last]; + + last++; + if (last == maxsize) + last = 0; + + } else { + queuesize++; + } + + sumofqueue += x; + + #if defined(STATS_NEEDED) || defined(FINAL_PREDICTOR) + longTermAvg.push(x); + #endif + elems[first] = x; + + first++; + if (first == maxsize) + first = 0; + } + + size_t num_data_elements() const + { + return queuesize; + } + + double avg() const + { + if (queuesize == 0) + return 0; + + assert(isvalid()); + return (double)sumofqueue/(double)queuesize; + } + + double avg_nocheck() const + { + if (queuesize == 0) + return 0; + + return (double)sumofqueue/(double)queuesize; + } + + #if defined(STATS_NEEDED) || defined(FINAL_PREDICTOR) + const AvgCalc& getLongtTerm() const + { + return longTermAvg; + } + + T prev(int32_t p) const + { + if (p > (int32_t)queuesize) + return 0; + + uint32_t e; + if (first > 0) { + e = first-1; + } else { + e = maxsize-1; + } + + while(p-- > 0) { + if (e == 0) { + e = maxsize-1; + } else { + e--; + } + } + return elems[e]; + } + #endif + + std::string getAvgPrint(size_t prec, size_t w) const + { + std::stringstream ss; + if (isvalid()) { + ss + << std::fixed << std::setprecision(prec) << std::setw(w) << std::right + << avg(); + } else { + ss << std::setw(5) << "?"; + } + + return ss.str(); + } + + bool isvalid() const + { + return (queuesize == maxsize); + } + + void clearAndResize(const size_t size) + { + clear(); + elems.resize(size); + maxsize = size; + } + + void clear() + { + first = 0; + last = 0; + queuesize = 0; + sumofqueue = 0; + + #if defined(STATS_NEEDED) || defined(FINAL_PREDICTOR) + longTermAvg.clear(); + #endif + } + + size_t get_size() const + { + return queuesize; + } + + size_t get_maxsize() const + { + return maxsize; + } +}; + +} //end namespace + +#endif //BOUNDEDQUEUE_H diff --git a/cryptominisat/cppsrc/src/bva.cpp b/cryptominisat/cppsrc/src/bva.cpp new file mode 100644 index 00000000..39265ff0 --- /dev/null +++ b/cryptominisat/cppsrc/src/bva.cpp @@ -0,0 +1,861 @@ +/****************************************** +Copyright (C) 2009-2020 Authors of CryptoMiniSat, see AUTHORS file + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. +***********************************************/ + +#include "bva.h" +#include "occsimplifier.h" +#include "solver.h" +#include "clausecleaner.h" +#include "subsumeimplicit.h" +#include "sqlstats.h" +#include +#include + +//#define CHECK_N_OCCUR + +using namespace CMSat; + +BVA::BVA(Solver* _solver, OccSimplifier* _simplifier) : + solver(_solver) + , simplifier(_simplifier) + , seen(solver->seen) + , seen2(solver->seen2) + , var_bva_order(VarBVAOrder(watch_irred_sizes)) +{} + +bool BVA::bounded_var_addition() +{ + bounded_var_elim_time_limit = + solver->conf.bva_time_limitM*2ULL*400LL *1000LL + *solver->conf.global_timeout_multiplier; + bva_verbosity = false; + + assert(solver->ok); + assert(solver->conf.do_bva); + + if (solver->conf.verbosity >= 3 || bva_verbosity) { + cout << "c [occ-bva] Running BVA" << endl; + } + + simplifier->limit_to_decrease = &bounded_var_elim_time_limit; + int64_t limit_orig = *simplifier->limit_to_decrease; + if (!simplifier->clear_vars_from_cls_that_have_been_set()) { + return false; + } + //TODO check if this is really needed (why is isRemoved a problem??) + solver->clean_occur_from_removed_clauses_only_smudged(); + + bva_worked = 0; + bva_simp_size = 0; + var_bva_order.clear(); + calc_watch_irred_sizes(); + for(size_t i = 0; i < solver->nVars()*2; i++) { + const Lit lit = Lit::toLit(i); + if (solver->value(lit) != l_Undef + || solver->varData[lit.var()].removed != Removed::none + ) { + continue; + } + var_bva_order.insert(lit.toInt()); + } + + double my_time = cpuTime(); + while(!var_bva_order.empty()) { + if (*simplifier->limit_to_decrease < 0 + || bva_worked >= solver->conf.bva_limit_per_call + || solver->must_interrupt_asap() + ) { + break; + } + + const Lit lit = Lit::toLit(var_bva_order.removeMin()); + if (solver->conf.verbosity >= 5 || bva_verbosity) { + cout << "c [occ-bva] trying lit " << lit << endl; + } + bool ok = try_bva_on_lit(lit); + if (!ok) + break; + } + solver->bva_changed(); + + bool time_out = *simplifier->limit_to_decrease <= 0; + const double time_used = cpuTime() - my_time; + double time_remain = float_div(*simplifier->limit_to_decrease ,limit_orig); + if (solver->conf.verbosity) { + cout + << "c [occ-bva] added: " << bva_worked + << " simp: " << bva_simp_size + << " 2lit: " << ((solver->conf.bva_also_twolit_diff + && (long)solver->sumConflicts >= solver->conf.bva_extra_lit_and_red_start) ? "Y" : "N") + << solver->conf.print_times(time_used, time_out, time_remain) + << endl; + } + if (solver->sqlStats) { + solver->sqlStats->time_passed( + solver + , "bva" + , time_used + , time_out + , time_remain + ); + } + runStats.time_used = time_used; + globalStats += runStats; + runStats.reset(); + + solver->clean_occur_from_removed_clauses_only_smudged(); + simplifier->free_clauses_to_free(); + return solver->okay(); +} + +void BVA::remove_duplicates_from_m_cls() +{ + if (m_cls.size() <= 1) + return; + + std::function mysort + = [&] (const OccurClause& a, const OccurClause& b) { + WatchType atype = a.ws.getType(); + WatchType btype = b.ws.getType(); + if (atype == WatchType::watch_binary_t && btype != WatchType::watch_binary_t) { + return true; + } + if (btype == WatchType::watch_binary_t && atype != WatchType::watch_binary_t) { + return false; + } + + assert(atype == btype); + switch(atype) { + case WatchType::watch_binary_t: { + //subsumption could have time-outed + //assert(a.ws.lit2() != b.ws.lit2() && "Implicit has been cleaned of duplicates!!"); + return a.ws.lit2() < b.ws.lit2(); + } + case WatchType::watch_clause_t: { + *simplifier->limit_to_decrease -= 20; + const Clause& cl_a = *solver->cl_alloc.ptr(a.ws.get_offset()); + const Clause& cl_b = *solver->cl_alloc.ptr(b.ws.get_offset()); + if (cl_a.size() != cl_b.size()) { + return cl_a.size() < cl_b.size(); + } + //Clauses' lits are sorted, yay! + for(size_t i = 0; i < cl_a.size(); i++) { + *simplifier->limit_to_decrease -= 1; + if (cl_a[i] != cl_b[i]) { + return cl_a[i] < cl_b[i]; + } + } + return false; + } + case WatchType::watch_bnn_t: //no idea what to do here, error out + case WatchType::watch_idx_t: + // This should never be here + assert(false); + exit(-1); + } + + assert(false); + return false; + }; + + *simplifier->limit_to_decrease -= 2*(int64_t)m_cls.size()*(int64_t)std::sqrt(m_cls.size()); + std::sort(m_cls.begin(), m_cls.end(), mysort); + size_t i = 0; + size_t j = 0; + for(; i+1 < m_cls.size(); i++) { + const Watched& prev = m_cls[j].ws; + const Watched& next = m_cls[i+1].ws; + if (prev.getType() != next.getType()) { + m_cls[j+1] = m_cls[i+1]; + j++; + continue; + } + + bool del = false; + switch(prev.getType()) { + case WatchType::watch_binary_t: { + if (prev.lit2() == next.lit2()) { + del = true; + } + break; + } + + case WatchType::watch_clause_t: { + *simplifier->limit_to_decrease -= 10; + const Clause& cl1 = *solver->cl_alloc.ptr(prev.get_offset()); + const Clause& cl2 = *solver->cl_alloc.ptr(next.get_offset()); + del = true; + if (cl1.size() != cl2.size()) { + break; + } + for(size_t at = 0; at < cl1.size(); at++) { + *simplifier->limit_to_decrease -= 1; + if (cl1[at] != cl2[at]) { + del = false; + break; + } + } + break; + } + + case WatchType::watch_bnn_t: //no idea what to do with BNN + case WatchType::watch_idx_t: + // This should never be here + assert(false); + exit(-1); + } + + if (!del) { + m_cls[j+1] = m_cls[i+1]; + //if (mark_irred) { + // m_cls[j+1].ws.setRed(false); + //} + j++; + } + } + m_cls.resize(m_cls.size()-(i-j)); + + if (solver->conf.verbosity >= 6 || bva_verbosity) { + cout << "m_cls after cleaning: " << endl; + for(const OccurClause& w: m_cls) { + cout << "-> " << solver->watched_to_string(w.lit, w.ws) << endl; + } + } +} + +bool BVA::try_bva_on_lit(const Lit lit) +{ + assert(solver->value(lit) == l_Undef); + assert(solver->varData[lit.var()].removed == Removed::none); + + m_cls.clear(); + m_lits.clear(); + m_lits.push_back(lit); + *simplifier->limit_to_decrease -= (int64_t)solver->watches[lit].size(); + for(const Watched w: solver->watches[lit]) { + if (!solver->redundant(w)) { + m_cls.push_back(OccurClause(lit, w)); + if (solver->conf.verbosity >= 6 || bva_verbosity) { + cout << "1st adding to m_cls " + << solver->watched_to_string(lit, w) + << endl; + } + } + } + remove_duplicates_from_m_cls(); + + while(true) { + potential.clear(); + fill_potential(lit); + if (*simplifier->limit_to_decrease < 0) { + return solver->okay(); + } + + size_t num_occur; + const lit_pair l_max = most_occurring_lit_in_potential(num_occur); + if (simplifies_system(num_occur)) { + m_lits.push_back(l_max); + m_cls.clear(); + *simplifier->limit_to_decrease -= (int64_t)potential.size()*3; + for(const PotentialClause pot: potential) { + if (pot.lits == l_max) { + m_cls.push_back(pot.occur_cl); + if (solver->conf.verbosity >= 6 || bva_verbosity) { + cout << "-- max is : (" << l_max.lit1 << ", " << l_max.lit2 << "), adding to m_cls " + << solver->watched_to_string(pot.occur_cl.lit, pot.occur_cl.ws) + << endl; + } + assert(pot.occur_cl.lit == lit); + } + } + } else { + break; + } + } + + const int simp_size = simplification_size(m_lits.size(), m_cls.size()); + if (simp_size <= solver->conf.min_bva_gain) { + return solver->okay(); + } + + const bool ok = bva_simplify_system(); + return ok; +} + +bool BVA::bva_simplify_system() +{ + touched.clear(); + int simp_size = simplification_size(m_lits.size(), m_cls.size()); + if (solver->conf.verbosity >= 6 || bva_verbosity) { + cout + << "c [occ-bva] YES Simplification by " + << simp_size + << " with matching lits: "; + for(const lit_pair l: m_lits) { + cout << "(" << l.lit1; + if (l.lit2 != lit_Undef) { + cout << ", " << l.lit2; + } + cout << "), "; + } + cout << endl; + cout << "c [occ-bva] cls: "; + for(OccurClause cl: m_cls) { + cout + << "(" << solver->watched_to_string(cl.lit, cl.ws) << ")" + << ", "; + } + cout << endl; + } + bva_worked++; + bva_simp_size += simp_size; + + solver->new_var(true, numeric_limits::max(), false); + const uint32_t newvar = solver->nVars()-1; + const Lit new_lit(newvar, false); + + //Binary clauses + for(const lit_pair m_lit: m_lits) { + bva_tmp_lits.clear(); + bva_tmp_lits.push_back(m_lit.lit1); + if (m_lit.lit2 != lit_Undef) { + bva_tmp_lits.push_back(m_lit.lit2); + } + bva_tmp_lits.push_back(new_lit); + Clause* newCl = solver->add_clause_int( + bva_tmp_lits, //lits to add + false, //redundant? + NULL, //stats + false, //attach if long? + &bva_tmp_lits, //put final lits back here + true, //add FRAT + new_lit //the first literal in FRAT + ); + + if (newCl != NULL) { + simplifier->link_in_clause(*newCl); + ClOffset offset = solver->cl_alloc.get_offset(newCl); + simplifier->clauses.push_back(offset); + } else { + for(Lit l: bva_tmp_lits) { + simplifier->n_occurs[l.toInt()]++; + } + } + touched.touch(bva_tmp_lits); + } + + //Longer clauses + for(const OccurClause m_cl: m_cls) { + bool ok = add_longer_clause(~new_lit, m_cl); + if (!ok) + return false; + } + + fill_m_cls_lits_and_red(); + for(const lit_pair replace_lit: m_lits) { + //cout << "Doing lit " << replace_lit << " replacing lit " << lit << endl; + for(const m_cls_lits_and_red& cl_lits_and_red: m_cls_lits) { + remove_matching_clause(cl_lits_and_red, replace_lit); + } + } + + update_touched_lits_in_bva(); + + return solver->okay(); +} + +void BVA::update_touched_lits_in_bva() +{ + const vector& touched_list = touched.getTouchedList(); + for(const uint32_t lit_uint: touched_list) { + const Lit lit = Lit::toLit(lit_uint); + if (var_bva_order.inHeap(lit.toInt())) { + watch_irred_sizes[lit.toInt()] = calc_watch_irred_size(lit); + var_bva_order.update(lit.toInt()); + } + + if (var_bva_order.inHeap((~lit).toInt())) { + watch_irred_sizes[(~lit).toInt()] = calc_watch_irred_size(~lit); + var_bva_order.update((~lit).toInt()); + } + } + touched.clear(); +} + +void BVA::fill_m_cls_lits_and_red() +{ + m_cls_lits.clear(); + vector tmp; + for(OccurClause& cl: m_cls) { + tmp.clear(); + bool red; + switch(cl.ws.getType()) { + case WatchType::watch_binary_t: { + tmp.push_back(cl.ws.lit2()); + red = cl.ws.red(); + break; + } + case WatchType::watch_clause_t: { + const Clause* cl_orig = solver->cl_alloc.ptr(cl.ws.get_offset()); + for(const Lit lit: *cl_orig) { + if (cl.lit != lit) { + tmp.push_back(lit); + } + } + red = cl_orig->red(); + break; + } + case WatchType::watch_idx_t: + default: + { + // This should never be here + assert(false); + exit(-1); + } + } + m_cls_lits.push_back(m_cls_lits_and_red(tmp, red)); + } +} + +void BVA::remove_matching_clause( + const m_cls_lits_and_red& cl_lits_and_red + , const lit_pair lit_replace +) { + if (solver->conf.verbosity >= 6 || bva_verbosity) { + cout + << "c [occ-bva] Removing cl " + //<< solver->watched_to_string(lit_replace, cl.ws) + << endl; + } + + to_remove.clear(); + to_remove.push_back(lit_replace.lit1); + if (lit_replace.lit2 != lit_Undef) { + to_remove.push_back(lit_replace.lit2); + } + for(const Lit cl_lit: cl_lits_and_red.lits) { + to_remove.push_back(cl_lit); + } + touched.touch(to_remove); + + switch(to_remove.size()) { + case 2: { + *simplifier->limit_to_decrease -= 2*(int64_t)solver->watches[to_remove[0]].size(); + assert(!solver->frat->enabled()); //TODO FRAT is broken here" + //*(solver->frat) << del << to_remove << fin; + solver->detach_bin_clause( + to_remove[0], to_remove[1], + false, //redundant + 0);// TODO ID + simplifier->n_occurs[to_remove[0].toInt()]--; + simplifier->n_occurs[to_remove[1].toInt()]--; + break; + } + + default: + Clause* cl_new = find_cl_for_bva(to_remove, cl_lits_and_red.red); + simplifier->unlink_clause(solver->cl_alloc.get_offset(cl_new)); + break; + } +} + +Clause* BVA::find_cl_for_bva( + const vector& torem + , const bool red +) const { + Clause* cl = NULL; + for(const Lit lit: torem) { + seen[lit.toInt()] = 1; + } + for(Watched w: solver->watches[torem[0]]) { + if (!w.isClause()) + continue; + + cl = solver->cl_alloc.ptr(w.get_offset()); + if (cl->red() != red + || cl->size() != torem.size() + ) { + continue; + } + #ifdef SLOW_DEBUG + assert(!cl->freed()); + assert(!cl->getRemoved()); + #endif + + bool OK = true; + for(const Lit lit: *cl) { + if (seen[lit.toInt()] == 0) { + OK = false; + break; + } + } + + if (OK) + break; + } + + for(const Lit lit: torem) { + seen[lit.toInt()] = 0; + } + + assert(cl != NULL); + return cl; +} + +bool BVA::add_longer_clause(const Lit new_lit, const OccurClause& cl) +{ + vector& lits = bva_tmp_lits; + lits.clear(); + switch(cl.ws.getType()) { + case WatchType::watch_binary_t: { + lits.resize(2); + lits[0] = new_lit; + lits[1] = cl.ws.lit2(); + Clause* cl_check = solver->add_clause_int( + lits, //lits to attach + false, //redundant? + NULL, + false, //attach? + &lits, //put back cls here + true, //FRAT? + new_lit //first FRAT literal + ); + for(Lit l: lits) { + simplifier->n_occurs[l.toInt()]++; + } + assert(cl_check == NULL); + break; + } + + case WatchType::watch_clause_t: { + const Clause& orig_cl = *solver->cl_alloc.ptr(cl.ws.get_offset()); + lits.resize(orig_cl.size()); + for(size_t i = 0; i < orig_cl.size(); i++) { + if (orig_cl[i] == cl.lit) { + lits[i] = new_lit; + } else { + lits[i] = orig_cl[i]; + } + } + ClauseStats backup_stats(orig_cl.stats); + Clause* newCl = solver->add_clause_int( + lits, //lits to add + false, //redundant? + &backup_stats, + false, //attach? + &lits, //put back final lits here + true, //FRAT + new_lit //first FRAT literal + ); + if (newCl != NULL) { + simplifier->link_in_clause(*newCl); + ClOffset offset = solver->cl_alloc.get_offset(newCl); + simplifier->clauses.push_back(offset); + } else { + for(Lit l: lits) { + simplifier->n_occurs[l.toInt()]++; + } + } + break; + } + + case WatchType::watch_bnn_t: + case WatchType::watch_idx_t: + // This should never be here + assert(false); + exit(-1); + break; + } + touched.touch(lits); + + return solver->okay(); +} + +string BVA::PotentialClause::to_string(const Solver* solver) const +{ + std::stringstream ss; + ss << solver->watched_to_string(occur_cl.lit, occur_cl.ws) + << " -- (diff) lit: " << lits.lit1 << ", " << lits.lit2; + + return ss.str(); +} + +int BVA::simplification_size( + const int m_lits_size + , const int m_cls_size +) const { + return m_lits_size*m_cls_size-m_lits_size-m_cls_size; +} + +void BVA::fill_potential(const Lit lit) +{ + for(const OccurClause& c: m_cls) { + if (*simplifier->limit_to_decrease < 0) + break; + + const Lit l_min = least_occurring_except(c); + if (l_min == lit_Undef) + continue; + + solver->watches.prefetch(l_min.toInt()); + m_lits_this_cl = m_lits; + *simplifier->limit_to_decrease -= (int64_t)m_lits_this_cl.size(); + for(const lit_pair lits: m_lits_this_cl) { + seen2[lits.hash(seen2.size())] = 1; + } + + if (solver->conf.verbosity >= 6 || bva_verbosity) { + cout + << "c [occ-bva] Examining clause for addition to 'potential':" + << solver->watched_to_string(c.lit, c.ws) + << " -- Least occurring in this CL: " << l_min + << endl; + } + + *simplifier->limit_to_decrease -= (int64_t)solver->watches[l_min].size()*3; + for(const Watched& d_ws: solver->watches[l_min]) { + if (*simplifier->limit_to_decrease < 0) + goto end; + + OccurClause d(l_min, d_ws); + const size_t sz_c = solver->cl_size(c.ws); + const size_t sz_d = solver->cl_size(d.ws); + if (c.ws != d.ws + && (sz_c == sz_d + || (sz_c+1 == sz_d + && solver->conf.bva_also_twolit_diff + && (long)solver->sumConflicts >= solver->conf.bva_extra_lit_and_red_start + ) + ) + && !solver->redundant(d.ws) + && lit_diff_watches(c, d) == lit + ) { + const lit_pair diff = lit_diff_watches(d, c); + if (seen2[diff.hash(seen2.size())] == 0) { + *simplifier->limit_to_decrease -= 3; + potential.push_back(PotentialClause(diff, c)); + m_lits_this_cl.push_back(diff); + seen2[diff.hash(seen2.size())] = 1; + + if (solver->conf.verbosity >= 6 || bva_verbosity) { + cout + << "c [occ-bva] Added to P: " + << potential.back().to_string(solver) + << endl; + } + } + } + } + + end: + for(const lit_pair lits: m_lits_this_cl) { + seen2[lits.hash(seen2.size())] = 0; + } + } +} + + +bool BVA::VarBVAOrder::operator()(const uint32_t lit1_uint, const uint32_t lit2_uint) const +{ + return watch_irred_sizes[lit1_uint] > watch_irred_sizes[lit2_uint]; +} + + + +bool BVA::simplifies_system(const size_t num_occur) const +{ + //If first run, at least 2 must match, nothing else matters + if (m_lits.size() == 1) { + return num_occur >= 2; + } + + assert(m_lits.size() > 1); + int orig_num_red = simplification_size(m_lits.size(), m_cls.size()); + int new_num_red = simplification_size(m_lits.size()+1, num_occur); + + if (new_num_red <= solver->conf.min_bva_gain) + return false; + + if (new_num_red < (orig_num_red+solver->conf.min_bva_gain)) + return false; + + return true; +} + + + +BVA::lit_pair BVA::most_occurring_lit_in_potential(size_t& largest) +{ + largest = 0; + lit_pair most_occur = lit_pair(lit_Undef, lit_Undef); + if (potential.size() > 1) { + *simplifier->limit_to_decrease -= (double)potential.size()*(double)std::log(potential.size())*0.2; + std::sort(potential.begin(), potential.end()); + } + + lit_pair last_occur = lit_pair(lit_Undef, lit_Undef); + size_t num = 0; + for(const PotentialClause pot: potential) { + if (last_occur != pot.lits) { + if (num >= largest) { + largest = num; + most_occur = last_occur; + } + last_occur = pot.lits; + num = 1; + } else { + num++; + } + } + if (num >= largest) { + largest = num; + most_occur = last_occur; + } + + if (solver->conf.verbosity >= 5 || bva_verbosity) { + cout + << "c [occ-bva] ---> Most occurring lit in p: " << most_occur.lit1 << ", " << most_occur.lit2 + << " occur num: " << largest + << endl; + } + + return most_occur; +} + +BVA::lit_pair BVA::lit_diff_watches(const OccurClause& a, const OccurClause& b) +{ + //assert(solver->cl_size(a.ws) == solver->cl_size(b.ws)); + assert(a.lit != b.lit); + solver->for_each_lit(b, [&](const Lit lit) {seen[lit.toInt()] = 1;}, simplifier->limit_to_decrease); + + size_t num = 0; + lit_pair toret = lit_pair(lit_Undef, lit_Undef); + const auto check_seen = [&] (const Lit lit) { + if (seen[lit.toInt()] == 0) { + if (num == 0) + toret.lit1 = lit; + else + toret.lit2 = lit; + + num++; + } + }; + solver->for_each_lit(a, check_seen, simplifier->limit_to_decrease); + solver->for_each_lit(b, [&](const Lit lit) {seen[lit.toInt()] = 0;}, simplifier->limit_to_decrease); + + if (num >= 1 && num <= 2) + return toret; + else + return lit_Undef; +} + + + +Lit BVA::least_occurring_except(const OccurClause& c) +{ + *simplifier->limit_to_decrease -= (int64_t)m_lits.size(); + for(const lit_pair lits: m_lits) { + seen[lits.lit1.toInt()] = 1; + if (lits.lit2 != lit_Undef) { + seen[lits.lit2.toInt()] = 1; + } + } + + Lit smallest = lit_Undef; + size_t smallest_val = numeric_limits::max(); + const auto check_smallest = [&] (const Lit lit) { + //Must not be in m_lits + if (seen[lit.toInt()] != 0) + return; + + const size_t watch_size = solver->watches[lit].size(); + if (watch_size < smallest_val) { + smallest = lit; + smallest_val = watch_size; + } + }; + solver->for_each_lit_except_watched(c, check_smallest, simplifier->limit_to_decrease); + + for(const lit_pair lits: m_lits) { + seen[lits.lit1.toInt()] = 0; + if (lits.lit2 != lit_Undef) { + seen[lits.lit2.toInt()] = 0; + } + } + + return smallest; +} + +void BVA::calc_watch_irred_sizes() +{ + watch_irred_sizes.clear(); + for(size_t i = 0; i < solver->nVars()*2; i++) { + const Lit lit = Lit::toLit(i); + const size_t irred_size = calc_watch_irred_size(lit); + watch_irred_sizes.push_back(irred_size); + } +} + +size_t BVA::calc_watch_irred_size(const Lit lit) const +{ + #ifdef CHECK_N_OCCUR + size_t num = 0; + watch_subarray_const ws = solver->watches[lit]; + for(const Watched w: ws) { + if (w.isBin()) { + num += !w.red(); + continue; + } + + assert(w.isClause()); + const Clause& cl = *solver->cl_alloc.ptr(w.get_offset()); + assert(!cl.freed()); + num += (!cl.getRemoved() && !cl.red()); + } + if (num != simplifier->n_occurs[lit.toInt()]) { + cout << "for lit "<< lit << endl; + cout << "n occ: "<< simplifier->n_occurs[lit.toInt()] << endl; + cout << "our count: "<< num << endl; + assert(false); + } + #endif + + return simplifier->n_occurs[lit.toInt()]; +} + +size_t BVA::mem_used() const +{ + size_t mem = 0; + mem += bva_tmp_lits.capacity()*sizeof(Lit); + mem += m_cls_lits.capacity()*sizeof(m_cls_lits_and_red); + for(const auto& m: m_cls_lits) { + mem += m.lits.capacity()*sizeof(Lit); + } + mem += to_remove.capacity()* sizeof(Lit); + mem += potential.capacity()*sizeof(PotentialClause); + mem += m_lits.capacity()*sizeof(lit_pair); + mem += m_lits_this_cl.capacity()*sizeof(lit_pair); + mem += m_cls.capacity()*sizeof(OccurClause); + mem += watch_irred_sizes.capacity()*sizeof(size_t); + mem += var_bva_order.mem_used(); + mem += touched.mem_used(); + return mem; +} diff --git a/cryptominisat/cppsrc/src/bva.h b/cryptominisat/cppsrc/src/bva.h new file mode 100644 index 00000000..d9e9aa7e --- /dev/null +++ b/cryptominisat/cppsrc/src/bva.h @@ -0,0 +1,201 @@ +/****************************************** +Copyright (C) 2009-2020 Authors of CryptoMiniSat, see AUTHORS file + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. +***********************************************/ + +#ifndef __BVA_H__ +#define __BVA_H__ + +#include "heap.h" +#include "watched.h" +#include "clause.h" +#include "touchlist.h" +#include +#include +using std::vector; + +namespace CMSat { + +class Solver; +class OccSimplifier; + +class BVA +{ +public: + BVA(Solver* _solver, OccSimplifier* _simplifier); + bool bounded_var_addition(); + size_t mem_used() const; + + struct Stats + { + double time_used = 0; + + Stats& operator +=(const Stats& other) { + time_used += other.time_used; + return *this; + } + + void reset() + { + *this = Stats(); + } + }; + + const Stats& get_stats() const; + +private: + Solver* solver; + OccSimplifier* simplifier; + vector& seen; + vector& seen2; + + Stats runStats; + Stats globalStats; + bool bva_verbosity = 0; + size_t bva_worked; + size_t bva_simp_size; + struct lit_pair{ + lit_pair(Lit a, Lit b = lit_Undef) + { + if (b == lit_Undef) { + lit1 = a; + } else { + assert(false && "lits are supposed to be sorted in occur lists"); + assert(a != b); + if (a > b) { + std::swap(a, b); + } + lit1 = a; + lit2 = b; + } + } + + bool operator==(const lit_pair& other) const + { + return lit1 == other.lit1 && lit2 == other.lit2; + } + + unsigned hash(const uint32_t N) const + { + unsigned long h; + h = lit1.toInt(); + + if (lit2 == lit_Undef) + return h % N; + + h = h*31 + lit2.toInt(); + return h % N; + } + + bool operator!=(const lit_pair& other) const + { + return !(*this == other); + } + + Lit lit1; + Lit lit2; + }; + struct PotentialClause { + PotentialClause(const lit_pair& _lits, const OccurClause& cl) : + lits(_lits) + , occur_cl(cl) + {} + + bool operator<(const PotentialClause& other) const + { + if (lits == other.lits) + return false; + + if (lits.lit1 != other.lits.lit1) + return lits.lit1 < other.lits.lit1; + + return lits.lit2 < other.lits.lit2; + } + + lit_pair lits; + OccurClause occur_cl; + string to_string(const Solver* solver) const; + }; + struct m_cls_lits_and_red + { + //Used during removal to lower overhead + m_cls_lits_and_red(const vector& _lits, bool _red) : + lits(_lits) + , red(_red) + {} + vector lits; + bool red; + }; + size_t calc_watch_irred_size(const Lit lit) const; + void calc_watch_irred_sizes(); + lit_pair most_occurring_lit_in_potential(size_t& num_occur); + lit_pair lit_diff_watches(const OccurClause& a, const OccurClause& b); + Lit least_occurring_except(const OccurClause& c); + bool simplifies_system(const size_t num_occur) const; + int simplification_size( + const int m_lit_size + , const int m_cls_size + ) const; + void fill_potential(const Lit lit); + bool try_bva_on_lit(const Lit lit); + bool bva_simplify_system(); + void update_touched_lits_in_bva(); + bool add_longer_clause(const Lit lit, const OccurClause& cl); + void remove_duplicates_from_m_cls(); + void remove_matching_clause( + const m_cls_lits_and_red& cl_lits + , const lit_pair lit_replace + ); + Clause* find_cl_for_bva( + const vector& torem + , const bool red + ) const; + void fill_m_cls_lits_and_red(); + vector bva_tmp_lits; //To reduce overhead + vector m_cls_lits; //used during removal to lower overhead + vector to_remove; //to reduce overhead + vector potential; + vector m_lits; + vector m_lits_this_cl; + vector m_cls; + vector watch_irred_sizes; + struct VarBVAOrder + { + explicit VarBVAOrder(vector& _watch_irred_sizes) : + watch_irred_sizes(_watch_irred_sizes) + {} + + bool operator()(const uint32_t lit1_uint, const uint32_t lit2_uint) const; + vector& watch_irred_sizes; + }; + Heap var_bva_order; + TouchList touched; + + int64_t bounded_var_elim_time_limit; +}; + +inline const BVA::Stats& BVA::get_stats() const +{ + return globalStats; +} + +} + +#endif //__BVA_H__ diff --git a/cryptominisat/cppsrc/src/cardfinder.cpp b/cryptominisat/cppsrc/src/cardfinder.cpp new file mode 100644 index 00000000..cff68f5a --- /dev/null +++ b/cryptominisat/cppsrc/src/cardfinder.cpp @@ -0,0 +1,416 @@ +/****************************************** +Copyright (C) 2009-2020 Authors of CryptoMiniSat, see AUTHORS file + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. +***********************************************/ + +#include "constants.h" +#include "cardfinder.h" +#include "time_mem.h" +#include "solver.h" +#include "watched.h" +#include "watchalgos.h" + +#include +#include + +//TODO read: https://sat-smt.in/assets/slides/daniel1.pdf + +using namespace CMSat; +using std::cout; +using std::endl; + +CardFinder::CardFinder(Solver* _solver) : + solver(_solver) + , seen(solver->seen) + , seen2(solver->seen2) + , toClear(solver->toClear) +{ +} + +//TODO order encoding! +//Also, convert to order encoding. + +std::string CardFinder::print_card(const vector& lits) const { + std::stringstream ss; + for(size_t i = 0; i < lits.size(); i++) { + ss << lits[i]; + if (i != lits.size()-1) { + ss << ", "; + } + } + + return ss.str(); +} + +bool CardFinder::find_connector(Lit lit1, Lit lit2) const +{ + //cout << "Finding connector: " << lit1 << ", " << lit2 << endl; + + //look through the shorter one + if (solver->watches[lit1].size() > solver->watches[lit2].size()) { + std::swap(lit1, lit2); + } + + for(const Watched& x : solver->watches[lit1]) { + if (!x.isBin()) { + continue; + } + + if (x.lit2() == lit2) + return true; + } + return false; +} + +void CardFinder::get_vars_with_clash(const vector& lits, vector& clash) const { + Lit last_lit = lit_Undef; + for(const Lit x: lits) { + if (x == ~last_lit) { + clash.push_back(x.var()); + } + last_lit = x; + } +} + +//See "Detecting cardinality constraints in CNF" +//By Armin Biere, Daniel Le Berre, Emmanuel Lonca, and Norbert Manthey +//Sect. 3.3 -- two-product encoding +// +void CardFinder::find_two_product_atmost1() { + vector> new_cards; + for(size_t at_row = 0; at_row < cards.size(); at_row++) { + vector& card_row = cards[at_row]; + seen2[at_row] = 1; + if (card_row.empty()) { + continue; + } + Lit r = card_row[0]; + + //find min(NAG(r)) + Lit l = lit_Undef; + for(const auto& ws: solver->watches[r]) { + if (!ws.isBin()) continue; + if (l == lit_Undef) { + l = ws.lit2(); + } else { + if (ws.lit2() < l) { + l = ws.lit2(); + } + } + } + if (l == lit_Undef) { + continue; + } + + //find the column + for(const auto& ws: solver->watches[l]) { + if (ws.isBin()) { + Lit c = ws.lit2(); + if (c == r) continue; + for(const auto& ws2: solver->watches[c]) { + if (ws2.isIdx()) { + size_t at_col = ws2.get_idx(); + if (seen2[at_col]) { + //only do row1->row2, it's good enough + //don't do reverse too + continue; + } + vector& card_col = cards[at_col]; + if (card_col.empty()) continue; + + /*cout << "c [cardfind] Potential card for" + << " row: " << print_card(card_row) + << " -- col: " << print_card(card_col) + << endl;*/ + + vector card; + + //mark all lits in row's bin-connected graph + for(const Lit row: card_row) { + for(const auto& ws3: solver->watches[row]) { + if (ws3.isBin()) { + seen[ws3.lit2().toInt()] = 1; + } + } + } + + //find matching column + for(const Lit col: card_col) { + for(const auto& ws3: solver->watches[col]) { + if (ws3.isBin()) { + Lit conn_lit = ws3.lit2(); + if (seen[conn_lit.toInt()]) { + //cout << "part of card: " << ~conn_lit << endl; + card.push_back(~conn_lit); + } + } + } + } + + if (card.size() > 2) { + /*cout << "Reassembled two product: " + << print_card(card) << endl;*/ + new_cards.push_back(card); + } + + //unmark + for(const Lit row: card_row) { + for(const auto& ws3: solver->watches[row]) { + if (ws3.isBin()) { + seen[ws3.lit2().toInt()] = 0; + } + } + } + } + } + } + } + } + + size_t old_size = cards.size(); + cards.resize(cards.size()+new_cards.size()); + for(auto& card: new_cards) { + std::sort(card.begin(), card.end()); + std::swap(cards[old_size], card); + old_size++; + } + + //clear seen2 + for(size_t at_row = 0; at_row < cards.size(); at_row++) { + seen2[at_row] = 0; + } +} + +void CardFinder::print_cards(const vector>& card_constraints) const { + for(const auto& card: card_constraints) { + cout << "c [cardfind] final: " << print_card(card) << endl; + } +} + + +void CardFinder::deal_with_clash(vector& clash) { + + vector idx_pos; + vector idx_neg; + + for(uint32_t var: clash) { + Lit lit = Lit(var, false); + if (seen[lit.toInt()] == 0 || seen[(~lit).toInt()] == 0) { + continue; + } + + //cout << "c [cardfind] Clash on var " << lit << endl; + for(auto ws: solver->watches[lit]) { + if (ws.isIdx()) { + idx_pos.push_back(ws.get_idx()); + + /*cout << "c [cardfind] -> IDX " << ws.get_idx() << ": " + << print_card(cards[ws.get_idx()]) << endl;*/ + } + } + for(auto ws: solver->watches[~lit]) { + if (ws.isIdx()) { + idx_neg.push_back(ws.get_idx()); + + /*cout << "c [cardfind] -> IDX " << ws.get_idx() << ": " + << print_card(cards[ws.get_idx()]) << endl;*/ + } + } + + //resolve each with each + for(uint32_t pos: idx_pos) { + for(uint32_t neg: idx_neg) { + assert(pos != neg); + //one has been removed already + if (cards[pos].empty() || cards[neg].empty()) { + continue; + } + + vector new_card; + bool found = false; + for(Lit l: cards[pos]) { + if (l == lit) { + found = true; + } else { + new_card.push_back(l); + } + } + assert(found); + + for(Lit l: cards[neg]) { + if (l == ~lit) { + found = true; + } else { + new_card.push_back(l); + } + } + assert(found); + + std::sort(new_card.begin(), new_card.end()); + /*cout << "c [cardfind] -> Combined card: " + << print_card(new_card) << endl;*/ + + //add the new cardinality constraint + for(Lit l: new_card) { + solver->watches[l].push(Watched(cards.size(), WatchType::watch_idx_t)); + } + cards.push_back(new_card); + } + } + + //clear old cardinality constraints + for(uint32_t pos: idx_pos) { + cards[pos].clear(); + } + for(uint32_t neg: idx_neg) { + cards[neg].clear(); + } + + idx_pos.clear(); + idx_neg.clear(); + } +} + +void CardFinder::clean_empty_cards() +{ + size_t j = 0; + for(size_t i = 0; i < cards.size(); i++) { + if (!cards[i].empty()) { + std::swap(cards[j], cards[i]); + j++; + } + } + cards.resize(j); +} + +//See "Detecting cardinality constraints in CNF" +//By Armin Biere, Daniel Le Berre, Emmanuel Lonca, and Norbert Manthey +//Sect. 3.1 -- greeedy algorithm. "S" there is "lits_in_card" here +// +void CardFinder::find_pairwise_atmost1() +{ + assert(toClear.size() == 0); + for (uint32_t i = 0; i < solver->nVars()*2; i++) { + const Lit l = Lit::toLit(i); + vector lits_in_card; + if (seen[l.toInt()]) { + //cout << "Skipping " << l << " we have seen it before" << endl; + continue; + } + + for(const Watched& x : solver->watches[~l]) { + if (!x.isBin()) { + continue; + } + const Lit other = x.lit2(); + + bool all_found = true; + for(const Lit other2: lits_in_card) { + if (!find_connector(other, ~other2)) { + all_found = false; + break; + } + } + if (all_found) { + lits_in_card.push_back(~other); + // cout << "added to lits_in_card: " << ~other << endl; + } + } + if (lits_in_card.size() > 1) { + lits_in_card.push_back(l); + for(const Lit l_c: lits_in_card) { + if (!seen[l_c.toInt()]) { + toClear.push_back(l_c); + } + seen[l_c.toInt()]++; + solver->watches[l_c].push(Watched(cards.size(), WatchType::watch_idx_t)); + solver->watches.smudge(l_c); + } + total_sizes+=lits_in_card.size(); + std::sort(lits_in_card.begin(), lits_in_card.end()); + verb_print(1, "found simple card " << print_card(lits_in_card) << " on lit " << l); + + //fast push-back + cards.resize(cards.size()+1); + std::swap(cards[cards.size()-1], lits_in_card); + + } else { + //cout << "lits_in_card.size():" << lits_in_card.size() << endl; + //cout << "Found none for " << l << endl; + } + } + + //Now deal with so-called "Nested encoding" + // i.e. x1+x2+x4+x5 <= 1 + // divided into the cardinality constraints + // x1+x2+x3 <= 1 and \not x3+x4+x5 <= 1 + //See sect. 3.2 of same paper + // + std::sort(toClear.begin(), toClear.end()); + vector vars_with_clash; + get_vars_with_clash(toClear, vars_with_clash); + deal_with_clash(vars_with_clash); + for(const Lit x: toClear) { + seen[x.toInt()] = 0; + } + toClear.clear(); +} + +void CardFinder::find_cards() +{ + cards.clear(); + double myTime = cpuTime(); + + find_pairwise_atmost1(); + find_two_product_atmost1(); + + //print result + clean_empty_cards(); + if (solver->conf.verbosity) { + verb_print(1, "[cardfind] All constraints below:"); + print_cards(cards); + } + + //clean indexes + for(auto& lit: solver->watches.get_smudged_list()) { + auto& ws = solver->watches[lit]; + size_t j = 0; + for(size_t i = 0; i < ws.size(); i++) { + if (!ws[i].isIdx()) { + ws[j++] = ws[i]; + } + } + ws.resize(j); + } + solver->watches.clear_smudged(); + + if (solver->conf.verbosity) { + double avg = 0; + if (cards.size() > 0) { + avg = (double)total_sizes/(double)cards.size(); + } + + cout << "c [cardfind] " + << "cards: " << cards.size() + << " avg size: " << avg + << solver->conf.print_times(cpuTime()-myTime) + << endl; + } +} diff --git a/cryptominisat/cppsrc/src/cardfinder.h b/cryptominisat/cppsrc/src/cardfinder.h new file mode 100644 index 00000000..db525d7f --- /dev/null +++ b/cryptominisat/cppsrc/src/cardfinder.h @@ -0,0 +1,80 @@ +/****************************************** +Copyright (C) 2009-2020 Authors of CryptoMiniSat, see AUTHORS file + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. +***********************************************/ + +#ifndef _CARDFINDER_H_ +#define _CARDFINDER_H_ + +#include +#include +#include +#include +#include +#include +#include +#include "xor.h" +#include "cset.h" +#include "watcharray.h" + +using std::vector; +using std::set; + +namespace CMSat { + +class Solver; + +class CardFinder +{ + +public: + CardFinder(Solver* solver); + void find_cards(); + const vector>& get_cards() const; + +private: + void get_vars_with_clash(const vector& lits, vector& vars) const; + void find_pairwise_atmost1(); + void deal_with_clash(vector& vars); + bool find_connector(Lit lit1, Lit lit2) const; + std::string print_card(const vector& lits) const; + void print_cards(const vector>& card_constraints) const; + void find_two_product_atmost1(); + void clean_empty_cards(); + + //from solver + Solver* solver; + vector& seen; + vector& seen2; + vector& toClear; + + //internal data + vector> cards; + uint64_t total_sizes = 0; +}; + +inline const vector>& CardFinder::get_cards() const +{ + return cards; +} + +} //end namespace + +#endif //_CARDFINDER_H_ diff --git a/cryptominisat/cppsrc/src/ccnr.cpp b/cryptominisat/cppsrc/src/ccnr.cpp new file mode 100644 index 00000000..444a60ae --- /dev/null +++ b/cryptominisat/cppsrc/src/ccnr.cpp @@ -0,0 +1,537 @@ +/****************************************** +Copyright (c) 2019, Shaowei Cai + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. +***********************************************/ + +#include "ccnr.h" +#include "ccnr_mersenne.h" + +#include +#include +#include +#include +#include + +using namespace CCNR; + +using std::cout; +using std::endl; +using std::string; + + +//constructor with default setting. +ls_solver::ls_solver(const bool aspiration) +{ + _max_tries = 100; + _max_steps = 1*1000 * 1000; + _random_seed = 1; + _time_limit = 3000; + _swt_threshold = 50; + _swt_p = 0.3; + _swt_q = 0.7; + _aspiration = aspiration; + _up_ratio = 0.3; //delete _up_ratio percents varibles + verbosity = 0; +} + +/**********************************build instance*******************************/ +bool ls_solver::make_space() +{ + if (0 == _num_vars || 0 == _num_clauses) { + cout << "c [ccnr] The formula size is zero." + "You may have forgotten to read the formula." << endl; + return false; + } + _vars.resize(_num_vars+1); + _clauses.resize(_num_clauses+1); + _solution.resize(_num_vars+1); + _best_solution.resize(_num_vars+1); + _index_in_unsat_clauses.resize(_num_clauses+1); + _index_in_unsat_vars.resize(_num_vars+1); + + return true; +} + +void ls_solver::build_neighborhood() +{ + vector neighbor_flag(_num_vars+1); + for (uint32_t j = 0; j < neighbor_flag.size(); ++j) { + neighbor_flag[j] = 0; + } + for (int v = 1; v <= _num_vars; ++v) { + variable *vp = &(_vars[v]); + for (lit lv: vp->literals) { + int c = lv.clause_num; + for (lit lc: _clauses[c].literals) { + if (!neighbor_flag[lc.var_num] && lc.var_num != v) { + neighbor_flag[lc.var_num] = 1; + vp->neighbor_var_nums.push_back(lc.var_num); + } + } + } + for (uint32_t j = 0; j < vp->neighbor_var_nums.size(); ++j) { + neighbor_flag[vp->neighbor_var_nums[j]] = 0; + } + } +} + +/****************local search**********************************/ +//bool *return value modified +bool ls_solver::local_search( + const vector *init_solution + , long long int _mems_limit +) { + bool result = false; + _random_gen.seed(_random_seed); + _best_found_cost = _num_clauses; + _conflict_ct.clear(); + _conflict_ct.resize(_num_vars+1,0); + + for (int t = 0; t < _max_tries; t++) { + initialize(init_solution); + if (0 == _unsat_clauses.size()) { + result = true; + break; + } + + for (_step = 0; _step < _max_steps; _step++) { + int flipv = pick_var(); + flip(flipv); + for(int var_idx:_unsat_vars) ++_conflict_ct[var_idx]; + if (_mems > _mems_limit) { + return result; + } + + + if ((int)_unsat_clauses.size() < _best_found_cost) { + _best_found_cost = _unsat_clauses.size(); + assert(_best_solution.size() == _solution.size()); + std::copy(_solution.begin(), _solution.end(), + _best_solution.begin()); + } + + if (_verbosity && + (_best_found_cost == 0 || (_step & 0x3ffff) == 0x3ffff) + ) { + cout << "c [ccnr] tries: " + << t << " steps: " << _step + << " best found: " << _best_found_cost + << endl; + } + + + if (_best_found_cost == 0) { + result = true; + break; + } + } + if (0 == _unsat_clauses.size()) { + result = true; + break; + } + } + _end_step = _step; + return result; +} + +/**********************************initialize*******************************/ +void ls_solver::clear_prev_data() +{ + _unsat_clauses.clear(); + _ccd_vars.clear(); + _unsat_vars.clear(); + for (int &item: _index_in_unsat_clauses) + item = 0; + for (int &item: _index_in_unsat_vars) + item = 0; +} + +void ls_solver::initialize(const vector *init_solution) +{ + clear_prev_data(); + if (!init_solution) { + //default random generation + for (int v = 1; v <= _num_vars; v++) { + _solution[v] = (_random_gen.next(2) == 0 ? 0 : 1); + } + } else { + if ((int)init_solution->size() != _num_vars+1) { + cout + << "ERROR: the init solution's size" + " is not equal to the number of variables." + << endl; + exit(-1); + } + for (int v = 1; v <= _num_vars; v++) { + _solution[v] = init_solution->at(v); + } + } + + //unsat_appears, will be updated when calling unsat_a_clause function. + for (int v = 1; v <= _num_vars; v++) { + _vars[v].unsat_appear = 0; + } + + //initialize data structure of clauses according to init solution + for (int c = 0; c < _num_clauses; c++) { + _clauses[c].sat_count = 0; + _clauses[c].sat_var = -1; + _clauses[c].weight = 1; + + for (lit l: _clauses[c].literals) { + if (_solution[l.var_num] == l.sense) { + _clauses[c].sat_count++; + _clauses[c].sat_var = l.var_num; + } + } + if (0 == _clauses[c].sat_count) { + unsat_a_clause(c); + } + } + _avg_clause_weight = 1; + _delta_total_clause_weight = 0; + initialize_variable_datas(); +} +void ls_solver::initialize_variable_datas() +{ + variable *vp; + //scores + for (int v = 1; v <= _num_vars; v++) { + vp = &(_vars[v]); + vp->score = 0; + for (lit l: vp->literals) { + int c = l.clause_num; + if (0 == _clauses[c].sat_count) { + vp->score += _clauses[c].weight; + } else if (1 == _clauses[c].sat_count && l.sense == _solution[l.var_num]) { + vp->score -= _clauses[c].weight; + } + } + } + //last flip step + for (int v = 1; v <= _num_vars; v++) { + _vars[v].last_flip_step = 0; + } + //cc datas + for (int v = 1; v <= _num_vars; v++) { + vp = &(_vars[v]); + vp->cc_value = 1; + if (vp->score > 0) //&&_vars[v].cc_value==1 + { + _ccd_vars.push_back(v); + vp->is_in_ccd_vars = 1; + } else { + vp->is_in_ccd_vars = 0; + } + } + //the virtual var 0 + vp = &(_vars[0]); + vp->score = 0; + vp->cc_value = 0; + vp->is_in_ccd_vars = 0; + vp->last_flip_step = 0; +} + + +/**********************pick variable*******************************************/ +int ls_solver::pick_var() +{ + //First, try to get the var with the highest score from _ccd_vars if any + //---------------------------------------- + int best_var = 0; + _mems += _ccd_vars.size()/8; + if (_ccd_vars.size() > 0) { + best_var = _ccd_vars[0]; + for (int v: _ccd_vars) { + if (_vars[v].score > _vars[best_var].score) { + best_var = v; + } else if (_vars[v].score == _vars[best_var].score && + _vars[v].last_flip_step < _vars[best_var].last_flip_step) { + best_var = v; + } + } + return best_var; + } + + //Aspriation Mode + //---------------------------------------- + if (_aspiration) { + _aspiration_score = _avg_clause_weight; + size_t i; + for (i = 0; i < _unsat_vars.size(); ++i) { + int v = _unsat_vars[i]; + if (_vars[v].score > _aspiration_score) { + best_var = v; + break; + } + } + for (++i; i < _unsat_vars.size(); ++i) { + int v = _unsat_vars[i]; + if (_vars[v].score > _vars[best_var].score) + best_var = v; + else if (_vars[v].score == _vars[best_var].score && + _vars[v].last_flip_step < _vars[best_var].last_flip_step) + best_var = v; + } + if (best_var != 0) + return best_var; + } + //=========================================c + + /**Diversification Mode**/ + update_clause_weights(); + + /*focused random walk*/ + int c = _unsat_clauses[_random_gen.next(_unsat_clauses.size())]; + clause *cp = &(_clauses[c]); + best_var = cp->literals[0].var_num; + for (size_t k = 1; k < cp->literals.size(); k++) { + int v = cp->literals[k].var_num; + if (_vars[v].score > _vars[best_var].score) { + best_var = v; + } else if (_vars[v].score == _vars[best_var].score && + _vars[v].last_flip_step < _vars[best_var].last_flip_step) { + best_var = v; + } + } + return best_var; +} + +/************************flip and update functions*****************************/ +void ls_solver::flip(int flipv) +{ + _solution[flipv] = 1 - _solution[flipv]; + int org_flipv_score = _vars[flipv].score; + _mems += _vars[flipv].literals.size(); + + // Go through each clause the literal is in and update status + for (lit l: _vars[flipv].literals) { + clause *cp = &(_clauses[l.clause_num]); + if (_solution[flipv] == l.sense) { + cp->sat_count++; + if (1 == cp->sat_count) { + sat_a_clause(l.clause_num); + cp->sat_var = flipv; + for (lit lc: cp->literals) { + _vars[lc.var_num].score -= cp->weight; + } + } else if (2 == cp->sat_count) { + _vars[cp->sat_var].score += cp->weight; + } + } else { + cp->sat_count--; + if (0 == cp->sat_count) { + unsat_a_clause(l.clause_num); + for (lit lc: cp->literals) { + _vars[lc.var_num].score += cp->weight; + } + } else if (1 == cp->sat_count) { + for (lit lc: cp->literals) { + if (_solution[lc.var_num] == lc.sense) { + _vars[lc.var_num].score -= cp->weight; + cp->sat_var = lc.var_num; + break; + } + } + } + } + } + _vars[flipv].score = -org_flipv_score; + _vars[flipv].last_flip_step = _step; + //update cc_values + update_cc_after_flip(flipv); +} +void ls_solver::update_cc_after_flip(int flipv) +{ + int last_item; + variable *vp = &(_vars[flipv]); + vp->cc_value = 0; + _mems += _ccd_vars.size()/4; + for (int index = _ccd_vars.size() - 1; index >= 0; index--) { + int v = _ccd_vars[index]; + if (_vars[v].score <= 0) { + last_item = _ccd_vars.back(); + _ccd_vars.pop_back(); + if (index < (int)_ccd_vars.size()) { + _ccd_vars[index] = last_item; + } + + _vars[v].is_in_ccd_vars = 0; + } + } + + //update all flipv's neighbor's cc to be 1 + _mems += vp->neighbor_var_nums.size()/4; + for (int v: vp->neighbor_var_nums) { + _vars[v].cc_value = 1; + if (_vars[v].score > 0 && !(_vars[v].is_in_ccd_vars)) { + _ccd_vars.push_back(v); + _vars[v].is_in_ccd_vars = 1; + } + } +} + +/*********************functions for basic operations***************************/ +void ls_solver::sat_a_clause(int the_clause) +{ + //use the position of the clause to store the last unsat clause in stack + int last_item = _unsat_clauses.back(); + _unsat_clauses.pop_back(); + int index = _index_in_unsat_clauses[the_clause]; + if (index < (int)_unsat_clauses.size()) { + _unsat_clauses[index] = last_item; + } + _index_in_unsat_clauses[last_item] = index; + //update unsat_appear and unsat_vars + for (lit l: _clauses[the_clause].literals) { + _vars[l.var_num].unsat_appear--; + if (0 == _vars[l.var_num].unsat_appear) { + last_item = _unsat_vars.back(); + _unsat_vars.pop_back(); + index = _index_in_unsat_vars[l.var_num]; + if (index < (int)_unsat_vars.size()) { + _unsat_vars[index] = last_item; + } + _index_in_unsat_vars[last_item] = index; + } + } +} +void ls_solver::unsat_a_clause(int the_clause) +{ + _index_in_unsat_clauses[the_clause] = _unsat_clauses.size(); + _unsat_clauses.push_back(the_clause); + //update unsat_appear and unsat_vars + for (lit l: _clauses[the_clause].literals) { + _vars[l.var_num].unsat_appear++; + if (1 == _vars[l.var_num].unsat_appear) { + _index_in_unsat_vars[l.var_num] = _unsat_vars.size(); + _unsat_vars.push_back(l.var_num); + } + } +} + +/************************clause weighting********************************/ +void ls_solver::update_clause_weights() +{ + for (int c: _unsat_clauses) { + _clauses[c].weight++; + } + for (int v: _unsat_vars) { + _vars[v].score += _vars[v].unsat_appear; + if (_vars[v].score > 0 && 1 == _vars[v].cc_value && !(_vars[v].is_in_ccd_vars)) { + _ccd_vars.push_back(v); + _vars[v].is_in_ccd_vars = 1; + } + } + _delta_total_clause_weight += _unsat_clauses.size(); + if (_delta_total_clause_weight >= _num_clauses) { + _avg_clause_weight += 1; + _delta_total_clause_weight -= _num_clauses; + if (_avg_clause_weight > _swt_threshold) { + smooth_clause_weights(); + } + } +} +void ls_solver::smooth_clause_weights() +{ + for (int v = 1; v <= _num_vars; v++) { + _vars[v].score = 0; + } + int scale_avg = _avg_clause_weight * _swt_q; + _avg_clause_weight = 0; + _delta_total_clause_weight = 0; + _mems += _num_clauses; + for (int c = 0; c < _num_clauses; ++c) { + clause *cp = &(_clauses[c]); + cp->weight = cp->weight * _swt_p + scale_avg; + if (cp->weight < 1) + cp->weight = 1; + _delta_total_clause_weight += cp->weight; + if (_delta_total_clause_weight >= _num_clauses) { + _avg_clause_weight += 1; + _delta_total_clause_weight -= _num_clauses; + } + if (0 == cp->sat_count) { + for (lit l: cp->literals) { + _vars[l.var_num].score += cp->weight; + } + } else if (1 == cp->sat_count) { + _vars[cp->sat_var].score -= cp->weight; + } + } + + //reset ccd_vars + _ccd_vars.clear(); + for (int v = 1; v <= _num_vars; v++) { + variable* vp = &(_vars[v]); + if (vp->score > 0 && 1 == vp->cc_value) { + _ccd_vars.push_back(v); + vp->is_in_ccd_vars = 1; + } else { + vp->is_in_ccd_vars = 0; + } + } +} + +/*****print solution*****************/ +void ls_solver::print_solution(bool need_verify) +{ + if (0 == get_cost()) + cout << "s SATISFIABLE" << endl; + else + cout << "s UNKNOWN" << endl; + + bool sat_flag = false; + cout << "c UP numbers: " << up_times << " times" << endl; + cout << "c flip numbers: " << flip_numbers << " times" << endl; + cout << "c UP avg flip number: " + << (double)(flip_numbers + 0.0) / up_times << " s" << endl; + if (need_verify) { + for (int c = 0; c < _num_clauses; c++) { + sat_flag = false; + for (lit l: _clauses[c].literals) { + if (_solution[l.var_num] == l.sense) { + sat_flag = true; + break; + } + } + if (!sat_flag) { + cout << "c Error: verify error in clause " << c << endl; + return; + } + } + cout << "c Verified." << endl; + } + if (verbosity > 0) { + cout << "v"; + for (int v = 1; v <= _num_vars; v++) { + cout << ' '; + if (_solution[v] == 0) + cout << '-'; + cout << v; + } + cout << endl; + } +} + +void ls_solver::set_verbosity(uint32_t verb) +{ + _verbosity = verb; +} diff --git a/cryptominisat/cppsrc/src/ccnr.h b/cryptominisat/cppsrc/src/ccnr.h new file mode 100644 index 00000000..54cb45e1 --- /dev/null +++ b/cryptominisat/cppsrc/src/ccnr.h @@ -0,0 +1,183 @@ +/****************************************** +Copyright (c) 2019, Shaowei Cai + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. +***********************************************/ + +#ifndef CCNR_H +#define CCNR_H + +#include +#include +#include +#include "ccnr_mersenne.h" + +using std::vector; + +namespace CCNR { + +//-------------------------- +//functions in basis.h & basis.cpp +struct lit { + unsigned char sense : 1; //is 1 for true literals, 0 for false literals. + int clause_num : 31; //clause num, begin with 0 + int var_num; //variable num, begin with 1 + lit(int the_lit, int the_clause) + { + var_num = abs(the_lit); + clause_num = the_clause; + sense = the_lit > 0 ? 1 : 0; + } + struct lit &operator^=(const struct lit &l) + { + sense ^= l.sense; + clause_num ^= l.clause_num; + var_num ^= l.var_num; + return *this; + } + void reset(void) + { + sense = 0; + clause_num = 0; + var_num = 0; + } + bool operator==(const struct lit &l) const + { + return sense == l.sense && clause_num == l.clause_num && var_num == l.var_num; + } + bool operator!=(const struct lit &l) const + { + return !(*this == l); + } +}; +struct variable { + vector literals; + vector neighbor_var_nums; + long long score; + long long last_flip_step; + int unsat_appear; //how many unsat clauses it appears in + bool cc_value; + bool is_in_ccd_vars; +}; +struct clause { + vector literals; + int sat_count; //no. of satisfied literals + int sat_var; + long long weight; +}; + +//--------------------------- +//functions in mersenne.h & mersenne.cpp + +class ls_solver +{ + public: + ls_solver(const bool aspiration); + bool parse_arguments(int argc, char **argv); + bool build_instance(std::string inst); + bool local_search( + const vector *init_solution = 0 + , long long int _mems_limit = 100*1000*1000 + ); + void print_solution(bool need_verify = 0); + void simple_print(); + int get_best_cost() + { + return _best_found_cost; + } + void set_verbosity(uint32_t verb); + + //formula + vector _vars; + vector _clauses; + int _num_vars; + int _num_clauses; + + //data structure used + vector _conflict_ct; + vector _unsat_clauses; // list of unsatisfied clauses + vector _index_in_unsat_clauses; // _index_in_unsat_clauses[var] tells where "var" is in _unsat_vars + vector _unsat_vars; // clauses are UNSAT due to these vars + vector _index_in_unsat_vars; + vector _ccd_vars; + + //solution information + vector _solution; + vector _best_solution; + + //functions for buiding data structure + bool make_space(); + void build_neighborhood(); + int get_cost() { return _unsat_clauses.size(); } + + private: + int _best_found_cost; + long long _mems = 0; + long long _step; + long long _max_steps; + int _max_tries; + int _time_limit; + + //aiding data structure + Mersenne _random_gen; //random generator + int _random_seed; + + /////////////////////////// + //algorithmic parameters + /////////////////////////// + int _aspiration_score; + + //clause weighting + int _swt_threshold; + float _swt_p; //w=w*p+ave_w*q + float _swt_q; + int _avg_clause_weight; + //------------------- + bool _aspiration; + float _up_ratio; //control how much variables need to be delete and assigned by up + + //================= + long long _delta_total_clause_weight; + + //main functions + void initialize(const vector *init_solution = 0); + void initialize_variable_datas(); + void clear_prev_data(); + int pick_var(); + void flip(int flipv); + void update_cc_after_flip(int flipv); + void update_clause_weights(); + void smooth_clause_weights(); + + //funcitons for basic operations + void sat_a_clause(int the_clause); + void unsat_a_clause(int the_clause); + + //-------------------- + long long _end_step; + uint32_t _verbosity = 0; + + long long up_times = 0; + long long flip_numbers = 0; + int verbosity; // 0 print sat/unsat & infomation; 1 print everything; +}; + +} // namespace CCNR + +#endif diff --git a/cryptominisat/cppsrc/src/ccnr_cms.cpp b/cryptominisat/cppsrc/src/ccnr_cms.cpp new file mode 100644 index 00000000..1e1484be --- /dev/null +++ b/cryptominisat/cppsrc/src/ccnr_cms.cpp @@ -0,0 +1,369 @@ +/****************************************** +Copyright (C) 2009-2020 Authors of CryptoMiniSat, see AUTHORS file + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. +***********************************************/ + +#include "time_mem.h" +#include +#include +#include +#include +#include "constants.h" +#include "ccnr_cms.h" +#include "solver.h" +#include "ccnr.h" +#include "sqlstats.h" +//#define SLOW_DEBUG + +using namespace CMSat; + +CMS_ccnr::CMS_ccnr(Solver* _solver) : + solver(_solver), + seen(_solver->seen), + toClear(_solver->toClear) +{ + ls_s = new CCNR::ls_solver(solver->conf.sls_ccnr_asipire); + ls_s->set_verbosity(solver->conf.verbosity); +} + +CMS_ccnr::~CMS_ccnr() +{ + delete ls_s; +} + +lbool CMS_ccnr::main(const uint32_t num_sls_called) +{ + //It might not work well with few number of variables + //rnovelty could also die/exit(-1), etc. + if (solver->nVars() < 50 || + solver->binTri.irredBins + solver->longIrredCls.size() < 10 + ) { + verb_print(1, "[ccnr] too few variables & clauses"); + return l_Undef; + } + double startTime = cpuTime(); + + if (!init_problem()) { + //it's actually l_False under assumptions + //but we'll set the real SAT solver deal with that + if (solver->conf.verbosity) { + cout << "c [ccnr] problem UNSAT under assumptions, returning to main solver" + << endl; + } + return l_Undef; + } + + vector phases(solver->nVars()+1); + for(uint32_t i = 0; i < solver->nVars(); i++) { + phases[i+1] = solver->varData[i].best_polarity; + } + + int res = ls_s->local_search(&phases, solver->conf.yalsat_max_mems*2*1000*1000); + lbool ret = deal_with_solution(res, num_sls_called); + + double time_used = cpuTime()-startTime; + if (solver->conf.verbosity) { + cout << "c [ccnr] time: " << time_used << endl; + } + if (solver->sqlStats) { + solver->sqlStats->time_passed_min( + solver + , "sls-ccnr" + , time_used + ); + } + + return ret; +} + +template +CMS_ccnr::add_cl_ret CMS_ccnr::add_this_clause(const T& cl) +{ + uint32_t sz = 0; + bool sat = false; + yals_lits.clear(); + for(size_t i3 = 0; i3 < cl.size(); i3++) { + Lit lit = cl[i3]; + assert(solver->varData[lit.var()].removed == Removed::none); + lbool val = l_Undef; + if (solver->value(lit) != l_Undef) { + val = solver->value(lit); + } else { + val = solver->lit_inside_assumptions(lit); + } + + if (val == l_True) { + //clause is SAT, skip! + sat = true; + continue; + } else if (val == l_False) { + continue; + } + int l = lit.var()+1; + l *= lit.sign() ? -1 : 1; + yals_lits.push_back(l); + sz++; + } + if (sat) { + return add_cl_ret::skipped_cl; + } + if (sz == 0) { + //it's unsat because of assumptions + if (solver->conf.verbosity) { + cout << "c [walksat] UNSAT because of assumptions in clause: " << cl << endl; + } + return add_cl_ret::unsat; + } + + for(auto& lit: yals_lits) { + ls_s->_clauses[cl_num].literals.push_back(CCNR::lit(lit, cl_num)); + } + cl_num++; + + return add_cl_ret::added_cl; +} + +bool CMS_ccnr::init_problem() +{ + if (solver->check_assumptions_contradict_foced_assignment()) + { + return false; + } + #ifdef SLOWDEBUG + solver->check_stats(); + #endif + + ls_s->_num_vars = solver->nVars(); + ls_s->_num_clauses = solver->longIrredCls.size() + solver->binTri.irredBins; + ls_s->make_space(); + + vector this_clause; + for(size_t i2 = 0; i2 < solver->nVars()*2; i2++) { + Lit lit = Lit::toLit(i2); + for(const Watched& w: solver->watches[lit]) { + if (w.isBin() && !w.red() && lit < w.lit2()) { + this_clause.clear(); + this_clause.push_back(lit); + this_clause.push_back(w.lit2()); + + if (add_this_clause(this_clause) == add_cl_ret::unsat) { + return false; + } + } + } + } + for(ClOffset offs: solver->longIrredCls) { + const Clause* cl = solver->cl_alloc.ptr(offs); + assert(!cl->freed()); + assert(!cl->getRemoved()); + + if (add_this_clause(*cl) == add_cl_ret::unsat) { + return false; + } + } + + //Shrink the space if we have to + assert(ls_s->_num_clauses >= (int)cl_num); + ls_s->_num_clauses = (int)cl_num; + ls_s->make_space(); + + for (int c=0; c < ls_s->_num_clauses; c++) { + for(CCNR::lit item: ls_s->_clauses[c].literals) { + int v = item.var_num; + ls_s->_vars[v].literals.push_back(item); + } + } + ls_s->build_neighborhood(); + + return true; +} + +struct ClWeightSorter +{ + bool operator()(const CCNR::clause& a, const CCNR::clause& b) + { + return a.weight > b.weight; + } +}; + +struct VarAndVal { + VarAndVal(uint32_t _var, long long _score) : + var(_var), + val(_score) + { + } + uint32_t var; + long long val; +}; + +struct VarValSorter +{ + bool operator()(const VarAndVal& a, const VarAndVal& b) { + return a.val > b.val; + } +}; + +vector> CMS_ccnr::get_bump_based_on_cls() +{ + verb_print(1,"[ccnr] bumping based on clause weights"); + + //Check prerequisites + assert(toClear.empty()); + SLOW_DEBUG_DO(for(const auto x: seen) assert(x == 0)); + + vector> tobump_cl_var; + std::sort(ls_s->_clauses.begin(), ls_s->_clauses.end(), ClWeightSorter()); + uint32_t vars_bumped = 0; + uint32_t individual_vars_bumped = 0; + for(const auto& c: ls_s->_clauses) { + if (vars_bumped > solver->conf.sls_how_many_to_bump) + break; + + for(uint32_t i = 0; i < c.literals.size(); i++) { + uint32_t v = c.literals[i].var_num-1; + if (v < solver->nVars() && + solver->varData[v].removed == Removed::none && + solver->value(v) == l_Undef && + seen[v] < solver->conf.sls_bump_var_max_n_times) + { + if (seen[v] == 0) individual_vars_bumped++; + seen[v]++; + toClear.push_back(Lit(v, false)); + tobump_cl_var.push_back(std::make_pair(v, 3.0)); + vars_bumped++; + } + } + } + + for(const auto x: toClear) seen[x.var()] = 0; + toClear.clear(); + + return tobump_cl_var; +} + +vector> CMS_ccnr::get_bump_based_on_var_scores() +{ + vector vs; + for(uint32_t i = 1; i < ls_s->_vars.size(); i++) { + vs.push_back(VarAndVal(i-1, ls_s->_vars[i].score)); + } + std::sort(vs.begin(), vs.end(), VarValSorter()); + + vector> tobump; + for(uint32_t i = 0; i < solver->conf.sls_how_many_to_bump; i++) { +// cout << "var: " << vs[i].var + 1 << " score: " << vs[i].val << endl; + tobump.push_back(std::make_pair(vs[i].var, 3.0)); + } + return tobump; +} + +vector> CMS_ccnr::get_bump_based_on_conflict_ct() +{ + if (solver->conf.verbosity) { + cout << "c [ccnr] bumping based on var unsat frequency: conflict_ct" << endl; + } + + vector> tobump; + int mymax = 0; + for(uint32_t i = 1; i < ls_s->_conflict_ct.size(); i++) { + mymax = std::max(mymax, ls_s->_conflict_ct[i]); + } + + for(uint32_t i = 1; i < ls_s->_conflict_ct.size(); i++) { + double val = ls_s->_conflict_ct[i]; + if (mymax > 0) { + tobump.push_back(std::make_pair(i-1, (double)val/(double)mymax * 3.0)); + } else { + tobump.push_back(std::make_pair(i-1, 0)); + } +// if (tobump.back().second > 0) { +// cout << "var: " << tobump.back().first << " bump by: " << tobump.back().second << endl; +// } + } + return tobump; +} + +lbool CMS_ccnr::deal_with_solution(int res, const uint32_t num_sls_called) +{ + if (solver->conf.sls_get_phase || res) { + if (solver->conf.verbosity) { + cout + << "c [ccnr] saving best assignment phase to stable_polar"; + if (res) cout << " + best_polar"; + cout << endl; + } + + for(size_t i = 0; i < solver->nVars(); i++) { + solver->varData[i].stable_polarity = ls_s->_best_solution[i+1]; + if (res) { + solver->varData[i].best_polarity = ls_s->_best_solution[i+1]; + } + } + } + + //Clause score sorting + vector> tobump; + switch (solver->conf.sls_bump_type) { + case 1: + tobump = get_bump_based_on_cls(); + break; + case 2: + assert(false && "Does not work, removed"); + break; + case 3: + tobump = get_bump_based_on_var_scores(); + break; + case 4: + tobump = get_bump_based_on_conflict_ct(); + break; + case 5: + if (num_sls_called % 3 == 0) { + tobump = get_bump_based_on_conflict_ct(); + } else { + tobump = get_bump_based_on_cls(); + } + break; + case 6: + if (num_sls_called % 3 == 0) { + tobump = get_bump_based_on_cls(); + } else { + tobump = get_bump_based_on_conflict_ct(); + } + break; + default: + assert(false && "No such SLS bump type"); + exit(-1); + } + + + for(const auto& v: tobump) solver->bump_var_importance_all(v.first); + if (solver->branch_strategy == branch::vsids) { + solver->vsids_decay_var_act(); + } + + + verb_print(1, "[ccnr] Bumped vars: " << tobump.size() + << " bump type: " << solver->conf.sls_bump_type); + + if (!res) verb_print(2, "[ccnr] ASSIGNMENT NOT FOUND"); + else verb_print(1, "[ccnr] ASSIGNMENT FOUND"); + + return l_Undef; +} diff --git a/cryptominisat/cppsrc/src/ccnr_cms.h b/cryptominisat/cppsrc/src/ccnr_cms.h new file mode 100644 index 00000000..c9db692a --- /dev/null +++ b/cryptominisat/cppsrc/src/ccnr_cms.h @@ -0,0 +1,81 @@ +/****************************************** +Copyright (C) 2009-2020 Authors of CryptoMiniSat, see AUTHORS file + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. +***********************************************/ + +#ifndef CMS_ccnr_H +#define CMS_ccnr_H + +#include +#include +#include +#include "solvertypes.h" + +namespace CCNR { + class ls_solver; +} + +namespace CMSat { + +class Solver; +using std::pair; +using std::make_pair; + +class CMS_ccnr { +public: + lbool main(const uint32_t num_sls_called); + CMS_ccnr(Solver* _solver); + ~CMS_ccnr(); + +private: + Solver* solver; + + /************************************/ + /* Main */ + /************************************/ + void flipvar(uint32_t toflip); + + /************************************/ + /* Initialization */ + /************************************/ + void parse_parameters(); + void init_for_round(); + bool init_problem(); + lbool deal_with_solution(int res, const uint32_t num_sls_called); + CCNR::ls_solver* ls_s = NULL; + uint32_t cl_num = 0; + + enum class add_cl_ret {added_cl, skipped_cl, unsat}; + template + add_cl_ret add_this_clause(const T& cl); + vector yals_lits; + vector& seen; + vector& toClear; + + //Bumping of variable scores + vector> get_bump_based_on_cls(); + vector> get_bump_based_on_var_scores(); + vector> get_bump_based_on_var_flips(); + vector> get_bump_based_on_conflict_ct(); +}; + +} + +#endif //CMS_WALKSAT_H diff --git a/cryptominisat/cppsrc/src/ccnr_mersenne.h b/cryptominisat/cppsrc/src/ccnr_mersenne.h new file mode 100644 index 00000000..c3dca9fa --- /dev/null +++ b/cryptominisat/cppsrc/src/ccnr_mersenne.h @@ -0,0 +1,190 @@ +/****************************************** +Copyright (c) 2019, Shaowei Cai + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. +***********************************************/ + +#ifndef CCNR_MERSENNE_H +#define CCNR_MERSENNE_H + +namespace CCNR { + +class Mersenne +{ + static const int N = 624; + unsigned int mt[N]; + int mti; + const int M = 397; + const unsigned int MATRIX_A = 0x9908b0dfUL; + const unsigned int UPPER_MASK = 0x80000000UL; + const unsigned int LOWER_MASK = 0x7fffffffUL; + + public: + Mersenne(); // seed with time-dependent value + Mersenne(int seed); // seed with int value; see comments for the seed() method + Mersenne(unsigned int *array, int count); // seed with array + Mersenne(const Mersenne ©); + Mersenne &operator=(const Mersenne ©); + void seed(int s); + void seed(unsigned int *array, int len); + unsigned int next32(); // generates random integer in [0..2^32-1] + int next31(); // generates random integer in [0..2^31-1] + double nextClosed(); // generates random float in [0..1], 2^53 possible values + double nextHalfOpen(); // generates random float in [0..1), 2^53 possible values + double nextOpen(); // generates random float in (0..1), 2^53 possible values + int next(int bound); // generates random integer in [0..bound), bound < 2^31 +}; + +//--------------------------- +//functions in mersenne.h & mersenne.cpp + +/* + Notes on seeding + + 1. Seeding with an integer + To avoid different seeds mapping to the same sequence, follow one of + the following two conventions: + a) Only use seeds in 0..2^31-1 (preferred) + b) Only use seeds in -2^30..2^30-1 (2-complement machines only) + + 2. Seeding with an array (die-hard seed method) + The length of the array, len, can be arbitrarily high, but for lengths greater + than N, collisions are common. If the seed is of high quality, using more than + N values does not make sense. +*/ +inline Mersenne::Mersenne() +{ + seed(0); +} +inline Mersenne::Mersenne(int s) +{ + seed(s); +} +inline Mersenne::Mersenne(unsigned int *init_key, int key_length) +{ + seed(init_key, key_length); +} +inline Mersenne::Mersenne(const Mersenne ©) +{ + *this = copy; +} +inline Mersenne &Mersenne::operator=(const Mersenne ©) +{ + for (int i = 0; i < N; i++) + mt[i] = copy.mt[i]; + mti = copy.mti; + return *this; +} +inline void Mersenne::seed(int se) +{ + unsigned int s = ((unsigned int)(se << 1)) + 1; + // Seeds should not be zero. Other possible solutions (such as s |= 1) + // lead to more confusion, because often-used low seeds like 2 and 3 would + // be identical. This leads to collisions only for rarely used seeds (see + // note in header file). + mt[0] = s & 0xffffffffUL; + for (mti = 1; mti < N; mti++) { + mt[mti] = (1812433253UL * (mt[mti - 1] ^ (mt[mti - 1] >> 30)) + mti); + mt[mti] &= 0xffffffffUL; + } +} +inline void Mersenne::seed(unsigned int *init_key, int key_length) +{ + int i = 1, j = 0, k = (N > key_length ? N : key_length); + seed(19650218UL); + for (; k; k--) { + mt[i] = (mt[i] ^ ((mt[i - 1] ^ (mt[i - 1] >> 30)) * 1664525UL)) + init_key[j] + j; + mt[i] &= 0xffffffffUL; + i++; + j++; + if (i >= N) { + mt[0] = mt[N - 1]; + i = 1; + } + if (j >= key_length) + j = 0; + } + for (k = N - 1; k; k--) { + mt[i] = (mt[i] ^ ((mt[i - 1] ^ (mt[i - 1] >> 30)) * 1566083941UL)) - i; + mt[i] &= 0xffffffffUL; + i++; + if (i >= N) { + mt[0] = mt[N - 1]; + i = 1; + } + } + mt[0] = 0x80000000UL; +} +inline unsigned int Mersenne::next32() +{ + unsigned int y; + static unsigned int mag01[2] = {0x0UL, MATRIX_A}; + if (mti >= N) { + int kk; + for (kk = 0; kk < N - M; kk++) { + y = (mt[kk] & UPPER_MASK) | (mt[kk + 1] & LOWER_MASK); + mt[kk] = mt[kk + M] ^ (y >> 1) ^ mag01[y & 0x1UL]; + } + for (; kk < N - 1; kk++) { + y = (mt[kk] & UPPER_MASK) | (mt[kk + 1] & LOWER_MASK); + mt[kk] = mt[kk + (M - N)] ^ (y >> 1) ^ mag01[y & 0x1UL]; + } + y = (mt[N - 1] & UPPER_MASK) | (mt[0] & LOWER_MASK); + mt[N - 1] = mt[M - 1] ^ (y >> 1) ^ mag01[y & 0x1UL]; + mti = 0; + } + y = mt[mti++]; + y ^= (y >> 11); + y ^= (y << 7) & 0x9d2c5680UL; + y ^= (y << 15) & 0xefc60000UL; + y ^= (y >> 18); + return y; +} +inline int Mersenne::next31() +{ + return (int)(next32() >> 1); +} +inline double Mersenne::nextClosed() +{ + unsigned int a = next32() >> 5, b = next32() >> 6; + return (a * 67108864.0 + b) * (1.0 / 9007199254740991.0); +} +inline double Mersenne::nextHalfOpen() +{ + unsigned int a = next32() >> 5, b = next32() >> 6; + return (a * 67108864.0 + b) * (1.0 / 9007199254740992.0); +} +inline double Mersenne::nextOpen() +{ + unsigned int a = next32() >> 5, b = next32() >> 6; + return (0.5 + a * 67108864.0 + b) * (1.0 / 9007199254740991.0); +} +inline int Mersenne::next(int bound) +{ + unsigned int value; + do { + value = next31(); + } while (value + (unsigned int)bound >= 0x80000000UL); + // Just using modulo doesn't lead to uniform distribution. This does. + return (int)(value % bound); +} + +} + +#endif diff --git a/cryptominisat/cppsrc/src/cl_predictors_abs.cpp b/cryptominisat/cppsrc/src/cl_predictors_abs.cpp new file mode 100644 index 00000000..1c43d02a --- /dev/null +++ b/cryptominisat/cppsrc/src/cl_predictors_abs.cpp @@ -0,0 +1,209 @@ +/****************************************** +Copyright (C) 2009-2020 Authors of CryptoMiniSat, see AUTHORS file + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. +***********************************************/ + +#include "cl_predictors_abs.h" +#include "solver.h" + +using namespace CMSat; + +extern const char* predictor_short_json_hash; +extern const char* predictor_long_json_hash; +extern const char* predictor_forever_json_hash; + +vector ClPredictorsAbst::get_hashes() const +{ + vector ret; + ret.push_back(string(predictor_short_json_hash)); + ret.push_back(string(predictor_long_json_hash)); + ret.push_back(string(predictor_forever_json_hash)); + + return ret; +} + +int ClPredictorsAbst::set_up_input( + const CMSat::Clause* const cl, + const uint64_t sumConflicts, + const double act_ranking_rel, + const double uip1_ranking_rel, + const double prop_ranking_rel, + const double sum_uip1_per_time_ranking, + const double sum_props_per_time_ranking, + const double sum_uip1_per_time_ranking_rel, + const double sum_props_per_time_ranking_rel, + const ReduceCommonData& commdata, + const Solver* solver, + float* at) +{ + //glue 0 can happen in case it's a ternary resolvent clause + //updated glue can actually be 1. Original glue cannot. + const ClauseStatsExtra& extra_stats = solver->red_stats_extra[cl->stats.extra_pos]; + assert(extra_stats.orig_glue != 1); + + assert(cl->stats.last_touched_any <= sumConflicts); + assert(extra_stats.introduced_at_conflict <= sumConflicts); + uint32_t last_touched_any_diff = sumConflicts - (uint64_t)cl->stats.last_touched_any; + double time_inside_solver = sumConflicts - (uint64_t)extra_stats.introduced_at_conflict; + + //To protect against unset values being used + assert(cl->stats.is_ternary_resolvent || + extra_stats.glueHist_longterm_avg > 0.9f); + + uint32_t x = 0; + /////////////// + at[x++] = sum_uip1_per_time_ranking_rel; +// rdb0.sum_uip1_per_time_ranking_rel +// 2 + at[x++] = sum_props_per_time_ranking_rel; +// rdb0.sum_props_per_time_ranking_rel +// 3 + at[x++] = act_ranking_rel; +// rdb0.act_ranking_rel +// 4 + at[x++] = uip1_ranking_rel; +// rdb0.uip1_ranking_rel +// 5 + at[x++] = prop_ranking_rel; +// rdb0.prop_ranking_rel +// 6 + + /////////////// + at[x++] = cl->stats.props_made; +// rdb0.props_made +// 10 + at[x++] = cl->stats.uip1_used; +// rdb0.uip1_used +// 11 + at[x++] = extra_stats.discounted_props_made; +// rdb0.discounted_props_made +// 12 + at[x++] = extra_stats.discounted_props_made2; +// rdb0.discounted_props_made2 +// 13 + at[x++] = extra_stats.discounted_props_made3; +// rdb0.discounted_props_made3 +// 14 + at[x++] = extra_stats.discounted_uip1_used; +// rdb0.discounted_uip1_used +// 15 + at[x++] = extra_stats.discounted_uip1_used2; +// rdb0.discounted_uip1_used2 +// 16 + at[x++] = extra_stats.discounted_uip1_used3; +// rdb0.discounted_uip1_used3 +// 17 + + ////////////////// + if (cl->stats.is_ternary_resolvent || + extra_stats.glueHist_longterm_avg == 0 //glueHist_longterm_avg does not exist for ternary + ) { + at[x++] = missing_val; + } else { + at[x++] = (double)extra_stats.glue_before_minim/(double)extra_stats.glueHist_longterm_avg; + } + //(cl.glue_before_minim/cl.glueHist_longterm_avg) +// 32 + + + if (commdata.avg_uip == 0 + ) { + at[x++] = missing_val; + } else { + at[x++] = (double)cl->stats.uip1_used/(double)commdata.avg_uip; + } + //(rdb0.uip1_used/rdb0_common.avg_uip1_used) +// 33 + + + if (cl->stats.is_ternary_resolvent || + solver->hist.glueHistLT.avg() == 0 + ) { + at[x++] = missing_val; + } else { + at[x++] = (double)cl->stats.glue/(double)solver->hist.glueHistLT.avg(); + } + //(rdb0.glue/rdb0_common.glueHistLT_avg) +// 34 + + + if (commdata.avg_props == 0) { + at[x++] = missing_val; + } else { + at[x++] = (double)cl->stats.props_made/(double)commdata.avg_props; + } + //(rdb0.props_made/rdb0_common.avg_props) +// 35 + + + if (time_inside_solver == 0) { + at[x++] = missing_val; + } else { + at[x++] = (double)extra_stats.sum_props_made/(double)time_inside_solver; + } + //(rdb0.sum_props_made/cl.time_inside_solver) +// 36 + + + if (time_inside_solver == 0) { + at[x++] = missing_val; + } else { + at[x++] = (double)extra_stats.sum_uip1_used/(double)time_inside_solver; + } + //(rdb0.sum_uip1_used/cl.time_inside_solver) +// 37 + + + if (cl->stats.is_ternary_resolvent || + extra_stats.num_total_lits_antecedents == 0 + ) { + at[x++] = missing_val; + } else { + at[x++] = (double)extra_stats.num_antecedents/(double)extra_stats.num_total_lits_antecedents; + } + //(cl.num_antecedents/cl.num_total_lits_antecedents) +// 38 + + + ////////////////// + if (cl->stats.is_ternary_resolvent || + extra_stats.trail_depth_level == 0 + ) { + at[x++] = missing_val; + } else { + at[x++] = (double)cl->stats.glue/(double)extra_stats.trail_depth_level; + } + //(rdb0.glue/cl.trail_depth_level) +// 42 + + + if (cl->stats.is_ternary_resolvent + ) { + at[x++] = missing_val; + } else { + at[x++] = (double)extra_stats.orig_glue; + } + //cl.orig_glue +// 43 + + + assert(x==PRED_COLS); + return PRED_COLS; +} diff --git a/cryptominisat/cppsrc/src/cl_predictors_abs.h b/cryptominisat/cppsrc/src/cl_predictors_abs.h new file mode 100644 index 00000000..cb8f49fc --- /dev/null +++ b/cryptominisat/cppsrc/src/cl_predictors_abs.h @@ -0,0 +1,119 @@ +/****************************************** +Copyright (C) 2009-2020 Authors of CryptoMiniSat, see AUTHORS file + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. +***********************************************/ + +#ifndef _CLPREDICTORS_ABST_H__ +#define _CLPREDICTORS_ABST_H__ + +#include +#include +#include +#include +#include +#include +#include "clause.h" + +#define PRED_COLS 22 + +using std::vector; + +namespace CMSat { + +enum predict_type {short_pred=0, long_pred=1, forever_pred=2}; + +class Clause; +class Solver; + +struct ReduceCommonData +{ + double safe_div(double a, double b) { + if (b == 0) { + assert(a == 0); + return 0; + } + return a/b; + } + + double avg_props; + //double avg_glue; CANNOT COUNT, ternary has no glue! + double avg_uip; + double avg_sum_uip1_used; + MedianCommonDataRDB median_data; + uint32_t all_learnt_size; + + ReduceCommonData() {} + ReduceCommonData( + uint32_t total_props, +// uint32_t total_glue, + uint32_t total_uip1_used, + uint32_t total_sum_uip1_used, + uint32_t size, + const MedianCommonDataRDB& _median_data) : + median_data(_median_data) + { + all_learnt_size = size; + avg_props = safe_div(total_props, size); + //avg_glue = safe_div(total_glue, size); + avg_uip = safe_div(total_uip1_used, size); + avg_sum_uip1_used = safe_div(total_sum_uip1_used, size); + } +}; + +class ClPredictorsAbst +{ +public: + ClPredictorsAbst() {missing_val = nanf("");} + virtual ~ClPredictorsAbst() {} + virtual int load_models(const std::string& short_fname, + const std::string& long_fname, + const std::string& forever_fname, + const std::string& best_feats_fname) = 0; + virtual int load_models_from_buffers() = 0; + vector get_hashes() const; + + virtual void predict_all( + float* const data, + const uint32_t num) = 0; + + virtual int get_step_size() {return PRED_COLS;} + + virtual int set_up_input( + const CMSat::Clause* const cl, + const uint64_t sumConflicts, + const double act_ranking_rel, + const double uip1_ranking_rel, + const double prop_ranking_rel, + const double sum_uip1_per_time_ranking, + const double sum_props_per_time_ranking, + const double sum_uip1_per_time_ranking_rel, + const double sum_props_per_time_ranking_rel, + const ReduceCommonData& commdata, + const Solver* solver, + float* at); + + virtual void get_prediction_at(ClauseStatsExtra& extdata, const uint32_t at) = 0; + virtual void finish_all_predict() = 0; + float missing_val; +}; + +} + +#endif diff --git a/cryptominisat/cppsrc/src/cl_predictors_lgbm.cpp b/cryptominisat/cppsrc/src/cl_predictors_lgbm.cpp new file mode 100644 index 00000000..951550a0 --- /dev/null +++ b/cryptominisat/cppsrc/src/cl_predictors_lgbm.cpp @@ -0,0 +1,156 @@ +/****************************************** +Copyright (C) 2009-2020 Authors of CryptoMiniSat, see AUTHORS file + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. +***********************************************/ + +#include "cl_predictors_lgbm.h" +#include "clause.h" +#include "solver.h" +#include +extern char predictor_short_json[]; +extern unsigned int predictor_short_json_len; + +extern char predictor_long_json[]; +extern unsigned int predictor_long_json_len; + +extern char predictor_forever_json[]; +extern unsigned int predictor_forever_json_len; + +using namespace CMSat; + +ClPredictorsLGBM::ClPredictorsLGBM() +{ +// safe_xgboost(XGBoosterCreate(0, 0, &(handles[predict_type::short_pred]))) +// safe_xgboost(XGBoosterCreate(0, 0, &(handles[predict_type::long_pred]))) +// safe_xgboost(XGBoosterCreate(0, 0, &(handles[predict_type::forever_pred]))) +// +// for(int i = 0; i < 3; i++) { +// safe_xgboost(XGBoosterSetParam(handles[i], "nthread", "1")) +// //safe_xgboost(XGBoosterSetParam(handles[i], "verbosity", "3")) +// } +} + +ClPredictorsLGBM::~ClPredictorsLGBM() +{ + for(uint32_t i = 0; i < 3; i++) { + LGBM_BoosterFree(handle[i]); + } +} + +int ClPredictorsLGBM::load_models(const std::string& short_fname, + const std::string& long_fname, + const std::string& forever_fname, + const std::string& best_feats_fname) +{ + int ret; + + ret = LGBM_BoosterCreateFromModelfile(short_fname.c_str(), &num_iterations[0], &handle[0]); + assert(ret == 0); + + ret = LGBM_BoosterCreateFromModelfile(long_fname.c_str(), &num_iterations[1], &handle[1]); + assert(ret == 0); + + ret = LGBM_BoosterCreateFromModelfile(forever_fname.c_str(), &num_iterations[2], &handle[2]); + assert(ret == 0); + return 1; +} + +int ClPredictorsLGBM::load_models_from_buffers() +{ + assert(false); + exit(-1); +// safe_xgboost(XGBoosterLoadModelFromBuffer( +// handles[predict_type::short_pred], predictor_short_json, predictor_short_json_len)); +// safe_xgboost(XGBoosterLoadModelFromBuffer( +// handles[predict_type::long_pred], predictor_long_json, predictor_long_json_len)); +// safe_xgboost(XGBoosterLoadModelFromBuffer( +// handles[predict_type::forever_pred], predictor_forever_json, predictor_forever_json_len)) + return 1; +} + +void ClPredictorsLGBM::predict_all( + float* const data, + const uint32_t num) +{ + for(uint32_t i = 0; i < 3; i ++) { + out_result[i].resize(num); + int64_t out_len; + + auto ret = LGBM_BoosterPredictForMat( + handle[i], + data, + C_API_DTYPE_FLOAT32, //type of "data" + num, //num rows + PRED_COLS, //num features + 1, //row major + C_API_PREDICT_NORMAL, // what should be predicted: normal, raw score, etc. + 0, //start iteration + -1, + "n_jobs=1", //other parameters for prediction (const char*) + &out_len, //length of output + out_result[i].data()); + assert(ret == 0); + assert(out_len == num); + } +} + +/*void ClPredictorsLGBM::predict_all( + float* data, + uint32_t num) +{ + for(uint32_t i = 0; i < 3; i ++) { + out_result[i].resize(num); + double* out = out_result[i].data(); + int64_t out_len; + + for(uint32_t x = 0; x < num; x++) { + auto ret = LGBM_BoosterPredictForMatSingleRow( + handle[i], + data, + C_API_DTYPE_FLOAT32, //type of "data" + PRED_COLS, //num features + 1, //row major + C_API_PREDICT_NORMAL, // what should be predicted: normal, raw score, etc. + 0, //start iteration + -1, + "n_jobs=1", //other parameters for prediction (const char*) + &out_len, //length of output + out + ); + assert(ret == 0); + assert(out_len == 1); + data += PRED_COLS; + out ++; + + } + } +}*/ + +void ClPredictorsLGBM::get_prediction_at(ClauseStatsExtra& extdata, const uint32_t at) +{ + extdata.pred_short_use = out_result[0][at]; + extdata.pred_long_use = out_result[1][at]; + extdata.pred_forever_use = out_result[2][at]; +} + +void CMSat::ClPredictorsLGBM::finish_all_predict() +{ + //safe_xgboost(XGDMatrixFree(dmat)) +} diff --git a/cryptominisat/cppsrc/src/cl_predictors_lgbm.h b/cryptominisat/cppsrc/src/cl_predictors_lgbm.h new file mode 100644 index 00000000..80675c96 --- /dev/null +++ b/cryptominisat/cppsrc/src/cl_predictors_lgbm.h @@ -0,0 +1,79 @@ +/****************************************** +Copyright (C) 2009-2020 Authors of CryptoMiniSat, see AUTHORS file + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. +***********************************************/ + +#ifndef _CLPREDICTORS_LGBM_H__ +#define _CLPREDICTORS_LGBM_H__ + +#include +#include +#include +//#include +#include +#include "clause.h" +#include "cl_predictors_abs.h" + +using std::vector; + +namespace CMSat { + +class Clause; +class Solver; + +class ClPredictorsLGBM : public ClPredictorsAbst +{ +public: + ClPredictorsLGBM(); + virtual ~ClPredictorsLGBM(); + virtual int load_models(const std::string& short_fname, + const std::string& long_fname, + const std::string& forever_fname, + const std::string& best_feats_fname) override; + virtual int load_models_from_buffers() override; + + float predict( + predict_type pred_type, + const CMSat::Clause* cl, + const uint64_t sumConflicts, + const double act_ranking_rel, + const double uip1_ranking_rel, + const double prop_ranking_rel, + const ReduceCommonData& commdata + ); + + virtual void predict_all( + float* const data, + const uint32_t num) override; + + virtual void get_prediction_at(ClauseStatsExtra& extdata, const uint32_t at) override; + virtual void finish_all_predict() override; + +private: + BoosterHandle handle[3]; + int num_iterations[3]; + DMatrixHandle dmat; + + vector out_result[3]; +}; + +} + +#endif diff --git a/cryptominisat/cppsrc/src/cl_predictors_py.cpp b/cryptominisat/cppsrc/src/cl_predictors_py.cpp new file mode 100644 index 00000000..55119b3e --- /dev/null +++ b/cryptominisat/cppsrc/src/cl_predictors_py.cpp @@ -0,0 +1,288 @@ +/****************************************** +Copyright (C) 2009-2020 Authors of CryptoMiniSat, see AUTHORS file + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. +***********************************************/ + +#include "cl_predictors_py.h" +#include "clause.h" +#include "solver.h" +#include + +static wchar_t* charToWChar(const char* text) +{ + const size_t size = strlen(text) + 1; + wchar_t* wText = new wchar_t[size]; + mbstowcs(wText, text, size); + return wText; +} + +extern char predictor_short_json[]; +extern unsigned int predictor_short_json_len; + +extern char predictor_long_json[]; +extern unsigned int predictor_long_json_len; + +extern char predictor_forever_json[]; +extern unsigned int predictor_forever_json_len; + + +using namespace CMSat; + +int ClPredictorsPy::set_up_input( + const CMSat::Clause* const cl, + const uint64_t sumConflicts, + const double act_ranking_rel, + const double uip1_ranking_rel, + const double prop_ranking_rel, + const double sum_uip1_per_time_ranking, + const double sum_props_per_time_ranking, + const double sum_uip1_per_time_ranking_rel, + const double sum_props_per_time_ranking_rel, + const ReduceCommonData& commdata, + const Solver* solver, + float* at) +{ + int x = 0; + + const ClauseStatsExtra& extra_stats = solver->red_stats_extra[cl->stats.extra_pos]; + uint32_t last_touched_any_diff = sumConflicts - (uint64_t)cl->stats.last_touched_any; + double time_inside_solver = sumConflicts - (uint64_t)extra_stats.introduced_at_conflict; + + at[x++] = cl->stats.is_ternary_resolvent; + at[x++] = cl->stats.which_red_array; + at[x++] = cl->stats.last_touched_any; + at[x++] = act_ranking_rel; + at[x++] = uip1_ranking_rel; + at[x++] = prop_ranking_rel; + at[x++] = last_touched_any_diff; + at[x++] = time_inside_solver; + at[x++] = cl->stats.props_made; + at[x++] = commdata.avg_props; + at[x++] = commdata.avg_uip; + at[x++] = solver->hist.conflSizeHistLT.avg(); + at[x++] = solver->hist.glueHistLT.avg(); + at[x++] = extra_stats.sum_props_made; + at[x++] = extra_stats.discounted_props_made; + at[x++] = extra_stats.discounted_props_made2; + at[x++] = extra_stats.discounted_props_made3; + at[x++] = extra_stats.discounted_uip1_used; + at[x++] = extra_stats.discounted_uip1_used2; + at[x++] = extra_stats.discounted_uip1_used3; + at[x++] = extra_stats.sum_uip1_used; + at[x++] = cl->stats.uip1_used; + at[x++] = cl->size(); + at[x++] = sum_uip1_per_time_ranking; + at[x++] = sum_props_per_time_ranking; + at[x++] = sum_uip1_per_time_ranking_rel; + at[x++] = sum_props_per_time_ranking_rel; + at[x++] = cl->distilled; + + //Ternary resolvents lack glue and antecedent data + if (cl->stats.is_ternary_resolvent) { + for(int i = 0; i < 14; i++) { + at[x++] = missing_val; + } + } else { + at[x++] = extra_stats.glueHist_avg; + at[x++] = extra_stats.antecedents_binIrred; + at[x++] = extra_stats.glueHistLT_avg; + at[x++] = extra_stats.glueHist_longterm_avg; + at[x++] = extra_stats.num_antecedents; + at[x++] = extra_stats.overlapHistLT_avg; + at[x++] = extra_stats.conflSizeHist_avg; + at[x++] = extra_stats.antecedents_binred; + at[x++] = extra_stats.num_total_lits_antecedents; + at[x++] = extra_stats.numResolutionsHistLT_avg; + at[x++] = cl->stats.glue; + at[x++] = extra_stats.orig_glue; + at[x++] = extra_stats.glue_before_minim; + at[x++] = extra_stats.trail_depth_level; + } + assert(x == NUM_RAW_FEATS); + + return NUM_RAW_FEATS; +} + + +ClPredictorsPy::ClPredictorsPy() +{ + for(uint32_t i=0; i < 3; i++) { + ret_data[i] = NULL; + } +} + +ClPredictorsPy::~ClPredictorsPy() +{ + //Free if we didn't already + if (ret_data[0]) { + for(uint32_t i=0; i < 3; i++) { + assert(ret_data[i]); + Py_DECREF(ret_data[i]); + } + } + Py_DECREF(pFunc); + + Py_Finalize(); +} + +int ClPredictorsPy::load_models(const std::string& short_fname, + const std::string& long_fname, + const std::string& forever_fname, + const std::string& best_feats_fname) +{ + Py_Initialize(); + import_array(); + wchar_t *tmp = charToWChar(best_feats_fname.c_str()); + PySys_SetArgv(1, &tmp); + + std::wstring pypath2(Py_GetPath()); + //std::wcout << L"path: " << pypath2 << std::endl; + + PyObject* pName = PyUnicode_FromString("ml_module"); + pModule = PyImport_Import(pName); + Py_DECREF(pName); + if (pModule == NULL) { + PyErr_Print(); + cout << "ERROR: Failed to load ml_module from the same place as \"" + best_feats_fname + "\"!" << endl; + exit(-1); + } + + // Create a dictionary for the contents of the module. + pDict = PyModule_GetDict(pModule); + pFunc = PyDict_GetItemString(pDict, "predict"); + + // Set up features + PyObject *set_up_features = PyDict_GetItemString(pDict, "set_up_features"); + pArgs = PyTuple_New(1); + PyTuple_SetItem(pArgs, 0, PyUnicode_FromString(best_feats_fname.c_str())); + PyObject* ret = PyObject_CallObject(set_up_features, pArgs); + if (ret == NULL) { + PyErr_Print(); + cout << "ERROR: Failed to set up features!" << endl; + exit(-1); + } + //Py_DECREF(set_up_features); + Py_DECREF(pArgs); + Py_DECREF(ret); + + + //Load models + PyObject* load_models = PyDict_GetItemString(pDict, "load_models"); + pArgs = PyTuple_New(3); + PyTuple_SetItem(pArgs, 0, PyUnicode_FromString(short_fname.c_str())); + PyTuple_SetItem(pArgs, 1, PyUnicode_FromString(long_fname.c_str())); + PyTuple_SetItem(pArgs, 2, PyUnicode_FromString(forever_fname.c_str())); + ret = PyObject_CallObject(load_models, pArgs); + if (ret == NULL) { + PyErr_Print(); + cout << "ERROR: Failed to load models !" << endl; + exit(-1); + } + //Py_DECREF(load_models); + Py_DECREF(pArgs); + Py_DECREF(ret); + //Py_DECREF(pModule); + //Py_DECREF(pDict); + return 1; +} + +int ClPredictorsPy::load_models_from_buffers() +{ + cout << "ERROR: it is not possible to load models from buffer in Python mode" << endl; + exit(-1); + return 1; +} + +void ClPredictorsPy::predict_all( + float* const data, + const uint32_t num) +{ + if (num == 0) { + return; + } + + // Create NumPy 2D array with data + npy_intp dims[2]; + dims[0] = num; + dims[1] = NUM_RAW_FEATS; + pArray = PyArray_SimpleNewFromData(2, dims, NPY_FLOAT, data); + assert(pArray != NULL); + + // Tuple to hold the arguments to the method + pArgs = PyTuple_New(1); + PyTuple_SetItem(pArgs, 0, pArray); + + // Call the function with the arguments + PyObject* pResult = PyObject_CallObject(pFunc, pArgs); + Py_DECREF(pArgs); + if(pResult == NULL) { + PyErr_Print(); + cout << "Calling the add method failed" << endl; + exit(-1); + } + + if (pResult->ob_type != &PyList_Type) { + cout << "ERROR: you didn't return List" << endl; + exit(-1); + } + + // See: https://numpy.org/devdocs/user/c-info.beyond-basics.html#basic-iteration + uint32_t num_elems = PyList_Size(pResult); + assert(num_elems == 3); + for(uint32_t i = 0; i < 3; i++) { + pRet[i] = PyList_GetItem(pResult, i); + ret_data[i] = (PyArrayObject *)PyArray_ContiguousFromObject(pRet[i], NPY_DOUBLE, 1, 1); + + //NOTE: PyArray_DATA has no effect on the reference count of the array it is applied to + // see: https://stackoverflow.com/questions/37919094/decrefing-after-a-call-to-pyarray-data + // So no decrefing needed for this one + out_result[i] = (double*)PyArray_DATA(ret_data[i]); + assert(PyArray_SIZE(ret_data[i]) == num); + //Py_DECREF(pRet[i]); + } + + //This should decrement all elements in the array, so we incremented it above. + Py_DECREF(pResult); +} + +void ClPredictorsPy::get_prediction_at(ClauseStatsExtra& extdata, const uint32_t at) +{ + extdata.pred_short_use = out_result[0][at]; + extdata.pred_long_use = out_result[1][at]; + extdata.pred_forever_use = out_result[2][at]; +} + +void CMSat::ClPredictorsPy::finish_all_predict() +{ + //Free previous result + if (ret_data[0] != NULL) { + for(uint32_t i=0; i < 3; i++) { +// assert(pRet[i]); +// Py_DECREF(pRet[i]); +// pRet[i] = NULL; + + assert(ret_data[i]); + Py_DECREF(ret_data[i]); + ret_data[i] = NULL; + } + } +} + + diff --git a/cryptominisat/cppsrc/src/cl_predictors_py.h b/cryptominisat/cppsrc/src/cl_predictors_py.h new file mode 100644 index 00000000..4c035c2e --- /dev/null +++ b/cryptominisat/cppsrc/src/cl_predictors_py.h @@ -0,0 +1,103 @@ +/****************************************** +Copyright (C) 2009-2020 Authors of CryptoMiniSat, see AUTHORS file + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. +***********************************************/ + +#ifndef _CLPREDICTORS_PY_H__ +#define _CLPREDICTORS_PY_H__ + +#include +#include +#include +#include "clause.h" +#include "cl_predictors_abs.h" + +#define NPY_NO_DEPRECATED_API NPY_1_7_API_VERSION +#include +#include + +#define NUM_RAW_FEATS 42 + +using std::vector; + +namespace CMSat { + +class Clause; +class Solver; + +class ClPredictorsPy : public ClPredictorsAbst +{ +public: + ClPredictorsPy(); + virtual ~ClPredictorsPy(); + virtual int load_models( + const std::string& short_fname, + const std::string& long_fname, + const std::string& forever_fname, + const std::string& best_feats_fname) override; + virtual int load_models_from_buffers() override; + + virtual int set_up_input( + const CMSat::Clause* const cl, + const uint64_t sumConflicts, + const double act_ranking_rel, + const double uip1_ranking_rel, + const double prop_ranking_rel, + const double sum_uip1_per_time_ranking, + const double sum_props_per_time_ranking, + const double sum_uip1_per_time_ranking_rel, + const double sum_props_per_time_ranking_rel, + const ReduceCommonData& commdata, + const Solver* solver, + float* at) override; + + virtual int get_step_size() override {return NUM_RAW_FEATS;} + + float predict( + predict_type pred_type, + const CMSat::Clause* cl, + const uint64_t sumConflicts, + const double act_ranking_rel, + const double uip1_ranking_rel, + const double prop_ranking_rel, + const ReduceCommonData& commdata + ); + + virtual void predict_all( + float* const data, + uint32_t const num) override; + + virtual void get_prediction_at(ClauseStatsExtra& extdata, const uint32_t at) override; + virtual void finish_all_predict() override; + +private: + double* out_result[3]; + PyObject *pDict = NULL; + PyObject *pFunc = NULL; + PyObject *pRet[3]; + PyObject *pArray = NULL; + PyObject *pArgs = NULL; + PyArrayObject* ret_data[3]; + PyObject* pModule; +}; + +} + +#endif diff --git a/cryptominisat/cppsrc/src/cl_predictors_xgb.cpp b/cryptominisat/cppsrc/src/cl_predictors_xgb.cpp new file mode 100644 index 00000000..9669877f --- /dev/null +++ b/cryptominisat/cppsrc/src/cl_predictors_xgb.cpp @@ -0,0 +1,166 @@ +/****************************************** +Copyright (C) 2009-2020 Authors of CryptoMiniSat, see AUTHORS file + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. +***********************************************/ + +#include "cl_predictors_xgb.h" +#include "clause.h" +#include "solver.h" +#include +#include +#include +extern char predictor_short_json[]; +extern unsigned int predictor_short_json_len; + +extern char predictor_long_json[]; +extern unsigned int predictor_long_json_len; + +extern char predictor_forever_json[]; +extern unsigned int predictor_forever_json_len; + +#define safe_xgboost(call) { \ + int err = (call); \ + if (err != 0) { \ + fprintf(stderr, "%s:%d: error in %s: %s\n", __FILE__, __LINE__, #call, XGBGetLastError()); \ + exit(1); \ + } \ +} + +using namespace CMSat; + +ClPredictorsXGB::ClPredictorsXGB() +{ + handles.resize(3); + safe_xgboost(XGBoosterCreate(0, 0, &(handles[predict_type::short_pred]))) + safe_xgboost(XGBoosterCreate(0, 0, &(handles[predict_type::long_pred]))) + safe_xgboost(XGBoosterCreate(0, 0, &(handles[predict_type::forever_pred]))) + + for(int i = 0; i < 3; i++) { + safe_xgboost(XGBoosterSetParam(handles[i], "nthread", "1")) + //safe_xgboost(XGBoosterSetParam(handles[i], "verbosity", "3")) + } +} + +ClPredictorsXGB::~ClPredictorsXGB() +{ + for(auto& h: handles) { + XGBoosterFree(h); + } +} + +int ClPredictorsXGB::load_models(const std::string& short_fname, + const std::string& long_fname, + const std::string& forever_fname, + const std::string& best_feats_fname) +{ + safe_xgboost(XGBoosterLoadModel(handles[predict_type::short_pred], short_fname.c_str())) + safe_xgboost(XGBoosterLoadModel(handles[predict_type::long_pred], long_fname.c_str())) + safe_xgboost(XGBoosterLoadModel(handles[predict_type::forever_pred], forever_fname.c_str())) + return 1; +} + +int ClPredictorsXGB::load_models_from_buffers() +{ + safe_xgboost(XGBoosterLoadModelFromBuffer( + handles[predict_type::short_pred], predictor_short_json, predictor_short_json_len)); + safe_xgboost(XGBoosterLoadModelFromBuffer( + handles[predict_type::long_pred], predictor_long_json, predictor_long_json_len)); + safe_xgboost(XGBoosterLoadModelFromBuffer( + handles[predict_type::forever_pred], predictor_forever_json, predictor_forever_json_len)) + return 0; +} + +void ClPredictorsXGB::predict_all( + float* const data, + const uint32_t num) +{ + safe_xgboost(XGDMatrixCreateFromMat(data, num, PRED_COLS, missing_val, &dmat)) + if (num == 0) { + return; + } + +//For checking in python using check_against_binary_dat +#if 0 + std::stringstream s; + s << "bin_dump" << num_dumps << ".csv"; + std::ofstream f; + f.open(s.str().c_str()); + float* data_ptr = data; + for(uint32_t i = 0; i < num; i ++) { + std::stringstream line; + for(uint32_t i2 = 0; i2 < PRED_COLS; i2++) { + line << std::setprecision(30) << *data_ptr; + if (i2+1 < PRED_COLS) { + line << ","; + } + data_ptr++; + } + f << line.str() << endl; + } + f.close(); + num_dumps++; +#endif + + bst_ulong out_len; + safe_xgboost(XGBoosterPredict( + handles[short_pred], + dmat, + 0, //0: normal prediction + 0, //use all trees + 0, //do not use for training + &out_len, + &out_result_short + )) + assert(out_len == num); + + safe_xgboost(XGBoosterPredict( + handles[long_pred], + dmat, + 0, //0: normal prediction + 0, //use all trees + 0, //do not use for training + &out_len, + &out_result_long + )) + assert(out_len == num); + + safe_xgboost(XGBoosterPredict( + handles[forever_pred], + dmat, + 0, //0: normal prediction + 0, //use all trees + 0, //do not use for training + &out_len, + &out_result_forever + )) + assert(out_len == num); +} + +void ClPredictorsXGB::get_prediction_at(ClauseStatsExtra& extdata, const uint32_t at) +{ + extdata.pred_short_use = (double)out_result_short[at]; + extdata.pred_long_use = (double)out_result_long[at]; + extdata.pred_forever_use = (double)out_result_forever[at]; +} + +void CMSat::ClPredictorsXGB::finish_all_predict() +{ + safe_xgboost(XGDMatrixFree(dmat)) +} diff --git a/cryptominisat/cppsrc/src/cl_predictors_xgb.h b/cryptominisat/cppsrc/src/cl_predictors_xgb.h new file mode 100644 index 00000000..2e3de3ef --- /dev/null +++ b/cryptominisat/cppsrc/src/cl_predictors_xgb.h @@ -0,0 +1,82 @@ +/****************************************** +Copyright (C) 2009-2020 Authors of CryptoMiniSat, see AUTHORS file + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. +***********************************************/ + +#ifndef _CLPREDICTORS_XGB_H__ +#define _CLPREDICTORS_XGB_H__ + +#include +#include +#include +#include +#include "clause.h" +#include "cl_predictors_abs.h" + +using std::vector; + +namespace CMSat { + +class Clause; +class Solver; + +class ClPredictorsXGB : public ClPredictorsAbst +{ +public: + ClPredictorsXGB(); + virtual ~ClPredictorsXGB(); + virtual int load_models(const std::string& short_fname, + const std::string& long_fname, + const std::string& forever_fname, + const std::string& best_feats_fname) override; + virtual int load_models_from_buffers() override; + + float predict( + predict_type pred_type, + const CMSat::Clause* cl, + const uint64_t sumConflicts, + const double act_ranking_rel, + const double uip1_ranking_rel, + const double prop_ranking_rel, + const ReduceCommonData& commdata + ); + + virtual void predict_all( + float* const data, + const uint32_t num) override; + + virtual void get_prediction_at(ClauseStatsExtra& extdata, const uint32_t at) override; + virtual void finish_all_predict() override; + +private: + vector handles; + DMatrixHandle dmat; + + const float *out_result_short; + const float *out_result_long; + const float *out_result_forever; + + //debugging + int num_dumps = 0; +}; + +} + +#endif diff --git a/cryptominisat/cppsrc/src/clabstraction.h b/cryptominisat/cppsrc/src/clabstraction.h new file mode 100644 index 00000000..d3bc1c85 --- /dev/null +++ b/cryptominisat/cppsrc/src/clabstraction.h @@ -0,0 +1,51 @@ +/****************************************** +Copyright (C) 2009-2020 Authors of CryptoMiniSat, see AUTHORS file + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. +***********************************************/ + + +#ifndef __CL_ABSTRACTION__H__ +#define __CL_ABSTRACTION__H__ + +#include + +typedef uint32_t cl_abst_type; +static const int cl_abst_modulo = 29; + +inline cl_abst_type abst_var(const uint32_t v) +{ + return 1UL << (v % cl_abst_modulo); +} + +template +cl_abst_type calcAbstraction(const T& ps) +{ + cl_abst_type abstraction = 0; + if (ps.size() > 50) { + return ~((cl_abst_type)(0ULL)); + } + + for (auto l: ps) + abstraction |= abst_var(l.var()); + + return abstraction; +} + +#endif //__CL_ABSTRACTION__H__ diff --git a/cryptominisat/cppsrc/src/clause.h b/cryptominisat/cppsrc/src/clause.h new file mode 100644 index 00000000..61380e18 --- /dev/null +++ b/cryptominisat/cppsrc/src/clause.h @@ -0,0 +1,700 @@ +/****************************************** +Copyright (C) 2009-2020 Authors of CryptoMiniSat, see AUTHORS file + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. +***********************************************/ + + +#ifndef CLAUSE_H +#define CLAUSE_H + +#include +#include +#include +#include +#include +#include + +#include "solverconf.h" +#include "solvertypes.h" +#include "constants.h" +#include "watched.h" +#include "alg.h" +#include "clabstraction.h" +#include "avgcalc.h" +#include "constants.h" + +namespace CMSat { + +class ClauseAllocator; + +/** +@brief Decides only using abstraction if clause A could subsume clause B + +@note: It can give false positives. Never gives false negatives. + +For A to subsume B, everything that is in A MUST be in B. So, if (A & ~B) +contains even one bit, it means that A contains something that B doesn't. So +A may be a subset of B only if (A & ~B) == 0 +*/ +inline bool subsetAbst(const cl_abst_type A, const cl_abst_type B) +{ + return ((A & ~B) == 0); +} + +template +struct AtecedentData +{ + void clear() + { + *this = AtecedentData(); + } + + uint64_t num() const + { + return binRed + binIrred + longIrred + longRed; + } + + template + AtecedentData& operator+=(const AtecedentData& other) + { + binRed += other.binRed; + binIrred += other.binIrred; + longIrred += other.longIrred; + longRed += other.longRed; + + glue_long_reds += other.glue_long_reds; + size_longs += other.size_longs; + + return *this; + } + + template + AtecedentData& operator-=(const AtecedentData& other) + { + binRed -= other.binRed; + binIrred -= other.binIrred; + longIrred -= other.longIrred; + longRed -= other.longRed; + + glue_long_reds -= other.glue_long_reds; + size_longs -= other.size_longs; + + return *this; + } + + uint32_t sum_size() const + { + uint32_t sum = 0; + sum += binIrred*2; + sum += binRed*2; + sum += size_longs.get_sum(); + + return sum; + } + + T binRed = 0; + T binIrred = 0; + T longIrred = 0; + T longRed = 0; + AvgCalc glue_long_reds; + AvgCalc size_longs; +}; + +struct ClauseStats +{ + ClauseStats() + { + //NOTE: we *MUST* set values to high default, as we do + //combineStats(default, newclause) to get combined stats. + glue = 1000; + is_decision = false; + marked_clause = false; + ttl = 0; + which_red_array = 7; //intentionally breaking it so we catch bugs, 7 NEVER exists + locked_for_data_gen = 0; + is_ternary_resolvent = 0; + activity = 0; + is_tracked = false; + } + + //Stored data + uint32_t glue:20; //currently in code limited to 100'000 + uint32_t is_decision:1; //a "decision clause", i.e. made out of decisions leading to conflict, not resolution + uint32_t marked_clause:1; + uint32_t ttl:1; + uint32_t which_red_array:3; + uint32_t locked_for_data_gen:1; + uint32_t is_ternary_resolvent:1; + uint32_t is_tracked:1; + union { + float activity; + uint32_t hash_val; //used in BreakID to remove equivalent clauses + }; + uint32_t last_touched_any = 0; + int32_t ID; + + #if defined(STATS_NEEDED) || defined (FINAL_PREDICTOR) || defined(NORMAL_CL_USE_STATS) + uint32_t extra_pos = numeric_limits::max(); + uint32_t uip1_used = 0; ///N.o. times claue was used during 1st UIP generation in this RDB + uint32_t props_made = 0; ///::max(); + uint32_t orig_size = numeric_limits::max(); + uint32_t introduced_at_conflict = 0; /// antec_data; + #endif + + float discount( + float discount_factor, + float orig, + uint32_t val + ) { + orig *= discount_factor; + orig += (float)val * (1.0f-discount_factor); + return orig; + } + + void update_rdb_stats(ClauseStats& stats) + { + sum_uip1_used += stats.uip1_used; + sum_props_made += stats.props_made; + + discounted_props_made = discount(0.8, discounted_props_made, stats.props_made); + discounted_uip1_used = discount(0.8, discounted_uip1_used, stats.uip1_used); + discounted_uip1_used3 = discount(0.9, discounted_uip1_used3, stats.uip1_used); + discounted_uip1_used2 = discount(0.4, discounted_uip1_used2, stats.uip1_used); + discounted_props_made2 = discount(0.4, discounted_props_made2, stats.props_made); + discounted_props_made3 = discount(0.9, discounted_props_made3, stats.props_made); + + #ifdef STATS_NEEDED + //unused discounted ones come here + #endif + + stats.update_rdb_stats(); + } + + void reset_rdb_stats(ClauseStats& stats) + { + #ifdef STATS_NEEDED + antec_data.clear(); + conflicts_made = 0; + ttl_stats = 0; + dump_no++; + #endif + + stats.reset_rdb_stats(); + } + + static ClauseStatsExtra combineStats(const ClauseStatsExtra& first, const ClauseStatsExtra& second) + { + //Create to-be-returned data + ClauseStatsExtra ret = first; + + #if defined(STATS_NEEDED) || defined (FINAL_PREDICTOR) + if (first.introduced_at_conflict == 0) { + ret.introduced_at_conflict = second.introduced_at_conflict; + } else if (second.introduced_at_conflict == 0) { + ret.introduced_at_conflict = first.introduced_at_conflict; + } else { + ret.introduced_at_conflict = std::min(first.introduced_at_conflict, second.introduced_at_conflict); + } + ret.sum_uip1_used = first.sum_uip1_used + second.sum_uip1_used; + ret.sum_props_made = first.sum_props_made + second.sum_props_made; + ret.discounted_props_made = first.discounted_props_made + second.discounted_props_made; + ret.discounted_uip1_used = first.discounted_uip1_used + second.discounted_uip1_used; + ret.orig_glue = std::min(first.orig_glue, second.orig_glue); + ret.discounted_uip1_used3 = first.discounted_uip1_used3 + second.discounted_uip1_used3; + ret.discounted_props_made2 = first.discounted_props_made2 + second.discounted_props_made2; + ret.discounted_uip1_used2 = first.discounted_uip1_used2 + second.discounted_uip1_used2; + ret.discounted_props_made3 = first.discounted_props_made3 + second.discounted_props_made3; + #endif + + #ifdef STATS_NEEDED + ret.dump_no = std::max(first.dump_no, second.dump_no); + ret.ttl_stats = std::max(first.ttl_stats, second.ttl_stats); + ret.conflicts_made = first.conflicts_made + second.conflicts_made; + ret.orig_connects_num_communities = std::max( + first.orig_connects_num_communities, + second.orig_connects_num_communities); + #endif + + return ret; + } +}; +#endif + +inline std::ostream& operator<<(std::ostream& os, const ClauseStats& stats) +{ + + os << "glue " << stats.glue << " "; + return os; +} + +/** +@brief Holds a clause. Does not allocate space for literals + +Literals are allocated by an external allocator that allocates enough space +for the class that it can hold the literals as well. I.e. it malloc()-s + sizeof(Clause)+LENGHT*sizeof(Lit) +to hold the clause. +*/ +class Clause +{ +public: + ClauseStats stats; + uint32_t isRed:1; /// + Clause(const V& ps, const uint32_t _introduced_at_conflict, const uint32_t _ID) + { + //assert(ps.size() > 2); + + stats.last_touched_any = _introduced_at_conflict; + assert(_ID > 0); + stats.ID = _ID; + + isFreed = false; + mySize = ps.size(); + isRed = false; + isRemoved = false; + distilled = 0; + is_ternary_resolved = false; + must_recalc_abst = true; + _used_in_xor = false; + _used_in_xor_full = false; + _xor_is_detached = false; + reloced = false; + disabled = false; + tried_to_remove = 0; + + for (uint32_t i = 0; i < ps.size(); i++) { + getData()[i] = ps[i]; + } + } + + typedef Lit* iterator; + typedef const Lit* const_iterator; + + uint32_t size() const + { + return mySize; + } + + bool used_in_xor() const + { + return _used_in_xor; + } + + void set_used_in_xor(const bool val) + { + _used_in_xor = val; + } + + bool used_in_xor_full() const + { + return _used_in_xor_full; + } + + void set_used_in_xor_full(const bool val) + { + _used_in_xor_full = val; + } + + void shrink(const uint32_t i) + { + assert(i <= size()); + mySize -= i; + if (i > 0) + setStrenghtened(); + } + + void resize (const uint32_t i) + { + assert(i <= size()); + if (i == size()) return; + mySize = i; + setStrenghtened(); + } + + //We MUST have just strengthen-ed the clause! + void enlarge_one() + { + mySize+=1; + must_recalc_abst = true; + } + + bool red() const + { + return isRed; + } + + bool freed() const + { + return isFreed; + } + + void reCalcAbstraction() + { + abst = calcAbstraction(*this); + must_recalc_abst = false; + } + + void setStrenghtened() + { + must_recalc_abst = true; + //is_ternary_resolved = false; //probably not a good idea + //is_distilled = false; //TODO? + } + + void recalc_abst_if_needed() + { + if (must_recalc_abst) { + reCalcAbstraction(); + } + } + + Lit& operator [] (const uint32_t i) + { + return *(getData() + i); + } + + const Lit& operator [] (const uint32_t i) const + { + return *(getData() + i); + } + + void makeIrred() + { + assert(isRed); + isRed = false; + } + + void strengthen(const Lit p) + { + remove(*this, p); + setStrenghtened(); + } + + void add(const Lit p) + { + mySize++; + getData()[mySize-1] = p; + setStrenghtened(); + } + + const Lit* begin() const + { + #ifdef SLOW_DEBUG + assert(!freed()); + assert(!getRemoved()); + #endif + return getData(); + } + + Lit* begin() + { + #ifdef SLOW_DEBUG + assert(!freed()); + assert(!getRemoved()); + #endif + return getData(); + } + + const Lit* end() const + { + return getData()+size(); + } + + Lit* end() + { + return getData()+size(); + } + + void setRemoved() + { + isRemoved = true; + } + + bool getRemoved() const + { + return isRemoved; + } + + void unset_removed() + { + isRemoved = false; + } + + void setFreed() + { + isFreed = true; + } + + bool getOccurLinked() const + { + return occurLinked; + } + + void setOccurLinked(bool toset) + { + occurLinked = toset; + } + + void print_extra_stats() const + { + cout + << "Clause size " << std::setw(4) << size(); + if (red()) { + cout << " glue : " << std::setw(4) << stats.glue; + } + cout << endl; + } + + void copy_to(vector& lits) { + lits.clear(); + for(const Lit l: *this) { + lits.push_back(l); + } + } +}; + +inline std::ostream& operator<<(std::ostream& os, const Clause& cl) +{ + for (uint32_t i = 0; i < cl.size(); i++) { + os << cl[i]; + + if (i+1 != cl.size()) + os << " "; + } + cout << " -- ID: " << cl.stats.ID; + + return os; +} + +struct BinaryXor +{ + uint32_t vars[2]; + bool rhs; + + BinaryXor(uint32_t var1, uint32_t var2, const bool _rhs) { + if (var1 > var2) { + std::swap(var1, var2); + } + vars[0] = var1; + vars[1] = var2; + rhs = _rhs; + } + + bool operator<(const BinaryXor& other) const + { + if (vars[0] != other.vars[0]) { + return vars[0] < other.vars[0]; + } + + if (vars[1] != other.vars[1]) { + return vars[1] < other.vars[1]; + } + + if (rhs != other.rhs) { + return (int)rhs < (int)other.rhs; + } + return false; + } +}; + +struct Sub0Ret { + ClauseStats stats; + #if defined(STATS_NEEDED) || defined(FINAL_PREDICTOR) + ClauseStatsExtra stats_extra; + #endif + bool subsumedIrred = 0; + uint32_t numSubsumed = 0; + + void clear() { + *this = Sub0Ret(); + } + + Sub0Ret& operator+=(const Sub0Ret& other) + { + numSubsumed += other.numSubsumed; + return *this; + } + +}; + +struct Sub1Ret { + Sub1Ret& operator+=(const Sub1Ret& other) + { + sub += other.sub; + str += other.str; + + return *this; + } + + void clear() { + *this = Sub1Ret(); + } + + size_t sub = 0; + size_t str = 0; + bool subsumedIrred = false; +}; + +} //end namespace + +#endif //CLAUSE_H diff --git a/cryptominisat/cppsrc/src/clauseallocator.cpp b/cryptominisat/cppsrc/src/clauseallocator.cpp new file mode 100644 index 00000000..7f32f639 --- /dev/null +++ b/cryptominisat/cppsrc/src/clauseallocator.cpp @@ -0,0 +1,369 @@ +/****************************************** +Copyright (C) 2009-2020 Authors of CryptoMiniSat, see AUTHORS file + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. +***********************************************/ + +#include "clauseallocator.h" + +#include +#include +#include +#include +#include +#include +#include "solvertypes.h" +#include "clause.h" +#include "solver.h" +#include "searcher.h" +#include "time_mem.h" +#include "sqlstats.h" +#include "gaussian.h" + +#ifdef USE_VALGRIND +#include "valgrind/valgrind.h" +#include "valgrind/memcheck.h" +#endif + +using namespace CMSat; + +using std::pair; +using std::cout; +using std::endl; + + +//For mild debug info: +//#define DEBUG_CLAUSEALLOCATOR + +//For listing each and every clause location: +//#define DEBUG_CLAUSEALLOCATOR2 + +#define MIN_LIST_SIZE (50000 * (sizeof(Clause) + 4*sizeof(Lit))/sizeof(BASE_DATA_TYPE)) +#define ALLOC_GROW_MULT 1.5 + +#define MAXSIZE ((1ULL << (EFFECTIVELY_USEABLE_BITS))-1) + +ClauseAllocator::ClauseAllocator() : + dataStart(NULL) + , size(0) + , capacity(0) + , currentlyUsedSize(0) +{ + assert(MIN_LIST_SIZE < MAXSIZE); +} + +/** +@brief Frees all stacks +*/ +ClauseAllocator::~ClauseAllocator() +{ + free(dataStart); +} + +void* ClauseAllocator::allocEnough( + uint32_t num_lits +) { + //Try to quickly find a place at the end of a dataStart + uint64_t neededbytes = sizeof(Clause) + sizeof(Lit)*num_lits; + uint64_t needed + = neededbytes/sizeof(BASE_DATA_TYPE) + (bool)(neededbytes % sizeof(BASE_DATA_TYPE)); + + if (size + needed > capacity) { + //Grow by default, but don't go under or over the limits + uint64_t newcapacity = capacity * ALLOC_GROW_MULT; + newcapacity = std::max(newcapacity, MIN_LIST_SIZE); + while (newcapacity < size+needed) { + newcapacity *= ALLOC_GROW_MULT; + } + assert(newcapacity >= size+needed); + newcapacity = std::min(newcapacity, MAXSIZE); + + //Oops, not enough space anyway + if (newcapacity < size + needed) { + std::cerr + << "ERROR: memory manager can't handle the load." +#ifndef LARGE_OFFSETS + << " **PLEASE RECOMPILE WITH -DLARGEMEM=ON**" +#endif + << " size: " << size + << " needed: " << needed + << " newcapacity: " << newcapacity + << endl; + std::cout + << "ERROR: memory manager can't handle the load." +#ifndef LARGE_OFFSETS + << " **PLEASE RECOMPILE WITH -DLARGEMEM=ON**" +#endif + << " size: " << size + << " needed: " << needed + << " newcapacity: " << newcapacity + << endl; + + throw std::bad_alloc(); + } + + //Reallocate data + BASE_DATA_TYPE* new_dataStart; + new_dataStart = (BASE_DATA_TYPE*)realloc( + dataStart + , newcapacity*sizeof(BASE_DATA_TYPE) + ); + + //Realloc failed? + if (new_dataStart == NULL) { + std::cerr + << "ERROR: while reallocating clause space" + << endl; + + throw std::bad_alloc(); + } + dataStart = new_dataStart; + + //Update capacity to reflect the update + capacity = newcapacity; + } + + //Add clause to the set + Clause* pointer = (Clause*)(dataStart + size); + size += needed; + currentlyUsedSize += needed; + + #ifdef USE_VALGRIND + VALGRIND_MAKE_MEM_UNDEFINED((char*)pointer, neededbytes); + #endif + return pointer; +} + +/** +@brief Given the pointer of the clause it finds a 32-bit offset for it + +Calculates the stack frame and the position of the pointer in the stack, and +rerturns a 32-bit value that is a concatenation of these two +*/ +ClOffset ClauseAllocator::get_offset(const Clause* ptr) const +{ + return ((BASE_DATA_TYPE*)ptr - dataStart); +} + +/** +@brief Frees a clause + +If clause was binary, it frees it in quite a normal way. If it isn't, then it +needs to set the data in the Clause that it has been freed, and updates the +stack it belongs to such that the stack can now that its effectively used size +is smaller + +NOTE: The size of claues can change. Therefore, currentlyUsedSizes can in fact +be incorrect, since it was incremented by the ORIGINAL size of the clause, but +when the clause is "freed", it is decremented by the POTENTIALLY SMALLER size +of the clause. Therefore, the "currentlyUsedSizes" is an overestimation!! +*/ +void ClauseAllocator::clauseFree(Clause* cl) +{ + assert(!cl->freed()); + cl->setFreed(); + uint64_t est_num_cl = cl->size(); + est_num_cl = std::max(est_num_cl, (uint64_t)3); //we sometimes allow gauss to allocate 3-long clauses + uint64_t bytes_freed = sizeof(Clause) + est_num_cl*sizeof(Lit); + uint64_t elems_freed = bytes_freed/sizeof(BASE_DATA_TYPE) + (bool)(bytes_freed % sizeof(BASE_DATA_TYPE)); + currentlyUsedSize -= elems_freed; + + #ifdef VALGRIND_MAKE_MEM_UNDEFINED + VALGRIND_MAKE_MEM_UNDEFINED(((char*)cl)+sizeof(Clause), cl->size()*sizeof(Lit)); + #endif +} + +void ClauseAllocator::clauseFree(ClOffset offset) +{ + Clause* cl = ptr(offset); + clauseFree(cl); +} + +ClOffset ClauseAllocator::move_cl( + ClOffset* newDataStart + , ClOffset*& new_ptr + , Clause* old +) const { + uint64_t bytesNeeded = sizeof(Clause) + old->size()*sizeof(Lit); + uint64_t sizeNeeded = bytesNeeded/sizeof(BASE_DATA_TYPE) + (bool)(bytesNeeded % sizeof(BASE_DATA_TYPE)); + memcpy(new_ptr, old, sizeNeeded*sizeof(BASE_DATA_TYPE)); + + ClOffset new_offset = new_ptr-newDataStart; + (*old)[0] = Lit::toLit(new_offset & 0xFFFFFFFF); + #ifdef LARGE_OFFSETS + (*old)[1] = Lit::toLit((new_offset>>32) & 0xFFFFFFFF); + #endif + old->reloced = true; + + new_ptr += sizeNeeded; + return new_offset; +} + +void ClauseAllocator::move_one_watchlist( + watch_subarray& ws, ClOffset* newDataStart, ClOffset*& new_ptr) +{ + for(Watched& w: ws) { + if (w.isClause()) { + Clause* old = ptr(w.get_offset()); + assert(!old->freed()); + Lit blocked = w.getBlockedLit(); + if (old->reloced) { + ClOffset new_offset = (*old)[0].toInt(); + #ifdef LARGE_OFFSETS + new_offset += ((uint64_t)(*old)[1].toInt())<<32; + #endif + w = Watched(new_offset, blocked); + } else { + ClOffset new_offset = move_cl(newDataStart, new_ptr, old); + w = Watched(new_offset, blocked); + } + } + } +} + +/** +@brief If needed, compacts stacks, removing unused clauses + +Firstly, the algorithm determines if the number of useless slots is large or +small compared to the problem size. If it is small, it does nothing. If it is +large, then it allocates new stacks, copies the non-freed clauses to these new +stacks, updates all pointers and offsets, and frees the original stacks. +*/ +void ClauseAllocator::consolidate( + Solver* solver + , const bool force + , bool lower_verb +) { + //If re-allocation is not really neccessary, don't do it + //Neccesities: + //1) There is too much memory allocated. Re-allocation will save space + // Avoiding segfault (max is 16 outerOffsets, more than 10 is near) + //2) There is too much empty, unused space (>30%) + if (!force + && (float_div(currentlyUsedSize, size) > 0.8 || currentlyUsedSize < (100ULL*1000ULL)) + ) { + if (solver->conf.verbosity >= 3 + || (lower_verb && solver->conf.verbosity) + ) { + cout << "c Not consolidating memory." << endl; + } + return; + } + const double myTime = cpuTime(); + + //Pointers that will be moved along + BASE_DATA_TYPE * const newDataStart = (BASE_DATA_TYPE*)malloc(currentlyUsedSize*sizeof(BASE_DATA_TYPE)); + BASE_DATA_TYPE * new_ptr = newDataStart; + + assert(sizeof(BASE_DATA_TYPE) % sizeof(Lit) == 0); + + vector visited(solver->watches.size(), 0); + for(auto& ws: solver->watches) { + move_one_watchlist(ws, newDataStart, new_ptr); + } + + update_offsets(solver->longIrredCls, newDataStart, new_ptr); + for(auto& lredcls: solver->longRedCls) { + update_offsets(lredcls, newDataStart, new_ptr); + } + update_offsets(solver->detached_xor_repr_cls, newDataStart, new_ptr); + + //Fix up propBy + for (size_t i = 0; i < solver->nVars(); i++) { + VarData& vdata = solver->varData[i]; + if (vdata.reason.isClause()) { + if (vdata.removed == Removed::none + && solver->decisionLevel() >= vdata.level + && vdata.level != 0 + && solver->value(i) != l_Undef + ) { + Clause* old = ptr(vdata.reason.get_offset()); + assert(!old->freed()); + ClOffset new_offset = (*old)[0].toInt(); + #ifdef LARGE_OFFSETS + new_offset += ((uint64_t)(*old)[1].toInt())<<32; + #endif + vdata.reason = PropBy(new_offset); + } else { + vdata.reason = PropBy(); + } + } + } + + //Update sizes + const uint64_t old_size = size; + size = new_ptr-newDataStart; + capacity = currentlyUsedSize; + currentlyUsedSize = size; + free(dataStart); + dataStart = newDataStart; + + const double time_used = cpuTime() - myTime; + if (solver->conf.verbosity >= 2 + || (lower_verb && solver->conf.verbosity) + ) { + size_t log_2_size = 0; + if (size > 0) { + //yes, it can be 0 (only binary clauses, for example) + log_2_size = std::log2(size); + } + cout << "c [mem] consolidate "; + cout << " old-sz: " << print_value_kilo_mega(old_size*sizeof(BASE_DATA_TYPE)) + << " new-sz: " << print_value_kilo_mega(size*sizeof(BASE_DATA_TYPE)) + << " new bits offs: " << std::fixed << std::setprecision(2) << log_2_size; + cout << solver->conf.print_times(time_used) + << endl; + } + if (solver->sqlStats) { + solver->sqlStats->time_passed_min( + solver + , "consolidate" + , time_used + ); + } +} + +void ClauseAllocator::update_offsets( + vector& offsets, + ClOffset* newDataStart, + ClOffset*& new_ptr +) { + + for(ClOffset& offs: offsets) { + Clause* old = ptr(offs); + if (!old->reloced) { + assert(old->used_in_xor() && old->used_in_xor_full()); + assert(old->_xor_is_detached); + offs = move_cl(newDataStart, new_ptr, old); + } else { + offs = (*old)[0].toInt(); + #ifdef LARGE_OFFSETS + offs += ((uint64_t)(*old)[1].toInt())<<32; + #endif + } + } +} + +size_t ClauseAllocator::mem_used() const +{ + uint64_t mem = 0; + mem += capacity*sizeof(BASE_DATA_TYPE); + + return mem; +} diff --git a/cryptominisat/cppsrc/src/clauseallocator.h b/cryptominisat/cppsrc/src/clauseallocator.h new file mode 100644 index 00000000..8d315d66 --- /dev/null +++ b/cryptominisat/cppsrc/src/clauseallocator.h @@ -0,0 +1,128 @@ +/****************************************** +Copyright (C) 2009-2020 Authors of CryptoMiniSat, see AUTHORS file + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. +***********************************************/ + +#ifndef CLAUSEALLOCATOR_H +#define CLAUSEALLOCATOR_H + + +#include "constants.h" +#include "cloffset.h" +#include "watched.h" +#include "clause.h" +#include "watcharray.h" + +#include +#include +#include + +namespace CMSat { + +class Clause; +class Solver; +class PropEngine; + +using std::map; +using std::vector; + +/** +@brief Allocates memory for (xor) clauses + +This class allocates memory in large chunks, then distributes it to clauses when +needed. When instructed, it consolidates the unused space (i.e. clauses free()-ed). +Essentially, it is a stack-like allocator for clauses. It is useful to have +this, because this way, we can address clauses according to their number, +which is 32-bit, instead of their address, which might be 64-bit +*/ +class ClauseAllocator { + public: + ClauseAllocator(); + ~ClauseAllocator(); + + template + Clause* Clause_new(const T& ps, const uint32_t conflictNum, const uint32_t ID) + { + if (ps.size() > (0x01UL << 28)) { + throw CMSat::TooLongClauseError(); + } + + void* mem = allocEnough(ps.size()); + Clause* real = new (mem) Clause(ps, conflictNum, ID); + return real; + } + + ClOffset get_offset(const Clause* ptr) const; + + inline Clause* ptr(const ClOffset offset) const + { + return (Clause*)(&dataStart[offset]); + } + + void clauseFree(Clause* c); + void clauseFree(ClOffset offset); + + void consolidate( + Solver* solver + , const bool force = false + , bool lower_verb = false + ); + + size_t mem_used() const; + + private: + void update_offsets( + vector& offsets, + ClOffset* newDataStart, + ClOffset*& new_ptr + ); + void move_one_watchlist( + watch_subarray& ws, ClOffset* newDataStart, ClOffset*& new_ptr); + + ClOffset move_cl( + ClOffset* newDataStart + , ClOffset*& new_ptr + , Clause* old + ) const; + + BASE_DATA_TYPE* dataStart; ///value(lit) == l_True) return true; + if (solver->value(watched.lit2()) == l_True) return true; + return false; +} + +void ClauseCleaner::clean_binary_implicit( + const Watched* i + , Watched*& j + , const Lit lit +) { + if (satisfied(*i, lit)) { + //Only delete once + if (lit < i->lit2()) { + (*solver->frat) << del << i->get_ID() << lit << i->lit2() << fin; + } + + if (i->red()) { + impl_data.remLBin++; + } else { + impl_data.remNonLBin++; + } + } else { + #ifdef SLOW_DEBUG + if (solver->value(i->lit2()) != l_Undef + || solver->value(lit) != l_Undef + ) { + cout << "ERROR binary during cleaning has non-l-Undef " + << " Bin clause: " << lit << " " << i->lit2() << endl + << " values: " << solver->value(lit) + << " " << solver->value(i->lit2()) + << endl; + } + #endif + + assert(solver->value(i->lit2()) == l_Undef); + assert(solver->value(lit) == l_Undef); + *j++ = *i; + } +} + +void ClauseCleaner::clean_implicit_watchlist( + watch_subarray& watch_list + , const Lit lit +) { + Watched* i = watch_list.begin(); + Watched* j = i; + for (Watched* end2 = watch_list.end(); i != end2; i++) { + if (i->isClause() || i->isBNN()) { + *j++ = *i; + continue; + } + + if (i->isBin()) { + clean_binary_implicit(i, j, lit); + continue; + } + } + watch_list.shrink_(i - j); +} + +void ClauseCleaner::clean_implicit_clauses() +{ + if (solver->conf.verbosity > 15) { + cout << "c cleaning implicit clauses" << endl; + } + + assert(solver->decisionLevel() == 0); + impl_data = ImplicitData(); + size_t wsLit = 0; + size_t wsLit2 = 2; + for (size_t end = solver->watches.size() + ; wsLit != end + ; wsLit++, wsLit2++ + ) { + if (wsLit2 < end + && !solver->watches[Lit::toLit(wsLit2)].empty() + ) { + solver->watches.prefetch(Lit::toLit(wsLit2).toInt()); + } + + const Lit lit = Lit::toLit(wsLit); + watch_subarray ws = solver->watches[lit]; + if (ws.empty()) + continue; + + clean_implicit_watchlist(ws, lit); + } + impl_data.update_solver_stats(solver); + + #ifdef DEBUG_IMPLICIT_STATS + solver->check_implicit_stats(); + #endif +} + +//return True if it's to be removed. +bool ClauseCleaner::clean_bnn(BNN& bnn, uint32_t bnn_idx) { + if (solver->conf.verbosity > 15) { + cout << "Cleaning BNN: " << bnn << endl; + } + + uint32_t i = 0; + uint32_t j = 0; + for(; i < bnn.size(); i++) { + Lit l = bnn[i]; + if (solver->value(l) == l_Undef) { + bnn[j++] = bnn[i]; + continue; + } + removeWBNN(solver->watches, l, bnn_idx); + removeWBNN(solver->watches, ~l, bnn_idx); + + if (solver->value(l) == l_False) { + //nothing + } else if (solver->value(l) == l_True) { + bnn.cutoff--; + } + } + bnn.resize(j); + + if (!bnn.set && solver->value(bnn.out) != l_Undef) { + removeWBNN(solver->watches, bnn.out, bnn_idx); + removeWBNN(solver->watches, ~bnn.out, bnn_idx); + if (solver->value(bnn.out) == l_False) { + for (auto& l: bnn) { + l = ~l; + } + bnn.cutoff = (int32_t)bnn.size()+1-bnn.cutoff; + } + bnn.set = true; + bnn.out = lit_Undef; + } + + lbool ret = solver->bnn_eval(bnn); + if (ret != l_Undef) { + if (ret == l_False) { + assert(false && "Not handled yet, but it's possible!!"); + solver->ok = false; + return true; + } + //remove + return true; + } + + //translate into clauses + if (solver->bnn_to_cnf(bnn)) { + return true; + } + + //cannot be removed + return false; +} + +void ClauseCleaner::clean_bnns_inter(vector& bnns) +{ + assert(solver->decisionLevel() == 0); + assert(solver->prop_at_head()); + + if (solver->conf.verbosity > 15) { + cout << "Cleaning BNNs" << endl; + } + + for (uint32_t i = 0; i < bnns.size() && solver->okay(); i++) { + BNN* bnn = solver->bnns[i]; + if (!bnn || bnn->isRemoved) + continue; + + if (clean_bnn(*bnn, i)) { + for(const auto& l: *bnn) { + solver->watches.smudge(l); + solver->watches.smudge(~l); + } + if (bnn->out != lit_Undef) { + solver->watches.smudge(bnn->out); + solver->watches.smudge(~bnn->out); + } + bnn->isRemoved = true; +// cout << "Removed BNN" << endl; + } + bnn->undefs = bnn->size(); + bnn->ts = 0; + } +} + +void ClauseCleaner::clean_clauses_inter(vector& cs) +{ + assert(solver->decisionLevel() == 0); + assert(solver->prop_at_head()); + + if (solver->conf.verbosity > 15) { + cout << "Cleaning clauses in vector<>" << endl; + } + + vector::iterator s, ss, end; + size_t at = 0; + for (s = ss = cs.begin(), end = cs.end(); s != end; ++s, ++at) { + if (at + 1 < cs.size()) { + Clause* pre_cl = solver->cl_alloc.ptr(cs[at+1]); + cmsat_prefetch(pre_cl); + } + + const ClOffset off = *s; + Clause& cl = *solver->cl_alloc.ptr(off); + + const Lit origLit1 = cl[0]; + const Lit origLit2 = cl[1]; + const auto origSize = cl.size(); + const bool red = cl.red(); + + if (clean_clause(cl)) { + solver->watches.smudge(origLit1); + solver->watches.smudge(origLit2); + cl.setRemoved(); + if (red) { + solver->litStats.redLits -= origSize; + } else { + solver->litStats.irredLits -= origSize; + } + delayed_free.push_back(off); + } else { + *ss++ = *s; + } + } + cs.resize(cs.size() - (s-ss)); +} + +bool ClauseCleaner::clean_clause(Clause& cl) +{ + //Don't clean if detached. We'll deal with it during re-attach. + if (cl._xor_is_detached) { + return false; + } + + assert(cl.size() > 2); + (*solver->frat) << deldelay << cl << fin; + solver->chain.clear(); + + #ifdef SLOW_DEBUG + uint32_t num_false_begin = 0; + Lit l1 = cl[0]; + Lit l2 = cl[1]; + num_false_begin += solver->value(cl[0]) == l_False; + num_false_begin += solver->value(cl[1]) == l_False; + #endif + + Lit *i, *j, *end; + uint32_t num = 0; + for (i = j = cl.begin(), end = i + cl.size(); i != end; i++, num++) { + lbool val = solver->value(*i); + if (val == l_Undef) { + *j++ = *i; + continue; + } + + if (val == l_True) { + (*solver->frat) << findelay; + return true; + } else { + solver->chain.push_back(solver->unit_cl_IDs[i->var()]); + } + } + + if (i != j) { + const auto orig_ID = cl.stats.ID; + INC_ID(cl); + cl.shrink(i-j); + (*solver->frat) << add << cl << chain << orig_ID; + for(auto const& id: solver->chain) (*solver->frat) << id; + (*solver->frat) << fin << findelay; + } else { + solver->frat->forget_delay(); + } + + assert(cl.size() != 0); + assert(cl.size() != 1); + assert(cl.size() > 1); + assert(solver->value(cl[0]) == l_Undef); + assert(solver->value(cl[1]) == l_Undef); + + #ifdef SLOW_DEBUG + //no l_True, so first 2 of orig must have been l_Undef + if (num_false_begin != 0) { + cout << "val " << l1 << ":" << solver->value(l1) << endl; + cout << "val " << l2 << ":" << solver->value(l2) << endl; + } + assert(num_false_begin == 0 && "Propagation wasn't full? Watch lit was l_False and clause wasn't satisfied"); + #endif + + if (i != j) { + cl.setStrenghtened(); + if (cl.size() == 2) { + solver->attach_bin_clause(cl[0], cl[1], cl.red(), cl.stats.ID); + return true; + } else { + if (cl.red()) { + solver->litStats.redLits -= i-j; + } else { + solver->litStats.irredLits -= i-j; + } + } + } + + return false; +} + +void ClauseCleaner::ImplicitData::update_solver_stats(Solver* solver) +{ + for(const BinaryClause& bincl: toAttach) { + assert(solver->value(bincl.getLit1()) == l_Undef); + assert(solver->value(bincl.getLit2()) == l_Undef); + solver->attach_bin_clause(bincl.getLit1(), + bincl.getLit2(), + bincl.isRed(), + bincl.getID()); + } + + assert(remNonLBin % 2 == 0); + assert(remLBin % 2 == 0); + solver->binTri.irredBins -= remNonLBin/2; + solver->binTri.redBins -= remLBin/2; +} + +void ClauseCleaner::clean_clauses_pre() +{ + assert(solver->watches.get_smudged_list().empty()); + assert(delayed_free.empty()); +} + +void ClauseCleaner::clean_clauses_post() +{ + for(ClOffset off: delayed_free) { + solver->free_cl(off); + } + delayed_free.clear(); +} + +void ClauseCleaner::clean_bnns_post() +{ + for(BNN*& bnn: solver->bnns) { + if (bnn && bnn->isRemoved) { + free(bnn); + bnn = NULL; + } + } +} + +bool ClauseCleaner::remove_and_clean_all() +{ + double myTime = cpuTime(); + assert(solver->okay()); + assert(solver->prop_at_head()); + assert(solver->decisionLevel() == 0); + *solver->frat << __PRETTY_FUNCTION__ << " start\n"; + + size_t last_trail = numeric_limits::max(); + while(last_trail != solver->trail_size()) { + last_trail = solver->trail_size(); + solver->ok = solver->propagate().isNULL(); + if (!solver->okay()) break; + if (!clean_all_xor_clauses()) break; + + clean_implicit_clauses(); + clean_clauses_pre(); + clean_bnns_inter(solver->bnns); + if (!solver->okay()) break; + + clean_clauses_inter(solver->longIrredCls); + for(auto& lredcls: solver->longRedCls) clean_clauses_inter(lredcls); + solver->clean_occur_from_removed_clauses_only_smudged(); + clean_clauses_post(); + clean_bnns_post(); + } + + #ifndef NDEBUG + if (solver->okay()) { + //Once we have cleaned the watchlists + //no watchlist whose lit is set may be non-empty + size_t wsLit = 0; + for(watch_array::const_iterator + it = solver->watches.begin(), end = solver->watches.end() + ; it != end + ; ++it, wsLit++ + ) { + const Lit lit = Lit::toLit(wsLit); + if (solver->value(lit) != l_Undef) { + if (!it->empty()) { + cout << "ERROR watches size: " << it->size() << endl; + for(const auto& w: *it) { + cout << "ERROR w: " << w << endl; + } + } + assert(it->empty()); + } + } + } + #endif + + verb_print(2, "[clean]" << solver->conf.print_times(cpuTime() - myTime)); + *solver->frat << __PRETTY_FUNCTION__ << " end\n"; + + return solver->okay(); +} + + +bool ClauseCleaner::clean_one_xor(Xor& x) +{ + // they encode information (see NOTE in cnf.h) so they MUST be in BDDs + // otherwise FRAT will fail + TBUDDY_DO(if (solver->frat->enabled()) assert(x.bdd)); + + bool rhs = x.rhs; + size_t i = 0; + size_t j = 0; + VERBOSE_PRINT("Trying to clean XOR: " << x); + for(size_t size = x.clash_vars.size(); i < size; i++) { + const auto& v = x.clash_vars[i]; + if (solver->value(v) == l_Undef) { + x.clash_vars[j++] = v; + } + } + x.clash_vars.resize(j); + + i = 0; + j = 0; + for(size_t size = x.size(); i < size; i++) { + uint32_t var = x[i]; + if (solver->value(var) != l_Undef) { + rhs ^= solver->value(var) == l_True; + } else { + x[j++] = var; + } + } + if (j < x.size()) { + x.resize(j); + x.rhs = rhs; + VERBOSE_PRINT("cleaned XOR: " << x); + } + + if (x.size() <= 2) { + solver->frat->flush(); + TBUDDY_DO(delete x.bdd); + TBUDDY_DO(x.bdd = NULL); + } + + switch(x.size()) { + case 0: + if (x.rhs == true) solver->ok = false; + if (!solver->ok) { + assert(solver->unsat_cl_ID == 0); + *solver->frat << add << ++solver->clauseID << fin; + solver->unsat_cl_ID = solver->clauseID; + } + return false; + case 1: { + assert(solver->okay()); + solver->enqueue(Lit(x[0], !x.rhs)); + solver->ok = solver->propagate().isNULL(); + return false; + } + case 2: + assert(solver->okay()); + solver->add_xor_clause_inter(vars_to_lits(x), x.rhs, true); + return false; + default: + return true; + } +} + +bool ClauseCleaner::clean_all_xor_clauses() +{ + assert(solver->okay()); + assert(solver->decisionLevel() == 0); + + size_t last_trail = numeric_limits::max(); + while(last_trail != solver->trail_size()) { + last_trail = solver->trail_size(); + if (!clean_xor_clauses(solver->xorclauses)) return false; + if (!clean_xor_clauses(solver->xorclauses_unused)) return false; + if (!clean_xor_clauses(solver->xorclauses_orig)) return false; + solver->ok = solver->propagate().isNULL(); + } + + // clean up removed_xorclauses_clash_vars + uint32_t j = 0; + for(uint32_t i = 0; i < solver->removed_xorclauses_clash_vars.size(); i++) { + if (solver->value(solver->removed_xorclauses_clash_vars[i]) == l_Undef) { + solver->removed_xorclauses_clash_vars[j++] = solver->removed_xorclauses_clash_vars[i]; + } + } + solver->removed_xorclauses_clash_vars.resize(j); + + return solver->okay(); +} + +bool ClauseCleaner::clean_xor_clauses(vector& xors) +{ + assert(solver->ok); + VERBOSE_DEBUG_DO(for(Xor& x : xors) cout << "orig XOR: " << x << endl); + + size_t last_trail = numeric_limits::max(); + while(last_trail != solver->trail_size()) { + last_trail = solver->trail_size(); + size_t i = 0; + size_t j = 0; + for(size_t size = xors.size(); i < size; i++) { + Xor& x = xors[i]; + if (!solver->okay()) { + xors[j++] = x; + continue; + } + + VERBOSE_PRINT("Checking to keep xor: " << x); + const bool keep = clean_one_xor(x); + if (keep) { + assert(x.size() > 2); + xors[j++] = x; + } else { + solver->removed_xorclauses_clash_vars.insert( + solver->removed_xorclauses_clash_vars.end() + , x.clash_vars.begin() + , x.clash_vars.end() + ); + VERBOSE_PRINT("NOT keeping XOR"); + } + } + xors.resize(j); + if (!solver->okay()) break; + solver->ok = solver->propagate().isNULL(); + } + VERBOSE_PRINT("clean_xor_clauses() finished"); + + return solver-> okay(); +} + +//returns TRUE if removed or solver is UNSAT +bool ClauseCleaner::full_clean(Clause& cl) +{ + (*solver->frat) << deldelay << cl << fin; + + Lit *i = cl.begin(); + Lit *j = i; + for (Lit *end = cl.end(); i != end; i++) { + if (solver->value(*i) == l_True) { + return true; + } + + if (solver->value(*i) == l_Undef) { + *j++ = *i; + } + } + + if (i != j) { + cl.shrink(i-j); + INC_ID(cl); + (*solver->frat) << add << cl << fin << findelay; + } else { + solver->frat->forget_delay(); + return false; + } + + if (cl.size() == 0) { + assert(solver->unsat_cl_ID == 0); + solver->unsat_cl_ID = cl.stats.ID; + solver->ok = false; + return true; + } + + if (cl.size() == 1) { + solver->enqueue(cl[0]); + *solver->frat << del << cl << del; // double unit delete + return true; + } + + if (cl.size() == 2) { + solver->attach_bin_clause(cl[0], cl[1], cl.red(), cl.stats.ID); + return true; + } + + return false; +} diff --git a/cryptominisat/cppsrc/src/clausecleaner.h b/cryptominisat/cppsrc/src/clausecleaner.h new file mode 100644 index 00000000..9e6eba48 --- /dev/null +++ b/cryptominisat/cppsrc/src/clausecleaner.h @@ -0,0 +1,94 @@ +/****************************************** +Copyright (C) 2009-2020 Authors of CryptoMiniSat, see AUTHORS file + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. +***********************************************/ + +#ifndef CLAUSECLEANER_H +#define CLAUSECLEANER_H + +#include "constants.h" +#include "watched.h" +#include "watcharray.h" +#include "clause.h" +#include "xor.h" +#include +using std::vector; + +namespace CMSat { + +class Solver; + +/** +@brief Cleans clauses from false literals & removes satisfied clauses +*/ +class ClauseCleaner +{ + public: + ClauseCleaner(Solver* solver); + + void clean_implicit_clauses(); + bool remove_and_clean_all(); + bool clean_all_xor_clauses(); + bool clean_xor_clauses(vector& xors); + bool clean_clause(Clause& c); + bool full_clean(Clause& cl); + + private: + bool clean_one_xor(Xor& x); + + //Implicit cleaning + struct ImplicitData + { + uint64_t remNonLBin = 0; + uint64_t remLBin = 0; + + //We can only attach these in delayed mode, otherwise we would + //need to manipulate the watchlist we are going through + vector toAttach; + + void update_solver_stats(Solver* solver); + }; + ImplicitData impl_data; + void clean_implicit_watchlist( + watch_subarray& watch_list + , const Lit lit + ); + void clean_binary_implicit( + const Watched* ws + , Watched*& j + , const Lit lit + ); + + void clean_clauses_pre(); + void clean_clauses_post(); + void clean_clauses_inter(vector& cs); + bool clean_bnn(BNN& bnn, uint32_t bnn_idx); + void clean_bnns_inter(vector& bnns); + void clean_bnns_post(); + + bool satisfied(const Watched& watched, Lit lit); + vector delayed_free; + + Solver* solver; +}; + +} //end namespace + +#endif //CLAUSECLEANER_H diff --git a/cryptominisat/cppsrc/src/cloffset.h b/cryptominisat/cppsrc/src/cloffset.h new file mode 100644 index 00000000..04b146d9 --- /dev/null +++ b/cryptominisat/cppsrc/src/cloffset.h @@ -0,0 +1,41 @@ +/************************************************************* +CryptoMiniSat --- Copyright (C) 2009-2020 Authors of CryptoMiniSat, see AUTHORS file + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. +***************************************************************/ + +#ifndef CLAUSEOFFSET_H +#define CLAUSEOFFSET_H + +#include "constants.h" + +namespace CMSat { + +#ifndef LARGE_OFFSETS +typedef uint32_t ClOffset; +#else +typedef uint64_t ClOffset; +#endif +#define CL_OFFSET_MAX (numeric_limits::max()) + + + +} + +#endif //CLAUSEOFFSET_H diff --git a/cryptominisat/cppsrc/src/cms_bosphorus.cpp b/cryptominisat/cppsrc/src/cms_bosphorus.cpp new file mode 100644 index 00000000..e929456a --- /dev/null +++ b/cryptominisat/cppsrc/src/cms_bosphorus.cpp @@ -0,0 +1,135 @@ +/****************************************** +Copyright (C) 2009-2020 Authors of CryptoMiniSat, see AUTHORS file + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. +***********************************************/ + +#include "cms_bosphorus.h" +#include "solver.h" +#include "sqlstats.h" +#include "bosphorus/bosphorus.hpp" +#include "time_mem.h" +#include "bosphorus/solvertypesmini.hpp" + +using namespace CMSat; + + +CMSBosphorus::CMSBosphorus(Solver* _solver) : + solver(_solver) +{} + +CMSBosphorus::~CMSBosphorus() +{ + delete bosph; +} + +void CMSBosphorus::add_clauses() +{ + //Add long clauses + for(const auto& offs: solver->longIrredCls) { + Clause & cl = *solver->cl_alloc.ptr(offs); + bosph->add_dimacs_cl(dimacs, (Bosph::Lit*)cl.getData(), cl.size()); + } + + //Add binary clauses + Lit lits[2]; + for(uint32_t i = 0; i < solver->nVars()*2; i++) { + Lit l = Lit::toLit(i); + lits[0] = l; + for(const auto& w: solver->watches[l]) { + if (w.isBin() && l < w.lit2() && !w.red()) { + lits[1] = w.lit2(); + bosph->add_dimacs_cl(dimacs, (Bosph::Lit*)lits, 2); + } + } + } +} + + +bool CMSBosphorus::doit() +{ + double myTime = cpuTime(); + uint32_t maxiters = 1; + + bosph = new Bosph::Bosphorus; + dimacs = bosph->new_dimacs(); + add_clauses(); + + auto anf = bosph->chunk_dimacs(dimacs); + auto orig_anf = bosph->copy_anf_no_replacer(anf); + + //simplify, etc. + bosph->simplify(anf, NULL, maxiters); + bosph->add_trivial_learnt_from_anf_to_learnt(anf, orig_anf); + bosph->delete_anf(orig_anf); + bosph->deduplicate(); + + auto cnf = bosph->cnf_from_anf_and_cnf(NULL, anf); + auto cls = bosph->get_clauses(cnf); + vector lits; + for(auto x: cls) { + bool use = true; + for(uint32_t i = 0; i < x.size(); i++) { + Bosph::Lit l = x.lits[i]; + if (l.var() >= solver->nVars()) { + use = false; + break; + } + } + if (use) { + lits.clear(); + for(uint32_t i = 0; i < x.size(); i++) { + Bosph::Lit* l = x.lits.data()+i; + lits.push_back(*((Lit*)l)); + } + cout << "c adding bosph cl: " << lits << endl; + Clause* cl = solver->add_clause_int( + lits //Literals in new clause + , true //Is the new clause redundant? + ); + if (cl) { + cl->stats.glue = 2; + auto cloffset = solver->cl_alloc.get_offset(cl); + solver->longRedCls[0].push_back(cloffset); + } + if (!solver->okay()) { + break; + } + } + } + bosph->delete_dimacs(dimacs); + + // Finish up + double time_used = cpuTime() - myTime; + if (solver->conf.verbosity) { + cout << "c [bosph] finished " + << solver->conf.print_times(time_used) + << endl; + } + + if (solver->sqlStats) { + solver->sqlStats->time_passed_min( + solver + , "bosph" + , time_used + ); + } + + return solver->okay(); +} diff --git a/cryptominisat/cppsrc/src/cms_bosphorus.h b/cryptominisat/cppsrc/src/cms_bosphorus.h new file mode 100644 index 00000000..51062fbd --- /dev/null +++ b/cryptominisat/cppsrc/src/cms_bosphorus.h @@ -0,0 +1,54 @@ +/****************************************** +Copyright (C) 2009-2020 Authors of CryptoMiniSat, see AUTHORS file + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. +***********************************************/ + +#ifndef CMS_BOSPHORUS_H +#define CMS_BOSPHORUS_H + +#include + +namespace Bosph { + class Bosphorus; + class DIMACS; +} + +namespace CMSat { + +class Solver; + +class CMSBosphorus +{ +public: + CMSBosphorus(Solver* _solver); + ~CMSBosphorus(); + bool doit(); + +private: + void add_clauses(); + + Solver* solver; + Bosph::Bosphorus* bosph = nullptr; + Bosph::DIMACS* dimacs = nullptr; +}; + +} + +#endif diff --git a/cryptominisat/cppsrc/src/cms_breakid.cpp b/cryptominisat/cppsrc/src/cms_breakid.cpp new file mode 100644 index 00000000..6f80d078 --- /dev/null +++ b/cryptominisat/cppsrc/src/cms_breakid.cpp @@ -0,0 +1,482 @@ +/****************************************** +Copyright (C) 2009-2020 Authors of CryptoMiniSat, see AUTHORS file + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. +***********************************************/ + +#include "constants.h" +#include "cms_breakid.h" +#include "solver.h" +#include "clausecleaner.h" +#include "breakid/breakid.hpp" +#include "varupdatehelper.h" +#include "varreplacer.h" +#include "occsimplifier.h" +#include "subsumeimplicit.h" +#include "sqlstats.h" +#include "completedetachreattacher.h" + +using namespace CMSat; + +BreakID::BreakID(Solver* _solver): + solver(_solver) +{ +} + +void BreakID::updateVars( + const vector& outerToInter + , const vector& /*interToOuter*/) +{ + if (symm_var != var_Undef) { + symm_var = getUpdatedVar(symm_var, outerToInter); + } +} + +template +BreakID::add_cl_ret BreakID::add_this_clause(const T& cl) +{ + uint32_t sz = 0; + bool sat = false; + brkid_lits.clear(); + for(size_t i3 = 0; i3 < cl.size(); i3++) { + Lit lit = cl[i3]; + assert(solver->varData[lit.var()].removed == Removed::none); + lbool val = l_Undef; + if (solver->value(lit) != l_Undef) { + val = solver->value(lit); + } else { + val = solver->lit_inside_assumptions(lit); + } + + if (val == l_True) { + //clause is SAT, skip! + sat = true; + continue; + } else if (val == l_False) { + continue; + } + brkid_lits.push_back(lit); + sz++; + } + if (sat) { + return add_cl_ret::skipped_cl; + } + if (sz == 0) { + //it's unsat because of assumptions + if (solver->conf.verbosity) { + cout << "c [breakid] UNSAT because of assumptions in clause: " << cl << endl; + } + return add_cl_ret::unsat; + } + + num_lits_in_graph += brkid_lits.size(); + breakid->add_clause((BID::BLit*)brkid_lits.data(), brkid_lits.size()); + brkid_lits.clear(); + + return add_cl_ret::added_cl; +} + +struct EqCls { + EqCls(ClauseAllocator& _alloc) : + cl_alloc(_alloc) + {} + + bool operator()(ClOffset off1, ClOffset off2) { + Clause* cl1 = cl_alloc.ptr(off1); + Clause* cl2 = cl_alloc.ptr(off2); + + if (cl1->stats.hash_val != cl2->stats.hash_val) { + return cl1->stats.hash_val < cl2->stats.hash_val; + } + + if (cl1->size() != cl2->size()) { + return cl1->size() < cl2->size(); + } + + //same hash, same size + for(uint32_t i = 0; i < cl1->size(); i++) { + if (cl1->getData()[i] != cl2->getData()[i]) { + return (cl1->getData()[i] < cl2->getData()[i]); + } + } + + //they are equivalent + return false; + } + + ClauseAllocator& cl_alloc; +}; + +static bool equiv(Clause* cl1, Clause* cl2) { + if (cl1->stats.hash_val != cl2->stats.hash_val) { + return false; + } + + if (cl1->size() != cl2->size()) { + return false; + } + + for(uint32_t i = 0; i < cl1->size(); i++) { + if (cl1->getData()[i] != cl2->getData()[i]) { + return false; + } + } + + return true; +} + +void BreakID::set_up_time_lim() +{ + set_time_lim = solver->conf.breakid_time_limit_K; + if (solver->nVars() < 5000) { + set_time_lim*=2; + } + if (num_lits_in_graph < 100000) { + set_time_lim*=2; + } + + set_time_lim *= 1000LL; + if (solver->conf.verbosity) { + cout << "c [breakid] set time lim: " << set_time_lim << endl; + } + + breakid->set_steps_lim(set_time_lim); +} + +bool BreakID::add_clauses() +{ + //Add binary clauses + vector this_clause; + for(size_t i2 = 0; i2 < solver->nVars()*2; i2++) { + Lit lit = Lit::toLit(i2); + for(const Watched& w: solver->watches[lit]) { + if (w.isBin() && !w.red() && lit < w.lit2()) { + this_clause.clear(); + this_clause.push_back(lit); + this_clause.push_back(w.lit2()); + + if (add_this_clause(this_clause) == add_cl_ret::unsat) { + return false; + } + } + } + } + + //Add long clauses + for(ClOffset offs: dedup_cls) { + const Clause* cl = solver->cl_alloc.ptr(offs); + assert(!cl->freed()); + assert(!cl->getRemoved()); + + if (add_this_clause(*cl) == add_cl_ret::unsat) { + return false; + } + } + + return true; +} + +bool BreakID::doit() +{ + assert(solver->okay()); + assert(solver->decisionLevel() == 0); + assert(!solver->frat->enabled()); + num_lits_in_graph = 0; + + if (!solver->conf.doStrSubImplicit) { + verb_print(1, "[breakid] cannot run BreakID without implicit submsumption, it would find too many (bad) symmetries"); + return solver->okay(); + } + + if (solver->check_assumptions_contradict_foced_assignment()) { + verb_print(1, "[breakid] forced assignments contradicted by assumptions, cannot run"); + return solver->okay(); + } + + if (!check_limits()) return solver->okay(); + if (!solver->clauseCleaner->remove_and_clean_all()) return solver->okay(); + + // Clean up solver state so it's easier to find symmetries + solver->subsumeImplicit->subsume_implicit(false, "-breakid"); + CompleteDetachReatacher reattacher(solver); + reattacher.detach_nonbins(); + remove_duplicates(); + double myTime = cpuTime(); + assert(breakid == NULL); + breakid = new BID::BreakID; + breakid->set_verbosity(0); + breakid->set_useMatrixDetection(solver->conf.breakid_matrix_detect); + breakid->set_symBreakingFormLength(solver->conf.breakid_max_constr_per_permut); + breakid->start_dynamic_cnf(solver->nVars()); + verb_print(1, "[breakid] version " << breakid->get_sha1_version()); + + // We can fail adding clauses if they are UNSAT under the current assumptions + if (!add_clauses()) { + delete breakid; + breakid = NULL; + + bool ok = reattacher.reattachLongs(); + assert(ok); + return solver->okay(); + } + + // Detect symmetries, detect subgroups + set_up_time_lim(); + breakid->end_dynamic_cnf(); + verb_print(1, "[breakid] Generators: " << breakid->get_num_generators()); + if (solver->conf.verbosity > 3) breakid->print_generators(std::cout); + verb_print(2, "[breakid] Detecting subgroups..."); + breakid->detect_subgroups(); + if (solver->conf.verbosity > 3) breakid->print_subgroups(cout); + + // Break symmetries, in BreakID + breakid->break_symm(); + + //reattach clauses + bool ok = reattacher.reattachLongs(); + assert(ok); + + // Break symmetries in CMS, given clauses given by BreakID + if (breakid->get_num_break_cls() != 0) break_symms_in_cms(); + + // Not needed actually, only for debug + //get_outer_permutations(); + + // Finish up + double time_used = cpuTime() - myTime; + int64_t remain = breakid->get_steps_remain(); + bool time_out = remain <= 0; + double time_remain = float_div(remain, set_time_lim); + if (solver->conf.verbosity) { + cout << "c [breakid] finished " + << solver->conf.print_times(time_used, time_out, time_remain) + << endl; + } + if (solver->sqlStats) { + solver->sqlStats->time_passed( + solver + , "breakid" + , time_used + , time_out + , time_remain + ); + } + + delete breakid; + breakid = NULL; + + return solver->okay(); +} + +void BreakID::get_outer_permutations() +{ + vector> perms_inter; + breakid->get_perms(&perms_inter); + for(const auto& p: perms_inter) { + unordered_map outer; + for(const auto& mymap: p) { + Lit from = Lit::toLit(mymap.first.toInt()); + Lit to = Lit::toLit(mymap.second.toInt()); + + from = solver->map_inter_to_outer(from); + to = solver->map_inter_to_outer(to); + + outer[from] = to; + } + perms_outer.push_back(outer); + } +} + +bool BreakID::check_limits() +{ + uint64_t tot_num_cls = solver->longIrredCls.size()+solver->binTri.irredBins; + uint64_t tot_num_lits = solver->litStats.irredLits + solver->binTri.irredBins*2; + if (solver->nVars() > solver->conf.breakid_vars_limit_K*1000ULL) { + if (solver->conf.verbosity) { + cout + << "c [breakid] max var limit exceeded, not running." + << " Num vars: " << print_value_kilo_mega(solver->nVars(), false) + << endl; + } + return false; + } + + if (tot_num_cls > solver->conf.breakid_cls_limit_K*1000ULL) { + if (solver->conf.verbosity) { + cout + << "c [breakid] max clause limit exceeded, not running." + << " Num clauses: " << print_value_kilo_mega(tot_num_cls, false) + << endl; + } + return false; + } + if (tot_num_lits > solver->conf.breakid_lits_limit_K*1000ULL) { + if (solver->conf.verbosity) { + cout + << "c [breakid] max literals limit exceeded, not running." + << " Num lits: " << print_value_kilo_mega(tot_num_lits, false) + << endl; + } + return false; + } + + return true; +} + +void BreakID::remove_duplicates() +{ + double myTime = cpuTime(); + dedup_cls.clear(); + + for(ClOffset offs: solver->longIrredCls) { + Clause* cl = solver->cl_alloc.ptr(offs); + assert(!cl->freed()); + assert(!cl->getRemoved()); + assert(!cl->red()); + std::sort(cl->begin(), cl->end()); + cl->stats.hash_val = hash_clause(cl->getData(), cl->size()); + dedup_cls.push_back(offs); + } + + std::sort(dedup_cls.begin(), dedup_cls.end(), EqCls(solver->cl_alloc)); + + size_t old_size = dedup_cls.size(); + if (dedup_cls.size() > 1 && true) { + vector::iterator prev = dedup_cls.begin(); + vector::iterator i = dedup_cls.begin(); + ++i; + Clause* prevcl = solver->cl_alloc.ptr(*prev); + for(vector::iterator end = dedup_cls.end(); i != end; ++i) { + Clause* cl = solver->cl_alloc.ptr(*i); + if (!equiv(cl, prevcl)) { + ++prev; + *prev = *i; + prevcl = cl; + } + } + ++prev; + dedup_cls.resize(prev-dedup_cls.begin()); + } + + double time_used = cpuTime() - myTime; + if (solver->conf.verbosity >= 1) { + cout << "c [breakid] tmp-rem-dup cls" + << " dupl: " << print_value_kilo_mega(old_size-dedup_cls.size(), false) + << solver->conf.print_times(time_used) + << endl; + } + if (solver->sqlStats) { + solver->sqlStats->time_passed_min( + solver + , "breakid-rem-dup" + , time_used + ); + } +} + +void BreakID::break_symms_in_cms() +{ + if (solver->conf.verbosity) { + cout << "c [breakid] Breaking cls: "<< breakid->get_num_break_cls() << endl; + cout << "c [breakid] Aux vars: "<< breakid->get_num_aux_vars() << endl; + } + for(uint32_t i = 0; i < breakid->get_num_aux_vars(); i++) solver->new_var(true); + if (solver->conf.breakid_use_assump) { + if (symm_var == var_Undef) { + solver->new_var(true); + symm_var = solver->nVars()-1; + solver->add_assumption(Lit(symm_var, true)); + } + assert(solver->varData[symm_var].removed == Removed::none); + } + + auto brk = breakid->get_brk_cls(); + for (const auto& cl: brk) { + vector* cl2 = (vector*)&cl; + if (solver->conf.breakid_use_assump) { + cl2->push_back(Lit(symm_var, false)); + } + for(const Lit& l: *cl2) { + assert(l.var() < solver->nVars()); + if (solver->conf.breakid_use_assump) { + assert(solver->value(l) == l_Undef); + } + } + Clause* newcl = solver->add_clause_int(*cl2 + , false //redundant + , NULL //stats + , true //attach + , NULL //return simplified + , true + , Lit(symm_var, false) + ); + if (newcl != NULL) { + ClOffset offset = solver->cl_alloc.get_offset(newcl); + solver->longIrredCls.push_back(offset); + } + } +} + +void BreakID::finished_solving() +{ + //Nothing actually +} + +void BreakID::start_new_solving() +{ + assert(solver->decisionLevel() == 0); + assert(solver->okay()); + if (symm_var == var_Undef) { + return; + } + + assert(solver->varData[symm_var].removed == Removed::none); + assert(solver->value(symm_var) != l_False + && "The symm var can never be foreced to FALSE, logic error"); + + //In certain conditions, in particular when the problem is UNSAT + //the symmetry assumption var can be forced to TRUE at level 0 + if (solver->value(symm_var) == l_True) { + symm_var = var_Undef; + return; + } + + assert(solver->value(symm_var) == l_Undef); + solver->enqueue(Lit(symm_var, false)); + PropBy ret = solver->propagate(); + assert(ret == PropBy() && "Must not fail on resetting symmetry var"); + symm_var = var_Undef; +} + + +void BreakID::update_var_after_varreplace() +{ + if (symm_var != var_Undef) { + symm_var = solver->varReplacer->get_var_replaced_with(symm_var); + } +} + +Lit BreakID::get_assumed_lit() const +{ + if (symm_var == var_Undef) { + return lit_Undef; + } else { + return Lit(symm_var, true); + } +} diff --git a/cryptominisat/cppsrc/src/cms_breakid.h b/cryptominisat/cppsrc/src/cms_breakid.h new file mode 100644 index 00000000..5d6deea2 --- /dev/null +++ b/cryptominisat/cppsrc/src/cms_breakid.h @@ -0,0 +1,92 @@ +/****************************************** +Copyright (C) 2009-2020 Authors of CryptoMiniSat, see AUTHORS file + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. +***********************************************/ + +#ifndef CMS_BREAKID_H +#define CMS_BREAKID_H + +#include +#include +#include "solvertypes.h" +#include "cloffset.h" + +using std::vector; +using std::unordered_map; + +namespace BID { +class BreakID; +} + +namespace CMSat { + +class Solver; + +class BreakID { +public: + BreakID(Solver* solver); + bool doit(); + void finished_solving(); + void start_new_solving(); + void updateVars( + const vector& outerToInter + , const vector& interToOuter); + void update_var_after_varreplace(); + Lit get_assumed_lit() const; + + static uint32_t hash_clause(const Lit* lits, const uint32_t size) { + uint32_t seed = size; + for(uint32_t i = 0; i < size; i++) { + uint32_t val = lits[i].toInt(); + seed ^= val + 0x9e3779b9 + (val << 6) + (val >> 2); + } + return seed; + } + +private: + void break_symms_in_cms(); + void get_outer_permutations(); + void remove_duplicates(); + void set_up_time_lim(); + bool add_clauses(); + bool check_limits(); + + enum class add_cl_ret {added_cl, skipped_cl, unsat}; + template + add_cl_ret add_this_clause(const T& cl); + vector brkid_lits; + + ///Valid permutations. Contains outer lits + vector > perms_outer; + + bool already_called = false; + //variable that is to be assumed to break symmetries + uint32_t symm_var = var_Undef; + int64_t set_time_lim; + uint64_t num_lits_in_graph; + vector dedup_cls; + + Solver* solver; + BID::BreakID* breakid = NULL; +}; + +} + +#endif diff --git a/cryptominisat/cppsrc/src/cms_windows_includes.h b/cryptominisat/cppsrc/src/cms_windows_includes.h new file mode 100644 index 00000000..361391c5 --- /dev/null +++ b/cryptominisat/cppsrc/src/cms_windows_includes.h @@ -0,0 +1,65 @@ +/****************************************** +Copyright (C) 2022 Axel Kemper (27-Sep-2022) + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. +***********************************************/ + +#pragma once + +#if _MSC_VER +#define _CRT_SECURE_NO_WARNINGS +#define _SCL_SECURE_NO_WARNINGS + +#include +#include "stdint.h" + +#if !defined(INTMAX_MAX) +#define INTMAX_MAX _I32_MAX +#endif + +#pragma warning(disable : 4244) // C4244 : 'Argument': Konvertierung von 'const uint64_t' in 'double', möglicher Datenverlust +#pragma warning(disable : 4267) // C4267 : 'return': Konvertierung von 'size_t' nach 'uint32_t', Datenverlust möglich +#pragma warning(disable : 4302) // C4302 : truncation +#pragma warning(disable : 4305) // C4302 : truncation double to float +#pragma warning(disable : 4311) // C4311 : pointer truncation +#pragma warning(disable : 4312) // C4312 : conversion from .. of greater size +#pragma warning(disable : 4789) // C4789 : buffer '' of size xx bytes will be overrun; + +#pragma warning(disable : 4800) // C4800 : 'const uint32_t' : Variable wird auf booleschen Wert('True' oder 'False') gesetzt(Auswirkungen auf Leistungsverhalten möglich) +#pragma warning(disable : 4805) // C4805 : '==' : unsichere Kombination von Typ 'unsigned short' mit Typ 'bool' in einer Operation +#pragma warning(disable : 4996) // C4996 : deprecated +#pragma warning(disable : 26495) // Always initialize a member variable +#pragma warning(disable : 26819) // Unannotated fallthrough between switch labels + + + +#if !defined(__PRETTY_FUNCTION__) && !defined(__GNUC__) +#define __PRETTY_FUNCTION__ __FUNCSIG__ +#endif + +#define __builtin_popcountll __popcnt64 +#define NO_DLL_EXPORT 1 + +// picosat +#define isatty(x) _isatty(x) +#define NO_USE_GZ 1 +#define NO_USE_PIPES 1 +#define NALLSIGNALS 1 + +#endif diff --git a/cryptominisat/cppsrc/src/cnf.cpp b/cryptominisat/cppsrc/src/cnf.cpp new file mode 100644 index 00000000..4e8e0287 --- /dev/null +++ b/cryptominisat/cppsrc/src/cnf.cpp @@ -0,0 +1,1020 @@ +/****************************************** +Copyright (C) 2009-2020 Authors of CryptoMiniSat, see AUTHORS file + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. +***********************************************/ + +#include "cnf.h" + +#include + +#include "vardata.h" +#include "solvertypes.h" +#include "clauseallocator.h" +#include "watchalgos.h" +#include "varupdatehelper.h" +#include "time_mem.h" + +using namespace CMSat; + +void CNF::new_var( + const bool bva, + const uint32_t orig_outer, + const bool /*insert_varorder*/) +{ + if (nVars() >= 1ULL<<28) { + cout << "ERROR! Variable requested is far too large" << endl; + throw std::runtime_error("ERROR! Variable requested is far too large"); + } + + minNumVars++; + enlarge_minimal_datastructs(); + if (orig_outer == numeric_limits::max()) { + //completely new var + enlarge_nonminimial_datastructs(); + + uint32_t minVar = nVars()-1; + uint32_t maxVar = nVarsOuter()-1; + interToOuterMain.push_back(maxVar); + const uint32_t x = interToOuterMain[minVar]; + interToOuterMain[minVar] = maxVar; + interToOuterMain[maxVar] = x; + + outerToInterMain.push_back(maxVar); + outerToInterMain[maxVar] = minVar; + outerToInterMain[x] = maxVar; + + swapVars(nVarsOuter()-1); + varData[nVars()-1].is_bva = bva; + if (bva) { + num_bva_vars ++; + } else { + outer_to_with_bva_map.push_back(nVarsOuter() - 1); + } + } else { + //Old var, re-inserted + assert(orig_outer < nVarsOuter()); + + const uint32_t minVar = nVars()-1; + uint32_t k = interToOuterMain[minVar]; + uint32_t z = outerToInterMain[orig_outer]; + interToOuterMain[minVar] = orig_outer; + interToOuterMain[z] = k; + + outerToInterMain[k] = z; + outerToInterMain[orig_outer] = minVar; + + swapVars(z); + } + + #ifdef SLOW_DEBUG + test_reflectivity_of_renumbering(); + #endif +} + +void CNF::new_vars(const size_t n) +{ + if (nVars() + n >= 1ULL<<28) { + cout << "ERROR! Variable requested is far too large" << endl; + std::exit(-1); + } + + minNumVars += n; + enlarge_minimal_datastructs(n); + enlarge_nonminimial_datastructs(n); + + size_t inter_at = interToOuterMain.size(); + interToOuterMain.insert(interToOuterMain.end(), n, 0); + + size_t outer_at = outerToInterMain.size(); + outerToInterMain.insert(outerToInterMain.end(), n, 0); + + size_t outer_to_with_bva_at = outer_to_with_bva_map.size(); + outer_to_with_bva_map.insert(outer_to_with_bva_map.end(), n, 0); + + for(int i = n-1; i >= 0; i--) { + const uint32_t minVar = nVars()-i-1; + const uint32_t maxVar = nVarsOuter()-i-1; + + interToOuterMain[inter_at++] = maxVar; + const uint32_t x = interToOuterMain[minVar]; + interToOuterMain[minVar] = maxVar; + interToOuterMain[maxVar] = x; + + outerToInterMain[outer_at++] = maxVar; + outerToInterMain[maxVar] = minVar; + outerToInterMain[x] = maxVar; + + swapVars(nVarsOuter()-i-1, i); + varData[nVars()-i-1].is_bva = false; + outer_to_with_bva_map[outer_to_with_bva_at++] = nVarsOuter()-i-1; + } + + #ifdef SLOW_DEBUG + test_reflectivity_of_renumbering(); + #endif +} + +void CNF::swapVars(const uint32_t which, const int off_by) +{ + std::swap(assigns[nVars()-off_by-1], assigns[which]); + std::swap(varData[nVars()-off_by-1], varData[which]); +} + +void CNF::enlarge_nonminimial_datastructs(size_t n) +{ + assigns.insert(assigns.end(), n, l_Undef); + unit_cl_IDs.insert(unit_cl_IDs.end(), n, 0); + varData.insert(varData.end(), n, VarData()); + depth.insert(depth.end(), n, 0); +} + +void CNF::enlarge_minimal_datastructs(size_t n) +{ + watches.insert(2*n); + gwatches.insert(2*n); + seen.insert(seen.end(), 2*n, 0); + seen2.insert(seen2.end(), 2*n, 0); + permDiff.insert(permDiff.end(), 2*n, 0); +} + +void CNF::save_on_var_memory() +{ + //never resize varData --> contains info about what is replaced/etc. + //never resize assigns --> contains 0-level assigns + //never resize interToOuterMain, outerToInterMain + + watches.resize(nVars()*2); + watches.consolidate(); + gwatches.resize(nVars()*2); + + for(auto& l: longRedCls) { + l.shrink_to_fit(); + } + longIrredCls.shrink_to_fit(); + + seen.resize(nVars()*2); + seen.shrink_to_fit(); + seen2.resize(nVars()*2); + seen2.shrink_to_fit(); + permDiff.resize(nVars()*2); + permDiff.shrink_to_fit(); +} + +//Test for reflectivity of interToOuterMain & outerToInterMain +void CNF::test_reflectivity_of_renumbering() const +{ + vector test(nVarsOuter()); + for(size_t i = 0; i < nVarsOuter(); i++) { + test[i] = i; + } + updateArrayRev(test, interToOuterMain); + #ifdef DEBUG_RENUMBER + for(size_t i = 0; i < nVarsOuter(); i++) { + cout << i << ": " + << std::setw(2) << test[i] << ", " + << std::setw(2) << outerToInterMain[i] + << endl; + } + #endif + + for(size_t i = 0; i < nVarsOuter(); i++) { + assert(test[i] == outerToInterMain[i]); + } + #ifdef DEBUG_RENUMBR + cout << "Passed test" << endl; + #endif +} + +inline void CNF::updateWatch( + watch_subarray ws + , const vector& outerToInter +) { + for(Watched *it = ws.begin(), *end = ws.end() + ; it != end + ; ++it + ) { + if (it->isBin()) { + it->setLit2( + getUpdatedLit(it->lit2(), outerToInter) + ); + continue; + } + + if (it->isBNN()) { + continue; + } + + assert(it->isClause()); + const Clause &cl = *cl_alloc.ptr(it->get_offset()); + Lit blocked_lit = it->getBlockedLit(); + blocked_lit = getUpdatedLit(it->getBlockedLit(), outerToInter); + bool found = false; + for(Lit lit: cl) { + if (lit == blocked_lit) { + found = true; + break; + } + } + if (!found) { + it->setElimedLit(cl[2]); + } else { + it->setElimedLit(blocked_lit); + } + } +} + +void CNF::updateVars( + const vector& outerToInter + , const vector& interToOuter + , const vector& interToOuter2 +) { + updateArray(varData, interToOuter); + updateArray(assigns, interToOuter); + updateArray(unit_cl_IDs, interToOuter); + updateBySwap(watches, seen, interToOuter2); + + for(watch_subarray w: watches) { + if (!w.empty()) + updateWatch(w, outerToInter); + } + + updateArray(interToOuterMain, interToOuter); + updateArrayMapCopy(outerToInterMain, outerToInter); +} + +uint64_t CNF::mem_used_longclauses() const +{ + uint64_t mem = 0; + mem += cl_alloc.mem_used(); + mem += longIrredCls.capacity()*sizeof(ClOffset); + for(auto& l: longRedCls) { + mem += l.capacity()*sizeof(ClOffset); + } + return mem; +} + +uint64_t CNF::print_mem_used_longclauses(const size_t totalMem) const +{ + uint64_t mem = mem_used_longclauses(); + print_stats_line("c Mem for longclauses" + , mem/(1024UL*1024UL) + , "MB" + , stats_line_percent(mem, totalMem) + , "%" + ); + + return mem; +} + +size_t CNF::cl_size(const Watched& ws) const +{ + switch(ws.getType()) { + case WatchType::watch_binary_t: + return 2; + + case WatchType::watch_clause_t: { + const Clause* cl = cl_alloc.ptr(ws.get_offset()); + return cl->size(); + } + + default: + assert(false); + return 0; + } +} + +string CNF::watches_to_string(const Lit lit, watch_subarray_const ws) const +{ + std::stringstream ss; + for(Watched w: ws) { + ss << watched_to_string(lit, w) << " -- "; + } + return ss.str(); +} + +string CNF::watched_to_string(Lit otherLit, const Watched& ws) const +{ + std::stringstream ss; + switch(ws.getType()) { + case WatchType::watch_binary_t: + ss << otherLit << ", " << ws.lit2(); + if (ws.red()) { + ss << "(red)"; + } + break; + + case WatchType::watch_clause_t: { + const Clause* cl = cl_alloc.ptr(ws.get_offset()); + for(size_t i = 0; i < cl->size(); i++) { + ss << (*cl)[i]; + if (i + 1 < cl->size()) + ss << ", "; + } + if (cl->red()) { + ss << "(red)"; + } + break; + } + + default: + assert(false); + break; + } + + return ss.str(); +} + +bool ClauseSizeSorter::operator () (const ClOffset x, const ClOffset y) +{ + Clause* cl1 = cl_alloc.ptr(x); + Clause* cl2 = cl_alloc.ptr(y); + return (cl1->size() < cl2->size()); +} + +size_t CNF::mem_used_renumberer() const +{ + size_t mem = 0; + mem += interToOuterMain.capacity()*sizeof(uint32_t); + mem += outerToInterMain.capacity()*sizeof(uint32_t); + mem += outer_to_with_bva_map.capacity()*sizeof(uint32_t); + return mem; +} + +vector CNF::build_outer_to_without_bva_map() const +{ + vector ret; + size_t at = 0; + for(size_t i = 0; i < nVarsOuter(); i++) { + if (!varData[map_outer_to_inter(i)].is_bva) { + ret.push_back(at); + at++; + } else { + ret.push_back(var_Undef); + } + } + + return ret; +} + +// ONLY used during getting clauses for external uses. NOT sane +vector CNF::build_outer_to_without_bva_map_extended() const +{ + assert(nVarsOutside() <= nVarsOuter()); + vector ret; + size_t at = 0; + uint32_t extra_map = nVarsOutside(); + for(size_t i = 0; i < nVarsOuter(); i++) { + if (!varData[map_outer_to_inter(i)].is_bva) { + ret.push_back(at); + at++; + } else { + ret.push_back(extra_map); + extra_map++; + } + } + assert(extra_map == nVarsOuter()); + + return ret; +} + +size_t CNF::mem_used() const +{ + size_t mem = 0; + mem += sizeof(conf); + mem += sizeof(binTri); + mem += seen.capacity()*sizeof(uint16_t); + mem += seen2.capacity()*sizeof(uint8_t); + mem += toClear.capacity()*sizeof(Lit); + + return mem; +} + +void CNF::test_all_clause_attached() const +{ + test_all_clause_attached(longIrredCls); + for(const vector& l: longRedCls) { + test_all_clause_attached(l); + } +} + +void CNF::test_all_clause_attached(const vector& offsets) const +{ + for (vector::const_iterator + it = offsets.begin(), end = offsets.end() + ; it != end + ; ++it + ) { + assert(normClauseIsAttached(*it)); + } +} + +bool CNF::normClauseIsAttached(const ClOffset offset) const +{ + bool attached = true; + const Clause& cl = *cl_alloc.ptr(offset); + assert(cl.size() > 2); + + attached &= findWCl(watches[cl[0]], offset); + attached &= findWCl(watches[cl[1]], offset); + + if (detached_xor_clauses && cl._xor_is_detached) { + //We expect this NOT to be attached, actually. + if (attached) { + cout + << "Failed. XOR-representing clause is NOT supposed to be attached" + << " clause: " << cl + << " _xor_is_detached: " << cl._xor_is_detached + << " detached_xor_clauses: " << detached_xor_clauses + << endl; + } + return !attached; + } + + bool satcl = satisfied(cl); + uint32_t num_false2 = 0; + num_false2 += value(cl[0]) == l_False; + num_false2 += value(cl[1]) == l_False; + if (!satcl) { + if (num_false2 != 0) { + cout << "Clause failed: " << cl << endl; + for(Lit l: cl) { + cout << "val " << l << " : " << value(l) << endl; + } + for(const Watched& w: watches[cl[0]]) { + cout << "watch " << cl[0] << endl; + if (w.isClause() && w.get_offset() == offset) { + cout << "Block lit: " << w.getBlockedLit() + << " val: " << value(w.getBlockedLit()) << endl; + } + } + for(const Watched& w: watches[cl[1]]) { + cout << "watch " << cl[1] << endl; + if (w.isClause() && w.get_offset() == offset) { + cout << "Block lit: " << w.getBlockedLit() + << " val: " << value(w.getBlockedLit()) << endl; + } + } + } + assert(num_false2 == 0 && "propagation was not full??"); + } + + return attached; +} + +void CNF::find_all_attach() const +{ + for (size_t i = 0; i < watches.size(); i++) { + const Lit lit = Lit::toLit(i); + for (uint32_t i2 = 0; i2 < watches[lit].size(); i2++) { + const Watched& w = watches[lit][i2]; + if (!w.isClause()) + continue; + + //Get clause + Clause* cl = cl_alloc.ptr(w.get_offset()); + assert(!cl->freed()); + + bool satcl = satisfied(*cl); + if (!satcl) { + if (value(w.getBlockedLit()) == l_True) { + cout << "ERROR: Clause " << *cl << " not satisfied, but its blocked lit, " + << w.getBlockedLit() << " is." << endl; + } + assert(value(w.getBlockedLit()) != l_True && "Blocked lit is satisfied but clause is NOT!!"); + } + + //Assert watch correctness + if ((*cl)[0] != lit + && (*cl)[1] != lit + ) { + std::cerr + << "ERROR! Clause " << (*cl) + << " not attached?" + << endl; + + assert(false); + std::exit(-1); + } + + //Clause in one of the lists + if (!find_clause(w.get_offset())) { + std::cerr + << "ERROR! did not find clause " << *cl + << endl; + + assert(false); + std::exit(1); + } + } + } + + find_all_attach(longIrredCls); + for(auto& lredcls: longRedCls) { + find_all_attach(lredcls); + } +} + +void CNF::find_all_attach(const vector& cs) const +{ + for(vector::const_iterator + it = cs.begin(), end = cs.end() + ; it != end + ; ++it + ) { + Clause& cl = *cl_alloc.ptr(*it); + bool should_be_attached = true; + if (detached_xor_clauses && cl._xor_is_detached) { + should_be_attached = false; + } + bool ret = findWCl(watches[cl[0]], *it); + if (ret != should_be_attached) { + cout + << "Clause " << cl + << " (red: " << cl.red() + << " used in xor: " << cl.used_in_xor() + << " detached xor: " << cl._xor_is_detached + << " should be attached: " << should_be_attached + << " )"; + if (ret) { + cout << " doesn't have its 1st watch attached!"; + } else { + cout << " HAS its 1st watch attached (but it should NOT)!"; + } + cout << endl; + + assert(false); + std::exit(-1); + } + + ret = findWCl(watches[cl[1]], *it); + if (ret != should_be_attached) { + cout + << "Clause " << cl + << " (red: " << cl.red() + << " used in xor: " << cl.used_in_xor() + << " detached xor: " << cl._xor_is_detached + << " should be attached: " << should_be_attached + << " )"; + if (ret) { + cout << " doesn't have its 2nd watch attached!"; + } else { + cout << " HAS its 2nd watch attached (but it should NOT)!"; + } + cout << endl; + + assert(false); + std::exit(-1); + } + } +} + + +bool CNF::find_clause(const ClOffset offset) const +{ + for (uint32_t i = 0; i < longIrredCls.size(); i++) { + if (longIrredCls[i] == offset) + return true; + } + + for(auto& lredcls: longRedCls) { + for (ClOffset off: lredcls) { + if (off == offset) + return true; + } + } + + return false; +} + +void CNF::check_wrong_attach() const +{ +#ifdef SLOW_DEBUG + for(auto& lredcls: longRedCls) { + for (ClOffset offs: lredcls) { + const Clause& cl = *cl_alloc.ptr(offs); + for (uint32_t i = 0; i < cl.size(); i++) { + if (i > 0) + assert(cl[i-1].var() != cl[i].var()); + } + } + } + for(watch_subarray_const ws: watches) { + check_watchlist(ws); + } +#endif +} + +void CNF::check_watchlist(watch_subarray_const ws) const +{ + for(const Watched& w: ws) { + if (!w.isClause()) { + continue; + } + + const ClOffset offs = w.get_offset(); + const Clause& c = *cl_alloc.ptr(offs); + Lit blockedLit = w.getBlockedLit(); + /*cout << "Clause " << c << " blocked lit: "<< blockedLit << " val: " << value(blockedLit) + << " blocked removed:" << !(varData[blockedLit.var()].removed == Removed::none) + << " cl satisfied: " << satisfied(&c) + << endl;*/ + assert(blockedLit.var() < nVars()); + + if (varData[blockedLit.var()].removed == Removed::none + //0-level FALSE --> clause cleaner removed it from clause, that's OK + && value(blockedLit) != l_False + && !satisfied(c) + ) { + bool found = false; + for(Lit l: c) { + if (l == blockedLit) { + found = true; + break; + } + } + if (!found) { + cout << "Did not find non-removed blocked lit " << blockedLit + << " val: " << value(blockedLit) << endl + << "In clause " << c << endl; + } + assert(found); + } + + } +} + + +uint64_t CNF::count_lits( + const vector& clause_array + , const bool red + , const bool allowFreed +) const { + uint64_t lits = 0; + for(vector::const_iterator + it = clause_array.begin(), end = clause_array.end() + ; it != end + ; ++it + ) { + const Clause& cl = *cl_alloc.ptr(*it); + if (cl.freed()) { + assert(allowFreed); + } else { + if ((cl.red() ^ red) == false) { + lits += cl.size(); + } + } + } + + return lits; +} + +void CNF::print_watchlist_stats() const +{ + uint64_t total_size = 0; + uint64_t total_size_lits = 0; + uint64_t total_cls = 0; + uint64_t bin_cls = 0; + uint64_t used_in_xor = 0; + uint64_t used_in_xor_full = 0; + for(auto const& ws: watches) { + for(auto const& w: ws) { + total_size+=1; + if (w.isBin()) { + total_size_lits+=2; + total_cls++; + bin_cls++; + } else if (w.isClause()) { + Clause* cl = cl_alloc.ptr(w.get_offset()); + assert(!cl->getRemoved()); + used_in_xor+=cl->used_in_xor(); + used_in_xor_full+=cl->used_in_xor_full(); + total_size_lits+=cl->size(); + total_cls++; + } + } + } + cout << "c [watchlist] avg watchlist size: " << float_div(total_size, watches.size()); + cout << " Avg cl size: " << float_div(total_size_lits, total_cls); + cout << " Cls: " << total_cls; + cout << " Total WS size: " << total_size; + cout << " used_in_xor: " << used_in_xor; + cout << " used_in_xor_full: " << used_in_xor_full; + cout << " bin cl: " << bin_cls; + cout << endl; +} + +void CNF::print_all_clauses() const +{ + for(vector::const_iterator + it = longIrredCls.begin(), end = longIrredCls.end() + ; it != end + ; ++it + ) { + Clause* cl = cl_alloc.ptr(*it); + cout + << "Normal clause offs " << *it + << " cl: " << *cl + << endl; + } + + + uint32_t wsLit = 0; + for (watch_array::const_iterator + it = watches.begin(), end = watches.end() + ; it != end + ; ++it, wsLit++ + ) { + Lit lit = Lit::toLit(wsLit); + watch_subarray_const ws = *it; + cout << "watches[" << lit << "]" << endl; + for (const Watched *it2 = ws.begin(), *end2 = ws.end() + ; it2 != end2 + ; it2++ + ) { + if (it2->isBin()) { + cout << "Binary clause part: " << lit << " , " << it2->lit2() << endl; + } else if (it2->isClause()) { + cout << "Normal clause offs " << it2->get_offset() << endl; + } + } + } +} + +bool CNF::no_marked_clauses() const +{ + for(ClOffset offset: longIrredCls) { + Clause* cl = cl_alloc.ptr(offset); + assert(!cl->stats.marked_clause); + } + + for(auto& lredcls: longRedCls) { + for(ClOffset offset: lredcls) { + Clause* cl = cl_alloc.ptr(offset); + assert(!cl->stats.marked_clause); + } + } + + return true; +} + +void CNF::add_frat(FILE* os) { + if (frat) delete frat; + frat = new DratFile(interToOuterMain); + frat->setFile(os); + frat->set_sumconflicts_ptr(&sumConflicts); + frat->set_sqlstats_ptr(sqlStats); +} + +vector CNF::get_outside_lit_incidence() +{ + assert(get_num_bva_vars() == 0); + vector inc; + inc.resize(nVars()*2, 0); + if (!okay()) return inc; + + for(uint32_t i = 0; i < nVars()*2; i++) { + const Lit l = Lit::toLit(i); + for(const auto& x: watches[l]) { + if (x.isBin() && + !x.red() && + l.var() < x.lit2().var()) //don't count twice + { + inc[x.lit2().toInt()]++; + inc[l.toInt()]++; + } + } + } + + for(const auto& offs: longIrredCls) { + Clause* cl = cl_alloc.ptr(offs); + for(const auto& l: *cl) { + inc[l.toInt()]++; + } + } + + //Map to outer + vector inc_outer(nVarsOuter()*2, 0); + for(uint32_t i = 0; i < inc.size(); i ++) { + const Lit outer = map_inter_to_outer(Lit::toLit(i)); + inc_outer[outer.toInt()] = inc[i]; + } + + //Map to outside + if (get_num_bva_vars() != 0) { + inc_outer = map_back_lits_to_without_bva(inc_outer); + } + return inc_outer; +} + +vector CNF::get_outside_var_incidence() +{ + assert(get_num_bva_vars() == 0); + assert(okay()); + + + vector inc; + inc.resize(nVarsOuter(), 0); + for(uint32_t i = 0; i < nVars()*2; i++) { + const Lit l = Lit::toLit(i); + for(const auto& x: watches[l]) { + if (x.isBin() && + !x.red() && + l.var() < x.lit2().var()) //don't count twice + { + inc[x.lit2().var()]++; + inc[l.var()]++; + } + } + } + + for(const auto& offs: longIrredCls) { + Clause* cl = cl_alloc.ptr(offs); + for(const auto& l: *cl) { + inc[l.var()]++; + } + } + + //Map to outer + vector inc_outer(nVarsOuter(), 0); + for(uint32_t i = 0; i < inc.size(); i ++) { + uint32_t outer = map_inter_to_outer(i); + inc_outer[outer] = inc[i]; + } + + //Map to outside + if (get_num_bva_vars() != 0) { + inc_outer = map_back_vars_to_without_bva(inc_outer); + } + return inc_outer; +} + +vector CNF::get_outside_var_incidence_also_red() +{ + vector inc; + inc.resize(nVars(), 0); + for(uint32_t i = 0; i < nVars()*2; i++) { + const Lit l = Lit::toLit(i); + for(const auto& x: watches[l]) { + if (x.isBin()) { + inc[x.lit2().var()]++; + inc[l.var()]++; + } + } + } + + for(const auto& offs: longIrredCls) { + Clause* cl = cl_alloc.ptr(offs); + for(const auto& l: *cl) { + inc[l.var()]++; + } + } + + for(const auto& reds: longRedCls) { + for(const auto& offs: reds) { + Clause* cl = cl_alloc.ptr(offs); + for(const auto& l: *cl) { + inc[l.var()]++; + } + } + } + + //Map to outer + vector inc_outer(nVarsOuter(), 0); + for(uint32_t i = 0; i < inc.size(); i ++) { + uint32_t outer = map_inter_to_outer(i); + inc_outer[outer] = inc[i]; + } + + //Map to outside + if (get_num_bva_vars() != 0) { + inc_outer = map_back_vars_to_without_bva(inc_outer); + } + return inc_outer; +} + +bool CNF::check_bnn_sane(BNN& bnn) +{ + //assert(decisionLevel() == 0); + + int32_t ts = 0; + int32_t undefs = 0; + for(const auto& l: bnn) { + if (value(l) == l_True) { + ts++; + } + + if (value(l) == l_Undef) { + undefs++; + } + } + assert(bnn.ts == ts); + assert(bnn.undefs == undefs); + + if (bnn.empty()) { + return false; + } + + // we are at the cutoff no matter what undef is + if (bnn.cutoff-ts <= 0) { + if (bnn.set) { + return true; //harmless, doesn't propagate + } + if (value(bnn.out) == l_False) + return false; //always true, BAD + if (value(bnn.out) == l_True) + return true; //harmless, doesn't propagate + + //should have propagated bnn.out + return false; + } + + // we are under the cutoff no matter what undef is + if (undefs < bnn.cutoff-ts) { + if (bnn.set) { + return false; //can never meet cutoff, BAD + } + if (value(bnn.out) == l_True) + return false; //can never meet cutoff, BAD + if (value(bnn.out) == l_False) + return true; + + //should have propagated bnn.out + return false; + } + + //it's set and cutoff can ONLY be met by ALL TRUE + if (((!bnn.set && value(bnn.out) == l_True) || bnn.set) && + undefs == bnn.cutoff-ts) + { + return false; + } + + return true; +} + +void CNF::check_no_zero_ID_bins() const +{ + for(uint32_t i = 0; i < nVars()*2; i++) { + Lit l = Lit::toLit(i); + for(const auto& w: watches[l]) { + //only do once per binary + if (w.isBin()) { + if (w.get_ID() == 0) { + cout << "ERROR, bin: " << l << " " << w.lit2() << " has ID " << w.get_ID() << endl; + } + assert(w.get_ID() > 0); + } + } + } +} + +// This requires occurrence lists to be linked in +bool CNF::zero_irred_cls(const CMSat::Lit lit) const +{ + for(auto const& w: watches[lit]) { + switch(w.getType()) { + case WatchType::watch_binary_t: + if (w.red()) continue; + else return false; + case WatchType::watch_clause_t: { + Clause* cl = cl_alloc.ptr(w.get_offset()); + if (cl->red()) continue; + else return false; + } + case WatchType::watch_idx_t: + release_assert(false); + continue; + case WatchType::watch_bnn_t: + return false; + } + } + return true; +} + +#ifdef USE_TBUDDY +void CNF::free_bdds(vector& xors) +{ + frat->flush(); + for(auto& x: xors) { + delete x.bdd; + x.bdd = NULL; + } +} +#endif diff --git a/cryptominisat/cppsrc/src/cnf.h b/cryptominisat/cppsrc/src/cnf.h new file mode 100644 index 00000000..8f71b5b1 --- /dev/null +++ b/cryptominisat/cppsrc/src/cnf.h @@ -0,0 +1,820 @@ +/****************************************** +Copyright (C) 2009-2020 Authors of CryptoMiniSat, see AUTHORS file + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. +***********************************************/ + +#pragma once + +#include +#include +#include + +#include "constants.h" +#include "vardata.h" +#include "propby.h" +#include "solverconf.h" +#include "solvertypes.h" +#include "watcharray.h" +#include "frat.h" +#include "clauseallocator.h" +#include "varupdatehelper.h" +#include "simplefile.h" +#include "gausswatched.h" +#include "xor.h" +#ifdef USE_TBUDDY +#include +#endif + +#ifdef ARJUN_SERIALIZE +#include +#endif + + +namespace CMSat { + +class ClauseAllocator; + +struct AssumptionPair { + AssumptionPair() + {} + + AssumptionPair(const Lit _outer, const Lit _outside): + lit_outer(_outer) + , lit_orig_outside(_outside) + { + } + + Lit lit_outer; + Lit lit_orig_outside; //not outer, but outside(!) + + bool operator==(const AssumptionPair& other) const { + return other.lit_outer == lit_outer && + other.lit_orig_outside == lit_orig_outside; + } + + bool operator<(const AssumptionPair& other) const + { + //Yes, we need reverse in terms of inverseness + return ~lit_outer < ~other.lit_outer; + } +}; + +struct BinTriStats +{ + uint64_t irredBins = 0; + uint64_t redBins = 0; +}; + +struct LitStats +{ + uint64_t irredLits = 0; + uint64_t redLits = 0; +}; + +class CNF +{ +public: + FastBackwData fast_backw; + void save_on_var_memory(); + void updateWatch(watch_subarray ws, const vector& outerToInter); + void updateVars( + const vector& outerToInter + , const vector& interToOuter + , const vector& interToOuter2 + ); + size_t mem_used_renumberer() const; + size_t mem_used() const; + + CNF(const SolverConf *_conf, std::atomic* _must_interrupt_inter) + { + if (_conf != NULL) { + conf = *_conf; + } + mtrand.seed(conf.origSeed); + frat = new Drat; + assert(_must_interrupt_inter != NULL); + must_interrupt_inter = _must_interrupt_inter; + longRedCls.resize(3); + longRedClsSizes.resize(3, 0); + } + + virtual ~CNF() + { + delete frat; + } + + ClauseAllocator cl_alloc; + SolverConf conf; + std::mt19937_64 mtrand; + + bool ok = true; //If FALSE, state of CNF is UNSAT + + watch_array watches; + vec> gwatches; + uint32_t num_sls_called = 0; + vector varData; + branch branch_strategy = branch::vsids; + string branch_strategy_str = "VSIDS"; + string branch_strategy_str_short = "vs"; + PolarityMode polarity_mode = PolarityMode::polarmode_automatic; //current polarity mode + uint32_t longest_trail_ever_stable = 0; + uint32_t longest_trail_ever_best = 0; + uint32_t longest_trail_ever_inv = 0; + vector depth; //for ancestors in intree probing + uint32_t minNumVars = 0; + + uint64_t sumConflicts = 0; + uint64_t sumDecisions = 0; + uint64_t sumAntecedents = 0; + uint64_t sumPropagations = 0; + uint64_t sumConflictClauseLits = 0; + uint64_t sumAntecedentsLits = 0; + uint64_t sumDecisionBasedCl = 0; + uint64_t sumClLBD = 0; + uint64_t sumClSize = 0; + + uint32_t latest_satzilla_feature_calc = 0; + uint64_t last_satzilla_feature_calc_confl = 0; + uint32_t latest_vardist_feature_calc = 0; + uint64_t last_vardist_feature_calc_confl = 0; + + unsigned cur_max_temp_red_lev2_cls = conf.max_temp_lev2_learnt_clauses; + + //Note that this array can have the same internal variable more than + //once, in case one has been replaced with the other. So if var 1 = var 2 + //and var 1 was set to TRUE and var 2 to be FALSE, then we'll have var 1 + //insided this array twice, once it needs to be set to TRUE and once FALSE + vector assumptions; + + //frat + Drat* frat; + void add_frat(FILE* os); + + //Clauses + vector longIrredCls; + + //if the solver object only saw add_clause and new_var(s) + bool fresh_solver = true; + + /** + level 0 = never remove + level 1 = check rarely + level 2 = check often + **/ + vector > longRedCls; + vector longRedClsSizes; + #if defined(STATS_NEEDED) || defined(FINAL_PREDICTOR) + vector red_stats_extra; + #endif + vector detached_xor_repr_cls; //these are still in longIrredCls + + // NOTE: xorclauses and xorclauses_unused ENCODE INFORMATION THAT's NOWHERE ELSE + // that's right. We can discover an XOR clause then strengthen the + // representing clauses to a binary, and then remove the + // binary with e.g. irred-bin-removal, which then leads to nothing representing + // the XOR clause! Then FRAT fails. This ALSO means that when cleaning the XOR clauses + // we can actually encounter UNSAT. Since it encodes information that's nowhere else. + vector xorclauses; // working set. Should be empty most of the time. + vector xorclauses_orig; // used to re-generate the matrix + vector xorclauses_unused; // used to help knowing when can we detach. Only makes sense when matrixes are set up. + + vector bnns; + vector> bnn_reasons; + vector bnn_confl_reason; + vector bnn_reasons_empty_slots; + vector removed_xorclauses_clash_vars; + bool detached_xor_clauses = false; + bool xor_clauses_updated = false; + BinTriStats binTri; + LitStats litStats; + int32_t clauseID = 0; + int64_t restartID = 1; + SQLStats* sqlStats = NULL; + + //Temporaries + vector seen; + vector seen2; + vector permDiff; + vector toClear; + uint64_t MYFLAG = 1; + + uint32_t level(Lit l) const + { + return varData[l.var()].level; + } + + bool okay() const + { + assert(! + (!ok && frat->enabled() && unsat_cl_ID == 0 && unsat_cl_ID != -1) && "If in UNSAT state, and we have FRAT, we MUST already know the unsat_cl_ID or it must be -1, i.e. known by tbuddy"); + return ok; + } + + lbool value (const uint32_t x) const + { + return assigns[x]; + } + + lbool value (const Lit p) const + { + return assigns[p.var()] ^ p.sign(); + } + + bool must_interrupt_asap() const + { + return must_interrupt_inter->load(std::memory_order_relaxed); + } + + void set_must_interrupt_asap() + { + must_interrupt_inter->store(true, std::memory_order_relaxed); + } + + void unset_must_interrupt_asap() + { + must_interrupt_inter->store(false, std::memory_order_relaxed); + } + + std::atomic* get_must_interrupt_inter_asap_ptr() + { + return must_interrupt_inter; + } + + const vector& get_bnns() const + { + return bnns; + } + + bool check_bnn_sane(BNN& bnn); + bool clause_locked(const Clause& c, const ClOffset offset) const; + bool redundant(const Watched& ws) const; + bool redundant_or_removed(const Watched& ws) const; + size_t cl_size(const Watched& ws) const; + string watched_to_string(Lit otherLit, const Watched& ws) const; + string watches_to_string(const Lit lit, watch_subarray_const ws) const; + bool satisfied(const ClOffset& off) const; + + uint64_t print_mem_used_longclauses(size_t totalMem) const; + uint64_t mem_used_longclauses() const; + template + void for_each_lit( + const OccurClause& cl + , Function func + , int64_t* limit + ) const; + template + void for_each_lit_except_watched( + const OccurClause& cl + , Function func + , int64_t* limit + ) const; + uint32_t map_inter_to_outer(const uint32_t inter) const + { + return interToOuterMain[inter]; + } + Lit map_inter_to_outer(const Lit lit) const + { + return Lit(interToOuterMain[lit.var()], lit.sign()); + } + uint32_t map_outer_to_inter(const uint32_t outer) const + { + return outerToInterMain[outer]; + } + void map_outer_to_inter(vector& outer) const + { + for(auto& v: outer) v = outerToInterMain[v]; + } + void map_inter_to_outer(vector& inter) const + { + for(auto& v: inter) v = interToOuterMain[v]; + } + Lit map_outer_to_inter(const Lit outer) const + { + return Lit(outerToInterMain[outer.var()], outer.sign()); + } + void map_inter_to_outer(vector& lits) const + { + updateLitsMap(lits, interToOuterMain); + } + void renumber_outer_to_inter_lits(vector& ps) const; + + uint32_t nVarsOutside() const + { + #ifdef DEBUG_SLOW + assert(outer_to_with_bva_map.size() == nVarsOuter() - num_bva_vars); + #endif + return nVarsOuter() - num_bva_vars; + } + + Lit map_to_with_bva(const Lit lit) const + { + return Lit(outer_to_with_bva_map.at(lit.var()), lit.sign()); + } + + uint32_t map_to_with_bva(const uint32_t var) const + { + return outer_to_with_bva_map.at(var); + } + + size_t nVars() const + { + return minNumVars; + } + + size_t nVarsOuter() const + { + return assigns.size(); + } + + size_t get_num_bva_vars() const + { + return num_bva_vars; + } + vector get_outside_var_incidence(); + vector get_outside_lit_incidence(); + vector get_outside_var_incidence_also_red(); + + vector build_outer_to_without_bva_map() const; + vector build_outer_to_without_bva_map_extended() const; + void clean_occur_from_removed_clauses(); + void clean_occur_from_removed_clauses_only_smudged(); + void clean_occur_from_idx_types_only_smudged(); + void clean_occur_from_idx(const Lit lit); + void clear_one_occur_from_removed_clauses(watch_subarray w); + bool no_marked_clauses() const; + void check_no_removed_or_freed_cl_in_watch() const; + bool normClauseIsAttached(const ClOffset offset) const; + void find_all_attach() const; + void find_all_attach(const vector& cs) const; + bool find_clause(const ClOffset offset) const; + void test_all_clause_attached() const; + void test_all_clause_attached(const vector& offsets) const; + void check_wrong_attach() const; + void check_watchlist(watch_subarray_const ws) const; + template + bool satisfied(const T& cl) const; + template bool no_duplicate_lits(const T& lits) const; + void check_no_duplicate_lits_anywhere() const; + void check_no_zero_ID_bins() const; + #ifdef USE_TBUDDY + void free_bdds(vector& xors); + #endif + +#ifdef ARJUN_SERIALIZE + template void unserialize(T& ar); + template void serialize(T& ar) const; +#endif + size_t get_num_long_cls() const; + size_t get_num_long_irred_cls() const; + size_t get_num_long_red_cls() const; + void print_all_clauses() const; + void print_watchlist_stats() const; + bool zero_irred_cls(const Lit lit) const; + template void clean_xor_no_prop(T& ps, bool& rhs); + template void clean_xor_vars_no_prop(T& ps, bool& rhs); + uint64_t count_lits( + const vector& clause_array + , const bool red + , const bool allowFreed + ) const; + + /** if set to TRUE, a clause has been removed during add_clause_int + that contained "lit, ~lit". So "lit" must be set to a value + Contains OUTER variables */ + vector undef_must_set_vars; + vector unit_cl_IDs; + int32_t unsat_cl_ID = 0; + +protected: + virtual void new_var( + const bool bva, + const uint32_t orig_outer, + const bool insert_varorder = true); + virtual void new_vars(const size_t n); + void test_reflectivity_of_renumbering() const; + + template + vector map_back_vars_to_without_bva(const vector& val) const; + template + vector map_back_lits_to_without_bva(const vector& val) const; + vector assigns; + + vector outerToInterMain; + vector interToOuterMain; + +private: + std::atomic *must_interrupt_inter; /// outer_to_with_bva_map; +}; + +template +void CNF::for_each_lit( + const OccurClause& cl + , Function func + , int64_t* limit +) const { + switch(cl.ws.getType()) { + case WatchType::watch_binary_t: + *limit -= 2; + func(cl.lit); + func(cl.ws.lit2()); + break; + + case WatchType::watch_clause_t: { + const Clause& clause = *cl_alloc.ptr(cl.ws.get_offset()); + *limit -= (int64_t)clause.size(); + for(const Lit lit: clause) { + func(lit); + } + break; + } + + case WatchType::watch_bnn_t : + case WatchType::watch_idx_t : + assert(false); + break; + } +} + +template +void CNF::for_each_lit_except_watched( + const OccurClause& cl + , Function func + , int64_t* limit +) const { + switch(cl.ws.getType()) { + case WatchType::watch_binary_t: + *limit -= 1; + func(cl.ws.lit2()); + break; + + case WatchType::watch_clause_t: { + const Clause& clause = *cl_alloc.ptr(cl.ws.get_offset()); + *limit -= clause.size(); + for(const Lit lit: clause) { + if (lit != cl.lit) { + func(lit); + } + } + break; + } + + case WatchType::watch_bnn_t: //no idea what to do with this, let's error + case WatchType::watch_idx_t: + assert(false); + break; + } +} + +struct ClauseSizeSorter +{ + explicit ClauseSizeSorter(const ClauseAllocator& _cl_alloc) : + cl_alloc(_cl_alloc) + {} + bool operator () (const ClOffset x, const ClOffset y); + const ClauseAllocator& cl_alloc; +}; + +inline bool CNF::redundant(const Watched& ws) const +{ + return ( (ws.isBin() && ws.red()) + || (ws.isClause() && cl_alloc.ptr(ws.get_offset())->red()) + ); +} + +inline bool CNF::redundant_or_removed(const Watched& ws) const +{ + if (ws.isBin()) { + return ws.red(); + } + + assert(ws.isClause()); + const Clause* cl = cl_alloc.ptr(ws.get_offset()); + return cl->red() || cl->getRemoved(); +} + +inline void CNF::clean_occur_from_removed_clauses() +{ + for(watch_subarray w: watches) { + clear_one_occur_from_removed_clauses(w); + } +} + +inline void CNF::clean_occur_from_removed_clauses_only_smudged() +{ + for(const Lit l: watches.get_smudged_list()) { + clear_one_occur_from_removed_clauses(watches[l]); + } + watches.clear_smudged(); + + #ifdef SLOW_DEBUG + for(const auto& ws: watches) { + for(const auto& w: ws) { + if (!w.isClause()) { + continue; + } + Clause* cl = cl_alloc.ptr(w.get_offset()); + assert(!cl->isRemoved); + } + } + #endif +} + +inline void CNF::clean_occur_from_idx_types_only_smudged() +{ + for(const Lit lit: watches.get_smudged_list()) { + clean_occur_from_idx(lit); + } + watches.clear_smudged(); +} + +inline void CNF::clean_occur_from_idx(const Lit lit) +{ + watch_subarray ws = watches[lit]; + Watched* i = ws.begin(); + Watched* j = ws.begin(); + for(const Watched* end = ws.end(); i < end; i++) { + if (!i->isIdx()) { + *j++ = *i; + } + } + ws.shrink(i-j); +} + +inline bool CNF::clause_locked(const Clause& c, const ClOffset offset) const +{ + return value(c[0]) == l_True + && varData[c[0].var()].reason.isClause() + && varData[c[0].var()].reason.get_offset() == offset; +} + +inline void CNF::clear_one_occur_from_removed_clauses(watch_subarray w) +{ + size_t i = 0; + size_t j = 0; + size_t end = w.size(); + for(; i < end; i++) { + const Watched ws = w[i]; + if (ws.isBNN()) { + BNN* bnn = bnns[ws.get_bnn()]; + if (!bnn->isRemoved) { + w[j++] = w[i]; + } + continue; + } + + if (ws.isBin()) { + w[j++] = w[i]; + continue; + } + + assert(ws.isClause()); + Clause* cl = cl_alloc.ptr(ws.get_offset()); + if (!cl->getRemoved()) { + w[j++] = w[i]; + } + } + w.shrink(i-j); +} + +inline void CNF::renumber_outer_to_inter_lits(vector& ps) const +{ + for (Lit& lit: ps) { + const Lit origLit = lit; + + //Update variable numbering + assert(lit.var() < nVarsOuter()); + lit = map_outer_to_inter(lit); + + if (conf.verbosity >= 52) { + cout + << "var-renumber updating lit " + << origLit + << " to lit " + << lit + << endl; + } + } +} + +template +inline vector unsign_lits(const T& lits) +{ + vector ret(lits.size()); + for(size_t i = 0; i < lits.size(); i++) { + ret[i] = lits[i].unsign(); + } + return ret; +} + +inline void CNF::check_no_removed_or_freed_cl_in_watch() const +{ + for(watch_subarray_const ws: watches) { + for(const Watched& w: ws) { + assert(!w.isIdx()); + if (w.isBin()) { + continue; + } + assert(w.isClause()); + Clause& cl = *cl_alloc.ptr(w.get_offset()); + assert(!cl.getRemoved()); + assert(!cl.freed()); + } + } +} + +template +bool CNF::satisfied(const T& cl) const { + for(Lit lit: cl) { + if (value(lit) == l_True) { + return true; + } + } + return false; +} + + +template +bool CNF::no_duplicate_lits(const T& lits) const +{ + vector x(lits.size()); + for(size_t i = 0; i < x.size(); i++) { + x[i] = lits[i]; + } + std::sort(x.begin(), x.end()); + for(size_t i = 1; i < x.size(); i++) { + if (x[i-1] == x[i]) + return false; + } + return true; +} + +inline void CNF::check_no_duplicate_lits_anywhere() const +{ + for(const ClOffset offs: longIrredCls) { + Clause * cl = cl_alloc.ptr(offs); + assert(no_duplicate_lits((*cl))); + } + for(const auto& l: longRedCls) { + for(const ClOffset offs: l) { + Clause * cl = cl_alloc.ptr(offs); + assert(no_duplicate_lits((*cl))); + } + } +} + +template +void CNF::clean_xor_no_prop(T& ps, bool& rhs) +{ + std::sort(ps.begin(), ps.end()); + Lit p; + uint32_t i, j; + for (i = j = 0, p = lit_Undef; i != ps.size(); i++) { + assert(ps[i].sign() == false); + + if (ps[i].var() == p.var()) { + //added, but easily removed + j--; + p = lit_Undef; + + //Flip rhs if neccessary + if (value(ps[i]) != l_Undef) { + rhs ^= value(ps[i]) == l_True; + } + + } else if (value(ps[i]) == l_Undef) { + //Add and remember as last one to have been added + ps[j++] = p = ps[i]; + + assert(varData[p.var()].removed != Removed::elimed); + } else { + //modify rhs instead of adding + rhs ^= value(ps[i]) == l_True; + } + } + ps.resize(ps.size() - (i - j)); +} + +template +void CNF::clean_xor_vars_no_prop(T& ps, bool& rhs) +{ + std::sort(ps.begin(), ps.end()); + uint32_t p; + uint32_t i, j; + for (i = j = 0, p = numeric_limits::max(); i != ps.size(); i++) { + if (ps[i] == p) { + //added, but easily removed + j--; + p = numeric_limits::max(); + + //Flip rhs if neccessary + if (value(ps[i]) != l_Undef) { + rhs ^= value(ps[i]) == l_True; + } + + } else if (value(ps[i]) == l_Undef) { + //Add and remember as last one to have been added + ps[j++] = p = ps[i]; + + assert(varData[p].removed != Removed::elimed); + } else { + //modify rhs instead of adding + rhs ^= value(ps[i]) == l_True; + } + } + if ((i - j) > 0) { + ps.resize(ps.size() - (i - j)); + //TODO tbdd ? + } +} + +template +vector CNF::map_back_lits_to_without_bva(const vector& val) const +{ + vector ret; + assert(val.size() == nVarsOuter()*2); + ret.reserve(nVarsOutside()*2); + for(size_t i = 0; i < nVarsOuter()*2; i++) { + Lit l = Lit::toLit(i); + if (!varData[map_outer_to_inter(l).var()].is_bva) { + ret.push_back(val[i]); + } + } + assert(ret.size() == nVarsOutside()*2); + return ret; +} + + +template +vector CNF::map_back_vars_to_without_bva(const vector& val) const +{ + vector ret; + assert(val.size() == nVarsOuter()); + ret.reserve(nVarsOutside()); + for(size_t i = 0; i < nVarsOuter(); i++) { + if (!varData[map_outer_to_inter(i)].is_bva) { + ret.push_back(val[i]); + } + } + assert(ret.size() == nVarsOutside()); + return ret; +} + +inline bool CNF::satisfied(const ClOffset& off) const +{ + Clause* cl = cl_alloc.ptr(off); + return satisfied(*cl); +} + +inline size_t CNF::get_num_long_irred_cls() const +{ + return longIrredCls.size(); +} + +inline size_t CNF::get_num_long_red_cls() const +{ + return longRedCls.size(); +} + +inline size_t CNF::get_num_long_cls() const +{ + return longIrredCls.size() + longRedCls.size(); +} + +#ifdef ARJUN_SERIALIZE +template void CNF::unserialize(T& ar) +{ + ar >> outer_to_with_bva_map; + ar >> num_bva_vars; +} + +template void CNF::serialize(T& ar) const +{ + ar << outer_to_with_bva_map; + ar << num_bva_vars; +} +#endif + +} diff --git a/cryptominisat/cppsrc/src/community_finder.cpp b/cryptominisat/cppsrc/src/community_finder.cpp new file mode 100644 index 00000000..08e2c047 --- /dev/null +++ b/cryptominisat/cppsrc/src/community_finder.cpp @@ -0,0 +1,150 @@ +/****************************************** +Copyright (C) 2009-2020 Authors of CryptoMiniSat, see AUTHORS file + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. +***********************************************/ + +#include "community_finder.h" +#include "time_mem.h" +#include "solver.h" +#include "occsimplifier.h" +#include "clauseallocator.h" +#include "sqlstats.h" +#include +#include +#include +#include + +using std::map; +using std::pair; +using std::make_pair; + +using namespace CMSat; + +CommunityFinder::CommunityFinder(Solver* _solver) : + solver(_solver) +{ +} + +void CMSat::CommunityFinder::compute() +{ + //Clean it + for(auto& v: solver->varData) { + v.community_num = numeric_limits::max(); + } + + //Check for too large + if (solver->nVars() > 300ULL*1000ULL) { + return; + } + + double myTime = cpuTime(); + map, long double> edges; + + //Binary clauses + for(uint32_t watched_at = 0; watched_at< solver->nVars()*2; watched_at++) { + Lit l = Lit::toLit(watched_at); + watch_subarray_const ws = solver->watches[l]; + for(uint32_t watched_at_sub = 0; watched_at_sub < ws.size(); watched_at_sub++) { + const Watched& w = ws[watched_at_sub]; + if (w.isBin() && + w.lit2() < l && + !w.red() + ) { + //VIG graph + uint32_t size = 2; + long double weight = 1.0L/((long double)size*((long double)size-1.0L)/2.0L); + + uint32_t v1 = l.var(); + uint32_t v2 = w.lit2().var(); + //must start with smallest + if (v2 < v1) { + std::swap(v1, v2); + } + auto edge = make_pair(v1, v2); + auto it = edges.find(edge); + if (it == edges.end()) { + edges[edge] = weight; + } else { + it->second+=weight; + } + } + } + } + + //Non-binary clauses + for(const auto& offs: solver->longIrredCls) { + const Clause* cl = solver->cl_alloc.ptr(offs); + //VIG graph + uint32_t size = cl->size(); + long double weight = 1.0L/((long double)size*((long double)size-1.0L)/2.0L); + for(uint32_t i = 0; i < cl->size(); i ++) { + for(uint32_t i2 = i+1; i2 < cl->size(); i2 ++) { + uint32_t v1 = (*cl)[i].var(); + uint32_t v2 = (*cl)[i2].var(); + + //must start with smallest + if (v2 < v1) { + std::swap(v1, v2); + } + auto edge = make_pair(v1, v2); + auto it = edges.find(edge); + if (it == edges.end()) { + edges[edge] = weight; + } else { + it->second+=weight; + } + } + } + } + + LouvainC::Communities graph; + for(const auto& it: edges) { + graph.add_edge(it.first.first, it.first.second, it.second); + } + graph.calculate(true); + auto mapping = graph.get_mapping(); + + for(const auto& x: mapping) { + assert(x.first < solver->nVars()); + assert(x.second < solver->nVars()); + solver->varData[x.first].community_num = x.second; + } + + //Recompute connects_num_communities for all redundant clauses + for(auto& cls: solver->longRedCls) { + for(auto& offs: cls) { + Clause* cl = solver->cl_alloc.ptr(offs); + const uint32_t comms = solver->calc_connects_num_communities(*cl); + solver->red_stats_extra[cl->stats.extra_pos].connects_num_communities = comms; + } + } + + + double time_passed = cpuTime() - myTime; + if (solver->conf.verbosity) { + cout << "c [louvain] Louvain communities found. T: " + << std::fixed << std::setprecision(2) + << solver->conf.print_times(time_passed) << endl; + } + + if (solver->sqlStats) { + solver->sqlStats->time_passed_min(solver, "louvain", time_passed); + } +} diff --git a/cryptominisat/cppsrc/src/community_finder.h b/cryptominisat/cppsrc/src/community_finder.h new file mode 100644 index 00000000..0f8f5c6a --- /dev/null +++ b/cryptominisat/cppsrc/src/community_finder.h @@ -0,0 +1,46 @@ +/****************************************** +Copyright (C) 2009-2020 Authors of CryptoMiniSat, see AUTHORS file + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. +***********************************************/ + + +#ifndef COMMUNITY_FINDER_H__ +#define COMMUNITY_FINDER_H__ + +#include +using std::vector; + +namespace CMSat { + +class Solver; + +class CommunityFinder { +public: + explicit CommunityFinder(Solver* _solver); + void compute(); + +private: + Solver* solver; + +}; + +} + +#endif diff --git a/cryptominisat/cppsrc/src/completedetachreattacher.cpp b/cryptominisat/cppsrc/src/completedetachreattacher.cpp new file mode 100644 index 00000000..7017d46e --- /dev/null +++ b/cryptominisat/cppsrc/src/completedetachreattacher.cpp @@ -0,0 +1,220 @@ +/****************************************** +Copyright (C) 2009-2020 Authors of CryptoMiniSat, see AUTHORS file + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. +***********************************************/ + +#include "completedetachreattacher.h" +#include "solver.h" +#include "sqlstats.h" +#include "varreplacer.h" +#include "clausecleaner.h" +#include "clauseallocator.h" + +using namespace CMSat; + +CompleteDetachReatacher::CompleteDetachReatacher(Solver* _solver) : + solver(_solver) +{ +} + +/** +@brief Completely detach all non-binary clauses +*/ +void CompleteDetachReatacher::detach_nonbins() +{ + assert(!solver->frat->something_delayed()); + ClausesStay stay; + + for (watch_array::iterator + it = solver->watches.begin(), end = solver->watches.end() + ; it != end + ; ++it + ) { + stay += clearWatchNotBinNotTri(*it); + } + + solver->litStats.redLits = 0; + solver->litStats.irredLits = 0; + + assert(stay.redBins % 2 == 0); + solver->binTri.redBins = stay.redBins/2; + + assert(stay.irredBins % 2 == 0); + solver->binTri.irredBins = stay.irredBins/2; +} + +/** +@brief Helper function for detachPointerUsingClauses() +*/ +CompleteDetachReatacher::ClausesStay CompleteDetachReatacher::clearWatchNotBinNotTri( + watch_subarray ws +) { + ClausesStay stay; + + Watched* i = ws.begin(); + Watched* j = i; + for (Watched* end = ws.end(); i != end; i++) { + if (i->isBin()) { + if (i->red()) + stay.redBins++; + else + stay.irredBins++; + + *j++ = *i; + } + } + ws.shrink_(i-j); + + return stay; +} + +bool CompleteDetachReatacher::reattachLongs(bool removeStatsFirst) +{ + if (solver->conf.verbosity >= 6) { + cout << "Cleaning and reattaching clauses" << endl; + } + + cleanAndAttachClauses(solver->longIrredCls, removeStatsFirst); + for(auto& lredcls: solver->longRedCls) { + cleanAndAttachClauses(lredcls, removeStatsFirst); + } + solver->clauseCleaner->clean_implicit_clauses(); + assert(!solver->frat->something_delayed()); + + if (solver->ok) { + solver->ok = (solver->propagate().isNULL()); + } + + return solver->okay(); +} + +void CompleteDetachReatacher::attachClauses( + vector& cs +) { + for (ClOffset offs: cs) { + Clause* cl = solver->cl_alloc.ptr(offs); + bool satisfied = false; + for(Lit lit: *cl) { + if (solver->value(lit) == l_True) { + satisfied = true; + } + } + if (!satisfied) { + assert(solver->value((*cl)[0]) == l_Undef); + assert(solver->value((*cl)[1]) == l_Undef); + } + solver->attachClause(*cl, false); + } +} + +/** +@brief Cleans clauses from failed literals/removes satisfied clauses from cs + +May change solver->ok to FALSE (!) +*/ +void CompleteDetachReatacher::cleanAndAttachClauses( + vector& cs + , bool removeStatsFirst +) { + vector::iterator i = cs.begin(); + vector::iterator j = i; + for (vector::iterator end = cs.end(); i != end; ++i) { + assert(!solver->frat->something_delayed()); + Clause* cl = solver->cl_alloc.ptr(*i); + + //Handle stat removal if need be + if (removeStatsFirst) { + if (cl->red()) { + solver->litStats.redLits -= cl->size(); + } else { + solver->litStats.irredLits -= cl->size(); + } + } + + if (clean_clause(cl)) { + solver->attachClause(*cl); + *j++ = *i; + } else { + solver->free_cl(*i); + } + } + cs.resize(cs.size() - (i-j)); +} + +/** +@brief Not only cleans a clause from false literals, but if clause is satisfied, it reports it +*/ +bool CompleteDetachReatacher::clean_clause(Clause* cl) +{ + (*solver->frat) << deldelay << *cl << fin; + Clause& ps = *cl; + if (ps.size() <= 2) { + cout + << "ERROR, clause is too small, and linked in: " + << *cl + << endl; + } + assert(ps.size() > 2); + + Lit *i = ps.begin(); + Lit *j = i; + for (Lit *end = ps.end(); i != end; i++) { + if (solver->value(*i) == l_True) { + (*solver->frat) << findelay; + return false; + } + if (solver->value(*i) == l_Undef) { + *j++ = *i; + } + } + ps.shrink(i-j); + + //Drat + if (i != j) { + INC_ID(*cl); + (*solver->frat) << add << *cl << fin << findelay; + } else { + solver->frat->forget_delay(); + } + + switch (ps.size()) { + case 0: + assert(solver->unsat_cl_ID == 0); + solver->unsat_cl_ID = cl->stats.ID; + solver->ok = false; + return false; + + case 1: + solver->enqueue(ps[0]); + (*solver->frat) << del << *cl << fin; //double unit delete + return false; + + case 2: { + solver->attach_bin_clause(ps[0], ps[1], ps.red(), cl->stats.ID); + return false; + } + + default: { + break; + } + } + + return true; +} diff --git a/cryptominisat/cppsrc/src/completedetachreattacher.h b/cryptominisat/cppsrc/src/completedetachreattacher.h new file mode 100644 index 00000000..e73a0474 --- /dev/null +++ b/cryptominisat/cppsrc/src/completedetachreattacher.h @@ -0,0 +1,85 @@ +/****************************************** +Copyright (C) 2009-2020 Authors of CryptoMiniSat, see AUTHORS file + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. +***********************************************/ + +#ifndef __COMPLETE_DETACH_REATTACHER__ +#define __COMPLETE_DETACH_REATTACHER__ + +#include "constants.h" +#include "watched.h" +#include "watcharray.h" + +namespace CMSat { + +class Solver; +class Clause; + +/** +@brief Helper class to completely detaches all(or only non-native) clauses + +Used in classes that (may) do a lot of clause-changning, in which case +detaching&reattaching of clauses would be neccessary to do +individually, which is \b very slow + +A main use-case is the following: +-# detach all clauses +-# play around with all clauses as desired. Cannot call solver.propagate() here +-# attach again +*/ +class CompleteDetachReatacher +{ + public: + explicit CompleteDetachReatacher(Solver* solver); + bool reattachLongs(bool removeStatsFrist = false); + void detach_nonbins(); + + private: + void attachClauses(vector& cs); + void cleanAndAttachClauses( + vector& cs + , bool removeStatsFrist + ); + bool clean_clause(Clause* cl); + + class ClausesStay { + public: + ClausesStay() : + redBins(0) + , irredBins(0) + {} + + ClausesStay& operator+=(const ClausesStay& other) { + redBins += other.redBins; + irredBins += other.irredBins; + return *this; + } + + uint64_t redBins; + uint64_t irredBins; + }; + ClausesStay clearWatchNotBinNotTri(watch_subarray ws); + + Solver* solver; +}; + +} //end namespace + +#endif //__COMPLETE_DETACH_REATTACHER__ diff --git a/cryptominisat/cppsrc/src/constants.h b/cryptominisat/cppsrc/src/constants.h new file mode 100644 index 00000000..3609e7cb --- /dev/null +++ b/cryptominisat/cppsrc/src/constants.h @@ -0,0 +1,201 @@ +/****************************************** +Copyright (C) 2009-2020 Authors of CryptoMiniSat, see AUTHORS file + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. +***********************************************/ + +#pragma once + +#include +#include +#include +#include +#include + +#define unif_uint_dist(x,y) std::uniform_int_distribution<> x(0, y) +inline uint32_t rnd_uint(std::mt19937_64& mtrand, const uint32_t maximum) { + unif_uint_dist(u, maximum); + return u(mtrand); +} + +// #define VERBOSE_DEBUG +// #define VERBOSE_DEBUG_FULLPROP +// #define DEBUG_DEPTH +// #define SLOW_DEBUG + +#if defined(_MSC_VER) +#define cmsat_prefetch(x) (void)(x) +#else +#define cmsat_prefetch(x) __builtin_prefetch(x) +#endif + +#if defined(_MSC_VER) +#include "cms_windows_includes.h" +#define release_assert(a) \ + do { \ + __pragma(warning(push)) \ + __pragma(warning(disable:4127)) \ + if (!(a)) {\ + __pragma(warning(pop)) \ + fprintf(stderr, "*** ASSERTION FAILURE in %s() [%s:%d]: %s\n", \ + __FUNCTION__, __FILE__, __LINE__, #a); \ + abort(); \ + } \ + } while (0) +#else +#define release_assert(a) \ + do { \ + if (!(a)) {\ + fprintf(stderr, "*** ASSERTION FAILURE in %s() [%s:%d]: %s\n", \ + __FUNCTION__, __FILE__, __LINE__, #a); \ + abort(); \ + } \ + } while (0) +#endif + +//We shift stuff around in Watched, so not all of 32 bits are useable. +//for STATS we have 64b values in the Clauses, so they must be aligned to 64 + +#if defined(STATS_NEEDED) +#define LARGE_OFFSETS +#define STATS_DO(x) do {x;} while (0) +#define INC_ID(cl) \ + do { \ + auto prev_id = (cl).stats.ID; \ + (cl).stats.ID = ++solver->clauseID; \ + if (solver->sqlStats && (cl).stats.is_tracked) solver->sqlStats->update_id(prev_id, (cl).stats.ID); \ + } while (0) +#else +#define STATS_DO(x) do {} while (0) +#define INC_ID(cl) \ + do { \ + (cl).stats.ID = ++solver->clauseID; \ + } while (0) +#endif + +#if defined(LARGE_OFFSETS) +#define BASE_DATA_TYPE uint64_t +#define EFFECTIVELY_USEABLE_BITS 62 +#else +#define BASE_DATA_TYPE uint32_t +#define EFFECTIVELY_USEABLE_BITS 30 +#endif + +#define MAX_XOR_RECOVER_SIZE 8 + +#if defined _WIN32 + #define DLL_PUBLIC __declspec(dllexport) +#else + #define DLL_PUBLIC __attribute__ ((visibility ("default"))) + #define DLL_LOCAL __attribute__ ((visibility ("hidden"))) +#endif + +/////////////////// +// Verbose Debug +/////////////////// + +//#define FRAT_DEBUG +//#define VERBOSE_DEBUG + +// verbose print +#ifdef VERBOSE_DEBUG +#define VERBOSE_PRINT(x) \ + do { std::cout << x << std::endl; } while (0) +#define VERBOSE_DEBUG_DO(x) do { x; } while (0) +#else +#define VERBOSE_PRINT(x) do { } while (0) +#define VERBOSE_DEBUG_DO(x) do { } while (0) +#endif +///// + +// slow debug +#ifdef SLOW_DEBUG +#define SLOW_DEBUG_DO(x) \ + do { x; } while (0) +#else +#define SLOW_DEBUG_DO(x) do { } while (0) +#endif +///// + +// verb_print +#define verb_print(a, x) \ + do { if (solver->conf.verbosity >= a) {std::cout << "c " << x << std::endl;} } while (0) +///// + +// debug watched +#ifdef DEBUG_WATCHED +#define DEBUG_WATCHED_DO(x) \ + do { x; } while (0) +#else +#define DEBUG_WATCHED_DO(x) do { } while (0) +#endif + + +// tbuddy +#ifdef USE_TBUDDY +#define TBUDDY_DO(x) \ + do { x; } while (0) +#else +#define TBUDDY_DO(x) do { } while (0) +#endif + +#ifdef VERBOSE_DEBUG +#define FAST_DEBUG +#define DEBUG_ATTACH_FULL +#define VERBOSE_DEBUG_XOR +#define VERBOSE_DEBUG_RECONSTRUCT +#endif + +#ifdef __GNUC__ + #define likely(x) __builtin_expect((x), 1) + #define unlikely(x) __builtin_expect((x), 0) +#else + #define likely(x) x + #define unlikely(x) x +#endif + +/////////////////// +// Silent Debug +/////////////////// + +#ifndef NDEBUG +//#define FAST_DEBUG +#endif + +#ifdef SLOW_DEBUG +#define FAST_DEBUG +#define DEBUG_PROPAGATEFROM +#define ENQUEUE_DEBUG +#define DEBUG_ATTACH_MORE +#define DEBUG_IMPLICIT_PAIRS_TRIPLETS +#define DEBUG_IMPLICIT_STATS +#define DEBUG_GAUSS +#define XOR_DEBUG +#endif + +#ifdef FAST_DEBUG +#define DEBUG_VARELIM +#define DEBUG_WATCHED +#define DEBUG_ATTACH +#define DEBUG_REPLACER +#define DEBUG_MARKED_CLAUSE +#define CHECK_N_OCCUR +#endif + +//#define DEBUG_ATTACH_FULL diff --git a/cryptominisat/cppsrc/src/cryptominisat.cpp b/cryptominisat/cppsrc/src/cryptominisat.cpp new file mode 100644 index 00000000..da9b9309 --- /dev/null +++ b/cryptominisat/cppsrc/src/cryptominisat.cpp @@ -0,0 +1,1980 @@ +/****************************************** +Copyright (C) 2009-2020 Authors of CryptoMiniSat, see AUTHORS file + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. +***********************************************/ + +#include "constants.h" +#include "cryptominisat.h" +#include "solver.h" +#include "frat.h" +#include "shareddata.h" + +#include +#include +#include +#include +#include +#include +#include +using std::thread; +using std::vector; + +#define CACHE_SIZE 10ULL*1000ULL*1000UL +#ifndef LIMITMEM +#define MAX_VARS (1ULL<<28) +#else +#define MAX_VARS 3000 +#endif + +using namespace CMSat; + +static bool print_thread_start_and_finish = false; + +namespace CMSat { + struct CMSatPrivateData { + explicit CMSatPrivateData(std::atomic* _must_interrupt) + { + must_interrupt = _must_interrupt; + if (must_interrupt == NULL) { + must_interrupt = new std::atomic(false); + must_interrupt_needs_delete = true; + } + } + ~CMSatPrivateData() + { + for(Solver* this_s: solvers) { + delete this_s; + } + if (must_interrupt_needs_delete) { + delete must_interrupt; + } + + delete log; //this will also close the file + delete shared_data; + } + CMSatPrivateData(const CMSatPrivateData&) = delete; + CMSatPrivateData& operator=(const CMSatPrivateData&) = delete; + + //Mult-threaded data + vector solvers; + SharedData *shared_data = NULL; + int which_solved = 0; + std::atomic* must_interrupt; + bool must_interrupt_needs_delete = false; + + bool okay = true; + + ///???? + std::ofstream* log = NULL; + int sql = 0; + double timeout = numeric_limits::max(); + bool interrupted = false; + + //variables and clauses added/to add. + //This is to make it faster to add variables/clasues + // by adding them in one go + unsigned cls = 0; + unsigned vars_to_add = 0; + unsigned total_num_vars = 0; + vector cls_lits; + + //For single call setup + uint32_t num_solve_simplify_calls = 0; + bool promised_single_call = false; + + //stats + uint64_t previous_sum_conflicts = 0; + uint64_t previous_sum_propagations = 0; + uint64_t previous_sum_decisions = 0; + vector cpu_times; + }; +} + +#ifdef USE_GPU +struct GPUThread +{ + GPUThread( + SharedData* _shared_data, + std::atomic* _must_interrupt): + shared_data(_shared_data), + must_interrupt(_must_interrupt) + {} + + void operator()() + { + uint32_t gpuReduceDbPeriod = 10000; + uint32_t gpuReduceDbPeriodInc = 10000; + + while (!must_interrupt->load(std::memory_order_relaxed)) { + shared_data->gpuClauseSharer->gpuRun(); + if (shared_data->gpuClauseSharer->getAddedClauseCount() - + shared_data->gpuClauseSharer->getAddedClauseCountAtLastReduceDb() >= gpuReduceDbPeriod) + { + shared_data->gpuClauseSharer->reduceDb(); + if (!shared_data->gpuClauseSharer->hasRunOutOfGpuMemoryOnce()) { + gpuReduceDbPeriod += gpuReduceDbPeriodInc; + } + } + //<<< maybe print stats>>> + } + } + + SharedData* shared_data; + std::atomic* must_interrupt; +}; +#endif + +struct DataForThread +{ + explicit DataForThread(CMSatPrivateData* data, const vector* _assumptions = NULL) : + solvers(data->solvers) + , cpu_times(data->cpu_times) + , lits_to_add(&(data->cls_lits)) + , vars_to_add(data->vars_to_add) + , assumptions(_assumptions) + , update_mutex(new std::mutex) + , which_solved(&(data->which_solved)) + , ret(new lbool(l_Undef)) + { + } + + ~DataForThread() + { + delete update_mutex; + delete ret; + } + vector& solvers; + vector& cpu_times; + vector *lits_to_add; + uint32_t vars_to_add; + const vector *assumptions; + std::mutex* update_mutex; + int *which_solved; + lbool* ret; +}; + +DLL_PUBLIC SATSolver::SATSolver( + void* config + , std::atomic* interrupt_asap + ) +{ + data = new CMSatPrivateData(interrupt_asap); + + if (config && ((SolverConf*) config)->verbosity) { + //NOT SAFE + //yes -- this system will use a lock, but the solver itself won't(!) + //so things will get mangled and printed wrongly + //print_thread_start_and_finish = true; + } + + data->solvers.push_back(new Solver((SolverConf*) config, data->must_interrupt)); + data->cpu_times.push_back(0.0); +} + +DLL_PUBLIC SATSolver::~SATSolver() +{ + delete data; +} + +void update_config(SolverConf& conf, unsigned thread_num) +{ + //Don't accidentally reconfigure everything to a specific value! + conf.origSeed += thread_num; + conf.thread_num = thread_num; + + switch(thread_num % 23) { + case 0: { + //default setup + break; + } + + case 1: { + //Minisat-like + conf.branch_strategy_setup = "vsids"; + conf.varElimRatioPerIter = 1; + conf.restartType = Restart::geom; + conf.polarity_mode = CMSat::PolarityMode::polarmode_neg; + + conf.inc_max_temp_lev2_red_cls = 1.02; + conf.ratio_keep_clauses[clean_to_int(ClauseClean::glue)] = 0; + conf.ratio_keep_clauses[clean_to_int(ClauseClean::activity)] = 0.5; + break; + } + case 2: { + conf.branch_strategy_setup = "vsids"; +// conf.polar_best_inv_every_n = 100; + break; + } + case 3: { + //Similar to CMS 2.9 except we look at learnt DB size insteead + //of conflicts to see if we need to clean. + conf.branch_strategy_setup = "vsids"; + conf.ratio_keep_clauses[clean_to_int(ClauseClean::glue)] = 0.5; + conf.ratio_keep_clauses[clean_to_int(ClauseClean::activity)] = 0; + conf.glue_put_lev0_if_below_or_eq = 0; + conf.inc_max_temp_lev2_red_cls = 1.03; + break; + } + case 4: { + //Similar to CMS 5.0 + conf.branch_strategy_setup = "vsids"; + conf.varElimRatioPerIter = 0.4; + conf.every_lev1_reduce = 0; + conf.every_lev2_reduce = 0; + conf.do_bva = false; + conf.max_temp_lev2_learnt_clauses = 30000; + conf.glue_put_lev0_if_below_or_eq = 4; + + conf.ratio_keep_clauses[clean_to_int(ClauseClean::glue)] = 0; + conf.ratio_keep_clauses[clean_to_int(ClauseClean::activity)] = 0.5; + break; + } + case 5: { + conf.branch_strategy_setup = "vsids"; + conf.never_stop_search = true; + break; + } + case 6: { + //Maple with backtrack + conf.branch_strategy_setup = "vsids"; +// conf.polar_stable_every_n = 10000; + break; + } + case 7: { + conf.branch_strategy_setup = "vsids"; + conf.do_bva = false; + conf.glue_put_lev0_if_below_or_eq = 2; + conf.varElimRatioPerIter = 1; + conf.inc_max_temp_lev2_red_cls = 1.04; + conf.ratio_keep_clauses[clean_to_int(ClauseClean::glue)] = 0.1; + conf.ratio_keep_clauses[clean_to_int(ClauseClean::activity)] = 0.3; + break; + } + case 8: { + //Different glue limit + conf.branch_strategy_setup = "vmtf"; + conf.glue_put_lev0_if_below_or_eq = 2; + conf.glue_put_lev1_if_below_or_eq = 2; + break; + } + case 9: { + conf.branch_strategy_setup = "vsids"; +// conf.polar_stable_every_n = 1; + break; + } + case 10: { + conf.branch_strategy_setup = "vsids"; + conf.polarity_mode = CMSat::PolarityMode::polarmode_pos; +// conf.polar_stable_every_n = 100000; + break; + } + case 11: { + conf.branch_strategy_setup = "vsids"; + conf.varElimRatioPerIter = 1; + conf.restartType = Restart::geom; + + conf.inc_max_temp_lev2_red_cls = 1.01; + conf.ratio_keep_clauses[clean_to_int(ClauseClean::glue)] = 0; + conf.ratio_keep_clauses[clean_to_int(ClauseClean::activity)] = 0.3; + break; + } + case 12: { + conf.branch_strategy_setup = "vmtf"; + conf.inc_max_temp_lev2_red_cls = 1.001; +// conf.polar_stable_every_n = 7; +// conf.polar_best_inv_every_n = 6; + break; + } + + case 13: { + //Minisat-like + conf.varElimRatioPerIter = 1; + conf.restartType = Restart::geom; + conf.polarity_mode = CMSat::PolarityMode::polarmode_neg; + + conf.inc_max_temp_lev2_red_cls = 1.02; + conf.ratio_keep_clauses[clean_to_int(ClauseClean::glue)] = 0; + conf.ratio_keep_clauses[clean_to_int(ClauseClean::activity)] = 0.5; + break; + } + case 14: { + //Different glue limit + conf.branch_strategy_setup = "vsids"; + conf.do_bva = false; + conf.doMinimRedMoreMore = 1; + conf.glue_put_lev0_if_below_or_eq = 4; + //conf.glue_put_lev2_if_below_or_eq = 8; + conf.max_num_lits_more_more_red_min = 3; + conf.max_glue_more_minim = 4; + break; + } + case 15: { + //Similar to CMS 2.9 except we look at learnt DB size insteead + //of conflicts to see if we need to clean. + conf.ratio_keep_clauses[clean_to_int(ClauseClean::glue)] = 0.5; + conf.ratio_keep_clauses[clean_to_int(ClauseClean::activity)] = 0; + conf.glue_put_lev0_if_below_or_eq = 0; + conf.inc_max_temp_lev2_red_cls = 1.03; +// conf.polar_stable_every_n = 2; + break; + } + case 16: { + //Similar to CMS 5.0 + conf.varElimRatioPerIter = 0.4; + conf.every_lev1_reduce = 0; + conf.every_lev2_reduce = 0; + conf.max_temp_lev2_learnt_clauses = 30000; + conf.glue_put_lev0_if_below_or_eq = 4; + + conf.ratio_keep_clauses[clean_to_int(ClauseClean::glue)] = 0; + conf.ratio_keep_clauses[clean_to_int(ClauseClean::activity)] = 0.5; + break; + } + case 17: { + //conf.max_temporary_learnt_clauses = 10000; + conf.do_bva = true; + break; + } + case 18: { + conf.branch_strategy_setup = "vsids"; + conf.every_lev1_reduce = 0; + conf.every_lev2_reduce = 0; + conf.glue_put_lev1_if_below_or_eq = 0; + conf.max_temp_lev2_learnt_clauses = 10000; + break; + } + + case 19: { + conf.do_bva = false; + conf.doMinimRedMoreMore = 0; + conf.orig_global_timeout_multiplier = 5; + conf.num_conflicts_of_search_inc = 1.15; + conf.more_red_minim_limit_binary = 600; + conf.max_num_lits_more_more_red_min = 20; +// conf.polar_stable_every_n = 4; + //conf.max_temporary_learnt_clauses = 10000; + break; + } + + case 20: { + //Luby + conf.branch_strategy_setup = "vmtf"; + conf.restart_inc = 1.5; + conf.restart_first = 100; + conf.restartType = Restart::luby; +// conf.polar_stable_every_n = 2; + break; + } + + case 21: { + conf.branch_strategy_setup = "vsids"; + conf.glue_put_lev0_if_below_or_eq = 3; + conf.glue_put_lev1_if_below_or_eq = 5; + break; + } + + case 22: { + conf.branch_strategy_setup = "vmtf"; + conf.doMinimRedMoreMore = 0; + conf.orig_global_timeout_multiplier = 5; + conf.num_conflicts_of_search_inc = 1.15; + conf.more_red_minim_limit_binary = 600; + conf.max_num_lits_more_more_red_min = 20; + //conf.max_temporary_learnt_clauses = 10000; + break; + } + + default: { + conf.varElimRatioPerIter = 0.1*(thread_num % 9); + if (thread_num % 4 == 0) { + conf.restartType = Restart::glue; + } + if (thread_num % 5 == 0) { + conf.restartType = Restart::geom; + } + conf.restart_first = 100 * (0.5*(thread_num % 5)); + conf.doMinimRedMoreMore = ((thread_num % 5) == 1); + break; + } + } +} + +DLL_PUBLIC void SATSolver::set_num_threads(unsigned num) +{ + if (num <= 0) { + const char err[] = "ERROR: Number of threads must be at least 1"; + std::cerr << err << endl; + throw std::runtime_error(err); + } + if (num == 1) { + return; + } + if (data->solvers.size() > 1) { + const char err[] = "ERROR: You must call set_num_threads() at most once"; + std::cerr << err << endl; + throw std::runtime_error(err); + } + + if (data->solvers[0]->frat->enabled() || + data->solvers[0]->conf.simulate_frat + ) { + const char err[] = "ERROR: FRAT cannot be used in multi-threaded mode"; + std::cerr << err << endl; + throw std::runtime_error(err); + } + + if (data->cls > 0 || nVars() > 0) { + const char err[] = "ERROR: You must first call set_num_threads() and only then add clauses and variables"; + std::cerr << err << endl; + throw std::runtime_error(err); + } + + #ifdef USE_BREAKID + if (num > 1) { + cout << "ERROR: BreakID cannot work with multiple threads. Something is off in the memory allocation of the library that's likely 'static'. Perhaps in 'bliss'. Exiting." << endl; + exit(-1); + } + #endif + + data->cls_lits.reserve(CACHE_SIZE); + for(unsigned i = 1; i < num; i++) { + SolverConf conf = data->solvers[0]->getConf(); + update_config(conf, i); + data->solvers.push_back(new Solver(&conf, data->must_interrupt)); + data->cpu_times.push_back(0.0); + } + + //set shared data + data->shared_data = new SharedData(data->solvers.size()); + #ifdef USE_GPU + data->shared_data->gpuClauseSharer->setCpuSolverCount(num); + #endif + for(unsigned i = 0; i < num; i++) { + SolverConf conf = data->solvers[i]->getConf(); + if (i >= 1) { + conf.verbosity = 0; + conf.doFindXors = 0; + } + data->solvers[i]->setConf(conf); + data->solvers[i]->set_shared_data((SharedData*)data->shared_data); + } +} + +struct OneThreadAddCls +{ + OneThreadAddCls(DataForThread& _data_for_thread, size_t _tid) : + data_for_thread(_data_for_thread) + , tid(_tid) + { + } + + void operator()() + { + Solver& solver = *data_for_thread.solvers[tid]; + solver.new_external_vars(data_for_thread.vars_to_add); + + vector lits; + vector vars; + bool ret = true; + size_t at = 0; + const vector& orig_lits = (*data_for_thread.lits_to_add); + const size_t size = orig_lits.size(); + while(at < size && ret) { + if (orig_lits[at] == lit_Undef) { + lits.clear(); + at++; + for(; at < size + && orig_lits[at] != lit_Undef + && orig_lits[at] != lit_Error + ; at++ + ) { + lits.push_back(orig_lits[at]); + } + ret = solver.add_clause_outside(lits); + } else { + vars.clear(); + at++; + bool rhs = orig_lits[at].sign(); + at++; + for(; at < size + && orig_lits[at] != lit_Undef + && orig_lits[at] != lit_Error + ; at++ + ) { + vars.push_back(orig_lits[at].var()); + } + ret = solver.add_xor_clause_outside(vars, rhs); + } + } + + if (!ret) { + data_for_thread.update_mutex->lock(); + *data_for_thread.ret = l_False; + data_for_thread.update_mutex->unlock(); + } + } + + DataForThread& data_for_thread; + const size_t tid; +}; + +//Add the cached clauses and variables to the threads +static bool actually_add_clauses_to_threads(CMSatPrivateData* data) +{ + DataForThread data_for_thread(data); + if (data->solvers.size() == 1) { + OneThreadAddCls t(data_for_thread, 0); + t.operator()(); + } else { + vector thds; + for(size_t i = 0; i < data->solvers.size(); i++) { + thds.push_back(thread(OneThreadAddCls(data_for_thread, i))); + } + for(std::thread& t: thds){ + t.join(); + } + } + bool ret = (*data_for_thread.ret != l_False); + + //clear what has been added + data->cls_lits.clear(); + data->vars_to_add = 0; + + return ret; +} + +DLL_PUBLIC void SATSolver::set_max_time(double max_time) +{ + assert(max_time >= 0 && "Cannot set negative limit on running time"); + + const auto target_time = cpuTime() + max_time; + for (Solver* s : data->solvers) { + s->conf.maxTime = target_time; + } +} + +DLL_PUBLIC void SATSolver::set_max_confl(uint64_t max_confl) +{ + for (Solver* s : data->solvers) { + s->set_max_confl(max_confl); + } +} + +DLL_PUBLIC void SATSolver::set_default_polarity(bool polarity) +{ + for (size_t i = 0; i < data->solvers.size(); ++i) { + Solver& s = *data->solvers[i]; + s.conf.polarity_mode = polarity ? PolarityMode::polarmode_pos : PolarityMode::polarmode_neg; + } +} + +DLL_PUBLIC void SATSolver::set_no_simplify() +{ + for (size_t i = 0; i < data->solvers.size(); ++i) { + Solver& s = *data->solvers[i]; + s.conf.doRenumberVars = false; + s.conf.simplify_at_startup = false; + s.conf.simplify_at_every_startup = false; + s.conf.full_simplify_at_startup = false; + s.conf.perform_occur_based_simp = false; + s.conf.do_simplify_problem = false; + } +} + +DLL_PUBLIC void SATSolver::set_allow_otf_gauss() +{ + for (size_t i = 0; i < data->solvers.size(); ++i) { + Solver& s = *data->solvers[i]; + //s.conf.reconfigure_at = 0; + //s.conf.reconfigure_val = 15; + s.conf.doFindXors = true; + s.conf.gaussconf.max_num_matrices = 10; + s.conf.gaussconf.max_matrix_columns = 10000000; + s.conf.gaussconf.max_matrix_rows = 10000; + s.conf.gaussconf.autodisable = false; + s.conf.xor_detach_reattach = true; + s.conf.allow_elim_xor_vars = false; + } +} + +DLL_PUBLIC void SATSolver::set_no_simplify_at_startup() +{ + for (size_t i = 0; i < data->solvers.size(); ++i) { + Solver& s = *data->solvers[i]; + s.conf.simplify_at_startup = false; + } +} + +DLL_PUBLIC void SATSolver::set_no_equivalent_lit_replacement() +{ + set_scc(0); +} + +DLL_PUBLIC void SATSolver::set_no_bva() +{ + set_bva(0); +} + +DLL_PUBLIC void SATSolver::set_simplify(const bool simp) +{ + for (size_t i = 0; i < data->solvers.size(); ++i) { + Solver& s = *data->solvers[i]; + s.conf.do_simplify_problem = simp; + } +} +DLL_PUBLIC void SATSolver::set_picosat_gate_limitK(const uint32_t lim) +{ + for (size_t i = 0; i < data->solvers.size(); ++i) { + Solver& s = *data->solvers[i]; + s.conf.picosat_gate_limitK = lim; + } +} + +DLL_PUBLIC void SATSolver::set_weaken_time_limitM(const uint32_t lim) +{ + for (size_t i = 0; i < data->solvers.size(); ++i) { + Solver& s = *data->solvers[i]; + s.conf.weaken_time_limitM = lim; + } +} + +DLL_PUBLIC void SATSolver::set_occ_based_lit_rem_time_limitM(const uint32_t lim) +{ + for (size_t i = 0; i < data->solvers.size(); ++i) { + Solver& s = *data->solvers[i]; + s.conf.occ_based_lit_rem_time_limitM = lim; + } +} + +DLL_PUBLIC double SATSolver::get_orig_global_timeout_multiplier() +{ + return data->solvers[0]->conf.orig_global_timeout_multiplier; +} + + +DLL_PUBLIC void SATSolver::set_orig_global_timeout_multiplier(const double mult) +{ + for (size_t i = 0; i < data->solvers.size(); ++i) { + Solver& s = *data->solvers[i]; + s.conf.orig_global_timeout_multiplier = mult; + } +} + + +DLL_PUBLIC void SATSolver::set_no_bve() +{ + for (size_t i = 0; i < data->solvers.size(); ++i) { + Solver& s = *data->solvers[i]; + s.conf.doVarElim = false; + } +} + +DLL_PUBLIC void SATSolver::set_bve(int bve) +{ + for (size_t i = 0; i < data->solvers.size(); ++i) { + Solver& s = *data->solvers[i]; + s.conf.doVarElim = bve; + } +} + + +DLL_PUBLIC void SATSolver::set_bve_too_large_resolvent(int too_large_resolvent) +{ + for (size_t i = 0; i < data->solvers.size(); ++i) { + Solver& s = *data->solvers[i]; + s.conf.velim_resolvent_too_large = too_large_resolvent; + } +} + +DLL_PUBLIC void SATSolver::set_greedy_undef() +{ + assert(false && "ERROR: Unfortunately, greedy undef is broken, please don't use it"); + std::cerr << "ERROR: Unfortunately, greedy undef is broken, please don't use it" << endl; + exit(-1); +} + +DLL_PUBLIC void SATSolver::set_sampling_vars(const vector* sampl_vars) +{ + for (size_t i = 0; i < data->solvers.size(); ++i) { + Solver& s = *data->solvers[i]; + s.conf.sampling_vars = sampl_vars; + } +} + + +DLL_PUBLIC void SATSolver::set_verbosity(unsigned verbosity) +{ + if (data->solvers.empty()) + return; + + Solver& s = *data->solvers[0]; + s.conf.verbosity = verbosity; +} + +DLL_PUBLIC void SATSolver::set_timeout_all_calls(double timeout) +{ + data->timeout = timeout; +} + +DLL_PUBLIC bool SATSolver::add_red_clause(const vector< Lit >& lits) { + // TODO: use the bulk-adding maybe... but lit_Undef is used for clauses + // and lit_Error for XOR clauses, so... it's a bit crowded + if (data->log) { (*data->log) << "c red " << lits << " 0" << endl; } + bool ret = actually_add_clauses_to_threads(data); + + if (!ret) return false; + for(auto& s: data->solvers) { + ret &= s->add_clause_outside(lits, true); + } + return ret; +} + +DLL_PUBLIC bool SATSolver::add_clause(const vector< Lit >& lits) +{ + if (data->log) { (*data->log) << lits << " 0" << endl; } + + bool ret = true; + if (data->solvers.size() > 1) { + if (data->cls_lits.size() + lits.size() + 1 > CACHE_SIZE) { + ret = actually_add_clauses_to_threads(data); + } + + data->cls_lits.push_back(lit_Undef); + for(Lit lit: lits) { + data->cls_lits.push_back(lit); + } + } else { + data->solvers[0]->new_vars(data->vars_to_add); + data->vars_to_add = 0; + + ret = data->solvers[0]->add_clause_outside(lits); + data->cls++; + } + + return ret; +} + +void add_xor_clause_to_log(const std::vector& vars, bool rhs, std::ofstream* file) +{ + if (vars.size() == 0) { + if (rhs) { + (*file) << "0" << endl; + } + } else { + if (!rhs) { + (*file) << "-"; + } + for(unsigned var: vars) { + (*file) << (var+1) << " "; + } + (*file) << " 0" << endl; + } +} + +DLL_PUBLIC bool SATSolver::add_xor_clause(const std::vector& vars, bool rhs) +{ + if (data->log) { + add_xor_clause_to_log(vars, rhs, data->log); + } + + bool ret = true; + if (data->solvers.size() > 1) { + if (data->cls_lits.size() + vars.size() + 1 > CACHE_SIZE) { + ret = actually_add_clauses_to_threads(data); + } + + data->cls_lits.push_back(lit_Error); + data->cls_lits.push_back(Lit(0, rhs)); + for(uint32_t var: vars) { + data->cls_lits.push_back(Lit(var, false)); + } + } else { + data->solvers[0]->new_vars(data->vars_to_add); + data->vars_to_add = 0; + + ret = data->solvers[0]->add_xor_clause_outside(vars, rhs); + data->cls++; + } + + return ret; +} + +DLL_PUBLIC bool SATSolver::add_bnn_clause( + const std::vector& lits, + signed cutoff, + Lit out) +{ + if (data->log) { + assert(false && "No logs for BNN yet"); + } + + //lit_Undef is == TRUE, but lit_Error is not accepted + assert(out != lit_Error); + + bool ret = true; + if (data->solvers.size() > 1) { + assert(false && "No multithreading for BNN yet"); + } else { + data->solvers[0]->new_vars(data->vars_to_add); + data->vars_to_add = 0; + + ret = data->solvers[0]->add_bnn_clause_outside( + lits, + cutoff, + out); + data->cls++; + } + + return ret; +} + +enum class Todo {todo_solve, todo_simplify}; + +struct OneThreadCalc +{ + OneThreadCalc( + DataForThread& _data_for_thread, + size_t _tid, + Todo _todo, + bool _only_sampling_solution + ) : + data_for_thread(_data_for_thread) + , tid(_tid) + , todo(_todo) + , only_sampling_solution(_only_sampling_solution) + { + assert(data_for_thread.cpu_times.size() > tid); + assert(data_for_thread.solvers.size() > tid); + } + + void operator()() + { + if (print_thread_start_and_finish) { + start_time = cpuTime(); + //data_for_thread.update_mutex->lock(); + //cout << "c Starting thread " << tid << endl; + //data_for_thread.update_mutex->unlock(); + } + + //Add clauses and variables + OneThreadAddCls cls_adder(data_for_thread, tid); + cls_adder(); + + //Solve or simplify + lbool ret; + if (todo == Todo::todo_solve) { + ret = data_for_thread.solvers[tid]->solve_with_assumptions(data_for_thread.assumptions, only_sampling_solution); + } else if (todo == Todo::todo_simplify) { + ret = data_for_thread.solvers[tid]->simplify_with_assumptions(data_for_thread.assumptions); + } else { + assert(false); + } + + assert(data_for_thread.cpu_times.size() > tid); + data_for_thread.cpu_times[tid] = cpuTime(); + if (print_thread_start_and_finish) { + data_for_thread.update_mutex->lock(); + ios::fmtflags f(cout.flags()); + cout << "c Finished thread " << tid << " with result: " << ret + << " T-diff: " << std::fixed << std::setprecision(2) + << (data_for_thread.cpu_times[tid]-start_time) + << endl; + cout.flags(f); + data_for_thread.update_mutex->unlock(); + } + + + if (ret != l_Undef) { + data_for_thread.update_mutex->lock(); + *data_for_thread.which_solved = tid; + *data_for_thread.ret = ret; + //will interrupt all of them + data_for_thread.solvers[0]->set_must_interrupt_asap(); + data_for_thread.update_mutex->unlock(); + } + } + + DataForThread& data_for_thread; + const size_t tid; + double start_time; + Todo todo; + bool only_sampling_solution; +}; + +lbool calc( + const vector< Lit >* assumptions, + Todo todo, + CMSatPrivateData *data, + bool only_sampling_solution = false, + const string* strategy = NULL +) { + //Sanity check + if (data->solvers.size() > 1 && data->sql > 0) { + std::cerr + << "Multithreaded solving and SQL cannot be specified at the same time" + << endl; + exit(-1); + } + + //Reset the interrupt signal if it was set + data->must_interrupt->store(false, std::memory_order_relaxed); + + //Set timeout information + if (data->timeout != numeric_limits::max()) { + for (size_t i = 0; i < data->solvers.size(); ++i) { + Solver& s = *data->solvers[i]; + s.conf.maxTime = cpuTime() + data->timeout; + } + } + + if (data->log) { + (*data->log) << "c Solver::"; + if (todo == Todo::todo_solve) { + (*data->log) << "solve"; + } else if (todo == Todo::todo_simplify) { + (*data->log) << "simplify"; + } else { + assert(false); + } + (*data->log) << "( "; + if (assumptions) { + (*data->log) << *assumptions; + } + (*data->log) << " )" << endl; + } + + //Deal with the single-thread case + if (data->solvers.size() == 1) { + data->solvers[0]->new_vars(data->vars_to_add); + data->vars_to_add = 0; + + lbool ret ; + if (todo == Todo::todo_solve) { + ret = data->solvers[0]->solve_with_assumptions(assumptions, only_sampling_solution); + } else if (todo == Todo::todo_simplify) { + ret = data->solvers[0]->simplify_with_assumptions(assumptions, strategy); + } + data->okay = data->solvers[0]->okay(); + data->cpu_times[0] = cpuTime(); + return ret; + } + + //Multi-threaded case + DataForThread data_for_thread(data, assumptions); + vector thds; + #ifdef USE_GPU + data->shared_data->gpuClauseSharer->setVarCount(data->total_num_vars); + #endif + for(size_t i = 0 + ; i < data->solvers.size() + ; i++ + ) { + thds.push_back(thread(OneThreadCalc( + data_for_thread, i, todo, only_sampling_solution))); + } + #ifdef USE_GPU + if (todo == Todo::todo_solve) { + GPUThread gpu_thread(data->shared_data, data->must_interrupt); + gpu_thread(); + } + #endif + + for(std::thread& t: thds){ + t.join(); + } + lbool real_ret = *data_for_thread.ret; + + //This does it for all of them, there is only one must-interrupt + data_for_thread.solvers[0]->unset_must_interrupt_asap(); + + //clear what has been added + data->cls_lits.clear(); + data->vars_to_add = 0; + data->okay = data->solvers[*data_for_thread.which_solved]->okay(); + return real_ret; +} + +DLL_PUBLIC lbool SATSolver::solve(const vector< Lit >* assumptions, bool only_sampling_solution) +{ + if (data->promised_single_call + && data->num_solve_simplify_calls > 0 + ) { + cout + << "ERROR: You promised to only call solve/simplify() once" + << " by calling set_single_run(), but you violated it. Exiting." + << endl; + exit(-1); + } + data->num_solve_simplify_calls++; + + //set information data (props, confl, dec) + data->previous_sum_conflicts = get_sum_conflicts(); + data->previous_sum_propagations = get_sum_propagations(); + data->previous_sum_decisions = get_sum_decisions(); + + return calc(assumptions, Todo::todo_solve, data, only_sampling_solution); +} + +DLL_PUBLIC lbool SATSolver::simplify(const vector< Lit >* assumptions, const string* strategy) +{ + if (data->promised_single_call + && data->num_solve_simplify_calls > 0 + ) { + cout + << "ERROR: You promised to only call solve/simplify() once" + << " by calling set_single_run(), but you violated it. Exiting." + << endl; + exit(-1); + } + data->num_solve_simplify_calls++; + + //set information data (props, confl, dec) + data->previous_sum_conflicts = get_sum_conflicts(); + data->previous_sum_propagations = get_sum_propagations(); + data->previous_sum_decisions = get_sum_decisions(); + + return calc(assumptions, Todo::todo_simplify, data, false, strategy); +} + +DLL_PUBLIC const vector< lbool >& SATSolver::get_model() const +{ + return data->solvers[data->which_solved]->get_model(); +} + +DLL_PUBLIC const std::vector& SATSolver::get_conflict() const +{ + + return data->solvers[data->which_solved]->get_final_conflict(); +} + +DLL_PUBLIC uint32_t SATSolver::nVars() const +{ + return data->solvers[0]->nVarsOutside() + data->vars_to_add; +} + +DLL_PUBLIC void SATSolver::new_var() +{ + new_vars(1); +} + +DLL_PUBLIC void SATSolver::new_vars(const size_t n) +{ + if (n >= MAX_VARS || + data->total_num_vars + n >= MAX_VARS) + { + throw CMSat::TooManyVarsError(); + } + + if (data->log) { + (*data->log) << "c Solver::new_vars( " << n << " )" << endl; + } + + data->vars_to_add += n; + data->total_num_vars += n; +} + +DLL_PUBLIC void SATSolver::add_sql_tag(const std::string& name, const std::string& val) +{ + for(Solver* solver: data->solvers) { + solver->add_sql_tag(name, val); + } +} + + +DLL_PUBLIC const char* SATSolver::get_version_sha1() +{ + return Solver::get_version_sha1(); +} + +DLL_PUBLIC const char* SATSolver::get_version() +{ + return Solver::get_version_tag(); +} + +DLL_PUBLIC const char* SATSolver::get_compilation_env() +{ + return Solver::get_compilation_env(); +} + +DLL_PUBLIC std::string SATSolver::get_text_version_info() +{ + std::stringstream ss; + ss << "c CryptoMiniSat version " << get_version() << endl; + ss << "c CMS Copyright (C) 2009-2020 Authors of CryptoMiniSat, see AUTHORS file" << endl; + ss << "c CMS SHA revision " << get_version_sha1() << endl; + ss << "c Using VMTF code by Armin Biere from CaDiCaL" << endl; + ss << "c Using Yalsat by Armin Biere, see Balint et al. Improving implementation of SLS solvers [...], SAT'14" << endl; + ss << "c Using WalkSAT by Henry Kautz, see Kautz and Selman Pushing the envelope: planning, propositional logic, and stochastic search, AAAI'96," << endl; + #ifdef USE_BREAKID + ss << "c Using BreakID by Devriendt, Bogaerts, Bruynooghe and Denecker" << endl; + ss << "c Using Bliss graph automorphism library (under LGPL) by Tommi Junttila" << endl; + ss << "c CMS is GPL licensed due to Bliss being linked. Build without Bliss to get MIT version" << endl; + #else + ss << "c CMS is MIT licensed" << endl; + #endif + + ss << "c Using code from 'When Boolean Satisfiability Meets Gauss-E. in a Simplex Way'" << endl; + ss << "c by C.-S. Han and J.-H. Roland Jiang in CAV 2012. Fixes by M. Soos" << endl; + ss << "c Using CCAnr from 'CCAnr: A Conf. Checking Based Local Search Solver [...]'" << endl; + ss << "c by Shaowei Cai, Chuan Luo, and Kaile Su, SAT 2015" << endl; + ss << "c CMS compilation env " << get_compilation_env() << endl; + #ifdef __GNUC__ + ss << "c CMS compiled with gcc version " << __VERSION__ << endl; + #else + ss << "c CMS compiled with non-gcc compiler" << endl; + #endif + + return ss.str(); +} + +DLL_PUBLIC void SATSolver::print_stats(double wallclock_time_started) const +{ + double cpu_time_total = cpuTimeTotal(); + + double cpu_time; + if (data->interrupted) { + //cannot know, we can only print one, so we print the 1st + cpu_time = data->cpu_times[0]; + } else { + //We print the winning solver's thread time + cpu_time = data->cpu_times[data->which_solved]; + } + + //If only one thread, then it's easy + if (data->solvers.size() == 1) { + cpu_time = cpu_time_total; + } + + data->solvers[data->which_solved]->print_stats(cpu_time, cpu_time_total, wallclock_time_started); +} + +DLL_PUBLIC void SATSolver::set_find_xors(bool do_find_xors) +{ + for (size_t i = 0; i < data->solvers.size(); ++i) { + Solver& s = *data->solvers[i]; + s.conf.doFindXors = do_find_xors; + } +} + +DLL_PUBLIC void SATSolver::set_frat(FILE* os) +{ + if (data->solvers.size() > 1) { + std::cerr << "ERROR: FRAT cannot be used in multi-threaded mode" << endl; + exit(-1); + } + if (nVars() > 0) { + std::cerr << "ERROR: FRAT cannot be set after variables have been added" << endl; + exit(-1); + } + + data->solvers[0]->conf.doBreakid = false; + data->solvers[0]->add_frat(os); + data->solvers[0]->conf.do_hyperbin_and_transred = true; +} + +DLL_PUBLIC void SATSolver::interrupt_asap() +{ + data->must_interrupt->store(true, std::memory_order_relaxed); +} + +void DLL_PUBLIC SATSolver::add_in_partial_solving_stats() +{ + data->solvers[data->which_solved]->add_in_partial_solving_stats(); + data->interrupted = true; +} + +DLL_PUBLIC std::vector SATSolver::get_zero_assigned_lits() const +{ + return data->solvers[data->which_solved]->get_zero_assigned_lits(); +} + +DLL_PUBLIC unsigned long SATSolver::get_sql_id() const +{ + return 0; +} + +DLL_PUBLIC bool SATSolver::okay() const +{ + return data->okay && data->solvers[0]->okay(); +} + +DLL_PUBLIC void SATSolver::log_to_file(std::string filename) +{ + if (data->log) { + std::cerr + << "ERROR: A file has already been designated for logging!" + << endl; + exit(-1); + } + + data->log = new std::ofstream(); + data->log->exceptions( std::ofstream::failbit | std::ofstream::badbit ); + data->log->open(filename.c_str(), std::ios::out); + if (!data->log->is_open()) { + std::cerr + << "ERROR: Cannot open record file '" << filename << "'" + << " for writing." + << endl; + exit(-1); + } +} + +DLL_PUBLIC std::vector > SATSolver::get_all_binary_xors() const +{ + return data->solvers[0]->get_all_binary_xors(); +} + +DLL_PUBLIC vector, bool> > +SATSolver::get_recovered_xors(bool xor_together_xors) const +{ + vector, bool> > ret; + Solver& s = *data->solvers[0]; + + std::pair, bool> tmp; + vector xors = s.get_recovered_xors(xor_together_xors); + for(const auto& x: xors) { + tmp.first = x.get_vars(); + tmp.second = x.rhs; + ret.push_back(tmp); + } + return ret; +} + +DLL_PUBLIC void SATSolver::set_sqlite(std::string filename) +{ + if (data->solvers.size() > 1) { + std::cerr + << "Multithreaded solving and SQL cannot be specified at the same time" + << endl; + exit(-1); + } + data->sql = 1; + data->solvers[0]->set_sqlite(filename); +} + +DLL_PUBLIC uint64_t SATSolver::get_sum_conflicts() +{ + uint64_t conlf = 0; + for (size_t i = 0; i < data->solvers.size(); ++i) { + Solver& s = *data->solvers[i]; + conlf += s.sumConflicts; + } + return conlf; +} + +DLL_PUBLIC uint64_t SATSolver::get_sum_conflicts() const +{ + uint64_t total_conflicts = 0; + for (Solver const* s : data->solvers) { + total_conflicts += s->sumConflicts; + } + return total_conflicts; +} + +DLL_PUBLIC uint64_t SATSolver::get_sum_propagations() +{ + uint64_t props = 0; + for (size_t i = 0; i < data->solvers.size(); ++i) { + Solver& s = *data->solvers[i]; + props += s.sumPropStats.propagations; + } + return props; +} + +DLL_PUBLIC uint64_t SATSolver::get_sum_propagations() const +{ + uint64_t total_propagations = 0; + for (Solver const* s : data->solvers) { + total_propagations += s->sumPropStats.propagations; + } + return total_propagations; +} + +DLL_PUBLIC uint64_t SATSolver::get_sum_decisions() +{ + uint64_t dec = 0; + for (size_t i = 0; i < data->solvers.size(); ++i) { + Solver& s = *data->solvers[i]; + dec += s.sumSearchStats.decisions; + } + return dec; +} + +DLL_PUBLIC uint64_t SATSolver::get_sum_decisions() const +{ + uint64_t total_decisions = 0; + for (Solver const* s : data->solvers) { + total_decisions += s->sumSearchStats.decisions; + } + return total_decisions; +} + +DLL_PUBLIC uint64_t SATSolver::get_last_conflicts() +{ + return get_sum_conflicts() - data->previous_sum_conflicts; +} + +DLL_PUBLIC uint64_t SATSolver::get_last_propagations() +{ + return get_sum_propagations() - data->previous_sum_propagations; +} + +DLL_PUBLIC uint64_t SATSolver::get_last_decisions() +{ + return get_sum_decisions() - data->previous_sum_decisions; +} + +void DLL_PUBLIC SATSolver::start_getting_small_clauses( + uint32_t max_len, + uint32_t max_glue, + bool red, + bool bva_vars, + bool simplified) +{ + actually_add_clauses_to_threads(data); + assert(data->solvers.size() >= 1); + data->solvers[0]->start_getting_small_clauses(max_len, max_glue, red, bva_vars, simplified); +} + +bool DLL_PUBLIC SATSolver::get_next_small_clause(std::vector& out, bool all_in_one) +{ + assert(data->solvers.size() >= 1); + return data->solvers[0]->get_next_small_clause(out, all_in_one); +} + +void DLL_PUBLIC SATSolver::end_getting_small_clauses() +{ + assert(data->solvers.size() >= 1); + data->solvers[0]->end_getting_small_clauses(); +} + +// Helper functions with more sane names +void DLL_PUBLIC SATSolver::start_getting_clauses(bool red, bool simplified) { + assert(data->solvers.size() >= 1); + data->solvers[0]->start_getting_small_clauses( + std::numeric_limits::max(), + std::numeric_limits::max(), + red, false, simplified); +} + +bool DLL_PUBLIC SATSolver::get_next_clause(std::vector &ret) { + return get_next_small_clause(ret); +} + +void DLL_PUBLIC SATSolver::end_getting_clauses() { + return end_getting_small_clauses(); +} +// Helper functions end + + +DLL_PUBLIC vector SATSolver::translate_sampl_set( + const vector& sampl_set) +{ + return data->solvers[0]->translate_sampl_set(sampl_set); +} + +void DLL_PUBLIC SATSolver::set_min_bva_gain(uint32_t min_bva_gain) +{ + for (size_t i = 0; i < data->solvers.size(); i++) { + data->solvers[i]->conf.min_bva_gain = min_bva_gain; + } +} + +void DLL_PUBLIC SATSolver::set_up_for_sample_counter(const uint32_t fixed_restart) +{ + for (size_t i = 0; i < data->solvers.size(); i++) { + SolverConf conf = data->solvers[i]->getConf(); + conf.doSLS = false; + conf.doBreakid = false; + conf.restartType = Restart::fixed; + conf.never_stop_search = true; + conf.branch_strategy_setup = "rand"; + conf.simplify_at_startup = false; + conf.doFindAndReplaceEqLits = false; + conf.do_distill_clauses = false; + conf.doFindXors = false; + conf.fixed_restart_num_confl = fixed_restart; + conf.polarity_mode = CMSat::PolarityMode::polarmode_rnd; + + data->solvers[i]->setConf(conf); + } +} + +void DLL_PUBLIC SATSolver::set_up_for_scalmc() +{ + for (size_t i = 0; i < data->solvers.size(); i++) { + SolverConf conf = data->solvers[i]->getConf(); + conf.doBreakid = false; + conf.gaussconf.max_matrix_columns = 10000000; + conf.gaussconf.max_matrix_rows = 10000; + conf.gaussconf.max_num_matrices = 2; + conf.gaussconf.autodisable = false; + conf.xor_detach_reattach = true; + conf.global_multiplier_multiplier_max = 1; + conf.orig_global_timeout_multiplier = 1.5; + conf.min_bva_gain = 1; + conf.xor_finder_time_limitM = 400; +// conf.polar_stable_every_n = 100000; //i.e. never + uint32_t xor_cut = 4; + assert(xor_cut >= 3); + conf.xor_var_per_cut = xor_cut-2; + + //Distill + conf.distill_sort = 4; + conf.distill_long_cls_time_limitM = 10ULL; + conf.distill_red_tier0_ratio = 0.7; + conf.distill_red_tier1_ratio = 0.07; + + + + + conf.simplify_at_startup = 1; + conf.varElimRatioPerIter = 1; +// conf.restartType = Restart::luby; + //conf.polarity_mode = CMSat::PolarityMode::polarmode_stable; +// conf.branch_strategy_setup = "vsids1"; + conf.bva_every_n = 1; + conf.do_simplify_problem = true; + conf.force_preserve_xors = true; + conf.diff_declev_for_chrono = -1; + conf.do_bosphorus = false; + data->solvers[i]->setConf(conf); + } +} + +void DLL_PUBLIC SATSolver::set_up_for_arjun() +{ + for (size_t i = 0; i < data->solvers.size(); i++) { + SolverConf conf = data->solvers[i]->getConf(); + conf.doBreakid = false; + //conf.gaussconf.max_num_matrices = 0; + //conf.xor_finder_time_limitM = 0; + //conf.xor_detach_reattach = true; + conf.global_multiplier_multiplier_max = 1; + conf.orig_global_timeout_multiplier = 2.5; + conf.do_bva = false; +// conf.polar_stable_every_n = 100000; //i.e. never use stable polarities + conf.do_hyperbin_and_transred = false; + conf.doTransRed = false; + + //conf.do_simplify_problem = false; //no simplification without explicity calling it +// conf.varElimRatioPerIter = 1; + conf.restartType = Restart::geom; + conf.polarity_mode = CMSat::PolarityMode::polarmode_best; + conf.branch_strategy_setup = "vsids1"; + conf.diff_declev_for_chrono = -1; + conf.do_bosphorus = false; + + //Distill + conf.distill_sort = 4; + conf.distill_long_cls_time_limitM = 10ULL; + conf.distill_red_tier0_ratio = 0.7; + conf.distill_red_tier1_ratio = 0.07; + + data->solvers[i]->setConf(conf); + } +} + +DLL_PUBLIC const vector& SATSolver::get_bnns() const +{ + return data->solvers[0]->get_bnns(); +} + +DLL_PUBLIC uint32_t SATSolver::get_verbosity() const +{ + const SolverConf& conf = data->solvers[0]->getConf(); + return conf.verbosity; +} + +DLL_PUBLIC void SATSolver::set_verbosity_detach_warning(bool verb) +{ + for (size_t i = 0; i < data->solvers.size(); i++) { + SolverConf conf = data->solvers[i]->getConf(); + conf.xor_detach_verb = verb; + data->solvers[i]->setConf(conf); + } +} + +DLL_PUBLIC void SATSolver::add_empty_cl_to_frat() +{ + data->solvers[data->which_solved]->add_empty_cl_to_frat(); +} + +DLL_PUBLIC void SATSolver::set_single_run() +{ + if (data->num_solve_simplify_calls > 0) { + cout << "ERROR: You must call set_single_run() before solving" << endl; + exit(-1); + } + data->promised_single_call = true; + + for (size_t i = 0; i < data->solvers.size(); ++i) { + Solver& s = *data->solvers[i]; + s.conf.breakid_use_assump = false; + } +} + +DLL_PUBLIC void SATSolver::set_var_weight(Lit lit, double weight) +{ + actually_add_clauses_to_threads(data); + for (size_t i = 0; i < data->solvers.size(); ++i) { + Solver& s = *data->solvers[i]; + s.set_var_weight(lit, weight); + } +} + +DLL_PUBLIC std::vector SATSolver::get_lit_incidence() +{ + actually_add_clauses_to_threads(data); + return data->solvers[data->which_solved]->get_outside_lit_incidence(); +} + +DLL_PUBLIC vector SATSolver::get_var_incidence() +{ + actually_add_clauses_to_threads(data); + return data->solvers[data->which_solved]->get_outside_var_incidence(); +} + +DLL_PUBLIC vector SATSolver::get_recovered_or_gates() +{ + actually_add_clauses_to_threads(data); + return data->solvers[0]->get_recovered_or_gates(); +} + +DLL_PUBLIC vector SATSolver::get_recovered_ite_gates() +{ + actually_add_clauses_to_threads(data); + return data->solvers[0]->get_recovered_ite_gates(); +} + +DLL_PUBLIC void SATSolver::set_renumber(const bool renumber) +{ + for(auto& s: data->solvers) { + s->conf.doRenumberVars = renumber; + } +} + +DLL_PUBLIC std::vector SATSolver::remove_definable_by_irreg_gate(const vector& vars) +{ + return data->solvers[0]->remove_definable_by_irreg_gate(vars); +} + +DLL_PUBLIC void SATSolver::clean_sampl_and_get_empties( + std::vector& sampl_vars, std::vector& empty_vars) +{ + return data->solvers[0]->clean_sampl_and_get_empties(sampl_vars, empty_vars); +} + +DLL_PUBLIC lbool SATSolver::find_fast_backw(FastBackwData fast_backw) +{ + assert(data->solvers.size() == 1); + data->solvers[0]->fast_backw = fast_backw; + bool backup_doVarElim = data->solvers[0]->conf.doVarElim; + data->solvers[0]->conf.doVarElim = true; + const auto ret = solve(NULL, true); + data->solvers[0]->fast_backw = FastBackwData(); + data->solvers[0]->conf.doVarElim = backup_doVarElim; + + return ret; +} + +DLL_PUBLIC void SATSolver::remove_and_clean_all() +{ + for(auto& s: data->solvers) { + if (!s->okay()) return; + s->remove_and_clean_all(); + } +} + +DLL_PUBLIC vector SATSolver::get_var_incidence_also_red() +{ + return data->solvers[data->which_solved]->get_outside_var_incidence_also_red(); +} + +DLL_PUBLIC void SATSolver::set_intree_probe(int val) +{ + for (size_t i = 0; i < data->solvers.size(); ++i) { + Solver& s = *data->solvers[i]; + s.conf.doIntreeProbe = val; + } +} + +DLL_PUBLIC void SATSolver::set_no_confl_needed() +{ + for (size_t i = 0; i < data->solvers.size(); ++i) { + Solver& s = *data->solvers[i]; + s.conf.conf_needed = false; + } +} + + +DLL_PUBLIC bool SATSolver::implied_by( + const std::vector& lits, + std::vector& out_implied +) +{ + return data->solvers[data->which_solved]->implied_by(lits, out_implied); +} + +DLL_PUBLIC void SATSolver::set_full_bve(int val) +{ + for (size_t i = 0; i < data->solvers.size(); ++i) { + Solver& s = *data->solvers[i]; + s.conf.do_full_varelim = val; + } +} + +DLL_PUBLIC void SATSolver::set_sls(int val) +{ + for (size_t i = 0; i < data->solvers.size(); ++i) { + Solver& s = *data->solvers[i]; + s.conf.doSLS = val; + } +} + +DLL_PUBLIC void SATSolver::reset_vsids() +{ + for (size_t i = 0; i < data->solvers.size(); ++i) { + Solver& s = *data->solvers[i]; + s.reset_vsids(); + } +} + +DLL_PUBLIC void SATSolver::set_scc(int val) +{ + for (size_t i = 0; i < data->solvers.size(); ++i) { + Solver& s = *data->solvers[i]; + s.conf.doFindAndReplaceEqLits = val; + } +} + +DLL_PUBLIC void SATSolver::set_distill(int val) +{ + for (size_t i = 0; i < data->solvers.size(); ++i) { + Solver& s = *data->solvers[i]; + s.conf.do_distill_clauses = val; + } +} + +DLL_PUBLIC void SATSolver::set_bva(int val) +{ + for (size_t i = 0; i < data->solvers.size(); ++i) { + Solver& s = *data->solvers[i]; + s.conf.do_bva = val; + + //Cannot have BVA on thread 0 when MPI is turned on + if (s.conf.do_bva && s.conf.is_mpi && i == 0) { + cout << "ERROR, cannot have MPI + BVA" << endl; + exit(-1); + } + } +} + +DLL_PUBLIC void SATSolver::set_polarity_mode(CMSat::PolarityMode mode) +{ + for (size_t i = 0; i < data->solvers.size(); ++i) { + Solver& s = *data->solvers[i]; + s.conf.polarity_mode = mode; + } +} + +DLL_PUBLIC CMSat::PolarityMode SATSolver::get_polarity_mode() const +{ + return data->solvers[0]->conf.polarity_mode; +} + +DLL_PUBLIC void SATSolver::set_full_bve_iter_ratio(double val) +{ + for (size_t i = 0; i < data->solvers.size(); ++i) { + Solver& s = *data->solvers[i]; + s.conf.varElimRatioPerIter = val; + } +} + +DLL_PUBLIC void SATSolver::set_xor_detach(bool val) +{ + for (size_t i = 0; i < data->solvers.size(); ++i) { + Solver& s = *data->solvers[i]; + s.conf.xor_detach_reattach = val; + } +} + +DLL_PUBLIC void SATSolver::set_max_red_linkin_size(uint32_t sz) +{ + for (size_t i = 0; i < data->solvers.size(); ++i) { + Solver& s = *data->solvers[i]; + s.conf.maxRedLinkInSize = sz; + } +} + +DLL_PUBLIC void SATSolver::get_all_irred_clauses(std::vector& ret) +{ + assert(data->solvers.size() >= 1); + Solver& s = *data->solvers[0]; + s.get_all_irred_clauses(ret); +} + +DLL_PUBLIC lbool SATSolver::probe(Lit l, uint32_t& min_props) +{ + assert(data->solvers.size() >= 1); + Solver& s = *data->solvers[0]; + return s.probe_outside(l, min_props); +} + +DLL_PUBLIC uint32_t SATSolver::simplified_nvars() +{ + assert(data->solvers.size() >= 1); + Solver& s = *data->solvers[0]; + return s.nVars(); +} + +DLL_PUBLIC void SATSolver::set_varelim_check_resolvent_subs(bool varelim_check_resolvent_subs) +{ + for (size_t i = 0; i < data->solvers.size(); ++i) { + Solver& s = *data->solvers[i]; + s.conf.varelim_check_resolvent_subs = varelim_check_resolvent_subs; + } +} + + +DLL_PUBLIC void SATSolver::open_file_and_dump_irred_clauses(const char* fname) +{ + vector cls; + get_all_irred_clauses(cls); + + uint32_t num_cls = 0; + int32_t max_vars = -1; + for(const Lit l: cls) { + if (l == lit_Undef) { + num_cls++; + } else { + if ((int32_t)l.var() > max_vars) { + max_vars = (int32_t)l.var(); + } + } + } + + std::ofstream f(fname); + f << "p cnf " << max_vars << " " << num_cls << endl; + for(const Lit l: cls) { + if (l == lit_Undef) { + f << " 0" << endl; + } else { + f << l << " "; + } + } +} + +DLL_PUBLIC void SATSolver::set_pred_short_size(int32_t sz) +{ + if (sz == -1) { + //set to default + SolverConf conf2; + sz = conf2.pred_short_size; + } else if (sz < 0) { + cout << "ERROR: only 'sz' parameters accepted are -1 for resetting to default, and >=0" << endl; + assert(false); + exit(-1); + } + + for (size_t i = 0; i < data->solvers.size(); ++i) { + Solver& s = *data->solvers[i]; + s.conf.pred_short_size = sz; + } +} + +DLL_PUBLIC void SATSolver::set_pred_long_size(int32_t sz) +{ + if (sz == -1) { + //set to default + SolverConf conf2; + sz = conf2.pred_long_size; + } else if (sz < 0) { + cout << "ERROR: only 'sz' parameters accepted are -1 for resetting to default, and >=0" << endl; + assert(false); + exit(-1); + } + + for (size_t i = 0; i < data->solvers.size(); ++i) { + Solver& s = *data->solvers[i]; + s.conf.pred_long_size = sz; + } +} + +DLL_PUBLIC void SATSolver::set_pred_forever_size(int32_t sz) +{ + if (sz == -1) { + //set to default + SolverConf conf2; + sz = conf2.pred_forever_size; + } else if (sz < 0) { + cout << "ERROR: only 'sz' parameters accepted are -1 for resetting to default, and >=0" << endl; + assert(false); + exit(-1); + } + + for (size_t i = 0; i < data->solvers.size(); ++i) { + Solver& s = *data->solvers[i]; + s.conf.pred_forever_size = sz; + } +} + +DLL_PUBLIC void SATSolver::set_pred_long_chunk(int32_t sz) +{ + if (sz == -1) { + //set to default + SolverConf conf2; + sz = conf2.pred_long_chunk; + } else if (sz < 0) { + cout << "ERROR: only 'sz' parameters accepted are -1 for resetting to default, and >=0" << endl; + assert(false); + exit(-1); + } + + for (size_t i = 0; i < data->solvers.size(); ++i) { + Solver& s = *data->solvers[i]; + s.conf.pred_long_chunk = sz; + } +} + +DLL_PUBLIC void SATSolver::set_pred_forever_chunk(int32_t sz) +{ + if (sz == -1) { + //set to default + SolverConf conf2; + sz = conf2.pred_forever_chunk; + } else if (sz < 0) { + cout << "ERROR: only 'sz' parameters accepted are -1 for resetting to default, and >=0" << endl; + assert(false); + exit(-1); + } + + for (size_t i = 0; i < data->solvers.size(); ++i) { + Solver& s = *data->solvers[i]; + s.conf.pred_forever_chunk = sz; + } +} + +DLL_PUBLIC void SATSolver::set_pred_forever_cutoff(int32_t sz) +{ + if (sz == -1) { + //set to default + SolverConf conf2; + sz = conf2.pred_forever_cutoff; + } else if (sz < 0) { + cout << "ERROR: only 'sz' parameters accepted are -1 for resetting to default, and >=0" << endl; + assert(false); + exit(-1); + } + + for (size_t i = 0; i < data->solvers.size(); ++i) { + Solver& s = *data->solvers[i]; + s.conf.pred_forever_cutoff = sz; + } +} + +DLL_PUBLIC void SATSolver::set_every_pred_reduce(int32_t sz) +{ + if (sz == -1) { + //set to default + SolverConf conf2; + sz = conf2.every_pred_reduce; + } else if (sz < 0) { + cout << "ERROR: only 'sz' parameters accepted are -1 for resetting to default, and >=0" << endl; + assert(false); + exit(-1); + } + + for (size_t i = 0; i < data->solvers.size(); ++i) { + Solver& s = *data->solvers[i]; + s.conf.every_pred_reduce = sz; + } +} + +DLL_PUBLIC void SATSolver::set_seed(const uint32_t seed) +{ + + for (size_t i = 0; i < data->solvers.size(); ++i) { + Solver& s = *data->solvers[i]; + s.set_seed(seed); + } +} + +#ifdef ARJUN_SERIALIZE +DLL_PUBLIC std::string SATSolver::serialize_solution_reconstruction_data() const +{ + Solver& s = *data->solvers[0]; + return s.serialize_solution_reconstruction_data(); +} + +DLL_PUBLIC void* SATSolver::create_extend_solution_setup(std::string& dat) +{ + std::atomic* must_inter = new std::atomic; + Solver* solver = new CMSat::Solver(NULL, must_inter); + solver->create_from_solution_reconstruction_data(dat); + + return (void*)solver; +} + +DLL_PUBLIC pair> SATSolver::extend_solution(void* s, const vector& simp_sol) +{ + CMSat::Solver* solver = (CMSat::Solver*)s; + return solver->extend_minimized_model(simp_sol); +} + +DLL_PUBLIC void SATSolver::delete_extend_solution_setup(void* s) +{ + CMSat::Solver* solver = (CMSat::Solver*)s; + delete solver->get_must_interrupt_inter_asap_ptr(); + delete solver; +} +#endif + +DLL_PUBLIC bool SATSolver::minimize_clause(std::vector& cl) +{ + Solver& s = *data->solvers[0]; + actually_add_clauses_to_threads(data); + return s.minimize_clause(cl); +} + + +DLL_PUBLIC bool SATSolver::backbone_simpl(int64_t max_confl, bool cmsgen, bool& finished) +{ + Solver& s = *data->solvers[0]; + actually_add_clauses_to_threads(data); + return s.backbone_simpl(max_confl, cmsgen, finished); +} + +DLL_PUBLIC bool SATSolver::removed_var(uint32_t var) const{ + Solver& s = *data->solvers[0]; + actually_add_clauses_to_threads(data); + return s.removed_var_ext(var); +} + + +DLL_PUBLIC void SATSolver::set_oracle_get_learnts(bool val) { + Solver& s = *data->solvers[0]; + s.conf.oracle_get_learnts = val; +} + +DLL_PUBLIC void SATSolver::set_oracle_removed_is_learnt(bool val) { + Solver& s = *data->solvers[0]; + s.conf.oracle_removed_is_learnt = val; +} diff --git a/cryptominisat/cppsrc/src/cryptominisat.h b/cryptominisat/cppsrc/src/cryptominisat.h new file mode 100644 index 00000000..64274dd1 --- /dev/null +++ b/cryptominisat/cppsrc/src/cryptominisat.h @@ -0,0 +1,320 @@ +/****************************************** +Copyright (C) 2009-2020 Authors of CryptoMiniSat, see AUTHORS file + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. +***********************************************/ + +#pragma once + +#include +#include +#include +#include +#include +#include +#include +#include "solvertypesmini.h" + +namespace CMSat { + struct CMSatPrivateData; + #ifdef _WIN32 + class __declspec(dllexport) SATSolver + #else + class SATSolver + #endif + { + public: + //////////////////////////// + // You can pass in a variable that if set to TRUE, will abort the + // solver as soon as possible. This bool can be set through a timer, + // or through a thread, etc. This gives you the possiblity to abort + // the solver any time you like, depending on some external factor + // such as time, or your own code's inner workings. + SATSolver(void* config = NULL + , std::atomic* interrupt_asap = NULL + ); + ~SATSolver(); + + //////////////////////////// + // Adding variables and clauses + ///////////////`///////////// + + void new_var(); //add a new variable to the solver + void new_vars(const size_t n); //and many new variables to the solver -- much faster + unsigned nVars() const; //get number of variables inside the solver + bool add_clause(const std::vector& lits); + bool add_red_clause(const std::vector& lits); + bool add_xor_clause(const std::vector& vars, bool rhs); + bool add_bnn_clause( + const std::vector& lits, + signed cutoff, + Lit out = lit_Undef + ); + void set_var_weight(Lit lit, double weight); + + //////////////////////////// + // Solving and simplifying + // You can call solve() multiple times: incremental mode is supported! + //////////////////////////// + + lbool solve(const std::vector* assumptions = 0, bool only_indep_solution = false); //solve the problem, optionally with assumptions. If only_indep_solution is set, only the independent variables set with set_independent_vars() are returned in the solution + lbool simplify(const std::vector* assumptions = NULL, const std::string* strategy = NULL); //simplify the problem, optionally with assumptions + const std::vector& get_model() const; //get model that satisfies the problem. Only makes sense if previous solve()/simplify() call was l_True + const std::vector& get_conflict() const; //get conflict in terms of the assumptions given in case the previous call to solve() was l_False + bool okay() const; //the problem is still solveable, i.e. the empty clause hasn't been derived + const std::vector& get_decisions_reaching_model() const; //get decisions that lead to model. may NOT work, in case the decisions needed were internal, extended variables. exit(-1)'s in case of such a case. you MUST check decisions_reaching_computed(). + + //////////////////////////// + // Debug all calls for later replay with --debuglit FILENAME + //////////////////////////// + void log_to_file(std::string filename); + + //////////////////////////// + // SQLite for statistics gathering + //////////////////////////// + void set_sqlite(std::string filename); + void add_sql_tag(const std::string& tagname, const std::string& tag); + unsigned long get_sql_id() const; + + //////////////////////////// + // Configuration + // -- Note that nothing else can be changed, only these. + // -- The main.cpp has access to the internal config, but it changes + // -- all the time and hence exposing it to the outside world would + // -- be very brittle. + //////////////////////////// + + void set_num_threads(unsigned n); //Number of threads to use. Must be set before any vars/clauses are added + void set_allow_otf_gauss(); //allow on-the-fly gaussian elimination + /** + * CPU time (in seconds) that can be consumed before the next call to solve() must return + * + * Because the elapsed CPU time depends on both the number of + * threads, and the activity of these threads, the elapsed time + * can wildly differ from wall clock time. + * + * \pre max_time >= 0 + */ + void set_max_time(double max_time); + /** + * Conflicts that can be consumed before the next call to solve() must return + * + * \pre max_confl >= 0 + */ + void set_max_confl(uint64_t max_confl); + void set_verbosity(unsigned verbosity = 0); //default is 0, silent + uint32_t get_verbosity() const; + void set_verbosity_detach_warning(bool verb); //default is 0, silent + void set_default_polarity(bool polarity); //default polarity when branching for all vars + void set_polarity_mode(CMSat::PolarityMode mode); //set polarity type + CMSat::PolarityMode get_polarity_mode() const; + void set_no_simplify(); //never simplify + void set_no_simplify_at_startup(); //doesn't simplify at start, faster startup time + void set_no_equivalent_lit_replacement(); //don't replace equivalent literals + void set_no_bva(); //No bounded variable addition + void set_no_bve(); //No bounded variable elimination + void set_bve(int bve); + void set_bve_too_large_resolvent(int too_large_resolvent); + void set_greedy_undef(); //Try to set variables to l_Undef in solution + void set_sampling_vars(const std::vector* sampl_vars); + void set_timeout_all_calls(double secs); //max timeout on all subsequent solve() or simplify + void set_up_for_scalmc(); //used to set the solver up for ScalMC configuration + void set_up_for_arjun(); + void set_up_for_sample_counter(const uint32_t fixed_restart); + void set_single_run(); //we promise to call solve() EXACTLY once + void set_intree_probe(int val); + void set_sls(int val); + void set_full_bve(int val); + void set_full_bve_iter_ratio(double val); + void set_scc(int val); + void set_bva(int val); + void set_distill(int val); + void reset_vsids(); + void set_no_confl_needed(); //assumptions-based conflict will NOT be calculated for next solve run + void set_xor_detach(bool val); + void set_simplify(const bool simp); + void set_find_xors(bool do_find_xors); + void set_min_bva_gain(uint32_t min_bva_gain); + void set_varelim_check_resolvent_subs(bool varelim_check_resolvent_subs); //check subumption and literal during varelim + void set_max_red_linkin_size(uint32_t sz); + void set_seed(const uint32_t seed); + void set_renumber(const bool renumber); + void set_weaken_time_limitM(const uint32_t lim); + void set_picosat_gate_limitK(const uint32_t lim); + void set_occ_based_lit_rem_time_limitM(const uint32_t lim); + void set_orig_global_timeout_multiplier(const double mult); + void set_oracle_get_learnts(bool val); + void set_oracle_removed_is_learnt(bool val); + double get_orig_global_timeout_multiplier(); + bool minimize_clause(std::vector& cl); + + //////////////////////////// + // Predictive system tuning + //////////////////////////// + void set_pred_short_size(int32_t sz = -1); + void set_pred_long_size(int32_t sz = -1); + void set_pred_forever_size(int32_t sz = -1); + void set_pred_long_chunk(int32_t sz = -1); + void set_pred_forever_chunk(int32_t sz = -1); + void set_pred_forever_cutoff(int32_t sz = -1); + void set_every_pred_reduce(int32_t sz = -1); + + //////////////////////////// + // Get generic info + //////////////////////////// + static const char* get_version(); //get solver version in string format + static const char* get_version_sha1(); //get SHA1 version string of the solver + static const char* get_compilation_env(); //get compilation environment string + static std::string get_text_version_info(); //get printable version and copyright text + + + //////////////////////////// + // Get info about only the last solve() OR simplify() call + // summed for all threads + //////////////////////////// + uint64_t get_last_conflicts(); //get total number of conflicts of last solve() or simplify() call of all threads + uint64_t get_last_propagations(); //get total number of propagations of last solve() or simplify() call made by all threads + uint64_t get_last_decisions(); //get total number of decisions of last solve() or simplify() call made by all threads + + + //////////////////////////// + //Get info about total sum of all time of all threads + //////////////////////////// + + uint64_t get_sum_conflicts(); //get total number of conflicts of all time of all threads + uint64_t get_sum_conflicts() const; //!< Return sum of all conflicts since construction across all the threads + uint64_t get_sum_propagations(); //get total number of propagations of all time made by all threads + uint64_t get_sum_propagations() const; //!< Returns sum of all propagations since construction across all the threads + uint64_t get_sum_decisions(); //get total number of decisions of all time made by all threads + uint64_t get_sum_decisions() const; //!< Returns sum of all decisions since construction across all the threads + + void print_stats(double wallclock_time_started = 0) const; //print solving stats. Call after solve()/simplify() + void set_frat(FILE* os); //set frat to ostream, e.g. stdout or a file + void add_empty_cl_to_frat(); // allows to treat SAT as UNSAT and perform learning + void interrupt_asap(); //call this asynchronously, and the solver will try to cleanly abort asap + void add_in_partial_solving_stats(); //used only by Ctrl+C handler. Ignore. + + //////////////////////////// + // Extract useful information from the solver + // This can be used in the theory solver + + //////////////////////////// + std::vector get_zero_assigned_lits() const; //get literals of fixed value + std::vector > get_all_binary_xors() const; //get all binary XORs that are = 0 + + ////////////////////// + // EXPERIMENTAL + std::vector, bool> > get_recovered_xors(bool xor_together_xors) const; //get XORs recovered. If "xor_together_xors" is TRUE, then xors that share a variable (and ONLY they share them) will be XORed together + std::vector get_recovered_or_gates(); + std::vector get_recovered_ite_gates(); + std::vector remove_definable_by_irreg_gate(const std::vector& vars); + void clean_sampl_and_get_empties(std::vector& sampl_vars, std::vector& empty_vars); + std::vector get_var_incidence(); + std::vector get_lit_incidence(); + std::vector get_var_incidence_also_red(); + std::vector get_vsids_scores(); + + lbool find_fast_backw(FastBackwData fast_backw); + void remove_and_clean_all(); + lbool probe(Lit l, uint32_t& min_props); + bool backbone_simpl(int64_t max_confl, bool cmsgen, bool& finished); + + //Given a set of literals to enqueue, returns: + // 1) Whether they imply UNSAT. If "false": UNSAT + // 2) into "out_implied" the set of literals they imply, including the literals themselves + // NOTES: + // * In case some variables have been eliminated, they cannot be implied + // * You must not put any variable into it that's been eliminated. Pass a pointer to solve() and simplif() to make sure some variables are never elimianted, or call set_no_bve() + // * You may get back some of the literals you gave + // * Order is not guaranteed: literals you gave as input may end up at the end or may not end up at all + // * It only returns literals that are newly implied. So you must call get_zero_assigned_lits() before to be sure you know what literals are implied at decision level 0 + bool implied_by( + const std::vector& lits, std::vector& out_implied); + + ////////////////////// + //Below must be done in-order. Multi-threading not allowed. + void start_getting_small_clauses(uint32_t max_len, uint32_t max_glue, bool red = true, bool bva_vars = false, bool simplified = false); + bool get_next_small_clause(std::vector& ret, bool all_in_one = false); //returns FALSE if no more + void end_getting_small_clauses(); + + void start_getting_clauses(bool red = false, bool simplified = true); + bool get_next_clause(std::vector &ret); + void end_getting_clauses(); + + uint32_t simplified_nvars(); + std::vector translate_sampl_set(const std::vector& sampl_set); + void get_all_irred_clauses(std::vector& ret); + const std::vector& get_bnns() const; + + // Solution reconstruction after minimization + std::string serialize_solution_reconstruction_data() const; + static void* create_extend_solution_setup(std::string& data); + static std::pair> extend_solution(void* s, const std::vector& simp_sol); + static void delete_extend_solution_setup(void* s); + + ///////////////////// + // Backwards compatibility, implemented using the above "small clauses" functions + void open_file_and_dump_irred_clauses(const char* fname); + bool removed_var(uint32_t var) const; + + private: + + //////////////////////////// + // Do not bother with this, it's private + //////////////////////////// + + CMSatPrivateData *data; + }; + + template + void copy_solver_to_solver(T* solver, T2* solver2) { + solver2->new_vars(solver->nVars()); + solver->start_getting_small_clauses( + std::numeric_limits::max(), + std::numeric_limits::max(), + false); + std::vector clause; + bool ret = true; + while (ret) { + ret = solver->get_next_small_clause(clause); + if (!ret) break; + solver2->add_clause(clause); + } + solver->end_getting_small_clauses(); + } + + template + void copy_simp_solver_to_solver(T* solver, T2* solver2) { + solver2->new_vars(solver->simplified_nvars()); + solver->start_getting_small_clauses( + std::numeric_limits::max(), + std::numeric_limits::max(), + false, + false, + true); //simplified + std::vector clause; + bool ret = true; + while (ret) { + ret = solver->get_next_small_clause(clause); + if (!ret) break; + solver2->add_clause(clause); + } + solver->end_getting_small_clauses(); + } +} diff --git a/cryptominisat/cppsrc/src/cryptominisat_c.cpp b/cryptominisat/cppsrc/src/cryptominisat_c.cpp new file mode 100644 index 00000000..16f57bae --- /dev/null +++ b/cryptominisat/cppsrc/src/cryptominisat_c.cpp @@ -0,0 +1,170 @@ +/****************************************** +Copyright (c) 2016, @Storyyeller + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. +***********************************************/ + +#include "cryptominisat_c.h" +#include "constants.h" +#include "cryptominisat.h" + + +// C wrappers for SATSolver so that it can be used from other languages (e.g. Rust) +using namespace CMSat; + +// Make sure the types we expose are C compatible and don't change unexpectedly +static_assert(sizeof(Lit) == sizeof(c_Lit), "Lit layout not c-compatible"); +static_assert(alignof(Lit) == alignof(c_Lit), "Lit layout not c-compatible"); +static_assert(sizeof(lbool) == sizeof(c_lbool), "lbool layout not c-compatible"); +static_assert(alignof(lbool) == alignof(c_lbool), "lbool layout not c-compatible"); + +const Lit* fromc(const c_Lit* x) +{ + return reinterpret_cast(x); +} +const lbool* fromc(const c_lbool* x) +{ + return reinterpret_cast(x); +} +const c_lbool* toc(const lbool* x) +{ + return reinterpret_cast(x); +} +const c_Lit* toc(const Lit* x) +{ + return reinterpret_cast(x); +} +c_lbool toc(lbool x) +{ + return {x.getValue()}; +} + +template +std::vector wrap(const T* vals, size_t num_vals) +{ + return std::vector(vals, vals + num_vals); +} + +template +Dest unwrap(const std::vector& vec) +{ + return Dest {toc(vec.data()), vec.size()}; +} + +#define NOEXCEPT_START noexcept { try { +#define NOEXCEPT_END } catch(...) { \ + std::cerr << "ERROR: exception thrown past FFI boundary" << std::endl;\ + std::exit(-1);\ +} } + +extern "C" +{ + + DLL_PUBLIC SATSolver* cmsat_new(void) NOEXCEPT_START { + return new SATSolver(); + } NOEXCEPT_END + + DLL_PUBLIC void cmsat_free(SATSolver* s) NOEXCEPT_START { + delete s; + } NOEXCEPT_END + + DLL_PUBLIC unsigned cmsat_nvars(const SATSolver* self) NOEXCEPT_START { + return self->nVars(); + } NOEXCEPT_END + + DLL_PUBLIC bool cmsat_add_clause(SATSolver* self, const c_Lit* lits, size_t num_lits) NOEXCEPT_START { + return self->add_clause(wrap(fromc(lits), num_lits)); + } NOEXCEPT_END + + DLL_PUBLIC bool cmsat_add_xor_clause(SATSolver* self, const unsigned* vars, size_t num_vars, bool rhs) NOEXCEPT_START { + return self->add_xor_clause(wrap(vars, num_vars), rhs); + } NOEXCEPT_END + + DLL_PUBLIC void cmsat_new_vars(SATSolver* self, const size_t n) NOEXCEPT_START { + self->new_vars(n); + } NOEXCEPT_END + + DLL_PUBLIC c_lbool cmsat_solve(SATSolver* self) NOEXCEPT_START { + return toc(self->solve(nullptr)); + } NOEXCEPT_END + + DLL_PUBLIC c_lbool cmsat_solve_with_assumptions(SATSolver* self, const c_Lit* assumptions, size_t num_assumptions) NOEXCEPT_START { + auto temp = wrap(fromc(assumptions), num_assumptions); + return toc(self->solve(&temp)); + } NOEXCEPT_END + + DLL_PUBLIC slice_lbool cmsat_get_model(const SATSolver* self) NOEXCEPT_START { + return unwrap(self->get_model()); + } NOEXCEPT_END + + DLL_PUBLIC slice_Lit cmsat_get_conflict(const SATSolver* self) NOEXCEPT_START { + return unwrap(self->get_conflict()); + } NOEXCEPT_END + + DLL_PUBLIC void cmsat_print_stats(const SATSolver* self) NOEXCEPT_START { + self->print_stats(); + } NOEXCEPT_END + + //Setup + DLL_PUBLIC void cmsat_set_num_threads(SATSolver* self, unsigned n) NOEXCEPT_START { + self->set_num_threads(n); + } NOEXCEPT_END + + DLL_PUBLIC void cmsat_set_verbosity(SATSolver* self, unsigned n) NOEXCEPT_START { + self->set_verbosity(n); + } NOEXCEPT_END + + DLL_PUBLIC void cmsat_set_default_polarity(SATSolver* self, int polarity) NOEXCEPT_START { + self->set_default_polarity(polarity); + } NOEXCEPT_END + + DLL_PUBLIC void cmsat_set_no_simplify(SATSolver* self) NOEXCEPT_START { + self->set_no_simplify(); + } NOEXCEPT_END + + DLL_PUBLIC void cmsat_set_no_simplify_at_startup(SATSolver* self) NOEXCEPT_START { + self->set_no_simplify_at_startup(); + } NOEXCEPT_END + + DLL_PUBLIC void cmsat_set_no_equivalent_lit_replacement(SATSolver* self) NOEXCEPT_START { + self->set_no_equivalent_lit_replacement(); + } NOEXCEPT_END + + DLL_PUBLIC void cmsat_set_no_bva(SATSolver* self) NOEXCEPT_START { + self->set_no_bva(); + } NOEXCEPT_END + + DLL_PUBLIC void cmsat_set_no_bve(SATSolver* self) NOEXCEPT_START { + self->set_no_bve(); + } NOEXCEPT_END + DLL_PUBLIC void cmsat_set_up_for_scalmc(SATSolver* self) NOEXCEPT_START { + self->set_up_for_scalmc(); + } NOEXCEPT_END + DLL_PUBLIC void cmsat_set_up_for_arjun(SATSolver* self) NOEXCEPT_START { + self->set_up_for_arjun(); + } NOEXCEPT_END + DLL_PUBLIC c_lbool cmsat_simplify(SATSolver* self, const c_Lit* assumptions, size_t num_assumptions) NOEXCEPT_START { + auto temp = wrap(fromc(assumptions), num_assumptions); + return toc(self->simplify(&temp)); + } NOEXCEPT_END + + DLL_PUBLIC void cmsat_set_max_time(SATSolver* self, double max_time) NOEXCEPT_START { + self->set_max_time(max_time); + } NOEXCEPT_END +} diff --git a/cryptominisat/cppsrc/src/cryptominisat_c.h b/cryptominisat/cppsrc/src/cryptominisat_c.h new file mode 100644 index 00000000..24071910 --- /dev/null +++ b/cryptominisat/cppsrc/src/cryptominisat_c.h @@ -0,0 +1,90 @@ +/****************************************** +Copyright (c) 2016, @Storyyeller + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. +***********************************************/ + +#pragma once +#include +#include + +typedef struct c_Lit { uint32_t x; } c_Lit; +typedef struct c_lbool { uint8_t x; } c_lbool; +typedef struct slice_Lit { const c_Lit* vals; size_t num_vals; } slice_Lit; +typedef struct slice_lbool { const c_lbool* vals; size_t num_vals; } slice_lbool; + +#ifdef __cplusplus + #define NOEXCEPT noexcept + + namespace CMSat{ struct SATSolver; } + using CMSat::SATSolver; + + extern "C" { +#else + // c stuff + #include + #define NOEXCEPT + + #define L_TRUE (0u) + #define L_FALSE (1u) + #define L_UNDEF (2u) + + // forward declaration + typedef struct SATSolver SATSolver; +#endif + +#if defined _WIN32 + #define CMS_DLL_PUBLIC __declspec(dllexport) +#else + #define CMS_DLL_PUBLIC __attribute__ ((visibility ("default"))) +#endif + +CMS_DLL_PUBLIC SATSolver* cmsat_new(void) NOEXCEPT; +CMS_DLL_PUBLIC void cmsat_free(SATSolver* s) NOEXCEPT; + +CMS_DLL_PUBLIC unsigned cmsat_nvars(const SATSolver* self) NOEXCEPT; +CMS_DLL_PUBLIC bool cmsat_add_clause(SATSolver* self, const c_Lit* lits, size_t num_lits) NOEXCEPT; +CMS_DLL_PUBLIC bool cmsat_add_xor_clause(SATSolver* self, const unsigned* vars, size_t num_vars, bool rhs) NOEXCEPT; +CMS_DLL_PUBLIC void cmsat_new_vars(SATSolver* self, const size_t n) NOEXCEPT; + +CMS_DLL_PUBLIC c_lbool cmsat_solve(SATSolver* self) NOEXCEPT; +CMS_DLL_PUBLIC c_lbool cmsat_solve_with_assumptions(SATSolver* self, const c_Lit* assumptions, size_t num_assumptions) NOEXCEPT; +CMS_DLL_PUBLIC slice_lbool cmsat_get_model(const SATSolver* self) NOEXCEPT; +CMS_DLL_PUBLIC slice_Lit cmsat_get_conflict(const SATSolver* self) NOEXCEPT; + +CMS_DLL_PUBLIC void cmsat_print_stats(const SATSolver* self) NOEXCEPT; + +CMS_DLL_PUBLIC void cmsat_set_num_threads(SATSolver* self, unsigned n) NOEXCEPT; +CMS_DLL_PUBLIC void cmsat_set_verbosity(SATSolver* self, unsigned n) NOEXCEPT; +CMS_DLL_PUBLIC void cmsat_set_default_polarity(SATSolver* self, int polarity) NOEXCEPT; +CMS_DLL_PUBLIC void cmsat_set_polarity_auto(SATSolver* self) NOEXCEPT; +CMS_DLL_PUBLIC void cmsat_set_no_simplify(SATSolver* self) NOEXCEPT; +CMS_DLL_PUBLIC void cmsat_set_no_simplify_at_startup(SATSolver* self) NOEXCEPT; +CMS_DLL_PUBLIC void cmsat_set_no_equivalent_lit_replacement(SATSolver* self) NOEXCEPT; +CMS_DLL_PUBLIC void cmsat_set_no_bva(SATSolver* self) NOEXCEPT; +CMS_DLL_PUBLIC void cmsat_set_no_bve(SATSolver* self) NOEXCEPT; +CMS_DLL_PUBLIC void cmsat_set_up_for_scalmc(SATSolver* self) NOEXCEPT; +CMS_DLL_PUBLIC void set_up_for_arjun(SATSolver* self) NOEXCEPT; +CMS_DLL_PUBLIC void cmsat_set_yes_comphandler(SATSolver* self) NOEXCEPT; +CMS_DLL_PUBLIC c_lbool cmsat_simplify(SATSolver* self, const c_Lit* assumptions, size_t num_assumptions) NOEXCEPT; +CMS_DLL_PUBLIC void cmsat_set_max_time(SATSolver* self, double max_time) NOEXCEPT; + +#ifdef __cplusplus +} // end extern c +#endif diff --git a/cryptominisat/cppsrc/src/cset.h b/cryptominisat/cppsrc/src/cset.h new file mode 100644 index 00000000..e132ad67 --- /dev/null +++ b/cryptominisat/cppsrc/src/cset.h @@ -0,0 +1,194 @@ +/* +Based on SatELite -- Copyright (c) 2003-2006, Niklas Een, Niklas Sorensson +Copyright (C) 2009-2020 Authors of CryptoMiniSat, see AUTHORS file + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. +***********************************************/ +#ifndef CSET_H +#define CSET_H + +#include +#include "constants.h" + +#include "clause.h" + +namespace CMSat { +using std::vector; + +/** +@brief Used to quicky add, remove and iterate through a clause set + +Used in OccSimplifier to put into a set all clauses that need to be treated +*/ +class CSet { + vector where; /// which; ///< List of clauses (for fast iteration). May contain 'Clause_NULL'. + vector free; ///::max()); + + if (where.size() < offs+1) + where.resize(offs+1, numeric_limits::max()); + + if (where[offs] != numeric_limits::max()) { + return false; + } + if (free.size() > 0){ + where[offs] = free.back(); + which[free.back()] = offs; + free.pop_back(); + }else{ + where[offs] = which.size(); + which.push_back(offs); + } + return true; + } + + bool alreadyIn(const ClOffset offs) const + { + //Don't check for special value + assert(offs != numeric_limits< uint32_t >::max()); + + if (where.size() < offs+1) + return false; + + return where[offs] != numeric_limits::max(); + } + + /** + @brief Fully clear the set + */ + void clear(void) { + where.clear(); + which.clear(); + free.clear(); + } + + /** + @brief A normal iterator to iterate through the set + + No other way exists of iterating correctly. + */ + class iterator + { + public: + explicit iterator(vector::iterator _it) : + it(_it) + {} + + iterator& operator++() + { + ++it; + return *this; + } + + bool operator!=(const iterator& iter) const + { + return (it != iter.it); + } + + ClOffset& operator*() { + return *it; + } + + vector::iterator& operator->() { + return it; + } + private: + vector::iterator it; + }; + + /** + @brief A constant iterator to iterate through the set + + No other way exists of iterating correctly. + */ + class const_iterator + { + public: + explicit const_iterator(vector::const_iterator _it) : + it(_it) + {} + + const_iterator& operator++() + { + ++it; + + return *this; + } + + bool operator!=(const const_iterator& iter) const + { + return (it != iter.it); + } + + const ClOffset& operator*() { + return *it; + } + + vector::const_iterator& operator->() { + return it; + } + private: + vector::const_iterator it; + }; + + ///@brief Get starting iterator + iterator begin() + { + return iterator(which.begin()); + } + + ///@brief Get ending iterator + iterator end() + { + return iterator(which.begin() + which.size()); + } + + ///@brief Get starting iterator (constant version) + const_iterator begin() const + { + return const_iterator(which.begin()); + } + + ///@brief Get ending iterator (constant version) + const_iterator end() const + { + return const_iterator(which.begin() + which.size()); + } +}; + +} //end namespace + +#endif //CSET_H diff --git a/cryptominisat/cppsrc/src/datasync.cpp b/cryptominisat/cppsrc/src/datasync.cpp new file mode 100644 index 00000000..385a9f06 --- /dev/null +++ b/cryptominisat/cppsrc/src/datasync.cpp @@ -0,0 +1,880 @@ +/****************************************** +Copyright (C) 2009-2020 Authors of CryptoMiniSat, see AUTHORS file + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. +***********************************************/ + +#include "datasync.h" +#include "varreplacer.h" +#include "solver.h" +#include "shareddata.h" + +#include +#include + +//#define VERBOSE_DEBUG_MPI_SENDRCV + +using namespace CMSat; + +DataSync::DataSync(Solver* _solver, SharedData* _sharedData) : + solver(_solver) + , sharedData(_sharedData) + , seen(solver->seen) + , toClear(solver->toClear) +{ +} + +void DataSync::finish_up_mpi() +{ + #ifdef USE_MPI + if (mpiSendData) { + //mpiSendData is only non-NULL when MPI is on and it's the 0 thread + assert(solver->conf.is_mpi); + assert(solver->conf.thread_num == 0); + + /*MPI_Status status; + int op_completed = false; + int err; + + err = MPI_Test(&sendReq, &op_completed, &status); + assert(err == MPI_SUCCESS); + if (!op_completed) { + err = MPI_Cancel(&sendReq); + assert(err == MPI_SUCCESS); + }*/ + delete[] mpiSendData; + mpiSendData = NULL; + } + #endif +} + +void DataSync::set_shared_data(SharedData* _sharedData) +{ + sharedData = _sharedData; + thread_id = _sharedData->cur_thread_id++; + #ifdef USE_MPI + set_up_for_mpi(); + #endif +} + +void DataSync::new_var(const bool bva) +{ + if (!enabled()) + return; + + if (!bva) { + syncFinish.push_back(0); + syncFinish.push_back(0); + } + assert(solver->nVarsOutside()*2 == syncFinish.size()); +} + +void DataSync::new_vars(size_t n) +{ + if (!enabled()) + return; + + syncFinish.insert(syncFinish.end(), 2*n, 0); + assert(solver->nVarsOutside()*2 == syncFinish.size()); +} + +void DataSync::save_on_var_memory() +{ +} + +void DataSync::rebuild_bva_map() +{ + must_rebuild_bva_map = true; +} + +void DataSync::updateVars( + const vector& /*outerToInter*/ + , const vector& /*interToOuter*/ +) { +} + +inline void DataSync::rebuild_bva_map_if_needed() +{ + if (must_rebuild_bva_map) { + outer_to_without_bva_map = solver->build_outer_to_without_bva_map(); + must_rebuild_bva_map = false; + } +} + +bool DataSync::syncData() +{ + if (!enabled() + || lastSyncConf + solver->conf.sync_every_confl >= solver->sumConflicts + ) { + return true; + } + numCalls++; + + assert(sharedData != NULL); + assert(solver->decisionLevel() == 0); + rebuild_bva_map_if_needed(); + + //SEND data + bool ok; + sharedData->unit_mutex.lock(); + ok = shareUnitData(); + sharedData->unit_mutex.unlock(); + if (!ok) { + return false; + } + solver->ok = solver->propagate().isNULL(); + if (!solver->ok) { + return false; + } + + //RECEIVE data + sharedData->bin_mutex.lock(); + extend_bins_if_needed(); + clear_set_binary_values(); + ok = shareBinData(); + sharedData->bin_mutex.unlock(); + if (!ok) { + return false; + } + + #ifdef USE_MPI + if (solver->conf.is_mpi + && solver->conf.thread_num == 0) + { + if (syncMPIFinish.size() < solver->nVarsOutside()*2) { + syncMPIFinish.resize(solver->nVarsOutside()*2, 0); + } + + if (!mpi_get_interrupt()) { + sharedData->unit_mutex.lock(); + sharedData->bin_mutex.lock(); + ok = mpi_recv_from_others(); + assert(solver->conf.every_n_mpi_sync > 0); + if (ok && + numCalls % solver->conf.every_n_mpi_sync == solver->conf.every_n_mpi_sync-1 + ) { + mpi_send_to_others(); + } + sharedData->unit_mutex.unlock(); + sharedData->bin_mutex.unlock(); + if (!ok) { + return false; + } + } + } + #endif + + lastSyncConf = solver->sumConflicts; + + return true; +} + +bool DataSync::shareUnitData() +{ + assert(solver->okay()); + assert(!solver->frat->enabled()); + + uint32_t thisGotUnitData = 0; + uint32_t thisSentUnitData = 0; + + SharedData& shared = *sharedData; + if (shared.value.size() < solver->nVarsOutside()) { + shared.value.insert( + shared.value.end(), + solver->nVarsOutside()-shared.value.size(), l_Undef); + } + for (uint32_t var = 0; var < solver->nVarsOutside(); var++) { + Lit thisLit = Lit(var, false); + thisLit = solver->map_to_with_bva(thisLit); + thisLit = solver->varReplacer->get_lit_replaced_with_outer(thisLit); + thisLit = solver->map_outer_to_inter(thisLit); + const lbool thisVal = solver->value(thisLit); + const lbool otherVal = shared.value[var]; + + if (thisVal == l_Undef && otherVal == l_Undef) { + continue; + } + + if (thisVal != l_Undef && otherVal != l_Undef) { + if (thisVal != otherVal) { + solver->ok = false; + return false; + } else { + continue; + } + } + + if (otherVal != l_Undef) { + assert(thisVal == l_Undef); + Lit litToEnqueue = thisLit ^ (otherVal == l_False); + if (solver->varData[litToEnqueue.var()].removed != Removed::none) { + continue; + } + + solver->enqueue(litToEnqueue); + + thisGotUnitData++; + continue; + } + + if (thisVal != l_Undef) { + assert(otherVal == l_Undef); + shared.value[var] = thisVal; + thisSentUnitData++; + continue; + } + } + stats.recvUnitData += thisGotUnitData; + stats.sentUnitData += thisSentUnitData; + + if (solver->conf.verbosity >= 1) { + cout + << "c [sync " << thread_id << " ]" + << " got units " << thisGotUnitData + << " (total: " << stats.recvUnitData << ")" + << " sent units " << thisSentUnitData + << " (total: " << stats.sentUnitData << ")" + << endl; + } + + return true; +} + +void CMSat::DataSync::signal_new_long_clause(const vector& cl) +{ + if (!enabled()) { + return; + } + assert(thread_id != -1); + //cout << "thread ID: " << thread_id << endl; + + #ifdef USE_GPU + rebuild_bva_map_if_needed(); + + //Don't signal clauses with BVA variables + clause_tmp.clear(); + for(Lit lit: cl) { + if (solver->varData[lit.var()].is_bva) { + return; + } + lit = solver->map_inter_to_outer(lit); + lit = map_outer_to_outside(lit); + clause_tmp.push_back(lit); + } + + signalled_gpu_long_cls++; + sharedData->gpuClauseSharer->addClause(thread_id, (int*)clause_tmp.data(), clause_tmp.size()); + #else + if (cl.size() == 2) { + signal_new_bin_clause(cl[0], cl[1]); + } + #endif +} + +#ifdef USE_GPU +void DataSync::unsetFromGpu(uint32_t level) { + if (!enabled()) { + return; + } + rebuild_bva_map_if_needed(); + + trail_tmp.clear(); + //assert(trailCopiedUntil < solver->trail.size()); + for(int i = ((int)solver->trail.size())-1; i >= (int)solver->trail_lim[level]; i--) { + Lit lit = solver->trail_at(i); + if (lit == lit_Undef) { + //This can happen because variables set at level 0 + // are cleared from the trail and set to lit_Undef + continue; + } + //cout << "lit: " << lit << endl; + if (solver->varData[lit.var()].is_bva) { + continue; + } + lit = solver->map_inter_to_outer(lit); + lit = map_outer_to_outside(lit); + trail_tmp.push_back(lit); + } + + if (!trail_tmp.empty()) { + sharedData->gpuClauseSharer->unsetSolverValues( + thread_id, + (int*)trail_tmp.data(), + trail_tmp.size()); + } + trailCopiedUntil = solver->trail_lim[level]; +} + +void DataSync::trySendAssignmentToGpu() { + if (!enabled()) { + return; + } + rebuild_bva_map_if_needed(); + + uint32_t sendUntil = solver->trail_size(); + if (sendUntil == 0) { + return; + } + if (trailCopiedUntil >= sendUntil) { + return; + } + +// if (thread_id == 0) { +// cout +// << "Set from point " << solver->trail_lim[level] +// << " count: " << sendUntil - trailCopiedUntil +// << " level: " << level +// << endl; +// } + + trail_tmp.clear(); + for(uint32_t i = trailCopiedUntil; i < sendUntil; i++) { + Lit lit = solver->trail_at(i); + if (lit == lit_Undef) { + //This can happen because variables set at level 0 + // are cleared from the trail and set to lit_Undef + continue; + } + if (solver->varData[lit.var()].is_bva) { + continue; + } + lit = solver->map_inter_to_outer(lit); + lit = map_outer_to_outside(lit); + trail_tmp.push_back(lit); + } + + bool success = sharedData->gpuClauseSharer->trySetSolverValues( + thread_id, + (int*)trail_tmp.data(), + trail_tmp.size()); + + + if (success) { + trailCopiedUntil = sendUntil-1; + sharedData->gpuClauseSharer->trySendAssignment(thread_id); + } +} + +PropBy CMSat::DataSync::pop_clauses() +{ + if (!enabled()) { + return PropBy(); + } + assert(thread_id != -1); + //cout << "thread ID: " << thread_id << endl; + + //cout << "Trying to pop." << thread_id << endl; + int* litsAsInt; + int count; + long gpuClauseId; + int decisionLevelAtConflict = -1; + PropBy by = PropBy(); + + while (sharedData->gpuClauseSharer->popReportedClause( + thread_id, litsAsInt, count, gpuClauseId)) + { + popped_clause++; +// if ((popped_clause & 0xfff) == 0xfff) { +// cout << "popped_clause: " << popped_clause +// << " thread id: " << thread_id +// << endl; +// } + + Lit *lits = (Lit*) litsAsInt; + for(int i = 0; i < count; i ++) { + lits[i] = solver->map_to_with_bva(lits[i]); + lits[i] = solver->varReplacer->get_lit_replaced_with_outer(lits[i]); + lits[i] = solver->map_outer_to_inter(lits[i]); + } + + by = solver->insert_gpu_clause(lits, count); + if (!solver->okay()) { + return PropBy(); + } + if (!by.isNULL()) { + decisionLevelAtConflict = solver->decisionLevel(); + } + } + + if ((int)solver->decisionLevel() == decisionLevelAtConflict) { + return by; + } + return PropBy(); +} +#endif + +//////////////////////////////////////// +// Non-GPU +//////////////////////////////////////// +#ifndef USE_GPU +bool DataSync::syncBinFromOthers() +{ + for (uint32_t wsLit = 0; wsLit < sharedData->bins.size(); wsLit++) { + if (sharedData->bins[wsLit].data == NULL) { + continue; + } + + Lit lit1 = Lit::toLit(wsLit); + lit1 = solver->map_to_with_bva(lit1); + lit1 = solver->varReplacer->get_lit_replaced_with_outer(lit1); + lit1 = solver->map_outer_to_inter(lit1); + if (solver->varData[lit1.var()].removed != Removed::none + || solver->value(lit1.var()) != l_Undef + ) { + continue; + } + + vector& bins = *sharedData->bins[wsLit].data; + watch_subarray ws = solver->watches[lit1]; + + assert(syncFinish.size() > wsLit); + if (bins.size() > syncFinish[wsLit] + && !syncBinFromOthers(lit1, bins, syncFinish[wsLit], ws) + ) { + return false; + } + } + + return true; +} + +bool DataSync::syncBinFromOthers( + const Lit lit + , const vector& bins + , uint32_t& finished + , watch_subarray ws +) { + assert(solver->varReplacer->get_lit_replaced_with(lit) == lit); + assert(solver->varData[lit.var()].removed == Removed::none); + + assert(toClear.empty()); + for (const Watched& w: ws) { + if (w.isBin()) { + toClear.push_back(w.lit2()); + assert(seen.size() > w.lit2().toInt()); + seen[w.lit2().toInt()] = true; + } + } + + vector lits(2); + for (uint32_t i = finished; i < bins.size(); i++) { + Lit otherLit = bins[i]; + otherLit = solver->map_to_with_bva(otherLit); + otherLit = solver->varReplacer->get_lit_replaced_with_outer(otherLit); + otherLit = solver->map_outer_to_inter(otherLit); + if (solver->varData[otherLit.var()].removed != Removed::none + || solver->value(otherLit) != l_Undef + ) { + continue; + } + assert(seen.size() > otherLit.toInt()); + if (!seen[otherLit.toInt()]) { + stats.recvBinData++; + lits[0] = lit; + lits[1] = otherLit; + + //Don't add FRAT: it would add to the thread data, too + solver->add_clause_int(lits, true, NULL, true, NULL, false); + if (!solver->okay()) { + goto end; + } + } + } + finished = bins.size(); + + end: + for (const Lit l: toClear) { + seen[l.toInt()] = false; + } + toClear.clear(); + + return solver->okay(); +} + +void DataSync::syncBinToOthers() +{ + for(const std::pair& bin: newBinClauses) { + add_bin_to_threads(bin.first, bin.second); + } + + newBinClauses.clear(); +} + +bool DataSync::add_bin_to_threads(Lit lit1, Lit lit2) +{ + assert(lit1 < lit2); + if (sharedData->bins[lit1.toInt()].data == NULL) { + return false; + } + + vector& bins = *sharedData->bins[lit1.toInt()].data; + for (const Lit lit : bins) { + if (lit == lit2) + return false; + } + + bins.push_back(lit2); + stats.sentBinData++; + return true; +} + +void DataSync::clear_set_binary_values() +{ + for(size_t i = 0; i < solver->nVarsOutside()*2; i++) { + Lit lit1 = Lit::toLit(i); + lit1 = solver->map_to_with_bva(lit1); + lit1 = solver->varReplacer->get_lit_replaced_with_outer(lit1); + lit1 = solver->map_outer_to_inter(lit1); + if (solver->value(lit1) != l_Undef) { + sharedData->bins[i].clear(); + } + } +} + +void DataSync::extend_bins_if_needed() +{ + assert(sharedData->bins.size() <= (solver->nVarsOutside())*2); + if (sharedData->bins.size() == (solver->nVarsOutside())*2) + return; + + sharedData->bins.resize(solver->nVarsOutside()*2); +} + +bool DataSync::shareBinData() +{ + assert(solver->okay()); + uint32_t oldRecvBinData = stats.recvBinData; + uint32_t oldSentBinData = stats.sentBinData; + + bool ok = syncBinFromOthers(); + syncBinToOthers(); + size_t mem = sharedData->calc_memory_use_bins(); + + if (solver->conf.verbosity >= 1) { + cout + << "c [sync " << thread_id << " ]" + << " got bins " << (stats.recvBinData - oldRecvBinData) + << " (total: " << stats.recvBinData << ")" + << " sent bins " << (stats.sentBinData - oldSentBinData) + << " (total: " << stats.sentBinData << ")" + << " mem use: " << mem/(1024*1024) << " M" + << endl; + } + + return ok; +} + +void DataSync::signal_new_bin_clause(Lit lit1, Lit lit2) +{ + if (!enabled()) { + return; + } + + if (must_rebuild_bva_map) { + outer_to_without_bva_map = solver->build_outer_to_without_bva_map(); + must_rebuild_bva_map = false; + } + + if (solver->varData[lit1.var()].is_bva) + return; + if (solver->varData[lit2.var()].is_bva) + return; + + lit1 = solver->map_inter_to_outer(lit1); + lit1 = map_outer_to_outside(lit1); + lit2 = solver->map_inter_to_outer(lit2); + lit2 = map_outer_to_outside(lit2); + + if (lit1.toInt() > lit2.toInt()) { + std::swap(lit1, lit2); + } + newBinClauses.push_back(std::make_pair(lit1, lit2)); +} +#endif + +/////////////////////////////////////// +// MPI +/////////////////////////////////////// +#ifdef USE_MPI +void DataSync::set_up_for_mpi() +{ + if (solver->conf.is_mpi) { + int err; + err = MPI_Comm_rank(MPI_COMM_WORLD, &mpiRank); + assert(err == MPI_SUCCESS); + + err = MPI_Comm_size(MPI_COMM_WORLD, &mpiSize); + assert(err == MPI_SUCCESS); + release_assert(mpiRank != 0); + assert(sharedData != NULL); + } +} + +//Interrupts are tag 1, coming from master (i.e. rank 0) +bool DataSync::mpi_get_interrupt() +{ + #ifdef VERBOSE_DEBUG_MPI_SENDRCV + std::cout << "-->> MPI " << mpiRank << " thread " << thread_id << + " trying to get interrupt" << endl; + #endif + + int flag; + MPI_Status status; + int err = MPI_Iprobe( + 0, //master source + 1, //tag "1" for finish interrupt + MPI_COMM_WORLD, &flag, &status); + assert(err == MPI_SUCCESS); + if (flag == false) { + return false; + } + + + //Receive the tag 1 message + unsigned buf; + err = MPI_Recv( + &buf, + 0, //data is empty + MPI_UNSIGNED, + 0, //source is master + 1, //tag is "1" + MPI_COMM_WORLD, &status); + assert(err == MPI_SUCCESS); + + //TODO should we cancel the potentially running SEND request? + + solver->set_must_interrupt_asap(); + + return true; +} + +bool DataSync::mpi_recv_from_others() +{ + int err; + MPI_Status status; + int flag; + int count; + uint32_t thisMpiRecvUnitData = 0; + uint32_t thisMpiRecvBinData = 0; + #ifdef VERBOSE_DEBUG_MPI_SENDRCV + std::cout << "-->> MPI " << mpiRank << " thread " << thread_id << + " syncing from MPI..." << std::endl; + #endif + + + //Check if there is data, tagged 0, from source 0 (root) + err = MPI_Iprobe(0, 0, MPI_COMM_WORLD, &flag, &status); + assert(err == MPI_SUCCESS); + if (flag == false) { + #ifdef VERBOSE_DEBUG_MPI_SENDRCV + std::cout << "-->> MPI " << mpiRank << " thread " << thread_id << + " No data to receive." << std::endl; + #endif + + //no data + return true; + } + + //Get data size + err = MPI_Get_count(&status, MPI_UNSIGNED, &count); + assert(err == MPI_SUCCESS); + #ifdef VERBOSE_DEBUG_MPI_SENDRCV + std::cout << "-->> MPI " << mpiRank << " thread " << thread_id << + " Receiving " << count << " uint32_t ..." << std::endl; + #endif + + //Receive data + uint32_t* buf = new uint32_t[count]; + err = MPI_Recv((unsigned*)buf, count, MPI_UNSIGNED, 0, 0, MPI_COMM_WORLD, &status); + assert(err == MPI_SUCCESS); + + //Unit clauses + int at = 0; + assert(solver->nVarsOutside() == buf[at]); + at++; + for (uint32_t var = 0; var < solver->nVarsOutside(); var++, at++) { + const lbool otherVal = toLbool(buf[at]); + if (!mpi_get_unit(otherVal, var, thisMpiRecvUnitData)) { + #ifdef VERBOSE_DEBUG_MPI_SENDRCV + std::cout << "-->> MPI " << mpiRank << " thread " << thread_id << + " solver FALSE" << std::endl; + #endif + goto end; + } + } + solver->ok = solver->propagate().isNULL(); + if (!solver->ok) { + goto end; + } + mpiRecvUnitData += thisMpiRecvUnitData; + + //Binary clauses + assert(buf[at] == solver->nVarsOutside()*2); + at++; + for (uint32_t wsLit = 0; wsLit < solver->nVarsOutside()*2; wsLit++) { + Lit lit = Lit::toLit(wsLit); + uint32_t num = buf[at]; + at++; + for (uint32_t i = 0; i < num; i++, at++) { + Lit otherLit = Lit::toLit(buf[at]); + thisMpiRecvBinData += add_bin_to_threads(lit, otherLit); + } + } + mpiRecvBinData += thisMpiRecvBinData; + + end: + #ifdef VERBOSE_DEBUG_MPI_SENDRCV + std::cout << "-->> MPI " << mpiRank << " thread " << thread_id << + " Received " << thisMpiRecvUnitData << " units (total: " << mpiRecvUnitData << ")" << std::endl; + std::cout << "-->> MPI " << mpiRank << " thread " << thread_id << + " Received " << thisMpiRecvBinData << " bins (total: " << mpiRecvBinData << ")" << std::endl; + #endif + + delete[] buf; + return solver->okay(); +} + +void DataSync::mpi_send_to_others() +{ + int err; + + //We still are sending data, let's do that first + if (mpiSendData != NULL) { + #ifdef VERBOSE_DEBUG_MPI_SENDRCV + std::cout << "-->> MPI " << mpiRank << " thread " << thread_id << + " Still sending data, waiting now." << std::endl; + #endif + + /*MPI_Status status; + int op_completed; + err = MPI_Request_get_status(sendReq, &op_completed, &status); + assert(err == MPI_SUCCESS); + if (op_completed) { + err = MPI_Wait(&sendReq, &status); + assert(err == MPI_SUCCESS);*/ + delete[] mpiSendData; + mpiSendData = NULL; + /*} else { + return; + }*/ + } + + #ifdef VERBOSE_DEBUG_MPI_SENDRCV + std::cout << "-->> MPI " << mpiRank << " thread " << thread_id << + " Building data to send via MPI..." << std::endl; + #endif + + //Set up units + assert(solver->nVarsOutside() == sharedData->value.size()); + vector data; + data.push_back(solver->nVarsOutside()); + for (uint32_t var = 0; var < solver->nVarsOutside(); var++) { + data.push_back(toInt(sharedData->value[var])); + } + + //Set up binaries + assert(sharedData->bins.size() == solver->nVarsOutside()*2); + uint32_t thisMpiSentBinData = 0; + data.push_back(solver->nVarsOutside()*2); + + for(uint32_t wsLit = 0; wsLit < solver->nVarsOutside()*2; wsLit++) { + //Lit lit1 = ~Lit::toLit(wsLit); + assert(syncMPIFinish.size() > wsLit); + if (sharedData->bins[wsLit].data == NULL) { + data.push_back(0); + continue; + } + uint32_t size = sharedData->bins[wsLit].data->size(); + assert(size >= syncMPIFinish[wsLit]); + uint32_t sizeToSend = size - syncMPIFinish[wsLit]; + data.push_back(sizeToSend); + for (uint32_t i = syncMPIFinish[wsLit]; i < size; i++) { + data.push_back(sharedData->bins[wsLit].data->at(i).toInt()); + thisMpiSentBinData++; + } + syncMPIFinish[wsLit] = size; + } + mpiSentBinData += thisMpiSentBinData; + + #ifdef VERBOSE_DEBUG_MPI_SENDRCV + std::cout << "-->> MPI " << mpiRank << " thread " << thread_id << + " Sending " << data.size() << " uint32_t -s" << std::endl; + std::cout << "-->> MPI " << mpiRank << " thread " << thread_id << + " and " << thisMpiSentBinData << " bins.." << std::endl; + #endif + + //Send the data + mpiSendData = new uint32_t[data.size()]; + std::copy(data.begin(), data.end(), mpiSendData); + //err = MPI_Isend(mpiSendData, data.size(), MPI_UNSIGNED, 0, 0, MPI_COMM_WORLD, &sendReq); + err = MPI_Send(mpiSendData, data.size(), MPI_UNSIGNED, 0, 0, MPI_COMM_WORLD); + assert(err == MPI_SUCCESS); + + #ifdef VERBOSE_DEBUG_MPI_SENDRCV + std::cout << "-->> MPI " << mpiRank << " thread " << thread_id << + " Sent MPI sync data" << std::endl; + #endif +} + +bool DataSync::mpi_get_unit( + const lbool otherVal, + const uint32_t var, + uint32_t& thisGotUnitData +) { + Lit l = Lit(var, false); + Lit lit1 = solver->map_to_with_bva(l); + lit1 = solver->varReplacer->get_lit_replaced_with_outer(lit1); + lit1 = solver->map_outer_to_inter(lit1); + const lbool thisVal = solver->value(lit1); + + if (thisVal == otherVal) { + return true; + } + + if (otherVal == l_Undef) { + return true; + } + + if (thisVal != l_Undef) { + if (thisVal != otherVal) { + solver->ok = false; + return false; + } else { + return true; + } + } + + assert(otherVal != l_Undef); + assert(thisVal == l_Undef); + Lit litToEnqueue = lit1 ^ (otherVal == l_False); + if (solver->varData[litToEnqueue.var()].removed != Removed::none) { + return true; + } + + solver->enqueue(litToEnqueue); + solver->ok = solver->propagate().isNULL(); + if (!solver->ok) { + return false; + } + + thisGotUnitData++; + + return true; +} +#endif diff --git a/cryptominisat/cppsrc/src/datasync.h b/cryptominisat/cppsrc/src/datasync.h new file mode 100644 index 00000000..bf415163 --- /dev/null +++ b/cryptominisat/cppsrc/src/datasync.h @@ -0,0 +1,156 @@ +/****************************************** +Copyright (C) 2009-2020 Authors of CryptoMiniSat, see AUTHORS file + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. +***********************************************/ + +#ifndef _DATASYNC_H_ +#define _DATASYNC_H_ + +#include "solvertypes.h" +#include "watched.h" +#include "propby.h" +#include "watcharray.h" +#ifdef USE_MPI +#include "mpi.h" +#endif //USE_MPI + +namespace CMSat { + +class Clause; +class SharedData; +class Solver; +class DataSync +{ + public: + DataSync(Solver* solver, SharedData* sharedData); + void finish_up_mpi(); + bool enabled(); + void set_shared_data(SharedData* sharedData); + void new_var(const bool bva); + void new_vars(const size_t n); + bool syncData(); + void save_on_var_memory(); + void rebuild_bva_map(); + void updateVars( + const vector& outerToInter + , const vector& interToOuter + ); + void signal_new_long_clause(const vector& clause); + + #ifdef USE_GPU + vector clause_tmp; + vector trail_tmp; + void unsetFromGpu(uint32_t level); + void trySendAssignmentToGpu(); + PropBy pop_clauses(); + uint32_t signalled_gpu_long_cls = 0; + uint32_t popped_clause = 0; + #endif + + struct Stats + { + uint32_t sentUnitData = 0; + uint32_t recvUnitData = 0; + uint32_t sentBinData = 0; + uint32_t recvBinData = 0; + }; + const Stats& get_stats() const; + + private: + void extend_bins_if_needed(); + Lit map_outer_to_outside(Lit lit) const; + bool shareUnitData(); + bool shareBinData(); + bool syncBinFromOthers(); + bool syncBinFromOthers(const Lit lit, const vector& bins, uint32_t& finished, watch_subarray ws); + void syncBinToOthers(); + void clear_set_binary_values(); + bool add_bin_to_threads(const Lit lit1, const Lit lit2); + void signal_new_bin_clause(Lit lit1, Lit lit2); + void rebuild_bva_map_if_needed(); + + + #ifdef USE_GPU + uint32_t trailCopiedUntil = 0; + #endif + int thread_id = -1; + + //stuff to sync + vector > newBinClauses; + + //stats + uint64_t lastSyncConf = 0; + vector syncFinish; + Stats stats; + + //Other systems + Solver* solver = NULL; + SharedData* sharedData = NULL; + + //MPI + #ifdef USE_MPI + void set_up_for_mpi(); + bool mpi_recv_from_others(); + void mpi_send_to_others(); + bool mpi_get_interrupt(); + bool mpi_get_unit( + const lbool otherVal, + const uint32_t var, + uint32_t& thisGotUnitData + ); + vector syncMPIFinish; + MPI_Request sendReq; + uint32_t* mpiSendData = NULL; + + int mpiRank = 0; + int mpiSize = 0; + uint32_t mpiRecvUnitData = 0; + uint32_t mpiRecvBinData = 0; + uint32_t mpiSentBinData = 0; + #endif + + + //misc + uint32_t numCalls = 0; + vector& seen; + vector& toClear; + vector outer_to_without_bva_map; + bool must_rebuild_bva_map = false; +}; + +inline const DataSync::Stats& DataSync::get_stats() const +{ + return stats; +} + +inline Lit DataSync::map_outer_to_outside(const Lit lit) const +{ + return Lit(outer_to_without_bva_map[lit.var()], lit.sign()); + +} + +inline bool DataSync::enabled() +{ + return sharedData != NULL; +} + +} + +#endif diff --git a/cryptominisat/cppsrc/src/datasyncserver.cpp b/cryptominisat/cppsrc/src/datasyncserver.cpp new file mode 100644 index 00000000..3bcc37f1 --- /dev/null +++ b/cryptominisat/cppsrc/src/datasyncserver.cpp @@ -0,0 +1,467 @@ +/****************************************** +Copyright (C) 2009-2020 Authors of CryptoMiniSat, see AUTHORS file + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. +***********************************************/ + +#include +#include + +#include "datasyncserver.h" +#include "solvertypes.h" +using std::vector; + +#define VERBOSE_DEBUG_MPI_SENDRCV + +using namespace CMSat; + +DataSyncServer::DataSyncServer() +{ + int err; + err = MPI_Comm_size(MPI_COMM_WORLD, &mpiSize); + assert(err == MPI_SUCCESS); + + sendRequests.resize(mpiSize); + sendRequestsFinished.resize(mpiSize, true); + interruptRequests.resize(mpiSize); + + int mpiRank; + err = MPI_Comm_rank(MPI_COMM_WORLD, &mpiRank); + assert(err == MPI_SUCCESS); + assert(mpiRank == 0); + + #ifdef VERBOSE_DEBUG_MPI_SENDRCV + std::cout << "c -->> MPI Server" + << " says -- mpiSize:" << mpiSize << std::endl; + #endif + assert(sizeof(unsigned) == sizeof(uint32_t)); +} + +DataSyncServer::~DataSyncServer() +{ + delete[] sendData; +} + +//Tag of messsage "0" +void DataSyncServer::mpi_recv_from_others() +{ + int err; + MPI_Status status; + int flag; + int count; + uint32_t thisRecvBinData = 0; + + //Check for message + err = MPI_Iprobe( + MPI_ANY_SOURCE, //from anyone (i.e. clients) + 0, //tag 0, i.e. unit/bin data + MPI_COMM_WORLD, &flag, &status); + assert(err == MPI_SUCCESS); + if (flag == false) { + return; + } + int source = status.MPI_SOURCE; + + //Get message size + err = MPI_Get_count(&status, MPI_UNSIGNED, &count); + assert(err == MPI_SUCCESS); + #ifdef VERBOSE_DEBUG_MPI_SENDRCV + std::cout << "c -->> MPI Server [from " << source << "]" + << " Counted " << count << " uint32_t-s" << std::endl; + #endif + + //Get message, BLOCKING + assert(sizeof(unsigned int) == 4); + uint32_t* buf = new uint32_t[count]; + err = MPI_Recv((unsigned*)buf, count, MPI_UNSIGNED, + source, + 0, //tag "0", i.e. unit/bin data + MPI_COMM_WORLD, MPI_STATUS_IGNORE); + assert(err == MPI_SUCCESS); + + #ifdef VERBOSE_DEBUG_MPI_SENDRCV + std::cout << "c -->> MPI Server [from " << source << "]" + << " Received data " << std::endl; + #endif + + int at = 0; + assert(num_vars == buf[at]); //the first uint32_t is the number of bytes, always + + //Sync all units, starts with num_vars + assert(num_vars == buf[at]); + at++; + for (uint32_t var = 0; var < num_vars; var++, at++) { + lbool val = toLbool(buf[at]); + if (value[var] == l_Undef) { + if (val != l_Undef){ + value[var] = val; + } + } else if (val != l_Undef && value[var] != val) { + //This will cause UNSAT real fast + value[var] = val; + } + } + + //Sync all binaries, starts with num_vars*2 + //for each Lit, there is SIZE of elements that follow, then the elements + assert(buf[at] == num_vars*2); + at++; + for (uint32_t wsLit = 0; wsLit < num_vars*2; wsLit++) { + Lit lit = ~Lit::toLit(wsLit); + uint32_t num = buf[at]; + at++; + for (uint32_t i = 0; i < num; i++, at++) { + Lit otherLit = Lit::toLit(buf[at]); + get_bin(lit, otherLit); + thisRecvBinData++; + } + } + recvBinData += thisRecvBinData; + + #ifdef VERBOSE_DEBUG_MPI_SENDRCV + std::cout << "c -->> MPI Server [from " << source << "]" + << " Obtained " << thisRecvBinData << " bins" << std::endl; + #endif + + delete[] buf; + numGotPacket++; +} + +void DataSyncServer::get_bin(const Lit lit1, const Lit lit2) +{ + assert(lit1 < lit2); + + //check if binary is already known + vector& thisBins = bins[(~lit1).toInt()]; + for (vector::const_iterator it = thisBins.begin(), end = thisBins.end(); it != end; ++it) { + if (*it == lit2) { + return; + } + } + + //binary not already known + thisBins.push_back(lit2); +} + +void DataSyncServer::finish_data_send() +{ + if (sendData == NULL) { + assert(send_requests_finished == true); + return; + } + + int err; + int numFinished = 0; + for (int i = 1; i < mpiSize; i++) { + if (sendRequestsFinished[i]) { + numFinished++; + continue; + } +// #ifdef VERBOSE_DEBUG_MPI_SENDRCV +// std::cout << "c -->> MPI Server" +// << " Checking if sending finished to " << i << std::endl; +// #endif + + MPI_Status status; + int op_completed; + err = MPI_Test(&(sendRequests[i]), &op_completed, &status); + assert(err == MPI_SUCCESS); + if (op_completed) { + //NOTE: no need to free, MPI_Test also frees it + sendRequestsFinished[i] = true; + numFinished++; + #ifdef VERBOSE_DEBUG_MPI_SENDRCV + std::cout << "c -->> MPI Server [to:" << i << "]" + << " Sending finished" << std::endl; + #endif + } else if (interrupt_sent) { + //If we have finished then we must cancel this otherwise we may hang + // waiting for a receive of a thread that itself has already found SAT/UNSAT on its own + + //NOTE: "It is still necessary to complete a communication that has been marked for cancellation, using a call to MPI_REQUEST_FREE, MPI_WAIT or MPI_TEST (or any of the derived operations)." + // --> So we cannot set sendRequesFinished -- we must still test! + + err = MPI_Cancel(&(sendRequests[i])); + assert(err == MPI_SUCCESS); + sendRequestsFinished[i] = true; + numFinished++; + #ifdef VERBOSE_DEBUG_MPI_SENDRCV + std::cout << "c -->> MPI Server [to:" << i << "]" + << " cancelling due to interrupt" << std::endl; + #endif + } + } + if (numFinished != mpiSize-1) { +// #ifdef VERBOSE_DEBUG_MPI_SENDRCV +// std::cout << "c -->> MPI Server" +// << " sending not all finished, exiting sendDataToAll" << std::endl; +// #endif + return; + } + send_requests_finished = true; + delete[] sendData; + sendData = NULL; +} + +void DataSyncServer::sendDataToAll() +{ + int err; + //If interrupt already sent, we just waited for things to be received + if (interrupt_sent) { + return; + } + + //Set up units. First, the num_vars, then the values + uint32_t thisSentBinData = 0; + vector data; + data.push_back((uint32_t)num_vars); + for (uint32_t var = 0; var < num_vars; var++) { + data.push_back(toInt(value[var])); + } + + //Binaries. First, the 2*num_vars, then the list sizes, then the data. + data.push_back((uint32_t)num_vars*2); + uint32_t at = 0; + for(vector >::const_iterator it = bins.begin(), end = bins.end(); it != end; ++it, at++) { + const vector& binSet = *it; + assert(binSet.size() >= syncMPIFinish[at]); + uint32_t sizeToSend = binSet.size() - syncMPIFinish[at]; + data.push_back(sizeToSend); + for (uint32_t i = syncMPIFinish[at]; i < binSet.size(); i++) { + data.push_back(binSet[i].toInt()); + thisSentBinData++; + } + syncMPIFinish[at] = binSet.size(); + } + sentBinData += thisSentBinData; + + //Send data as tag 0 + sendData = new uint32_t[data.size()]; + std::copy(data.begin(), data.end(), sendData); + for (int i = 1; i < mpiSize; i++) { + err = MPI_Isend(sendData, data.size(), MPI_UNSIGNED, i, 0, MPI_COMM_WORLD, &(sendRequests[i])); + assert(err == MPI_SUCCESS); + #ifdef VERBOSE_DEBUG_MPI_SENDRCV + std::cout << "c -->> MPI Server [to " << i << "]" + << " Sent " << data.size() << " uint32_t -s" << std::endl; + std::cout << "c -->> MPI Server [to " << i << "]" + << " Sent " << thisSentBinData << " bins " << std::endl; + #endif + sendRequestsFinished[i] = false; + } + lastSendNumGotPacket = numGotPacket; + send_requests_finished = false; +} + + +//Tag of message "1" +bool DataSyncServer::check_interrupt_and_forward_to_all() +{ + int err; + MPI_Status status; + int flag; + + //Check for interrupt data + err = MPI_Iprobe( + MPI_ANY_SOURCE, + 1, //check tag "1", i.e. interrupt tag data + MPI_COMM_WORLD, &flag, &status); + int source = status.MPI_SOURCE; + assert(err == MPI_SUCCESS); + if (flag == false) { + return false; + } + + #ifdef VERBOSE_DEBUG_MPI_SENDRCV + std::cout << "c -->> MPI Server" + << " Got interrupt from " << source << std::endl; + #endif + + int count; + err = MPI_Get_count(&status, MPI_UNSIGNED, &count); + assert(err == MPI_SUCCESS); + + #ifdef VERBOSE_DEBUG_MPI_SENDRCV + std::cout << "c -->> MPI Server" + << " Interrupt from " << source << " has size " << count << std::endl; + #endif + + //Get the interrupt signal, tagged 1, with the solution. BLOCKING. + uint32_t* buf = new uint32_t[count]; + err = MPI_Recv(buf, count, MPI_UNSIGNED, + source, //coming from source + 1, //tag "1", i.e. interrupt + MPI_COMM_WORLD, &status); + assert(err == MPI_SUCCESS); + + int at = 0; + solution_val = toLbool(buf[at++]); + if (solution_val == l_True) { + model.resize(buf[at++]); + assert((int)model.size() == count-2); + for(uint32_t i = 0; i < model.size(); i++) { + int val = buf[at++]; + model[i] = toLbool(val); + } + } + delete[] buf; + +// #ifdef VERBOSE_DEBUG_MPI_SENDRCV + std::cout << "c -->> MPI Server" + << " got solution from " << source << std::endl; +// #endif + + //Send to all except: the one who sent it (source) and ourselves (0) + for (int i = 1; i < mpiSize; i++) { + if (i == source) { + continue; + } +// #ifdef VERBOSE_DEBUG_MPI_SENDRCV + std::cout << "c -->> MPI Server" + << " sending interrupt to " << i << std::endl; +// #endif + + err = MPI_Isend( + NULL, // buf is actually empty that we send + 0, // sending 0 bytes + MPI_UNSIGNED, + i, // send to "i" target + 1, // tag "1" i.e. interrupt + MPI_COMM_WORLD, &(interruptRequests[i])); + assert(err == MPI_SUCCESS); + } + + return true; +} + +void CMSat::DataSyncServer::print_solution() +{ + cout << "v "; + for(uint32_t i = 0; i < model.size(); i++) { + if (model[i] == l_True) { + cout << i+1 << " "; + } else if (model[i] == l_False) { + cout << "-" << i+1 << " "; + } else { + assert(false && "We should always have full model"); + } + } + cout << endl; +} + +void CMSat::DataSyncServer::send_cnf_to_solvers() +{ + std::cout << "c -->> MPI Server" + << "sending file to all solvers..." << endl; + + value.resize(num_vars, l_Undef); + bins.resize(num_vars*2); + syncMPIFinish.resize(num_vars*2, 0); + + int err; + bool finished = false; + Lit buf[1024]; + uint32_t at = 0; + uint32_t i = 0; + + //first byte we send is the number of variables + buf[i] = Lit(num_vars, false); + i++; + + while(!finished) { + for(;i < 1024; i++) { + if (clauses_array.size() <= at) { + buf[i] = lit_Error; + finished = true; + continue; + } + + buf[i] = clauses_array[at]; + at++; + } + err = MPI_Bcast(buf, 1024, MPI_UNSIGNED, 0, MPI_COMM_WORLD); + assert(err == MPI_SUCCESS); + i = 0; + } + assert(clauses_array.size() == at); + + std::cout << "c -->> MPI Server" + << " sent file to all solvers" << endl; +} + +void CMSat::DataSyncServer::new_var() +{ + num_vars++; +} + +void CMSat::DataSyncServer::add_xor_clause(const vector& vars, bool& rhs) +{ + assert(false); +} + + +void CMSat::DataSyncServer::new_vars(uint32_t i) +{ + num_vars+=i; +} + +void CMSat::DataSyncServer::add_clause(const vector& lits) +{ + for(const auto& lit: lits) { + clauses_array.push_back(lit); + } + clauses_array.push_back(lit_Undef); +} + +lbool DataSyncServer::actAsServer() +{ + //both interrupt_sent AND send_requests_finished must be OK to exit + while(!(interrupt_sent && send_requests_finished)) { + mpi_recv_from_others(); + finish_data_send(); + + if (lastSendNumGotPacket+(mpiSize/2)+1 < numGotPacket && + send_requests_finished && + !interrupt_sent) + { + sendDataToAll(); + } + + if (!interrupt_sent && + check_interrupt_and_forward_to_all()) + { + interrupt_sent = true; + + //HACK below, we don't cleanly exit + if (solution_val == l_True) { + cout << "s SATISFIABLE" << endl; + } else if (solution_val == l_False) { + cout << "s UNSATISFIABLE" << endl; + } else { + assert(false); + } + MPI_Abort(MPI_COMM_WORLD, 0); + exit(0); + } + usleep(1); + } + + return solution_val; +} + diff --git a/cryptominisat/cppsrc/src/datasyncserver.h b/cryptominisat/cppsrc/src/datasyncserver.h new file mode 100644 index 00000000..e8b6de0b --- /dev/null +++ b/cryptominisat/cppsrc/src/datasyncserver.h @@ -0,0 +1,82 @@ +/****************************************** +Copyright (C) 2009-2020 Authors of CryptoMiniSat, see AUTHORS file + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. +***********************************************/ + +#ifndef DATASYNC_SERVER_H +#define DATASYNC_SERVER_H + +#include +#include "mpi.h" + +#include "solvertypes.h" +#include "shareddata.h" + +namespace CMSat { + +class DataSyncServer { + public: + DataSyncServer(); + ~DataSyncServer(); + lbool actAsServer(); + void print_solution(); + void send_cnf_to_solvers(); + void add_clause(const vector& lits); + void new_vars(uint32_t i); + void new_var(); + void add_xor_clause(const vector& vars, bool& rhs); + uint32_t nVars() const { + return num_vars; + } + + private: + void mpi_recv_from_others(); + void get_bin(const Lit lit1, const Lit lit2); + void sendDataToAll(); + bool check_interrupt_and_forward_to_all(); + void finish_data_send(); + + std::vector syncMPIFinish; + std::vector > bins; + std::vector value; + std::vector clauses_array; + + uint32_t *sendData = NULL; + bool send_requests_finished = true; + + std::vector sendRequests; + std::vector sendRequestsFinished; + std::vector interruptRequests; + + vector model; + lbool solution_val = l_Undef; + bool interrupt_sent = false; + + int mpiSize; + uint32_t num_vars = 0; + uint32_t recvBinData = 0; + uint32_t sentBinData = 0; + uint32_t numGotPacket = 0; + uint32_t lastSendNumGotPacket = 0; +}; + +} + +#endif //DATASYNC_SERVER_H diff --git a/cryptominisat/cppsrc/src/dimacsparser.h b/cryptominisat/cppsrc/src/dimacsparser.h new file mode 100644 index 00000000..ae207f66 --- /dev/null +++ b/cryptominisat/cppsrc/src/dimacsparser.h @@ -0,0 +1,733 @@ +/***************************************************************************** +MiniSat -- Copyright (c) 2003-2006, Niklas Een, Niklas Sorensson +CryptoMiniSat -- Copyright (C) 2009-2020 Authors of CryptoMiniSat, see AUTHORS file + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. +******************************************************************************/ + +#pragma once + +#include +#include "streambuffer.h" +#include "solvertypesmini.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include + +using std::vector; +using std::cout; +using std::endl; + +namespace CMSat { + +template +class DimacsParser +{ + public: + DimacsParser(S* solver, const std::string* debugLib, unsigned _verbosity); + + template bool parse_DIMACS( + T input_stpeam, + const bool strict_header, + uint32_t offset_vars = 0); + uint64_t max_var = numeric_limits::max(); + vector sampling_vars; + bool sampling_vars_found = false; + vector weights; + uint32_t must_mult_exp2 = 0; + const std::string dimacs_spec = "http://www.satcompetition.org/2009/format-benchmarks2009.html"; + const std::string please_read_dimacs = "\nPlease read DIMACS specification at http://www.satcompetition.org/2009/format-benchmarks2009.html"; + + private: + bool parse_DIMACS_main(C& in); + bool readClause(C& in); + bool parse_and_add_clause(C& in); + bool parse_and_add_xor_clause(C& in); + #ifdef ENABLE_BNN + bool parse_and_add_bnn_clause(C& in); + #endif + bool match(C& in, const char* str); + bool parse_header(C& in); + bool parseComments(C& in, const std::string& str); + std::string stringify(uint32_t x) const; + bool check_var(const uint32_t var); + bool parseWeight(C& in); + + #ifdef DEBUG_DIMACSPARSER_CMS + bool parse_solve_simp_comment(C& in, const bool solve); + void write_solution_to_debuglib_file(const lbool ret) const; + #endif + + bool parseIndependentSet(C& in); + std::string get_debuglib_fname() const; + + + S* solver; + std::string debugLib; + unsigned verbosity; + + //Stat + size_t lineNum; + + //Printing partial solutions to debugLibPart1..N.output when "debugLib" is set to TRUE + uint32_t debugLibPart = 1; + + //check header strictly + bool strict_header = false; + bool header_found = false; + int num_header_vars = 0; + int num_header_cls = 0; + uint32_t offset_vars = 0; + + //Reduce temp overhead + vector lits; + vector vars; + + size_t norm_clauses_added = 0; + size_t xor_clauses_added = 0; + #ifdef ENABLE_BNN + size_t bnn_clauses_added = 0; + #endif +}; + + +template +DimacsParser::DimacsParser( + S* _solver + , const std::string* _debugLib + , unsigned _verbosity +): + solver(_solver) + , verbosity(_verbosity) + , lineNum(0) +{ + if (_debugLib) { + debugLib = *_debugLib; + } +} + +template +std::string DimacsParser::stringify(uint32_t x) const +{ + std::ostringstream o; + o << x; + return o.str(); +} + +template +bool DimacsParser::check_var(const uint32_t var) +{ + if (var > max_var) { + std::cerr + << "ERROR! " + << "Variable requested is too large for DIMACS parser parameter: " + << var << endl + << "--> At line " << lineNum+1 + << please_read_dimacs + << endl; + return false; + } + + if (var >= (1ULL<<28)) { + std::cerr + << "ERROR! " + << "Variable requested is far too large: " << var + 1 << endl + << "--> At line " << lineNum+1 + << please_read_dimacs + << endl; + return false; + } + + if (strict_header && !header_found) { + std::cerr + << "ERROR! " + << "DIMACS header ('p cnf vars cls') never found!" << endl; + return false; + } + + if ((int)var >= num_header_vars && strict_header) { + std::cerr + << "ERROR! " + << "Variable requested is larger than the header told us." << endl + << " -> var is : " << var + 1 << endl + << " -> header told us maximum will be : " << num_header_vars << endl + << " -> At line " << lineNum+1 + << endl; + return false; + } + + if (var >= solver->nVars()) { + assert(!strict_header); + solver->new_vars(var - solver->nVars() +1); + } + + return true; +} + +template +bool DimacsParser::readClause(C& in) +{ + int32_t parsed_lit; + uint32_t var; + for (;;) { + if (!in.parseInt(parsed_lit, lineNum)) { + return false; + } + if (parsed_lit == 0) { + break; + } + + var = std::abs(parsed_lit)-1; + var += offset_vars; + + if (!check_var(var)) { + return false; + } + + lits.push_back( (parsed_lit > 0) ? Lit(var, false) : Lit(var, true) ); + if (*in != ' ') { + std::cerr + << "ERROR! " + << "After last element on the line must be 0" << endl + << "--> At line " << lineNum+1 + << please_read_dimacs + << endl + << endl; + return false; + } + } + + return true; +} + +template +bool DimacsParser::match(C& in, const char* str) +{ + for (; *str != 0; ++str, ++in) + if (*str != *in) + return false; + return true; +} + +#ifdef DEBUG_DIMACSPARSER_CMS +template +bool DimacsParser::parseWeight(C& in) +{ + if (match(in, "w ")) { + int32_t slit; + double weight; + if (in.parseInt(slit, lineNum) + && in.parseDouble(weight, lineNum) + ) { + if (slit == 0) { + cout << "ERROR: Cannot define weight of literal 0!" << endl; + exit(-1); + } + uint32_t var = std::abs(slit)-1; + bool sign = slit < 0; + Lit lit = Lit(var, sign); + solver->set_var_weight(lit, weight); + //cout << "lit: " << lit << " weight: " << std::setprecision(12) << weight << endl; + if (weight < 0) { + cout << "ERROR: while definint weight, variable " << var+1 << " has is negative weight: " << weight << " -- line " << lineNum << endl; + exit(-1); + } + return true; + } else { + cout << "ERROR: weight is incorrect on line " << lineNum << endl; + exit(-1); + } + } else { + cout << "ERROR: weight is not given on line " << lineNum << endl; + exit(-1); + } + return true; +} +#endif + +template +bool DimacsParser::parse_header(C& in) +{ + ++in; + in.skipWhitespace(); + std::string str; + in.parseString(str); + if (str == "cnf") { + if (header_found && strict_header) { + std::cerr << "ERROR: CNF header ('p cnf vars cls') found twice in file! Exiting." << endl; + exit(-1); + } + header_found = true; + + if (!in.parseInt(num_header_vars, lineNum) + || !in.parseInt(num_header_cls, lineNum) + ) { + return false; + } + if (verbosity) { + cout << "c -- header says num vars: " << std::setw(12) << num_header_vars << endl; + cout << "c -- header says num clauses:" << std::setw(12) << num_header_cls << endl; + } + if (num_header_vars < 0) { + std::cerr << "ERROR: Number of variables in header cannot be less than 0" << endl; + return false; + } + if (num_header_cls < 0) { + std::cerr << "ERROR: Number of clauses in header cannot be less than 0" << endl; + return false; + } + num_header_vars += offset_vars; + + if (solver->nVars() < (size_t)num_header_vars) { + solver->new_vars(num_header_vars-solver->nVars()); + } + } else { + std::cerr + << "PARSE ERROR! Unexpected char (hex: " << std::hex + << std::setw(2) + << std::setfill('0') + << "0x" << *in + << std::setfill(' ') + << std::dec + << ")" + << " At line " << lineNum+1 + << "' in the header" + << please_read_dimacs + << endl; + return false; + } + + return true; +} + +template +std::string DimacsParser::get_debuglib_fname() const +{ + std::string sol_fname = debugLib + "-debugLibPart" + stringify(debugLibPart) +".output"; + return sol_fname; +} + +#ifdef DEBUG_DIMACSPARSER_CMS +template +bool DimacsParser::parse_solve_simp_comment(C& in, const bool solve) +{ + vector assumps; + in.skipWhitespace(); + while(*in != ')') { + int lit; + if (!in.parseInt(lit, lineNum)) { + return false; + } + assumps.push_back(Lit(std::abs(lit)-1, lit < 0)); + in.skipWhitespace(); + } + + if (verbosity) { + cout + << "c -----------> Solver::" + << (solve ? "solve" : "simplify") + <<" called (number: " + << std::setw(3) << debugLibPart << ") with assumps :"; + for(Lit lit: assumps) { + cout << lit << " "; + } + cout << "<-----------" << endl; + } + + lbool ret; + if (solve) { + if (verbosity) { + cout << "c Solution will be written to: " + << get_debuglib_fname() << endl; + } + ret = solver->solve(&assumps); + write_solution_to_debuglib_file(ret); + debugLibPart++; + } else { + ret = solver->simplify(&assumps); + } + + if (verbosity >= 6) { + cout << "c Parsed Solver::" + << (solve ? "solve" : "simplify") + << endl; + } + return true; +} + +template +void DimacsParser::write_solution_to_debuglib_file(const lbool ret) const +{ + //Open file for writing + std::string s = get_debuglib_fname(); + std::ofstream partFile; + partFile.open(s.c_str()); + if (!partFile) { + std::cerr << "ERROR: Cannot open part file '" << s << "'"; + std::exit(-1); + } + + //Output to part file the result + if (ret == l_True) { + partFile << "s SATISFIABLE\n"; + partFile << "v "; + for (uint32_t i = 0; i != solver->nVars(); i++) { + if (solver->get_model()[i] != l_Undef) + partFile + << ((solver->get_model()[i]==l_True) ? "" : "-") + << (i+1) << " "; + } + partFile << "0\n"; + } else if (ret == l_False) { + partFile << "conflict "; + for (Lit lit: solver->get_conflict()) { + partFile << lit << " "; + } + partFile + << "\ns UNSAT\n"; + } else if (ret == l_Undef) { + cout << "c timeout, exiting" << endl; + std::exit(15); + } else { + assert(false); + } + partFile.close(); +} +#endif + +template +bool DimacsParser::parseComments(C& in, const std::string& str) +{ + #ifdef DEBUG_DIMACSPARSER_CMS + if (!debugLib.empty() && str.substr(0, 13) == "Solver::solve") { + if (!parse_solve_simp_comment(in, true)) { + return false; + } + } else if (!debugLib.empty() && str.substr(0, 16) == "Solver::simplify") { + if (!parse_solve_simp_comment(in, false)) { + return false; + } + } else + #endif + if (str == "red") { + in.skipWhitespace(); + lits.clear(); + if (!readClause(in)) return false; + solver->add_red_clause(lits); + } + if (str == "MUST") { + std::string str2; + in.skipWhitespace(); + in.parseString(str2); + if (str2 != "MULTIPLY") { + cout << "ERROR: expected 'MULTIPLY' after 'MUST'" << endl; + return false; + } + in.skipWhitespace(); + in.parseString(str2); + if (str2 != "BY") { + cout << "ERROR: expected 'BY' after 'MUST MULTIPLY'" << endl; + return false; + } + in.skipWhitespace(); + assert(*in == '2');++in; + assert(*in == '*');++in; + assert(*in == '*');++in; + if (!in.parseInt(must_mult_exp2, lineNum)) { + return false; + } + } + if (!debugLib.empty() && str == "Solver::new_var()") { + solver->new_var(); + + if (verbosity >= 6) { + cout << "c Parsed Solver::new_var()" << endl; + } + } else if (!debugLib.empty() && str == "Solver::new_vars(") { + in.skipWhitespace(); + int n; + if (!in.parseInt(n, lineNum)) { + return false; + } + solver->new_vars(n); + + if (verbosity >= 6) { + cout << "c Parsed Solver::new_vars( " << n << " )" << endl; + } + } else if (str == "ind") { + sampling_vars_found = true; + if (!parseIndependentSet(in)) { + return false; + } + } else if (str == "p") { + in.skipWhitespace(); + std::string str2; + in.parseString(str2); + if (str2 == "show") { + in.skipWhitespace(); + sampling_vars_found = true; + if (!parseIndependentSet(in)) { return false; } + } else { + cout << "ERROR, 'c p' followed by unknown text: '" << str2 << "'" << endl; + exit(-1); + } + } else { + if (verbosity >= 6) { + cout + << "didn't understand in CNF file comment line:" + << "'c " << str << "'" + << endl; + } + } + in.skipLine(); + lineNum++; + return true; +} + +template +bool DimacsParser::parse_and_add_clause(C& in) +{ + lits.clear(); + if (!readClause(in)) { + return false; + } + in.skipWhitespace(); + if (!in.skipEOL(lineNum)) { + return false; + } + lineNum++; + solver->add_clause(lits); + norm_clauses_added++; + return true; +} + +#ifdef ENABLE_BNN +// This parses a threshold constraint of the form: +// b lit1..litn 0 cutoff 0 [output_lit] +// where output_lit is optional and if missing is assumed to be TRUE +// basically, lit1+lit2+litN >= cutoff <=> output_lit=TRUE +// where lit1 is 1 if it's TRUE and 0 otherwise +template +bool DimacsParser::parse_and_add_bnn_clause(C& in) +{ + // Read in inputs to BNN + lits.clear(); + if (!readClause(in)) { + return false; + } + if (lits.empty()) { + std::cerr + << "ERROR! " + << "BNN constraint has empty set of inputs" << endl + << "--> At line " << lineNum+1 + << endl; + return false; + } + + // Read cutoff + int32_t cutoff; + if (!in.parseInt(cutoff, lineNum)) { + return false; + } + + in.skipWhitespace(); + + Lit out = lit_Undef; + if (*in != '\n') { + // Read in output var + int32_t parsed_lit; + if (!in.parseInt(parsed_lit, lineNum)) { + return false; + } + assert(parsed_lit != 0); + uint32_t var = std::abs(parsed_lit)-1; + var += offset_vars; + + //off-by-one internally. + if (!check_var(var)) { + return false; + } + out = Lit(var, parsed_lit < 0); + } + + // Line finished + in.skipLine(); + lineNum++; + + solver->add_bnn_clause(lits, cutoff, out); + bnn_clauses_added++; + return true; +} +#endif + +template +bool DimacsParser::parse_and_add_xor_clause(C& in) +{ + lits.clear(); + if (!readClause(in)) { + return false; + } + if (!in.skipEOL(lineNum)) { + return false; + } + lineNum++; + if (lits.empty()) + return true; + + bool rhs = true; + vars.clear(); + for(Lit& lit: lits) { + vars.push_back(lit.var()); + if (lit.sign()) { + rhs ^= true; + } + } + solver->add_xor_clause(vars, rhs); + xor_clauses_added++; + return true; +} + +template +bool DimacsParser::parse_DIMACS_main(C& in) +{ + std::string str; + + for (;;) { + in.skipWhitespace(); + switch (*in) { + case EOF: + return true; + case 'p': + if (!parse_header(in)) { + return false; + } + in.skipLine(); + lineNum++; + break; + + #ifdef DEBUG_DIMACSPARSER_CMS + case 'w': + if (!parseWeight(in)) { + return false; + } + in.skipLine(); + lineNum++; + break; + #endif + case 'c': + ++in; + in.parseString(str); + if (!parseComments(in, str)) { + return false; + } + break; + case 'x': + ++in; + if (!parse_and_add_xor_clause(in)) { + return false; + } + break; + case 'b': + #ifdef ENABLE_BNN + ++in; + if (!parse_and_add_bnn_clause(in)) { + return false; + } + #else + std::cout << "ERROR: BNN encounered but not enabled in parsing. Exiting." << endl; + exit(-1); + #endif + break; + case '\n': + if (verbosity) { + std::cout + << "c WARNING: Empty line at line number " << lineNum+1 + << " -- this is not part of the DIMACS specifications (" + << dimacs_spec << "). Ignoring." + << endl; + } + in.skipLine(); + lineNum++; + break; + default: + if (!parse_and_add_clause(in)) { + return false; + } + break; + } + } + + return true; +} + +template +template +bool DimacsParser::parse_DIMACS( + T input_stream, + const bool _strict_header, + uint32_t _offset_vars) +{ + debugLibPart = 1; + strict_header = _strict_header; + offset_vars = _offset_vars; + const uint32_t origNumVars = solver->nVars(); + + C in(input_stream); + if ( !parse_DIMACS_main(in)) { + return false; + } + + if (verbosity) { + cout + << "c -- clauses added: " << norm_clauses_added << endl + << "c -- xor clauses added: " << xor_clauses_added << endl + #ifdef ENABLE_BNN + << "c -- bnn clauses added: " << bnn_clauses_added << endl + #endif + << "c -- vars added " << (solver->nVars() - origNumVars) + << endl; + } + + return true; +} + +template +bool DimacsParser::parseIndependentSet(C& in) +{ + int32_t parsed_lit; + for (;;) { + if (!in.parseInt(parsed_lit, lineNum)) { + return false; + } + if (parsed_lit == 0) { + break; + } + uint32_t var = std::abs(parsed_lit) - 1; + sampling_vars.push_back(var); + } + return true; +} + +} diff --git a/cryptominisat/cppsrc/src/distillerbin.cpp b/cryptominisat/cppsrc/src/distillerbin.cpp new file mode 100644 index 00000000..ab14962b --- /dev/null +++ b/cryptominisat/cppsrc/src/distillerbin.cpp @@ -0,0 +1,328 @@ +/****************************************** +Copyright (C) 2009-2020 Authors of CryptoMiniSat, see AUTHORS file + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. +***********************************************/ + +#include +#include +#include + +#include "distillerbin.h" +#include "clausecleaner.h" +#include "time_mem.h" +#include "solver.h" +#include "watchalgos.h" +#include "clauseallocator.h" +#include "sqlstats.h" + + +using namespace CMSat; +using std::cout; +using std::endl; + +#ifdef VERBOSE_DEBUG +#define VERBOSE_SUBSUME_NONEXIST +#endif + +//#define VERBOSE_SUBSUME_NONEXIST + +DistillerBin::DistillerBin(Solver* _solver) : + solver(_solver) +{} + +bool DistillerBin::distill() +{ + assert(solver->ok); + numCalls++; + runStats.clear(); + *solver->frat << __PRETTY_FUNCTION__ << " start\n"; + + if (!distill_bin_cls_all(1.0)) { + goto end; + } + +end: + globalStats += runStats; + if (solver->conf.verbosity) { + if (solver->conf.verbosity >= 3) + runStats.print(solver->nVars()); + else + runStats.print_short(solver); + } + runStats.clear(); + *solver->frat << __PRETTY_FUNCTION__ << " end\n"; + + return solver->okay(); +} + + +bool DistillerBin::distill_bin_cls_all( + double time_mult +) { + assert(solver->ok); + if (time_mult == 0.0) return solver->okay(); + verb_print(6, "Doing distillation branch for long clauses"); + + double myTime = cpuTime(); + const size_t origTrailSize = solver->trail_size(); + *solver->frat << __PRETTY_FUNCTION__ << " start\n"; + + //Time-limiting + maxNumProps = + solver->conf.distill_long_cls_time_limitM*200LL*1000ULL + *solver->conf.global_timeout_multiplier; + + if (solver->litStats.irredLits + solver->litStats.redLits < + (500ULL*1000ULL*solver->conf.var_and_mem_out_mult) + ) { + maxNumProps *=2; + } + maxNumProps *= time_mult; + orig_maxNumProps = maxNumProps; + + //stats setup + oldBogoProps = solver->propStats.bogoProps; + uint32_t potential_size = solver->binTri.irredBins; + runStats.potentialClauses += potential_size; + runStats.numCalled += 1; + + bool time_out; + vector todo; + for(uint32_t i = 0; i < solver->nVars()*2; i ++) { + const Lit lit = Lit::toLit(i); + todo.push_back(lit); + } + std::shuffle(todo.begin(), todo.end(), solver->mtrand); + for(const auto& lit: todo) { + time_out = go_through_bins(lit); + if (time_out || !solver->okay()) { + break; + } + } + + const double time_used = cpuTime() - myTime; + const double time_remain = float_div( + maxNumProps - ((int64_t)solver->propStats.bogoProps-(int64_t)oldBogoProps), + orig_maxNumProps); + if (solver->conf.verbosity >= 2) { + cout << "c [distill-bin] cls" + << " tried: " << runStats.checkedClauses << "/" << potential_size + << endl; + } + if (solver->sqlStats) { + solver->sqlStats->time_passed( + solver + , "distill bin cls" + , time_used + , time_out + , time_remain + ); + } + *solver->frat << __PRETTY_FUNCTION__ << " end\n"; + + //Update stats + runStats.time_used += time_used; + runStats.zeroDepthAssigns += solver->trail_size() - origTrailSize; + + return solver->okay(); +} + +bool DistillerBin::go_through_bins( + const Lit lit1 +) { + solver->watches[lit1].copyTo(tmp); + + for (const auto& w: tmp) { + if (!w.isBin() || //check if we are bin + lit1 > w.lit2() || // don't do it 2x + w.red()) // only irred + { + continue; + } + + //if done enough, stop doing it + if ((int64_t)solver->propStats.bogoProps-(int64_t)oldBogoProps >= maxNumProps + || solver->must_interrupt_asap() + ) { + if (solver->conf.verbosity >= 3) { + cout + << "c Need to finish distillation -- ran out of prop (=allocated time)" + << endl; + } + runStats.timeOut++; + return true; + } + runStats.checkedClauses++; + const Lit lit2 = w.lit2(); + + //we will detach the clause no matter what + maxNumProps -= solver->watches[lit1].size(); + maxNumProps -= solver->watches[lit2].size(); + maxNumProps -= 2; + + if (solver->value(lit1) == l_True || solver->value(lit2) == l_True) { + solver->detach_bin_clause(lit1, lit2, w.red(), w.get_ID()); + (*solver->frat) << del << w.get_ID() << lit1 << lit2 << fin; + continue; + } + + //Try to distill clause + if (!try_distill_bin(lit1, lit2, w)) { + //UNSAT + return false; + } + } + + return false; +} + +bool DistillerBin::try_distill_bin( + Lit lit1, + Lit lit2, + const Watched& w +) { + assert(solver->okay()); + assert(solver->prop_at_head()); + assert(solver->decisionLevel() == 0); + #ifdef FRAT_DEBUG + if (solver->conf.verbosity >= 6) { + cout << "Trying to distill clause:" << lits << endl; + } + #endif + + //Try different ordering + if (rnd_uint(solver->mtrand, 1) == 1) std::swap(lit1, lit2); + + //Disable this clause + findWatchedOfBin(solver->watches, lit1, lit2, false, w.get_ID()).mark_bin_cl(); + findWatchedOfBin(solver->watches, lit2, lit1, false, w.get_ID()).mark_bin_cl(); + + solver->new_decision_level(); + PropBy confl; + solver->enqueue(~lit1); + confl = solver->propagate(); + + if (confl.isNULL()) { + if (solver->value(lit2) == l_True) { + //clause can be removed + confl = PropBy(ClOffset(0)); + } else if (solver->value(lit2) == l_False) { + //Unit derived + solver->cancelUntil(0); + vector x(1); + x[0] = lit1; + solver->add_clause_int(x); + solver->detach_bin_clause(lit1, lit2, false, w.get_ID()); + (*solver->frat) << del << w.get_ID() << lit1 << lit2 << fin; + runStats.numClShorten++; + return solver->okay(); + } else if (solver->value(lit2) == l_Undef) { + solver->enqueue(~lit2); + confl = solver->propagate(); + } + } + + if (!confl.isNULL()) { + solver->cancelUntil(0); + solver->detach_bin_clause(lit1, lit2, false, w.get_ID()); + (*solver->frat) << del << w.get_ID() << lit1 << lit2 << fin; + runStats.clRemoved++; + return true; + } + + //Nothing happened + solver->cancelUntil(0); + auto &w1 = findWatchedOfBin(solver->watches, lit1, lit2, false, w.get_ID()); + assert(w1.bin_cl_marked()); + w1.unmark_bin_cl(); + + auto &w2 = findWatchedOfBin(solver->watches, lit2, lit1, false, w.get_ID()); + assert(w2.bin_cl_marked()); + w2.unmark_bin_cl(); + + return true; +} + +DistillerBin::Stats& DistillerBin::Stats::operator+=(const Stats& other) +{ + time_used += other.time_used; + timeOut += other.timeOut; + zeroDepthAssigns += other.zeroDepthAssigns; + numClShorten += other.numClShorten; + numLitsRem += other.numLitsRem; + checkedClauses += other.checkedClauses; + potentialClauses += other.potentialClauses; + numCalled += other.numCalled; + clRemoved += other.clRemoved; + + return *this; +} + +void DistillerBin::Stats::print_short(const Solver* _solver) const +{ + cout + << "c [distill-bin]" + << " useful: "<< numClShorten+clRemoved + << "/" << checkedClauses << "/" << potentialClauses + << " lits-rem: " << numLitsRem + << " cl-rem: " << clRemoved + << " 0-depth-assigns: " << zeroDepthAssigns + << _solver->conf.print_times(time_used, timeOut) + << endl; +} + +void DistillerBin::Stats::print(const size_t nVars) const +{ + cout << "c -------- DISTILL-BIN STATS --------" << endl; + print_stats_line("c time" + , time_used + , ratio_for_stat(time_used, numCalled) + , "per call" + ); + + print_stats_line("c timed out" + , timeOut + , stats_line_percent(timeOut, numCalled) + , "% of calls" + ); + + print_stats_line("c distill/checked/potential" + , numClShorten + , checkedClauses + , potentialClauses + ); + + print_stats_line("c lits-rem", + numLitsRem + ); + print_stats_line("c 0-depth-assigns", + zeroDepthAssigns + , stats_line_percent(zeroDepthAssigns, nVars) + , "% of vars" + ); + cout << "c -------- DISTILL STATS END --------" << endl; +} + +double DistillerBin::mem_used() const +{ + double mem_used = sizeof(DistillerBin); + mem_used += lits.size()*sizeof(Lit); + return mem_used; +} diff --git a/cryptominisat/cppsrc/src/distillerbin.h b/cryptominisat/cppsrc/src/distillerbin.h new file mode 100644 index 00000000..f8d292d9 --- /dev/null +++ b/cryptominisat/cppsrc/src/distillerbin.h @@ -0,0 +1,104 @@ +/****************************************** +Copyright (C) 2009-2020 Authors of CryptoMiniSat, see AUTHORS file + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. +***********************************************/ + +#ifndef _DISTILLERBIN_ +#define _DISTILLERBIN_ + +#include +#include "clause.h" +#include "constants.h" +#include "solvertypes.h" +#include "cloffset.h" +#include "watcharray.h" +#include "propby.h" + +namespace CMSat { + +using std::vector; + +class Solver; +class Clause; + +class DistillerBin { + public: + explicit DistillerBin(Solver* solver); + bool distill(); + + struct Stats + { + void clear() + { + Stats _tmp; + *this = _tmp; + } + + Stats& operator+=(const Stats& other); + void print_short(const Solver* solver) const; + void print(const size_t nVars) const; + + double time_used = 0.0; + uint64_t timeOut = 0; + uint64_t zeroDepthAssigns = 0; + uint64_t numClShorten = 0; + uint64_t numLitsRem = 0; + uint64_t checkedClauses = 0; + uint64_t potentialClauses = 0; + uint64_t numCalled = 0; + uint64_t clRemoved = 0; + }; + + const Stats& get_stats() const; + double mem_used() const; + + private: + + bool try_distill_bin( + Lit lit1, + Lit lit2, + const Watched& w + ); + bool distill_bin_cls_all(double time_mult); + bool go_through_bins(const Lit lit); + Solver* solver; + vec tmp; + + //For distill + vector lits; + uint64_t oldBogoProps; + int64_t maxNumProps; + int64_t orig_maxNumProps; + + //Global status + Stats runStats; + Stats globalStats; + size_t numCalls = 0; + +}; + +inline const DistillerBin::Stats& DistillerBin::get_stats() const +{ + return globalStats; +} + +} //end namespace + +#endif //__DISTILLERALL_WITH_ALL_H__ diff --git a/cryptominisat/cppsrc/src/distillerlitrem.cpp b/cryptominisat/cppsrc/src/distillerlitrem.cpp new file mode 100644 index 00000000..58e82ece --- /dev/null +++ b/cryptominisat/cppsrc/src/distillerlitrem.cpp @@ -0,0 +1,405 @@ +/****************************************** +Copyright (C) 2009-2020 Authors of CryptoMiniSat, see AUTHORS file + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. +***********************************************/ + +#include "distillerlitrem.h" +#include "clausecleaner.h" +#include "time_mem.h" +#include "solver.h" +#include "watchalgos.h" +#include "clauseallocator.h" +#include "sqlstats.h" + +#include +using namespace CMSat; +using std::cout; +using std::endl; + +#ifdef VERBOSE_DEBUG +#define VERBOSE_SUBSUME_NONEXIST +#endif + +//#define VERBOSE_SUBSUME_NONEXIST + +DistillerLitRem::DistillerLitRem(Solver* _solver) : + solver(_solver) +{} + +bool DistillerLitRem::distill_lit_rem() +{ + assert(solver->ok); + numCalls++; + runStats.clear(); + + + if (!solver->remove_and_clean_all()) { + goto end; + } + if (!distill_long_cls_all(solver->longIrredCls, 1)) { + goto end; + } + +end: + globalStats += runStats; + if (solver->conf.verbosity) { + if (solver->conf.verbosity >= 3) + runStats.print(solver->nVars()); + else + runStats.print_short(solver); + } + runStats.clear(); + + return solver->okay(); +} + +struct ClauseSizeSorterLargestFirst +{ + ClauseSizeSorterLargestFirst(const ClauseAllocator& _cl_alloc) : + cl_alloc(_cl_alloc) + {} + + const ClauseAllocator& cl_alloc; + + bool operator()(const ClOffset off1, const ClOffset off2) const + { + const Clause* cl1 = cl_alloc.ptr(off1); + const Clause* cl2 = cl_alloc.ptr(off2); + + //Correct order if c1's size is larger + return cl1->size() > cl2->size(); + } +}; + +bool DistillerLitRem::go_through_clauses( + vector& cls, + uint32_t at +) { + double myTime = cpuTime(); + bool time_out = false; + vector::iterator i, j; + i = j = cls.begin(); + for (vector::iterator end = cls.end() + ; i != end + ; ++i + ) { + //Check if we are in state where we only copy offsets around + if (time_out || !solver->ok) { + *j++ = *i; + continue; + } + + //if done enough, stop doing it + if ((int64_t)solver->propStats.bogoProps-(int64_t)oldBogoProps >= maxNumProps + || solver->must_interrupt_asap() + ) { + if (solver->conf.verbosity >= 3) { + cout + << "c Need to finish distillation -- ran out of prop (=allocated time)" + << endl; + } + runStats.timeOut++; + time_out = true; + } + + //Get pointer + ClOffset offset = *i; + ClOffset offset2; + Clause& cl = *solver->cl_alloc.ptr(offset); + if (cl.size() <= at) { + *j++ = *i; + continue; + } + + if (cl.used_in_xor() && + solver->conf.force_preserve_xors + ) { + *j++ = *i; + continue; + } + + //Time to dereference + maxNumProps -= 5; + + if (cl._xor_is_detached + + //If it's a redundant that's not very good, let's not distill it + || ( +#ifdef FINAL_PREDICTOR + solver->conf.pred_distill_only_smallgue && +#else + false && +#endif + cl.red() && + cl.stats.glue > 3) + ) { + *j++ = *i; + continue; + } + runStats.checkedClauses++; + assert(cl.size() > 2); + + //we will detach the clause no matter what + maxNumProps -= solver->watches[cl[0]].size(); + maxNumProps -= solver->watches[cl[1]].size(); + + maxNumProps -= cl.size(); + if (solver->satisfied(cl)) { + solver->detachClause(cl); + solver->free_cl(&cl); + continue; + } + + //Try to distill clause + offset2 = try_distill_clause_and_return_new( + offset + , &cl.stats + , at + ); + + if (offset2 != CL_OFFSET_MAX) { + *j++ = offset2; + } + } + cls.resize(cls.size()- (i-j)); + + runStats.time_used += cpuTime() - myTime; + return time_out; +} + +bool DistillerLitRem::distill_long_cls_all( + vector& offs + , double time_mult +) { + assert(solver->ok); + if (time_mult == 0.0) { + return solver->okay(); + } + + if (solver->conf.verbosity >= 6) { + cout + << "c Doing distillation branch for long clauses" + << endl; + } + + const size_t origTrailSize = solver->trail_size(); + + //Time-limiting + maxNumProps = + 5*1000LL*1000ULL + *solver->conf.global_timeout_multiplier; + + if (solver->litStats.irredLits + solver->litStats.redLits < + (500ULL*1000ULL*solver->conf.var_and_mem_out_mult) + ) { + maxNumProps *=2; + } + maxNumProps *= time_mult; + orig_maxNumProps = maxNumProps; + + //stats setup + oldBogoProps = solver->propStats.bogoProps; + runStats.potentialClauses += offs.size(); + runStats.numCalled += 1; + + bool time_out = false; + for(uint32_t i = 0; i < 10 && !time_out; i++) { + uint32_t prev_cls_tried = runStats.cls_tried; + time_out = go_through_clauses(offs, i); + if (solver->conf.verbosity >= 2) { + runStats.print_short(solver); + } + + //Max clause size reached + if (runStats.cls_tried == prev_cls_tried) { + break; + } + } + + const double time_remain = float_div( + maxNumProps - ((int64_t)solver->propStats.bogoProps-(int64_t)oldBogoProps), + orig_maxNumProps); + if (solver->conf.verbosity >= 3) { + cout << "c [distill-litrem] " + << " tried: " << runStats.checkedClauses << "/" << offs.size() + << endl; + } + if (solver->sqlStats) { + solver->sqlStats->time_passed( + solver + , "distill-litrem" + , runStats.time_used + , time_out + , time_remain + ); + } + + + //Update stats + runStats.zeroDepthAssigns += solver->trail_size() - origTrailSize; + + return solver->okay(); +} + +ClOffset DistillerLitRem::try_distill_clause_and_return_new( + ClOffset offset + , const ClauseStats* const stats + , const uint32_t at +) { + assert(solver->prop_at_head()); + assert(solver->decisionLevel() == 0); + const size_t origTrailSize = solver->trail_size(); + runStats.cls_tried++; + + Clause& cl = *solver->cl_alloc.ptr(offset); + const bool red = cl.red(); + + uint32_t orig_size = cl.size(); + assert(cl.size() > at); + Lit torem = cl[at]; + //if (solver->conf.verbosity >= 6) { + // cout << "Trying to rem lit: " << torem << " from clause:" << cl << endl; + //} + + solver->new_decision_level(); + for (const auto& l: cl) { + Lit lit = l; + if (lit == torem) { + lit = ~lit; + } + //cout << "Enq: " << ~lit << endl; + solver->enqueue(~lit); + } + assert(solver->ok); + PropBy confl = solver->propagate(); + solver->cancelUntil(0); + + //Couldn't remove literal + if (confl.isNULL()) { + return offset; + } + + //Managed to remove literal + lits.clear(); + for(const auto& l: cl) { + if (l != torem) { + lits.push_back(l); + } + } +// cout +// << "Failed" +// << " confl.isNULL(): " << confl.isNULL() +// << " i: " << i +// << " at: " << at +// << " cl before: " << cl +// << " cl after: " << lits +// << endl; + + //We can remove the literal + (*solver->frat) << deldelay << cl << fin; + solver->detachClause(cl, false); + runStats.numLitsRem += orig_size - lits.size(); + runStats.numClShorten++; + + // we have to copy because the re-alloc can invalidate the data + ClauseStats backup_stats(*stats); + // new clause will inherit this clause's ID + // so let's set this to 0, this way, when we free() it, it won't be + // deleted as per cl_last_in_solver + solver->free_cl(offset, false); + Clause *cl2 = solver->add_clause_int(lits, red, &backup_stats); + (*solver->frat) << findelay; + assert(solver->trail_size() == origTrailSize); + + if (cl2 != NULL) { + return solver->cl_alloc.get_offset(cl2); + } else { + #ifdef STATS_NEEDED + solver->stats_del_cl(offset); + #endif + //it became a bin/unit/zero + return CL_OFFSET_MAX; + } +} + +DistillerLitRem::Stats& DistillerLitRem::Stats::operator+=(const Stats& other) +{ + time_used += other.time_used; + timeOut += other.timeOut; + zeroDepthAssigns += other.zeroDepthAssigns; + numClShorten += other.numClShorten; + numLitsRem += other.numLitsRem; + checkedClauses += other.checkedClauses; + potentialClauses += other.potentialClauses; + numCalled += other.numCalled; + + return *this; +} + +void DistillerLitRem::Stats::print_short(const Solver* _solver) const +{ + cout + << "c [distill-litrem]" + << " useful: "<< numClShorten + << "/" << checkedClauses << "/" << potentialClauses + << " lits-rem: " << numLitsRem + << " 0-depth-assigns: " << zeroDepthAssigns + << _solver->conf.print_times(time_used, timeOut) + << endl; +} + +void DistillerLitRem::Stats::print(const size_t nVars) const +{ + cout << "c -------- DISTILL-LITREM STATS --------" << endl; + print_stats_line("c time" + , time_used + , ratio_for_stat(time_used, numCalled) + , "per call" + ); + + print_stats_line("c timed out" + , timeOut + , stats_line_percent(timeOut, numCalled) + , "% of calls" + ); + + print_stats_line("c distill/checked/potential" + , numClShorten + , checkedClauses + , potentialClauses + ); + + print_stats_line("c lits-rem", + numLitsRem + ); + print_stats_line("c 0-depth-assigns", + zeroDepthAssigns + , stats_line_percent(zeroDepthAssigns, nVars) + , "% of vars" + ); + cout << "c -------- DISTILL STATS END --------" << endl; +} + +double DistillerLitRem::mem_used() const +{ + double mem_used = sizeof(DistillerLitRem); + mem_used += lits.size()*sizeof(Lit); + return mem_used; +} diff --git a/cryptominisat/cppsrc/src/distillerlitrem.h b/cryptominisat/cppsrc/src/distillerlitrem.h new file mode 100644 index 00000000..bec21620 --- /dev/null +++ b/cryptominisat/cppsrc/src/distillerlitrem.h @@ -0,0 +1,101 @@ +/****************************************** +Copyright (C) 2009-2020 Authors of CryptoMiniSat, see AUTHORS file + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. +***********************************************/ + +#ifndef _DISTILLERLITREM_H_ +#define _DISTILLERLITREM_H_ + +#include +#include "clause.h" +#include "constants.h" +#include "solvertypes.h" +#include "cloffset.h" +#include "watcharray.h" + +namespace CMSat { + +using std::vector; + +class Solver; +class Clause; + +class DistillerLitRem { + public: + explicit DistillerLitRem(Solver* solver); + bool distill_lit_rem(); + + struct Stats + { + void clear() + { + Stats tmp; + *this = tmp; + } + + Stats& operator+=(const Stats& other); + void print_short(const Solver* solver) const; + void print(const size_t nVars) const; + + double time_used = 0.0; + uint64_t timeOut = 0; + uint64_t zeroDepthAssigns = 0; + uint64_t numLitsRem = 0; + uint64_t checkedClauses = 0; + uint64_t potentialClauses = 0; + uint64_t cls_tried = 0; + uint64_t numCalled = 0; + uint64_t numClShorten = 0; + }; + + const Stats& get_stats() const; + double mem_used() const; + + private: + bool distill_long_cls_all(vector& offs, double time_mult); + bool go_through_clauses(vector& cls, uint32_t at); + ClOffset try_distill_clause_and_return_new( + ClOffset offset + , const ClauseStats* const stats + , uint32_t at + ); + Solver* solver; + + //For distill + vector lits; + uint64_t oldBogoProps; + int64_t maxNumProps; + int64_t orig_maxNumProps; + + //Global status + Stats runStats; + Stats globalStats; + size_t numCalls = 0; + +}; + +inline const DistillerLitRem::Stats& DistillerLitRem::get_stats() const +{ + return globalStats; +} + +} //end namespace + +#endif //_DISTILLERLITREM_H_ diff --git a/cryptominisat/cppsrc/src/distillerlong.cpp b/cryptominisat/cppsrc/src/distillerlong.cpp new file mode 100644 index 00000000..be55cb13 --- /dev/null +++ b/cryptominisat/cppsrc/src/distillerlong.cpp @@ -0,0 +1,704 @@ +/****************************************** +Copyright (C) 2009-2020 Authors of CryptoMiniSat, see AUTHORS file + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. +***********************************************/ + +#include "distillerlong.h" +#include "clausecleaner.h" +#include "constants.h" +#include "time_mem.h" +#include "solver.h" +#include "watchalgos.h" +#include "clauseallocator.h" +#include "sqlstats.h" + +#include +#include +using namespace CMSat; +using std::cout; +using std::endl; + +#ifdef VERBOSE_DEBUG +#define VERBOSE_SUBSUME_NONEXIST +#endif + +//#define VERBOSE_DEBUG + +//#define VERBOSE_SUBSUME_NONEXIST + +struct ClauseSizeSorterLargestFirst +{ + ClauseSizeSorterLargestFirst(const ClauseAllocator& _cl_alloc) : + cl_alloc(_cl_alloc) + {} + + const ClauseAllocator& cl_alloc; + + bool operator()(const ClOffset off1, const ClOffset off2) const + { + const Clause* cl1 = cl_alloc.ptr(off1); + const Clause* cl2 = cl_alloc.ptr(off2); + + //Correct order if c1's size is larger + return cl1->size() > cl2->size(); + } +}; + +#ifdef FINAL_PREDICTOR +struct ClauseSorterFirstInSolver +{ + ClauseSorterFirstInSolver(const ClauseAllocator& _cl_alloc, const vector& _extras) : + cl_alloc(_cl_alloc), + extras(_extras) + {} + + const ClauseAllocator& cl_alloc; + const vector& extras; + + bool operator()(const ClOffset off1, const ClOffset off2) const + { + const Clause* cl1 = cl_alloc.ptr(off1); + const Clause* cl2 = cl_alloc.ptr(off2); + + const auto& extra1 = extras[cl1->stats.extra_pos]; + const auto& extra2 = extras[cl2->stats.extra_pos]; + + //Correct order if c1 was introduced earlier goes first + return extra1.introduced_at_conflict < extra2.introduced_at_conflict; + } +}; +#endif + +struct ClauseSorterSmallGlueFirst +{ + ClauseSorterSmallGlueFirst(const ClauseAllocator& _cl_alloc) : + cl_alloc(_cl_alloc) + {} + + const ClauseAllocator& cl_alloc; + + bool operator()(const ClOffset off1, const ClOffset off2) const + { + const Clause* cl1 = cl_alloc.ptr(off1); + const Clause* cl2 = cl_alloc.ptr(off2); + + //Correct order if c1's glue is smaller + return cl1->stats.glue < cl2->stats.glue; + } +}; + +#ifdef FINAL_PREDICTOR +struct ClauseSorterBestPredFirst +{ + ClauseSorterBestPredFirst(const ClauseAllocator& _cl_alloc, vector& _extra_data) : + cl_alloc(_cl_alloc), + extra_data(_extra_data) + {} + + const ClauseAllocator& cl_alloc; + const vector& extra_data; + + bool operator()(const ClOffset off1, const ClOffset off2) const + { + const Clause* cl1 = cl_alloc.ptr(off1); + const Clause* cl2 = cl_alloc.ptr(off2); + const auto& ext1 = extra_data[cl1->stats.extra_pos]; + const auto& ext2 = extra_data[cl2->stats.extra_pos]; + + if (cl1->size() != cl2->size()) { + return cl1->size() > cl2->size(); + } + //Correct order if c1's predicted use is larger + return ext1.pred_short_use > ext2.pred_short_use; + } +}; +#endif + +struct LitCountDescSort +{ + LitCountDescSort(const vector& _lit_counts) : + lit_counts(_lit_counts) + {} + + bool operator()(const Lit& lit1, const Lit& lit2) { + return lit_counts[lit1.toInt()] > lit_counts[lit2.toInt()]; + } + + + const vector& lit_counts; +}; + +DistillerLong::DistillerLong(Solver* _solver) : + solver(_solver) +{} + +bool DistillerLong::distill(const bool red, bool only_rem_cl) +{ + assert(solver->ok); + numCalls_red += (unsigned)red; + numCalls_irred += (unsigned)!red; + runStats.clear(); + *solver->frat << __PRETTY_FUNCTION__ << " start\n"; + + if (!red) { + if (!distill_long_cls_all( + solver->longIrredCls, + solver->conf.distill_irred_alsoremove_ratio, + true, //also remove + only_rem_cl, + red)) + { + goto end; + } + globalStats += runStats; + runStats.clear(); + + if (!only_rem_cl) { + if (!distill_long_cls_all( + solver->longIrredCls, + solver->conf.distill_irred_noremove_ratio, + false, //also remove + only_rem_cl, + red)) + { + goto end; + } + } + globalStats += runStats; + runStats.clear(); + } else { + //Redundant + if (!distill_long_cls_all( + solver->longRedCls[0], + solver->conf.distill_red_tier0_ratio, + false, //dont' remove (it's always redundant) + only_rem_cl, + red, + 0)) //red lev (only to print) + { + goto end; + } + globalStats += runStats; + runStats.clear(); + + if (!distill_long_cls_all( + solver->longRedCls[1], + solver->conf.distill_red_tier1_ratio, + false, //dont' remove (it's always redundant) + only_rem_cl, + red, + 1)) // //red lev (only to print) + { + goto end; + } + globalStats += runStats; + runStats.clear(); + } + +end: + lit_counts.clear(); + lit_counts.shrink_to_fit(); + *solver->frat << __PRETTY_FUNCTION__ << " end\n"; + + return solver->okay(); +} + +bool DistillerLong::distill_long_cls_all( + vector& offs + , double time_mult + , bool also_remove + , bool only_remove + , bool red + , uint32_t red_lev +) { + assert(solver->ok); + if (time_mult == 0.0) return solver->okay(); + verb_print(6, "c Doing distillation branch for long clauses"); + + double myTime = cpuTime(); + const size_t origTrailSize = solver->trail_size(); + + //Time-limiting + maxNumProps = + solver->conf.distill_long_cls_time_limitM*1000LL*1000ULL + *solver->conf.global_timeout_multiplier; + + if (solver->litStats.irredLits + solver->litStats.redLits < + (500ULL*1000ULL*solver->conf.var_and_mem_out_mult) + ) { + maxNumProps *=2; + } + maxNumProps *= time_mult; + orig_maxNumProps = maxNumProps; + + //stats setup + oldBogoProps = solver->propStats.bogoProps; + runStats.numCalled += 1; + + //Shuffle only when it's non-learnt run (i.e. also_remove) + if (//Don't shuffle when it's very-very large, too expensive + offs.size() < 100ULL*1000ULL*1000ULL) + { + if (solver->conf.distill_sort == 0) { + //Nothing + + } else if (solver->conf.distill_sort == 1) { + std::sort(offs.begin(), + offs.end(), + ClauseSizeSorterLargestFirst(solver->cl_alloc) + ); + } else if (solver->conf.distill_sort == 2) { + std::sort(offs.begin(), + offs.end(), + ClauseSorterSmallGlueFirst(solver->cl_alloc) + ); + } else if (solver->conf.distill_sort == 3) { + #ifdef FINAL_PREDICTOR + if (red) { + //This ensures fixed order. Otherwise, due to reducedb's ordering clauses around, it'd always be very hectic order, effectively random order + std::sort(offs.begin(), + offs.end(), + ClauseSorterFirstInSolver(solver->cl_alloc, solver->red_stats_extra) + ); + } + #else + cout << "ERROR: only distill sort 0, 1 and 2 are recognized" << endl; + exit(-1); + #endif + } else if (solver->conf.distill_sort == 4) { + bool randomly_sort = rnd_uint(solver->mtrand, solver->conf.distill_rand_shuffle_order_every_n) == 0; + if (randomly_sort) { + std::shuffle(offs.begin(), offs.end(), solver->mtrand); + } else { + std::sort(offs.begin(), + offs.end(), + ClauseSizeSorterLargestFirst(solver->cl_alloc) + ); + } + } + } + + //Prioritize + lit_counts.clear(); + lit_counts.resize(solver->nVars()*2, 0); + vector todo; + todo.reserve(offs.size()); + for(uint32_t prio = 0; prio < (red ? 1: 2); prio ++) { + uint32_t j = 0; + for(uint32_t i = 0; i < offs.size(); i ++) { + Clause* cl = solver->cl_alloc.ptr(offs[i]); + VERBOSE_PRINT("Clause at " << i << " is: " << *cl); + bool ok = false; + if (!cl->stats.is_ternary_resolvent + && !solver->satisfied(*cl) + ) { + if (also_remove) { + if (cl->tried_to_remove == prio) { + ok = true; + } + } else { + if (cl->distilled == prio) { + ok = true; + } + } + } + + if (ok) { + for(const auto& l: *cl) lit_counts[l.toInt()]++; + todo.push_back(offs[i]); + VERBOSE_PRINT("Adding this one to TODO"); + } else { + offs[j++] = offs[i]; + continue; + } + } + offs.resize(j); + } + const uint32_t orig_todo_size = todo.size(); + runStats.potentialClauses += orig_todo_size; + + assert(runStats.checkedClauses == 0); + bool time_out = go_through_clauses(todo, also_remove, only_remove); + + //Add back the prioritized clauses + for(const auto off: todo) offs.push_back(off); + + const double time_used = cpuTime() - myTime; + const double time_remain = float_div( + maxNumProps - ((int64_t)solver->propStats.bogoProps-(int64_t)oldBogoProps), + orig_maxNumProps); + if (solver->conf.verbosity >= 1) { + cout << "c [distill-long"; + if (red) { + cout << "-red" << red_lev << "]"; + } else { + cout << "-irred]"; + } + cout + << " cls" + << " tried: " << runStats.checkedClauses << "/" << orig_todo_size + << solver->conf.print_times(time_used, time_out, time_remain) + << endl; + } + if (solver->sqlStats) { + solver->sqlStats->time_passed( + solver + , "distill long cls" + , time_used + , time_out + , time_remain + ); + } + + //Update stats + runStats.time_used += time_used; + runStats.zeroDepthAssigns += solver->trail_size() - origTrailSize; + + return solver->okay(); +} + +bool DistillerLong::go_through_clauses( + vector& cls, + bool also_remove, bool only_remove + +) { + bool time_out = false; + vector::iterator i, j; + i = j = cls.begin(); + for (vector::iterator end = cls.end() + ; i != end + ; ++i + ) { + VERBOSE_PRINT("At offset: " << *i); + + //Check if we are in state where we only copy offsets around + if (time_out || !solver->ok) { + *j++ = *i; + continue; + } + + //Get pointer + ClOffset offset = *i; + Clause& cl = *solver->cl_alloc.ptr(offset); + + //if done enough, stop doing it + if ((int64_t)solver->propStats.bogoProps-(int64_t)oldBogoProps >= maxNumProps + || solver->must_interrupt_asap() + ) { + if (solver->conf.verbosity >= 3) { + cout + << "c Need to finish distillation -- ran out of prop (=allocated time)" + << endl; + } + runStats.timeOut++; + time_out = true; + } + + //check XOR + if (cl.used_in_xor() && + solver->conf.force_preserve_xors + ) { + *j++ = *i; + VERBOSE_PRINT("Skipping offset for XOR " << *i); + continue; + } + + //Time to dereference + maxNumProps -= 5; + + //If we already tried this clause, then move to next + if (cl._xor_is_detached || + + //If it's a redundant that's not very good, let's not distill it + ( + #ifdef FINAL_PREDICTOR + solver->conf.pred_distill_only_smallgue && + #else + false && + #endif + cl.red() && + cl.stats.glue > 3) //TODO I don't like this at all for FINAL_PREDICTOR !!!! + ) { + *j++ = *i; + VERBOSE_PRINT("Skipping offset " << *i); + continue; + } + if (also_remove) { + cl.tried_to_remove = 1; + } else { + cl.distilled = 1; + } + runStats.checkedClauses++; + assert(cl.size() > 2); + + //Try to distill clause + ClOffset offset2 = try_distill_clause_and_return_new( + offset, &cl.stats + , also_remove, only_remove + ); + + if (offset2 != CL_OFFSET_MAX) { + *j++ = offset2; + } + } + cls.resize(cls.size()- (i-j)); + + return time_out; +} + +ClOffset DistillerLong::try_distill_clause_and_return_new( + ClOffset offset, const ClauseStats* const stats, + const bool also_remove, const bool only_remove +) { + assert(solver->prop_at_head()); + assert(solver->decisionLevel() == 0); + bool True_confl = false; + PropBy confl; + + //Disable this clause + Clause& cl = *solver->cl_alloc.ptr(offset); + Lit cl_lit1 = cl[0]; + Lit cl_lit2 = cl[1]; + cl.disabled = true; + *solver->frat << deldelay << cl << fin; + const bool red = cl.red(); + if (red) assert(!also_remove); + VERBOSE_PRINT("Trying to distill clause:" << cl); + + uint32_t orig_size = cl.size(); + uint32_t i = 0; + uint32_t j = 0; + for (uint32_t sz = cl.size(); i < sz; i++) { + if (solver->value(cl[i]) == l_True) { + goto rem; + } + if (solver->value(cl[i]) == l_Undef) { + cl[j++] = cl[i]; + } + } + cl.resize(j); + assert(cl.size() > 1); //this must have already been propagated + + solver->new_decision_level(); + i = 0; + j = 0; + + + // Sort them differently once in a while, so all literals have a chance of + // being removed + if (solver->conf.distill_sort == 4 && + cl.size() < 500) //Don't sort them if they are too large, it can be really slow + { + //Sort them differently once in a while, so all literals have a chance of + //being removed + if (offset % 2 == 0) { + std::sort(cl.begin(), cl.end(), VSIDS_largest_first(solver->var_act_vsids)); + } else { + std::sort(cl.begin(), cl.end(), LitCountDescSort(lit_counts)); + } + } + + for (uint32_t sz = cl.size(); i < sz; i++) { + const Lit lit = cl[i]; + lbool val = solver->value(lit); + if (val == l_Undef) { + solver->enqueue(~lit); + cl[j++] = cl[i]; + + maxNumProps -= 5; + if (!red && also_remove) { + //ONLY propagate on irred + confl = solver->propagate(); + } else { + //Normal propagation, on all clauses + confl = solver->propagate(); + } + if (!confl.isNULL()) { + break; + } + } else if (val == l_False) { + // if we don't want to shorten, then don't remove literals + if (only_remove) cl[j++] = cl[i]; + } else { + assert(val == l_True); + cl[j++] = cl[i]; + True_confl = true; + confl = solver->varData[cl[i].var()].reason; + break; + } + } + assert(solver->ok); + cl.resize(j); + + //Actually, we can remove the clause! + VERBOSE_PRINT("also_remove: " << also_remove + << "red: " << red + << "True_confl: " << True_confl + << "confl.isNULL(): " << confl.isNULL()); + + + if (also_remove && !red && !True_confl && !confl.isNULL()) { + VERBOSE_PRINT("CL Removed."); + rem: + solver->cancelUntil(0); + solver->detach_modified_clause(cl_lit1, cl_lit2, orig_size, &cl); + (*solver->frat) << findelay; + solver->free_cl(offset); + runStats.clRemoved++; + return CL_OFFSET_MAX; + } + + //Couldn't simplify the clause + if (j == orig_size && !True_confl && confl.isNULL()) { + #ifdef VERBOSE_DEBUG + cout << "CL Cannot be simplified." << endl; + #endif + cl.disabled = false; + solver->cancelUntil(0); + std::swap(*std::find(cl.begin(), cl.end(), cl_lit1), cl[0]); + std::swap(*std::find(cl.begin(), cl.end(), cl_lit2), cl[1]); + solver->frat->forget_delay(); + return offset; + } + + #ifdef VERBOSE_DEBUG + if (j < i) { + cout + << "c Distillation branch effective." << endl + << "c --> shortened cl:" << cl<< endl + << "c --> orig size:" << orig_size << endl + << "c --> new size:" << j << endl; + } else { + cout + << "c Distillation branch NOT effective." << endl + << "c --> orig size:" << orig_size << endl; + } + #endif + + bool lits_set = false; + //TODO BNN removed this, but needs to be fixed. + /*if (red && j > 1 && (!confl.isNULL() || True_confl)) { + #ifdef VERBOSE_DEBUG + cout + << "c Distillation even more effective." << endl + << "c --> orig shortened cl:" << cl << endl; + #endif + maxNumProps -= 20; + lits.clear(); + if (True_confl) { + lits.push_back(cl[cl.size()-1]); + } + solver->simple_create_learnt_clause(confl, lits, True_confl); + if (lits.size() < cl.size()) { + #ifdef VERBOSE_DEBUG + cout + << "c --> more shortened cl:" << lits << endl; + #endif + lits_set = true; + } + }*/ + solver->cancelUntil(0); + solver->detach_modified_clause(cl_lit1, cl_lit2, orig_size, &cl); + runStats.numLitsRem += orig_size - cl.size(); + runStats.numClShorten++; + + //Make new clause + if (!lits_set) { + lits.resize(cl.size()); + std::copy(cl.begin(), cl.end(), lits.begin()); + } + + // we have to copy because the re-alloc can invalidate the data + ClauseStats backup_stats(*stats); + // new clause will inherit this clause's ID + // so let's set this to 0, this way, when we free() it, it won't be + // deleted as per cl_last_in_solver + solver->free_cl(offset, false); + Clause *cl2 = solver->add_clause_int(lits, red, &backup_stats); + *solver->frat << findelay; + + if (cl2 != NULL) { + //This new, distilled clause has been distilled now. + if (also_remove) { + cl2->tried_to_remove = 1; + } else { + cl2->distilled = 1; + } + return solver->cl_alloc.get_offset(cl2); + } else { + STATS_DO(solver->stats_del_cl(offset)); + //it became a bin/unit/zero + return CL_OFFSET_MAX; + } +} + +DistillerLong::Stats& DistillerLong::Stats::operator+=(const Stats& other) +{ + time_used += other.time_used; + timeOut += other.timeOut; + zeroDepthAssigns += other.zeroDepthAssigns; + numClShorten += other.numClShorten; + numLitsRem += other.numLitsRem; + checkedClauses += other.checkedClauses; + potentialClauses += other.potentialClauses; + numCalled += other.numCalled; + clRemoved += other.clRemoved; + + return *this; +} + +void DistillerLong::Stats::print(const size_t nVars) const +{ + cout << "c -------- DISTILL-LONG STATS --------" << endl; + print_stats_line("c time" + , time_used + , ratio_for_stat(time_used, numCalled) + , "per call" + ); + + print_stats_line("c timed out" + , timeOut + , stats_line_percent(timeOut, numCalled) + , "% of calls" + ); + + print_stats_line("c distill/checked/potential" + , numClShorten + , checkedClauses + , potentialClauses + ); + + print_stats_line("c lits-rem", + numLitsRem + ); + print_stats_line("c 0-depth-assigns", + zeroDepthAssigns + , stats_line_percent(zeroDepthAssigns, nVars) + , "% of vars" + ); + cout << "c -------- DISTILL STATS END --------" << endl; +} + +double DistillerLong::mem_used() const +{ + double mem_used = sizeof(DistillerLong); + mem_used += lits.size()*sizeof(Lit); + return mem_used; +} diff --git a/cryptominisat/cppsrc/src/distillerlong.h b/cryptominisat/cppsrc/src/distillerlong.h new file mode 100644 index 00000000..d6d6357c --- /dev/null +++ b/cryptominisat/cppsrc/src/distillerlong.h @@ -0,0 +1,106 @@ +/****************************************** +Copyright (C) 2009-2020 Authors of CryptoMiniSat, see AUTHORS file + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. +***********************************************/ + +#ifndef _DISTILLERLONG_H_ +#define _DISTILLERLONG_H_ + +#include +#include "clause.h" +#include "constants.h" +#include "solvertypes.h" +#include "cloffset.h" +#include "watcharray.h" + +namespace CMSat { + +using std::vector; + +class Solver; +class Clause; + +class DistillerLong { + public: + explicit DistillerLong(Solver* solver); + bool distill(const bool red, bool only_rem_cl = false); + + struct Stats + { + void clear() + { + Stats tmp; + *this = tmp; + } + + Stats& operator+=(const Stats& other); + void print(const size_t nVars) const; + + double time_used = 0.0; + uint64_t timeOut = 0; + uint64_t zeroDepthAssigns = 0; + uint64_t numClShorten = 0; + uint64_t numLitsRem = 0; + uint64_t checkedClauses = 0; + uint64_t potentialClauses = 0; + uint64_t numCalled = 0; + uint64_t clRemoved = 0; + }; + + const Stats& get_stats() const; + double mem_used() const; + + private: + ClOffset try_distill_clause_and_return_new( + ClOffset offset + , const ClauseStats* const stats + , const bool also_remove, const bool only_remove + ); + bool distill_long_cls_all( + vector& offs, double time_mult, + bool also_remove, + bool only_remove, + bool red, uint32_t red_lev = numeric_limits::max()); + bool go_through_clauses(vector& cls, const bool also_remove, const bool only_remove); + Solver* solver; + + //For distill + vector lit_counts; + vector lits; + uint64_t oldBogoProps; + int64_t maxNumProps; + int64_t orig_maxNumProps; + + //Global status + Stats runStats; + Stats globalStats; + size_t numCalls_red = 0; + size_t numCalls_irred = 0; + +}; + +inline const DistillerLong::Stats& DistillerLong::get_stats() const +{ + return globalStats; +} + +} //end namespace + +#endif //_DISTILLERLONG_H_ diff --git a/cryptominisat/cppsrc/src/distillerlongwithimpl.cpp b/cryptominisat/cppsrc/src/distillerlongwithimpl.cpp new file mode 100644 index 00000000..35e74a01 --- /dev/null +++ b/cryptominisat/cppsrc/src/distillerlongwithimpl.cpp @@ -0,0 +1,532 @@ +/****************************************** +Copyright (C) 2009-2020 Authors of CryptoMiniSat, see AUTHORS file + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. +***********************************************/ + +#include "distillerlongwithimpl.h" +#include "clausecleaner.h" +#include "time_mem.h" +#include "solver.h" +#include "watchalgos.h" +#include "clauseallocator.h" +#include "sqlstats.h" + +#include +#include +using namespace CMSat; +using std::cout; +using std::endl; + +#ifdef VERBOSE_DEBUG +#define VERBOSE_SUBSUME_NONEXIST +#endif + +//#define VERBOSE_SUBSUME_NONEXIST + +DistillerLongWithImpl::DistillerLongWithImpl(Solver* _solver) : + solver(_solver) + , seen(solver->seen) + , seen2(solver->seen2) + , numCalls(0) +{} + +bool DistillerLongWithImpl::distill_long_with_implicit(const bool alsoStrengthen) +{ + assert(solver->ok); + numCalls++; + if (!solver->clauseCleaner->remove_and_clean_all()) goto end; + *solver->frat << __PRETTY_FUNCTION__ << " start\n"; + + runStats.redWatchBased.clear(); + runStats.irredWatchBased.clear(); + + if (!sub_str_all_cl_with_watch(solver->longIrredCls, false, false)) + goto end; + + if (solver->longRedCls[0].size() > 0 + && !sub_str_all_cl_with_watch(solver->longRedCls[0], true, false) + ) { + goto end; + } + + if (alsoStrengthen) { + if (!sub_str_all_cl_with_watch(solver->longIrredCls, false, true)) + goto end; + + if (solver->longRedCls[0].size() > 0 + && !sub_str_all_cl_with_watch(solver->longRedCls[0], true, true) + ) { + goto end; + } + } + +end: + globalStats += runStats; + if (solver->conf.verbosity) { + if (solver->conf.verbosity >= 3) + runStats.print(); + else + runStats.print_short(solver); + } + runStats.clear(); + *solver->frat << __PRETTY_FUNCTION__ << " end\n"; + + return solver->okay(); +} + +void DistillerLongWithImpl::strengthen_clause_with_watch( + const Lit lit + , const Watched* wit +) { + //Strengthening w/ bin + if (wit->isBin() + && seen[lit.toInt()] //We haven't yet removed it + ) { + if (seen[(~wit->lit2()).toInt()]) { + thisremLitBin++; + seen[(~wit->lit2()).toInt()] = 0; + } + } +} + +bool DistillerLongWithImpl::subsume_clause_with_watch( + const Lit lit + , Watched* wit + , const Clause& cl +) { + //Subsumption w/ bin + if (wit->isBin() && + seen2[wit->lit2().toInt()] + ) { + //If subsuming irred with redundant, make the redundant into irred + if (wit->red() && !cl.red()) { + wit->setRed(false); + timeAvailable -= (long)solver->watches[wit->lit2()].size()*3; + findWatchedOfBin(solver->watches, wit->lit2(), lit, true, wit->get_ID()).setRed(false); + solver->binTri.redBins--; + solver->binTri.irredBins++; + } + watch_based_data.subBin++; + isSubsumed = true; + return true; + } + + //Extension w/ bin + if (wit->isBin() + && !wit->red() + && !seen2[(~(wit->lit2())).toInt()] + ) { + seen2[(~(wit->lit2())).toInt()] = 1; + lits2.push_back(~(wit->lit2())); + } + + return false; +} + +void DistillerLongWithImpl::str_and_sub_using_watch( + Clause& cl + , const Lit lit + , const bool alsoStrengthen +) { + //Go through the watchlist + watch_subarray thisW = solver->watches[lit]; + timeAvailable -= (long)thisW.size()*2 + 5; + for(Watched* wit = thisW.begin(), *wend = thisW.end() + ; wit != wend + ; wit++ + ) { + //Can't do anything with a clause + if (!wit->isBin()) + continue; + + timeAvailable -= 5; + + if (alsoStrengthen) { + strengthen_clause_with_watch(lit, wit); + } + + const bool subsumed = subsume_clause_with_watch(lit, wit, cl); + if (subsumed) + return; + } +} + +void DistillerLongWithImpl::strsub_with_watch( + bool alsoStrengthen + , Clause& cl +) { + //Go through each literal and subsume/strengthen with it + Lit *lit2 = cl.begin(); + lit2++; + for (const Lit + *lit = cl.begin(), *end = cl.end() + ; lit != end && !isSubsumed + ; lit++, lit2++ + ) { + if (lit2 < end) { + solver->watches.prefetch(lit2->toInt()); + } + str_and_sub_using_watch(cl, *lit, alsoStrengthen); + } + assert(lits2.size() > 1); +} + +bool DistillerLongWithImpl::sub_str_cl_with_watch( + ClOffset& offset + , const bool alsoStrengthen +) { + Clause& cl = *solver->cl_alloc.ptr(offset); + assert(cl.size() > 2); + + if (solver->conf.verbosity >= 10) { + cout << "Examining str clause:" << cl << endl; + } + + timeAvailable -= (long)cl.size()*2; + tmpStats.totalLits += cl.size(); + tmpStats.triedCls++; + isSubsumed = false; + thisremLitBin = 0; + + //Fill 'seen' + lits2.clear(); + for (const Lit lit: cl) { + seen[lit.toInt()] = 1; + seen2[lit.toInt()] = 1; + lits2.push_back(lit); + } + + strsub_with_watch(alsoStrengthen, cl); + + //Clear 'seen2' + timeAvailable -= (long)lits2.size()*3; + for (const Lit lit: lits2) { + seen2[lit.toInt()] = 0; + } + + //Clear 'seen' and fill new clause data + lits.clear(); + timeAvailable -= (long)cl.size()*3; + for (const Lit lit: cl) { + if (!isSubsumed + && seen[lit.toInt()] + ) { + lits.push_back(lit); + } + seen[lit.toInt()] = 0; + } + + if (isSubsumed) + return true; + + //Nothing to do + if (lits.size() == cl.size()) { + return false; + } + + return remove_or_shrink_clause(cl, offset); +} + +//returns FALSE in case clause is shortened, and TRUE in case it is removed +bool DistillerLongWithImpl::remove_or_shrink_clause(Clause& cl, ClOffset& offset) +{ + //Remove or shrink clause + timeAvailable -= (long)cl.size()*10; + watch_based_data.remLitBin += thisremLitBin; + tmpStats.shrinked++; + timeAvailable -= (long)lits.size()*2 + 50; + ClauseStats backup_stats(cl.stats); + Clause* c2 = solver->add_clause_int(lits, cl.red(), &backup_stats); + if (c2 != NULL) { + solver->detachClause(offset); + // new clause will inherit this clause's ID + // so let's set this to 0, this way, when we free() it, it won't be + // deleted as per cl_last_in_solver + solver->free_cl(offset, false); + offset = solver->cl_alloc.get_offset(c2); + return false; + } + + //Implicit clause or non-existent after addition, remove + return true; +} + +void DistillerLongWithImpl::randomise_order_of_clauses(vector& clauses) { + timeAvailable -= (long)clauses.size()*2; + std::shuffle(clauses.begin(), clauses.end(), solver->mtrand); +} + +uint64_t DistillerLongWithImpl::calc_time_available( + const bool alsoStrengthen + , const bool red +) const { + //If it hasn't been to successful until now, don't do it so much + const Stats::WatchBased* stats = NULL; + if (red) { + stats = &(globalStats.redWatchBased); + } else { + stats = &(globalStats.irredWatchBased); + } + + uint64_t maxCountTime = + solver->conf.watch_based_str_time_limitM*1000LL*1000LL + *solver->conf.global_timeout_multiplier; + if (!alsoStrengthen) { + maxCountTime *= 2; + } + if (stats->numCalled > 2 + && stats->triedCls > 0 //avoid division by zero + && stats->totalLits > 0 //avoid division by zero + && float_div(stats->numClSubsumed, stats->triedCls) < 0.05 + && float_div(stats->numLitsRem, stats->totalLits) < 0.05 + ) { + maxCountTime *= 0.5; + } + + return maxCountTime; +} + +bool DistillerLongWithImpl::sub_str_all_cl_with_watch( + vector& clauses + , bool red + , bool alsoStrengthen +) { + assert(solver->ok); + + //Stats + double myTime = cpuTime(); + + const int64_t orig_time_available = calc_time_available(alsoStrengthen, red); + timeAvailable = orig_time_available; + tmpStats = Stats::WatchBased(); + tmpStats.totalCls = clauses.size(); + tmpStats.numCalled = 1; + watch_based_data.clear(); + bool need_to_finish = false; + + //don't randomise if it's too large. + if (clauses.size() < 100*10000*1000) { + randomise_order_of_clauses(clauses); + } + + size_t i = 0; + size_t j = i; + ClOffset offset; + Clause* cl; + const size_t end = clauses.size(); + for ( + ; i < end + ; i++ + ) { + //Timeout? + if (timeAvailable <= 0 + || !solver->okay() + ) { + need_to_finish = true; + tmpStats.ranOutOfTime++; + } + + //Check status + offset = clauses[i]; + if (need_to_finish) { + goto copy; + } + + cl = solver->cl_alloc.ptr(offset); + if (cl->used_in_xor() && + solver->conf.force_preserve_xors) + { + goto copy; + } + + if (sub_str_cl_with_watch(offset, alsoStrengthen)) { + solver->detachClause(offset); + solver->free_cl(offset); + continue; + } + + copy: + clauses[j++] = offset; + } + clauses.resize(clauses.size() - (i-j)); + #ifdef DEBUG_IMPLICIT_STATS + solver->check_implicit_stats(); + #endif + + dump_stats_for_sub_str_all_cl_with_watch(red + , alsoStrengthen + , myTime + , orig_time_available + ); + + return solver->okay(); +} + +void DistillerLongWithImpl::dump_stats_for_sub_str_all_cl_with_watch( + bool red + , bool alsoStrengthen + , double myTime + , double orig_time_available +) { + //Set stats + const double time_used = cpuTime() - myTime; + const bool time_out = timeAvailable < 0; + const double time_remain = float_div(timeAvailable, orig_time_available); + tmpStats.numClSubsumed += watch_based_data.get_cl_subsumed(); + tmpStats.numLitsRem += watch_based_data.get_lits_rem(); + tmpStats.cpu_time = time_used; + if (red) { + runStats.redWatchBased += tmpStats; + } else { + runStats.irredWatchBased += tmpStats; + } + if (solver->conf.verbosity >= 2) { + if (solver->conf.verbosity >= 10) { + cout << "red:" << red << " alsostrenghten:" << alsoStrengthen << endl; + } + watch_based_data.print(); + + cout << "c [distill-with-bin-ext]" + << solver->conf.print_times(time_used, time_out, time_remain) + << endl; + } + if (solver->sqlStats) { + std::stringstream ss; + ss << "shorten" + << (alsoStrengthen ? " and str" : "") + << (red ? " red" : " irred") + << " cls" + ; + solver->sqlStats->time_passed( + solver + , ss.str() + , time_used + , time_out + , time_remain + ); + } +} + +void DistillerLongWithImpl::WatchBasedData::clear() +{ + WatchBasedData tmp; + *this = tmp; +} + +size_t DistillerLongWithImpl::WatchBasedData::get_cl_subsumed() const +{ + return subBin; +} + +size_t DistillerLongWithImpl::WatchBasedData::get_lits_rem() const +{ + return remLitBin; +} + +void DistillerLongWithImpl::WatchBasedData::print() const +{ + cout + << "c [distill-with-bin-ext] bin-based" + << " lit-rem: " << remLitBin + << " cl-sub: " << subBin + << endl; +} + +DistillerLongWithImpl::Stats& DistillerLongWithImpl::Stats::operator+=(const Stats& other) +{ + irredWatchBased += other.irredWatchBased; + redWatchBased += other.redWatchBased; + return *this; +} + +void DistillerLongWithImpl::Stats::print_short(const Solver* _solver) const +{ + irredWatchBased.print_short("irred", _solver); + redWatchBased.print_short("red", _solver); +} + +void DistillerLongWithImpl::Stats::print() const +{ + cout << "c -------- STRENGTHEN STATS --------" << endl; + cout << "c --> watch-based on irred cls" << endl; + irredWatchBased.print(); + + cout << "c --> watch-based on red cls" << endl; + redWatchBased.print(); + cout << "c -------- STRENGTHEN STATS END --------" << endl; +} + + +void DistillerLongWithImpl::Stats::WatchBased::print_short( + const string& type, const Solver* _solver) const +{ + cout << "c [distill] watch-based " + << std::setw(5) << type + << "-- " + << " cl tried " << std::setw(8) << triedCls + << " cl-sh " << std::setw(5) << shrinked + << " cl-rem " << std::setw(4) << numClSubsumed + << " lit-rem " << std::setw(6) << numLitsRem + << _solver->conf.print_times(cpu_time, ranOutOfTime) + << endl; +} + +void DistillerLongWithImpl::Stats::WatchBased::print() const +{ + print_stats_line("c time" + , cpu_time + , ratio_for_stat(cpu_time, numCalled) + , "s/call" + ); + + print_stats_line("c shrinked/tried/total" + , shrinked + , triedCls + , totalCls + ); + + print_stats_line("c subsumed/tried/total" + , numClSubsumed + , triedCls + , totalCls + ); + + print_stats_line("c lits-rem" + , numLitsRem + , stats_line_percent(numLitsRem, totalLits) + , "% of lits tried" + ); + + print_stats_line("c called " + , numCalled + , stats_line_percent(ranOutOfTime, numCalled) + , "% ran out of time" + ); + +} + +double DistillerLongWithImpl::mem_used() const +{ + double mem = sizeof(DistillerLongWithImpl); + mem+= lits.size()*sizeof(Lit); + mem +=lits2.size()*sizeof(Lit); + + return mem; +} diff --git a/cryptominisat/cppsrc/src/distillerlongwithimpl.h b/cryptominisat/cppsrc/src/distillerlongwithimpl.h new file mode 100644 index 00000000..8acf2898 --- /dev/null +++ b/cryptominisat/cppsrc/src/distillerlongwithimpl.h @@ -0,0 +1,181 @@ +/****************************************** +Copyright (C) 2009-2020 Authors of CryptoMiniSat, see AUTHORS file + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. +***********************************************/ + +#ifndef __DISTILLERWITHBIN_H__ +#define __DISTILLERWITHBIN_H__ + +#include +#include "clause.h" +#include "constants.h" +#include "solvertypes.h" +#include "cloffset.h" +#include "watcharray.h" + +namespace CMSat { + +using std::vector; + +class Solver; +class Clause; + +class DistillerLongWithImpl { + public: + DistillerLongWithImpl(Solver* solver); + bool distill_long_with_implicit(bool alsoStrengthen); + + struct Stats + { + void clear() + { + Stats tmp; + *this = tmp; + } + + Stats& operator+=(const Stats& other); + void print_short(const Solver* solver) const; + void print() const; + + struct WatchBased + { + double cpu_time = 0.0; + uint64_t numLitsRem = 0; + uint64_t numClSubsumed = 0; + uint64_t triedCls = 0; + uint64_t shrinked = 0; + uint64_t totalCls = 0; + uint64_t totalLits = 0; + uint64_t ranOutOfTime = 0; + uint64_t numCalled = 0; + + void clear() + { + WatchBased tmp; + *this = tmp; + } + + void print_short(const string& type, const Solver* solver) const; + void print() const; + + WatchBased& operator+=(const WatchBased& other) + { + cpu_time += other.cpu_time; + numLitsRem += other.numLitsRem; + numClSubsumed += other.numClSubsumed; + triedCls += other.triedCls; + shrinked += other.shrinked; + totalCls += other.totalCls; + totalLits += other.totalLits; + ranOutOfTime += other.ranOutOfTime; + numCalled += other.numCalled; + + return *this; + } + }; + + WatchBased irredWatchBased; + WatchBased redWatchBased; + }; + + const Stats& get_stats() const; + double mem_used() const; + + private: + + bool remove_or_shrink_clause(Clause& cl, ClOffset& offset); + void strsub_with_watch( + bool alsoStrengthen + , Clause& cl + ); + void dump_stats_for_sub_str_all_cl_with_watch( + bool red + , bool alsoStrengthen + , double myTime + , double orig_time_available + ); + + struct WatchBasedData + { + size_t remLitBin = 0; + size_t subBin = 0; + void clear(); + size_t get_cl_subsumed() const; + size_t get_lits_rem() const; + void print() const; + }; + WatchBasedData watch_based_data; + bool isSubsumed; + size_t thisremLitBin; + void str_and_sub_using_watch( + Clause& cl + , const Lit lit + , const bool alsoStrengthen + ); + void strengthen_clause_with_watch( + const Lit lit + , const Watched* wit + ); + bool subsume_clause_with_watch( + const Lit lit + , Watched* wit + , const Clause& cl + ); + Stats::WatchBased tmpStats; + //bool needToFinish; + bool sub_str_cl_with_watch( + ClOffset& offset + , const bool alsoStrengthen + ); + void randomise_order_of_clauses(vector& clauses); + uint64_t calc_time_available( + const bool alsoStrengthen + , const bool red + ) const; + + bool sub_str_all_cl_with_watch( + vector& clauses + , bool red + , bool alsoStrengthen + ); + int64_t timeAvailable; + + //Working set + Solver* solver; + vector lits; + vector lits2; + vector& seen; + vector& seen2; + + //Global status + Stats runStats; + Stats globalStats; + size_t numCalls = 0; + +}; + +inline const DistillerLongWithImpl::Stats& DistillerLongWithImpl::get_stats() const +{ + return globalStats; +} + +} //end namespace + +#endif //__DISTILLERWITHBIN_H__ diff --git a/cryptominisat/cppsrc/src/frat.cpp b/cryptominisat/cppsrc/src/frat.cpp new file mode 100644 index 00000000..fb5bb3aa --- /dev/null +++ b/cryptominisat/cppsrc/src/frat.cpp @@ -0,0 +1,25 @@ +/****************************************** +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. +***********************************************/ + +#include "frat.h" + +namespace CMSat { + void Drat::flush() {} +} diff --git a/cryptominisat/cppsrc/src/frat.h b/cryptominisat/cppsrc/src/frat.h new file mode 100644 index 00000000..ac75b46b --- /dev/null +++ b/cryptominisat/cppsrc/src/frat.h @@ -0,0 +1,491 @@ +/****************************************** +Copyright (C) 2009-2020 Authors of CryptoMiniSat, see AUTHORS file + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. +***********************************************/ + +#ifndef __FRAT_H__ +#define __FRAT_H__ + +#include "constants.h" +#include "clause.h" +#include "sqlstats.h" + +#include +#include +#include + +using std::vector; +// #define DEBUG_FRAT + +#if 0 +#define FRAT_PRINT((...) \ + do { \ + const uint32_t tmp_num = sprintf((char*)buf_ptr, __VA_ARGS__); \ + buf_ptr+=tmp_num; \ + buf_len+=tmp_num; \ + } while (0) +#else +#define FRAT_PRINT(...) do {} while (0) +#endif + + +namespace CMSat { + +enum DratFlag{fin, deldelay, del, findelay, add, origcl, chain, finalcl, reloc}; + +class Drat +{ +public: + Drat() + { + } + + virtual ~Drat() + { + } + + virtual bool enabled() + { + return false; + } + + virtual void set_sumconflicts_ptr(uint64_t*) + { + } + + virtual void set_sqlstats_ptr(SQLStats*) + { + } + + virtual void forget_delay() + { + } + + virtual bool get_conf_id() { + return false; + } + + virtual bool something_delayed() + { + return false; + } + + virtual Drat& operator<<(const int32_t) + { + return *this; + } + + virtual Drat& operator<<(const Lit) + { + return *this; + } + + virtual Drat& operator<<(const Clause&) + { + return *this; + } + + virtual Drat& operator<<(const vector&) + { + return *this; + } + + virtual Drat& operator<<(const char*) + { + return *this; + } + + virtual Drat& operator<<(const DratFlag) + { + return *this; + } + + virtual void setFile(FILE*) + { + } + + virtual FILE* getFile() + { + return NULL; + } + + virtual void flush(); + + int buf_len; + unsigned char* drup_buf = NULL; + unsigned char* buf_ptr = NULL; +}; + +template +class DratFile: public Drat +{ +public: + DratFile(vector& _interToOuterMain) : + interToOuterMain(_interToOuterMain) + { + drup_buf = new unsigned char[2 * 1024 * 1024]; + buf_ptr = drup_buf; + buf_len = 0; + memset(drup_buf, 0, 2 * 1024 * 1024); + + del_buf = new unsigned char[2 * 1024 * 1024]; + del_ptr = del_buf; + del_len = 0; + } + + virtual ~DratFile() + { + flush(); + delete[] drup_buf; + delete[] del_buf; + } + + virtual void set_sumconflicts_ptr(uint64_t* _sumConflicts) override + { + sumConflicts = _sumConflicts; + } + + virtual void set_sqlstats_ptr(SQLStats* _sqlStats) override + { + sqlStats = _sqlStats; + } + + virtual Drat& operator<<(const int32_t clauseID) override + { + if (must_delete_next) { + byteDRUPdID(clauseID); + } else { + byteDRUPaID(clauseID); + } + return *this; + } + + virtual FILE* getFile() override + { + return drup_file; + } + + void flush() override + { + binDRUP_flush(); + } + + void binDRUP_flush() { + fwrite(drup_buf, sizeof(unsigned char), buf_len, drup_file); + buf_ptr = drup_buf; + buf_len = 0; + } + + void setFile(FILE* _file) override + { + drup_file = _file; + } + + bool something_delayed() override + { + return delete_filled; + } + + void forget_delay() override + { + del_ptr = del_buf; + del_len = 0; + must_delete_next = false; + delete_filled = false; + } + + bool enabled() override + { + return true; + } + + int del_len = 0; + unsigned char* del_buf; + unsigned char* del_ptr; + + bool delete_filled = false; + bool must_delete_next = false; + + Drat& operator<<(const Clause& cl) override + { + if (must_delete_next) { + byteDRUPdID(cl.stats.ID); + for(const Lit l: cl) byteDRUPd(l); + } else { + byteDRUPaID(cl.stats.ID); + for(const Lit l: cl) byteDRUPa(l); + } + + return *this; + } + + Drat& operator<<(const vector& cl) override + { + if (must_delete_next) { + for(const Lit l: cl) { + byteDRUPd(l); + } + } else { + for(const Lit l: cl) { + byteDRUPa(l); + } + } + + return *this; + } + + Drat& operator<<(const DratFlag flag) override + { + switch (flag) + { + case DratFlag::fin: + if (must_delete_next) { + if (binfrat) { + *del_ptr++ = 0; + del_len++; + } else { + *del_ptr++ = '0'; + *del_ptr++ = '\n'; + del_len+=2; + } + delete_filled = true; + } else { + if (binfrat) { + *buf_ptr++ = 0; + buf_len++; + } else { + *buf_ptr++ = '0'; + *buf_ptr++ = '\n'; + buf_len+=2; + } + if (buf_len > 1048576) { + binDRUP_flush(); + } + if (adding && sqlStats) sqlStats->set_id_confl(cl_id, *sumConflicts); + FRAT_PRINT("c set_id_confl (%d, %lld), adding: %d\n", cl_id, *sumConflicts, adding); + } + cl_id = 0; + must_delete_next = false; + break; + + case DratFlag::deldelay: + adding = false; + assert(!delete_filled); + forget_delay(); + *del_ptr++ = 'd'; + del_len++; + if (!binfrat) { + *del_ptr++ = ' '; + del_len++; + } + delete_filled = false; + must_delete_next = true; + break; + + case DratFlag::findelay: + assert(delete_filled); + memcpy(buf_ptr, del_buf, del_len); + buf_len += del_len; + buf_ptr += del_len; + if (buf_len > 1048576) { + binDRUP_flush(); + } + + forget_delay(); + break; + + case DratFlag::add: + adding = true; + cl_id = 0; + *buf_ptr++ = 'a'; + buf_len++; + if (!binfrat) { + *buf_ptr++ = ' '; + buf_len++; + } + break; + + case DratFlag::chain: + if (!binfrat) { + *buf_ptr++ = '0'; + *buf_ptr++ = ' '; + *buf_ptr++ = 'l'; + *buf_ptr++ = ' '; + buf_len+=4; + } + break; + + case DratFlag::del: + adding = false; + *buf_ptr++ = 'd'; + buf_len++; + if (!binfrat) { + *buf_ptr++ = ' '; + buf_len++; + } + break; + + case DratFlag::reloc: + adding = false; + forget_delay(); + *buf_ptr++ = 'r'; + buf_len++; + if (!binfrat) { + *buf_ptr++ = ' '; + buf_len++; + } + break; + + case DratFlag::finalcl: + adding = false; + forget_delay(); + *buf_ptr++ = 'f'; + buf_len++; + if (!binfrat) { + *buf_ptr++ = ' '; + buf_len++; + } + break; + + case DratFlag::origcl: + adding = false; + forget_delay(); + *buf_ptr++ = 'o'; + buf_len++; + if (!binfrat) { + *buf_ptr++ = ' '; + buf_len++; + } + + break; + + } + + return *this; + } + +private: + Drat& operator<<(const Lit lit) override + { + if (must_delete_next) { + byteDRUPd(lit); + } else { + byteDRUPa(lit); + } + + return *this; + } + + void byteDRUPa(const Lit l) + { + uint32_t v = l.var(); + v = interToOuterMain[v]; + if (binfrat) { + unsigned int u = 2 * (v + 1) + l.sign(); + do { + *buf_ptr++ = (u & 0x7f) | 0x80; + buf_len++; + u = u >> 7; + } while (u); + // End marker of this unsigned number + *(buf_ptr - 1) &= 0x7f; + } else { + uint32_t num = sprintf( + (char*)buf_ptr, "%s%d ", (l.sign() ? "-": ""), l.var()+1); + buf_ptr+=num; + buf_len+=num; + } + } + + virtual Drat& operator<<([[maybe_unused]] const char* str) override + { + #ifdef DEBUG_FRAT + this->flush(); + uint32_t num = sprintf((char*)buf_ptr, "c %s", str); + buf_ptr+=num; + buf_len+=num; + this->flush(); + #endif + + return *this; + } + + void byteDRUPaID(const int32_t id) + { + if (adding && cl_id == 0) cl_id = id; + if (binfrat) { + for(unsigned i = 0; i < 6; i++) { + *buf_ptr++ = (id>>(8*i))&0xff; + buf_len++; + } + } else { + uint32_t num = sprintf((char*)buf_ptr, "%d ", id); + buf_ptr+=num; + buf_len+=num; + } + } + + void byteDRUPdID(const int32_t id) + { + if (binfrat) { + for(unsigned i = 0; i < 6; i++) { + *del_ptr++ = (id>>(8*i))&0xff; + del_len++; + } + } else { + uint32_t num = sprintf((char*)del_ptr, "%d ", id); + del_ptr+=num; + del_len+=num; + } + } + + void byteDRUPd(Lit l) + { + uint32_t v = l.var(); + v = interToOuterMain[v]; + if (binfrat) { + unsigned int u = 2 * (v + 1) + l.sign(); + do { + *del_ptr++ = (u & 0x7f) | 0x80; + del_len++; + u = u >> 7; + } while (u); + + // End marker of this unsigned number + *(del_ptr - 1) &= 0x7f; + } else { + uint32_t num = sprintf( + (char*)del_ptr, "%s%d ", (l.sign() ? "-": ""), l.var()+1); + del_ptr+=num; + del_len+=num; + } + } + + bool adding = false; + int32_t cl_id = 0; + FILE* drup_file = nullptr; + vector& interToOuterMain; + uint64_t* sumConflicts = nullptr; + SQLStats* sqlStats = NULL; +}; + +} + +#endif //__FRAT_H__ diff --git a/cryptominisat/cppsrc/src/fuzz.cpp b/cryptominisat/cppsrc/src/fuzz.cpp new file mode 100644 index 00000000..0d448f3c --- /dev/null +++ b/cryptominisat/cppsrc/src/fuzz.cpp @@ -0,0 +1,71 @@ +/************************************************************* +Copyright (C) 2009-2020 Authors of CryptoMiniSat, see AUTHORS file + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. +***************************************************************/ + +#include +#include "cryptominisat.h" +#include "dimacsparser.h" + +struct MyText { + const unsigned char* txt = 0; + size_t size = 0; + size_t at = 0; +}; + +typedef size_t(*fread_op_text)(void*, size_t, size_t, MyText&); + +using namespace CMSat; + +static size_t text_read(void* buf, size_t num, size_t count, MyText& f) +{ + if (f.size == f.at) { + return EOF; + } + + size_t toread = num*count; + if (toread > f.size-f.at) { + toread = f.size-f.at; + } + memcpy(buf, f.txt + f.at, toread); + //cout << "read in" << toread << endl; + f.at += toread; + + return toread; +} + +extern "C" int LLVMFuzzerTestOneInput(const unsigned char *data, size_t size) { + SATSolver S; + S.set_verbosity(0); + //solver->set_num_threads(num_threads); + + DimacsParser > parser(&S, "", 0); + parser.max_var = 1000; + MyText t; + t.at = 0; + t.size = size; + t.txt = data; + if (!parser.parse_DIMACS(t)) { + return 0; + } + S.solve(); + //cout << "Ret is sat: " << (ret == l_True) << endl; + return 0; +} diff --git a/cryptominisat/cppsrc/src/gatefinder.cpp b/cryptominisat/cppsrc/src/gatefinder.cpp new file mode 100644 index 00000000..b462db62 --- /dev/null +++ b/cryptominisat/cppsrc/src/gatefinder.cpp @@ -0,0 +1,374 @@ +/****************************************** +Copyright (C) 2009-2020 Authors of CryptoMiniSat, see AUTHORS file + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. +***********************************************/ + +#include "gatefinder.h" +#include "time_mem.h" +#include "solver.h" +#include "occsimplifier.h" +#include "subsumestrengthen.h" +#include "clauseallocator.h" +#include +#include +#include "sqlstats.h" + +using namespace CMSat; +using std::cout; +using std::endl; + +GateFinder::GateFinder(OccSimplifier *_simplifier, Solver *_solver) : + numDotPrinted(0) + , simplifier(_simplifier) + , solver(_solver) + , seen(_solver->seen) + , seen2(_solver->seen2) + , toClear(solver->toClear) +{ +// sizeSortedOcc.resize(solver->conf.maxGateBasedClReduceSize+1); +} + +void GateFinder::cleanup() +{ + solver->clean_occur_from_idx_types_only_smudged(); + orGates.clear(); +} + +void GateFinder::find_all() +{ + runStats.clear(); + orGates.clear(); + + assert(solver->watches.get_smudged_list().empty()); + find_or_gates_and_update_stats(); + if (solver->conf.doPrintGateDot) print_graphviz_dot(); + VERBOSE_DEBUG_DO(for(auto g: orGates) cout << "found: OR gate" << g << endl;); + + if (solver->conf.verbosity >= 3) runStats.print(solver->nVars()); + globalStats += runStats; + solver->sumSearchStats.num_gates_found_last = orGates.size(); +} + +void GateFinder::find_or_gates_and_update_stats() +{ + assert(solver->ok); + + double myTime = cpuTime(); + const int64_t orig_numMaxGateFinder = + solver->conf.gatefinder_time_limitM*100LL*1000LL + *solver->conf.global_timeout_multiplier; + numMaxGateFinder = orig_numMaxGateFinder; + simplifier->limit_to_decrease = &numMaxGateFinder; + + find_or_gates(); + runStats.gatesSize += 2*orGates.size(); + runStats.num+=orGates.size(); + + const double time_used = cpuTime() - myTime; + const bool time_out = (numMaxGateFinder <= 0); + const double time_remain = float_div(numMaxGateFinder, orig_numMaxGateFinder); + runStats.findGateTime = time_used; + runStats.find_gate_timeout = time_out; + if (solver->sqlStats) { + solver->sqlStats->time_passed( + solver + , "gate find" + , time_used + , time_out + , time_remain + ); + } + + verb_print(1, "[occ-gates]" + << " found: " << print_value_kilo_mega(runStats.num) + << " avg-s: " << std::fixed << std::setprecision(1) + << float_div(runStats.gatesSize, runStats.num) + /*<< " avg-s: " << std::fixed << std::setprecision(1) + << float_div(learntGatesSize, numRed)*/ + << solver->conf.print_times(time_used, time_out, time_remain)); +} + +struct IncidenceSorter +{ + IncidenceSorter(const vector& _inc) : + inc(_inc) + {} + + bool operator()(const uint32_t a, const uint32_t b) { + return inc[a] < inc[b]; + } + + const vector& inc; +}; + +void GateFinder::find_or_gates() +{ + if (solver->nVars() < 1) + return; + + const size_t offs = rnd_uint(solver->mtrand, solver->nVars()*2-1); + for(size_t i = 0 + ; i < solver->nVars()*2 + && *simplifier->limit_to_decrease > 0 + && !solver->must_interrupt_asap() + ; i++ + ) { + const size_t at = (offs + i) % (solver->nVars()*2); + const Lit lit = Lit::toLit(at); + find_or_gates_in_sweep_mode(lit); + find_or_gates_in_sweep_mode(~lit); + } +} + +void GateFinder::find_or_gates_in_sweep_mode(const Lit lit) +{ + assert(toClear.empty()); + + //From the clauses + //a V -b + //a V -c + //mark b and c with seen[b]=1 and seen[c]=1 + watch_subarray_const ws = solver->watches[lit]; + *simplifier->limit_to_decrease -= ws.size(); + for(const Watched w: ws) { + if (w.isBin() && !w.red()) { + seen[(~w.lit2()).toInt()] = 1; + toClear.push_back(~w.lit2()); + } + } + //avoid loops + seen[(~lit).toInt()] = 0; + + //Now look for + //b V c V -a + //so look through watches[-a] and check for 3-long clauses + watch_subarray_const ws2 = solver->watches[~lit]; + *simplifier->limit_to_decrease -= ws2.size(); + for(const Watched w: ws2) { + //Looking for tri or longer + if (!w.isClause()) continue; + ClOffset offset = w.get_offset(); + const Clause& cl = *solver->cl_alloc.ptr(offset); + if (cl.red() || cl.getRemoved() || cl.size() > 5) continue; + tmp_lhs.clear(); + + bool ok = true; + for(auto const& l: cl) { + if (l != ~lit && !seen[l.toInt()]) { + ok = false; + break; + } + if (l != ~lit) tmp_lhs.push_back(l); + } + if (!ok) continue; + SLOW_DEBUG_DO(assert(std::is_sorted(tmp_lhs.begin(), tmp_lhs.end()))); + add_gate_if_not_already_inside(lit, tmp_lhs, cl.stats.ID); + } + + *simplifier->limit_to_decrease -= toClear.size(); + for(const Lit toclear: toClear) seen[toclear.toInt()] = 0; + toClear.clear(); +} + + +void GateFinder::add_gate_if_not_already_inside( + const Lit rhs , const vector& lhs, const int32_t ID) +{ + OrGate gate(rhs, lhs, ID); + for (Watched ws: solver->watches[gate.rhs]) { + if (ws.isIdx() + && orGates[ws.get_idx()] == gate + ) { + return; + } + } + link_in_gate(gate); +} + +void GateFinder::link_in_gate(const OrGate& gate) +{ + const size_t at = orGates.size(); + orGates.push_back(gate); + solver->watches[gate.rhs].push(Watched(at, WatchType::watch_idx_t)); + solver->watches.smudge(gate.rhs); +} + +////////////////////////// PRINTING ////////////////////////////// + +void GateFinder::print_graphviz_dot() +{ + std::stringstream ss; + ss << "Gates" << (numDotPrinted++) << ".dot"; + std::string filenename = ss.str(); + std::ofstream file(filenename.c_str(), std::ios::out); + file << "digraph G {" << endl; + vector gateUsed; + gateUsed.resize(orGates.size(), false); + size_t index = 0; + for (const OrGate& orGate: orGates) { + index++; + for (const Lit lit: orGate.get_lhs()) { + for (Watched ws: solver->watches[lit]) { + if (!ws.isIdx()) { + continue; + } + uint32_t at = ws.get_idx(); + + //The same one, skip + if (at == index) + continue; + + file << "Gate" << at; + gateUsed[at] = true; + file << " -> "; + + file << "Gate" << index; + gateUsed[index] = true; + + file << "[arrowsize=\"0.4\"];" << endl; + } + + /*vector& occ2 = gateOccEq[(~*it2).toInt()]; + for (vector::const_iterator it3 = occ2.begin(), end3 = occ2.end(); it3 != end3; it3++) { + if (*it3 == index) continue; + + file << "Gate" << *it3; + gateUsed[*it3] = true; + file << " -> "; + + file << "Gate" << index; + gateUsed[index] = true; + + file << "[style = \"dotted\", arrowsize=\"0.4\"];" << endl; + }*/ + } + } + + for (index = 0; index < orGates.size(); index++) { + if (gateUsed[index]) { + file << "Gate" << index << " [ shape=\"point\""; + file << ", size = 0.8"; + file << ", style=\"filled\""; + file << ", color=\"darkseagreen\""; + file << "];" << endl; + } + } + + file << "}" << endl; + file.close(); + cout << "c Printed gate structure to file " << filenename << endl; +} + +GateFinder::Stats& GateFinder::Stats::operator+=(const Stats& other) +{ + findGateTime += other.findGateTime; + find_gate_timeout += other.find_gate_timeout; + orBasedTime += other.orBasedTime; + or_based_timeout += other.or_based_timeout; + varReplaceTime += other.varReplaceTime; + andBasedTime += other.andBasedTime; + and_based_timeout += other.and_based_timeout; + erTime += other.erTime; + + //OR-gate + orGateUseful += other.orGateUseful; + numLongCls += other.numLongCls; + numLongClsLits += other.numLongClsLits; + litsRem += other.litsRem; + varReplaced += other.varReplaced; + + //And-gate + andGateUseful += other.andGateUseful; + clauseSizeRem += other.clauseSizeRem; + + //ER + numERVars += other.numERVars; + + //Gates + gatesSize += other.gatesSize; + num += other.num; + + return *this; +} + +void GateFinder::Stats::print(const size_t nVars) const +{ + cout << "c -------- GATE FINDING ----------" << endl; + print_stats_line("c time" + , total_time() + ); + + print_stats_line("c find gate time" + , findGateTime + , stats_line_percent(findGateTime, total_time()) + , "% time" + ); + + print_stats_line("c gate-based cl-sh time" + , orBasedTime + , stats_line_percent(orBasedTime, total_time()) + , "% time" + ); + + print_stats_line("c gate-based cl-rem time" + , andBasedTime + , stats_line_percent(andBasedTime, total_time()) + , "% time" + ); + + print_stats_line("c gate-based varrep time" + , varReplaceTime + , stats_line_percent(varReplaceTime, total_time()) + , "% time" + ); + + print_stats_line("c gatefinder cl-short" + , orGateUseful + , stats_line_percent(orGateUseful, numLongCls) + , "% long cls" + ); + + print_stats_line("c gatefinder lits-rem" + , litsRem + , stats_line_percent(litsRem, numLongClsLits) + , "% long cls lits" + ); + + print_stats_line("c gatefinder cl-rem" + , andGateUseful + , stats_line_percent(andGateUseful, numLongCls) + , "% long cls" + ); + + print_stats_line("c gatefinder cl-rem's lits" + , clauseSizeRem + , stats_line_percent(clauseSizeRem, numLongClsLits) + , "% long cls lits" + ); + + print_stats_line("c gatefinder var-rep" + , varReplaced + , stats_line_percent(varReplaced, nVars) + , "% vars" + ); + + cout << "c -------- GATE FINDING END ----------" << endl; +} + diff --git a/cryptominisat/cppsrc/src/gatefinder.h b/cryptominisat/cppsrc/src/gatefinder.h new file mode 100644 index 00000000..8da388c2 --- /dev/null +++ b/cryptominisat/cppsrc/src/gatefinder.h @@ -0,0 +1,165 @@ +/****************************************** +Copyright (C) 2009-2020 Authors of CryptoMiniSat, see AUTHORS file + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. +***********************************************/ + +#ifndef _GATEFINDER_H_ +#define _GATEFINDER_H_ + +#include "solvertypes.h" +#include "cset.h" +#include +#include "watcharray.h" +#include + +namespace CMSat { + +class Solver; +class OccSimplifier; +using std::set; + +inline std::ostream& operator<<(std::ostream& os, const OrGate& gate) +{ + os << " gate " << " lits: "; + for(auto const& l: gate.lits) os << l << ","; + os << " rhs: " << gate.rhs << " ID: " << gate.ID; + return os; +} + +class GateFinder +{ +public: + GateFinder(OccSimplifier *simplifier, Solver *control); + void find_all(); + void cleanup(); + const vector& get_gates() const; + + //Stats + struct Stats + { + void clear() + { + Stats tmp; + *this = tmp; + } + + double total_time() const + { + return findGateTime + orBasedTime + varReplaceTime + + andBasedTime + erTime; + } + Stats& operator+=(const Stats& other); + void print(const size_t nVars) const; + + //Time + double findGateTime = 0.0; + uint32_t find_gate_timeout = 0; + double orBasedTime = 0.0; + uint32_t or_based_timeout = 0; + double varReplaceTime = 0.0; + double andBasedTime = 0.0; + uint32_t and_based_timeout = 0; + double erTime = 0.0; + + //OR-gate + uint64_t orGateUseful = 0; + uint64_t numLongCls = 0; + uint64_t numLongClsLits = 0; + int64_t litsRem = 0; + + //Var-replace + uint64_t varReplaced = 0; + + //And-gate + uint64_t andGateUseful = 0; + uint64_t clauseSizeRem = 0; + + //ER + uint64_t numERVars = 0; + + //Gates + uint64_t gatesSize = 0; + uint64_t num = 0; + }; + + const Stats& get_stats() const; + +private: + OrGate* find_gate_to_elim_on(Lit lit, uint32_t cutoff); + void print_graphviz_dot(); + + //Setup + void link_in_gate(const OrGate& gate); + void add_gate_if_not_already_inside(const Lit rhs, const vector& lhs, const int32_t ID); + void find_or_gates_in_sweep_mode(Lit lit); + + //Finding + vector tmp_lhs; + void find_or_gates_and_update_stats(); + void find_or_gates(); + void findOrGate( + const Lit rhs + , const Lit lit1 + , const Lit lit2 + ); + + vector subs; //to reduce overhead of allocation + size_t findEqOrGates(); + + //Indexes, gate data + vector orGates; //List of OR gates + + //For temporaries + vector seen2Set; //Bits that have been set in seen2, and later need to be cleared + set clToUnlink; + + //Stats + Stats runStats; + Stats globalStats; + + //Limits + int64_t numMaxGateFinder; + int64_t numMaxShortenWithGates; + int64_t numMaxClRemWithGates; + + //long-term stats + uint64_t numDotPrinted; + + //Main data + OccSimplifier *simplifier; + Solver *solver; + vector& seen; + vector& seen2; + vector& toClear; +}; + +inline const GateFinder::Stats& GateFinder::get_stats() const +{ + return globalStats; +} + +inline const vector& GateFinder::get_gates() const +{ + return orGates; +} + +} //end namespace + +#endif //_GATEFINDER_H_ diff --git a/cryptominisat/cppsrc/src/gaussian.cpp b/cryptominisat/cppsrc/src/gaussian.cpp new file mode 100644 index 00000000..d9ab64fd --- /dev/null +++ b/cryptominisat/cppsrc/src/gaussian.cpp @@ -0,0 +1,1584 @@ +/****************************************** +Copyright (c) 2012 Cheng-Shen Han +Copyright (c) 2012 Jie-Hong Roland Jiang +Copyright (C) 2009-2020 Authors of CryptoMiniSat, see AUTHORS file + +For more information, see " When Boolean Satisfiability Meets Gaussian +Elimination in a Simplex Way." by Cheng-Shen Han and Jie-Hong Roland Jiang +in CAV (Computer Aided Verification), 2012: 410-426 + + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. +***********************************************/ + +#include +#include +#include +#include +#include + +#include "gaussian.h" +#include "clause.h" +#include "clausecleaner.h" +#include "datasync.h" +#include "propby.h" +#include "solver.h" +#include "time_mem.h" +#include "varreplacer.h" +#ifdef USE_TBUDDY +#include "tbdd.h" +#include "prover.h" +#endif + +// #define VERBOSE_DEBUG +// #define SLOW_DEBUG + +// don't delete gauss watches, but check when propagating and +// lazily delete then +// #define LAZY_DELETE_HACK + +using std::cout; +using std::endl; +using std::ostream; +using std::set; + +using namespace CMSat; + +// if variable is not in Gaussian matrix , assiag unknown column +static const uint32_t unassigned_col = numeric_limits::max(); + +EGaussian::EGaussian( + Solver* _solver, + const uint32_t _matrix_no, + const vector& _xorclauses) : +xorclauses(_xorclauses), +solver(_solver), +matrix_no(_matrix_no) +{ + TBUDDY_DO(one_len_ilist = ilist_new(1)); + TBUDDY_DO(ilist_resize(one_len_ilist, 1)); +} + +EGaussian::~EGaussian() { + delete_gauss_watch_this_matrix(); + for(auto& x: tofree) delete[] x; + TBUDDY_DO(for(auto& x: xorclauses) assert(x.bdd == NULL && "GMatrix needs finalization before deletion")); + TBUDDY_DO(assert(frat_ids.empty())); + tofree.clear(); + + delete cols_unset; + delete cols_vals; + delete tmp_col; + delete tmp_col2; + TBUDDY_DO(ilist_free(one_len_ilist)); + TBUDDY_DO(ilist_free(ilist_tmp)); +} + +struct ColSorter { + explicit ColSorter(Solver* _solver) : + solver(_solver) + { + for(const auto& ass: solver->assumptions) { + Lit p = solver->map_outer_to_inter(ass.lit_outer); + if (p.var() < solver->nVars()) { + assert(solver->seen.size() > p.var()); + solver->seen[p.var()] = 1; + } + } + } + + void finishup() + { + for(const auto& ass: solver->assumptions) { + Lit p = solver->map_outer_to_inter(ass.lit_outer); + if (p.var() < solver->nVars()) { + solver->seen[p.var()] = 0; + } + } + } + + bool operator()(const uint32_t a, const uint32_t b) + { + assert(solver->seen.size() > a); + assert(solver->seen.size() > b); + if (solver->seen[b] && !solver->seen[a]) { + return true; + } + + if (!solver->seen[b] && solver->seen[a]) { + return false; + } + + return false; + //return solver->varData[a].level < solver->varData[b].level; + //return solver->var_act_vsids[a] > solver->var_act_vsids[b]; + } + + Solver* solver; +}; + +void EGaussian::select_columnorder() { + var_to_col.clear(); + var_to_col.resize(solver->nVars(), unassigned_col); + vector vars_needed; + uint32_t largest_used_var = 0; + + for (const Xor& x : xorclauses) { + for (const uint32_t v : x) { + assert(solver->value(v) == l_Undef); + if (var_to_col[v] == unassigned_col) { + vars_needed.push_back(v); + var_to_col[v] = unassigned_col - 1; + largest_used_var = std::max(largest_used_var, v); + } + } + } + + if (vars_needed.size() >= numeric_limits::max() / 2 - 1) { + cout << "c Matrix has too many rows, exiting select_columnorder" << endl; + assert(false); + exit(-1); + } + if (xorclauses.size() >= numeric_limits::max() / 2 - 1) { + cout << "c Matrix has too many rows, exiting select_columnorder" << endl; + assert(false); + exit(-1); + } + var_to_col.resize(largest_used_var + 1); + + + ColSorter c(solver); + std::sort(vars_needed.begin(), vars_needed.end(),c); + c.finishup(); + + #ifdef COL_ORDER_DEBUG_VERBOSE_DEBUG + cout << "col order: " << endl; + for(auto& x: vars_needed) { + bool assump = false; + for(const auto& ass: solver->assumptions) { + if (solver->map_outer_to_inter(ass.lit_outer).var() == x) { + assump = true; + } + } + cout << "assump:" << (int)assump + << " act: " << std::setprecision(2) << std::scientific + << solver->var_act_vsids[x] << std::fixed + << " level: " << solver->varData[x].level + << endl; + } + #endif + + + col_to_var.clear(); + for (uint32_t v : vars_needed) { + assert(var_to_col[v] == unassigned_col - 1); + col_to_var.push_back(v); + var_to_col[v] = col_to_var.size() - 1; + } + + // for the ones that were not in the order_heap, but are marked in var_to_col + for (uint32_t v = 0; v != var_to_col.size(); v++) { + if (var_to_col[v] == unassigned_col - 1) { + // assert(false && "order_heap MUST be complete!"); + col_to_var.push_back(v); + var_to_col[v] = col_to_var.size() - 1; + } + } + + #ifdef VERBOSE_DEBUG_MORE + cout << "(" << matrix_no << ") num_xorclauses: " << num_xorclauses << endl; + cout << "(" << matrix_no << ") col_to_var: "; + std::copy(col_to_var.begin(), col_to_var.end(), + std::ostream_iterator(cout, ",")); + cout << endl; + cout << "num_cols:" << num_cols << endl; + cout << "col is set:" << endl; + std::copy(col_is_set.begin(), col_is_set.end(), + std::ostream_iterator(cout, ",")); + #endif +} + +void EGaussian::fill_matrix() { + assert(solver->trail_size() == solver->qhead); + var_to_col.clear(); + + // decide which variable in matrix column and the number of rows + select_columnorder(); + num_rows = xorclauses.size(); + num_cols = col_to_var.size(); + if (num_rows == 0 || num_cols == 0) { + return; + } + TBUDDY_DO(ilist_tmp = ilist_new(num_cols)); + mat.resize(num_rows, num_cols); // initial gaussian matrix + + bdd_matrix.clear(); + for (uint32_t row = 0; row < num_rows; row++) { + const Xor& c = xorclauses[row]; + mat[row].set(c, var_to_col, num_cols); + vector line; + line.resize(num_rows, 0); + line[row] = 1; + bdd_matrix.push_back(line); + } + assert(bdd_matrix.size() == num_rows); + + // reset + var_has_resp_row.clear(); + var_has_resp_row.resize(solver->nVars(), 0); + row_to_var_non_resp.clear(); + + delete_gauss_watch_this_matrix(); + + //reset satisfied_xor state + assert(solver->decisionLevel() == 0); + satisfied_xors.clear(); + satisfied_xors.resize(num_rows, 0); +} + +void EGaussian::delete_gauss_watch_this_matrix() +{ + for (size_t ii = 0; ii < solver->gwatches.size(); ii++) { + clear_gwatches(ii); + } +} + +void EGaussian::clear_gwatches(const uint32_t var) +{ + //if there is only one matrix, don't check, just empty it + if (solver->gmatrices.size() == 0) { + solver->gwatches[var].clear(); + return; + } + + GaussWatched* i = solver->gwatches[var].begin(); + GaussWatched* j = i; + for(GaussWatched* end = solver->gwatches[var].end(); i != end; i++) { + if (i->matrix_num != matrix_no) { + *j++ = *i; + } + } + solver->gwatches[var].shrink(i-j); +} + +bool EGaussian::full_init(bool& created) { + assert(solver->okay()); + assert(solver->decisionLevel() == 0); + assert(initialized == false); + *solver->frat << __PRETTY_FUNCTION__ << " start\n"; + created = true; + + uint32_t trail_before; + while (true) { + trail_before = solver->trail_size(); + solver->clauseCleaner->clean_xor_clauses(xorclauses); + + fill_matrix(); + before_init_density = get_density(); + if (num_rows == 0 || num_cols == 0) { + created = false; + return solver->okay(); + } + + eliminate(); + + // find some row already true false, and insert watch list + gret ret = init_adjust_matrix(); + + switch (ret) { + case gret::confl: + return false; + break; + case gret::prop: + assert(solver->decisionLevel() == 0); + solver->ok = solver->propagate().isNULL(); + if (!solver->ok) { + if (solver->conf.verbosity >= 5) { + cout << "c eliminate & adjust matrix during init lead to UNSAT" << endl; + } + return false; + } + break; + default: + break; + } + + assert(solver->prop_at_head()); + + //Let's exit if nothing new happened + if (solver->trail_size() == trail_before) break; + } + SLOW_DEBUG_DO(check_watchlist_sanity()); + verb_print(2, "c [gauss] initialised matrix " << matrix_no); + + xor_reasons.resize(num_rows); + uint32_t num_64b = num_cols/64+(bool)(num_cols%64); + for(auto& x: tofree) { + delete[] x; + } + tofree.clear(); + delete cols_unset; + delete cols_vals; + delete tmp_col; + delete tmp_col2; + + int64_t* x = new int64_t[num_64b+1]; + tofree.push_back(x); + cols_unset = new PackedRow(num_64b, x); + + x = new int64_t[num_64b+1]; + tofree.push_back(x); + cols_vals = new PackedRow(num_64b, x); + + x = new int64_t[num_64b+1]; + tofree.push_back(x); + tmp_col = new PackedRow(num_64b, x); + + x = new int64_t[num_64b+1]; + tofree.push_back(x); + tmp_col2 = new PackedRow(num_64b, x); + + cols_vals->rhs() = 0; + cols_unset->rhs() = 0; + tmp_col->rhs() = 0; + tmp_col2->rhs() = 0; + after_init_density = get_density(); + + initialized = true; + update_cols_vals_set(true); + SLOW_DEBUG_DO(check_invariants()); + + *solver->frat << __PRETTY_FUNCTION__ << " end\n"; + return solver->okay(); +} + +#ifdef USE_TBUDDY +void EGaussian::xor_in_bdd(const uint32_t a, const uint32_t b) +{ + for(uint32_t i = 0; i < bdd_matrix[a].size(); i ++) { + bdd_matrix[a][i] ^= bdd_matrix[b][i]; + } +} +#endif + +void EGaussian::eliminate() { + PackedMatrix::iterator end_row_it = mat.begin() + num_rows; + PackedMatrix::iterator rowI = mat.begin(); + uint32_t row_i = 0; + uint32_t col = 0; + + // Gauss-Jordan Elimination + while (row_i != num_rows && col != num_cols) { + PackedMatrix::iterator row_with_1_in_col = rowI; + uint32_t row_with_1_in_col_n = row_i; + + //Find first "1" in column. + for (; row_with_1_in_col != end_row_it; ++row_with_1_in_col, row_with_1_in_col_n++) { + if ((*row_with_1_in_col)[col]) { + break; + } + } + + //We have found a "1" in this column + if (row_with_1_in_col != end_row_it) { + //cout << "col zeroed:" << col << " var is: " << col_to_var[col] + 1 << endl; + var_has_resp_row[col_to_var[col]] = 1; + + // swap row row_with_1_in_col and rowIt + if (row_with_1_in_col != rowI) { + (*rowI).swapBoth(*row_with_1_in_col); + std::swap(bdd_matrix[row_i], bdd_matrix[row_with_1_in_col_n]); + } + + // XOR into *all* rows that have a "1" in column COL + // Since we XOR into *all*, this is Gauss-Jordan (and not just Gauss) + uint32_t k = 0; + for (PackedMatrix::iterator k_row = mat.begin() + ; k_row != end_row_it + ; ++k_row, k++ + ) { + // xor rows K and I + if (k_row != rowI) { + if ((*k_row)[col]) { + (*k_row).xor_in(*rowI); + if (solver->frat->enabled()) TBUDDY_DO(xor_in_bdd(k, row_i)); + } + } + } + row_i++; + ++rowI; + } + col++; + } + //print_matrix(); +} + +vector* EGaussian::get_reason(const uint32_t row, int32_t& out_ID) +{ + *solver->frat << __PRETTY_FUNCTION__ << " start\n"; + if (!xor_reasons[row].must_recalc) { + out_ID = xor_reasons[row].ID; + return &(xor_reasons[row].reason); + } + + // Clean up previous one + #ifdef USE_TBUDDY + if (solver->frat->enabled() && xor_reasons[row].ID != 0) { + solver->frat->flush(); + delete xor_reasons[row].constr; + one_len_ilist[0] = xor_reasons[row].ID; + VERBOSE_PRINT("calling tbuddy to delete clause ID " << xor_reasons[row].ID); + delete_clauses(one_len_ilist); + } + #endif + + vector& tofill = xor_reasons[row].reason; + tofill.clear(); + + mat[row].get_reason( + tofill, + solver->assigns, + col_to_var, + *cols_vals, + *tmp_col2, + xor_reasons[row].propagated); + + #ifdef USE_TBUDDY + if (solver->frat->enabled()) { + solver->frat->flush(); + VERBOSE_PRINT("Expecting tbuddy to prove: " << tofill); + xor_reasons[row].constr = bdd_create(row, tofill.size()); + ilist_resize(ilist_tmp, tofill.size()); + for(uint32_t i = 0; i < tofill.size(); i++) { + ilist_tmp[i] = (tofill[i].var()+1) * (tofill[i].sign() ? -1 :1); + } + out_ID = assert_clause(ilist_tmp); + VERBOSE_PRINT("ID of asserted get_reason ID: " << out_ID); + } + #endif + + xor_reasons[row].must_recalc = false; + xor_reasons[row].ID = out_ID; + *solver->frat << __PRETTY_FUNCTION__ << " end\n"; + return &tofill; +} + +#ifdef USE_TBUDDY +tbdd::xor_constraint* EGaussian::bdd_create(const uint32_t row_n, const uint32_t expected_sz) +{ + assert(solver->frat->enabled()); + *solver->frat << __PRETTY_FUNCTION__ << " start\n"; + + solver->frat->flush(); + tbdd::xor_set xset; + for(uint32_t i = 0; i < bdd_matrix[row_n].size(); i++) { + if (bdd_matrix[row_n][i]) { + xset.add(*xorclauses[i].create_bdd_xor()); + } + } + auto x = xset.sum(); + VERBOSE_DEBUG_DO( + cout << "vars in BDD: "; + cout <get_variables(), stdout, " "); + cout << endl + ); + + #ifdef SLOW_DEBUG + auto const& bdd_vars = x->get_variables(); + uint32_t sz = (uint32_t)ilist_length(x->get_variables()); + for(int i = 0; i < ilist_length(bdd_vars); i++) { + auto const v = bdd_vars[i]; + assert(v > 0); + assert(v <= (int)solver->unit_cl_IDs.size()); + if (solver->unit_cl_IDs[v-1] != 0) sz--; + } + /*cout << "bdd_create expected size: " << expected_sz + << " got sz: " << ilist_length(x->get_variables()) + << " without units: " << sz << endl;*/ + + //NOTE + // Since during xor clause cleaning we don't re-generate the bdd-s + // the ilist_length(x->get_variables()) will contain stuff that is already unit + // hence we may need to check that the size of the generated XOR is zero, if not + // we need to add the empty clause ourselves. + + #endif + + *solver->frat << __PRETTY_FUNCTION__ << " end\n"; + return x; +} +#endif + +gret EGaussian::init_adjust_matrix() +{ + assert(solver->decisionLevel() == 0); + assert(row_to_var_non_resp.empty()); + assert(satisfied_xors.size() >= num_rows); + *solver->frat << __PRETTY_FUNCTION__ << " start\n"; + VERBOSE_PRINT("mat[" << matrix_no << "] init adjusting matrix"); + + PackedMatrix::iterator end = mat.begin() + num_rows; + PackedMatrix::iterator rowI = mat.begin(); //row index iterator + uint32_t row_i = 0; // row index + uint32_t adjust_zero = 0; // elimination row + + while (rowI != end) { + uint32_t non_resp_var; + const uint32_t popcnt = (*rowI).find_watchVar( + tmp_clause, col_to_var, var_has_resp_row, non_resp_var); + + switch (popcnt) { + + //Conflict or satisfied + case 0: + VERBOSE_PRINT("Empty XOR during init_adjust_matrix, rhs: " << (*rowI).rhs()); + adjust_zero++; + + // conflict + if ((*rowI).rhs()) { + #ifdef USE_TBUDDY + if (solver->frat->enabled()) { + unsat_bdd = bdd_create(row_i, 0); + + assert(solver->unsat_cl_ID == 0); + if (ilist_length(unsat_bdd->get_variables()) != 0) { + *solver->frat << add << ++solver->clauseID << fin; + solver->unsat_cl_ID = solver->clauseID; + } else { + assert(unsat_bdd->get_phase() == 1); + solver->unsat_cl_ID = -1;//solver->clauseID; + } + } + #endif + solver->ok = false; + VERBOSE_PRINT("-> empty clause during init_adjust_matrix"); + VERBOSE_PRINT("-> conflict on row: " << row_i); + return gret::confl; + } + VERBOSE_PRINT("-> empty on row: " << row_i); + VERBOSE_PRINT("-> Satisfied XORs set for row: " << row_i); + satisfied_xors[row_i] = 1; + break; + + //Unit (i.e. toplevel unit) + case 1: + { + VERBOSE_PRINT("Unit XOR during init_adjust_matrix, vars: " << tmp_clause); + bool xorEqualFalse = !mat[row_i].rhs(); + tmp_clause[0] = Lit(tmp_clause[0].var(), xorEqualFalse); + assert(solver->value(tmp_clause[0].var()) == l_Undef); + #ifdef USE_TBUDDY + if (solver->frat->enabled()) { + tbdd::xor_constraint* bdd = bdd_create(row_i, 1); + ilist out = ilist_new(1); + ilist_resize(out, 1); + out[0] = (tmp_clause[0].var()+1) * (tmp_clause[0].sign() ? -1 :1); + const int32_t ID = assert_clause(out); + frat_ids.push_back(BDDCl{out, ID}); + VERBOSE_PRINT("ID of this unit: " << ID << " unit is: " << tmp_clause); + delete bdd; + } + #endif + + solver->enqueue(tmp_clause[0]); + + VERBOSE_PRINT("-> UNIT during adjust: " << tmp_clause[0]); + VERBOSE_PRINT("-> Satisfied XORs set for row: " << row_i); + satisfied_xors[row_i] = 1; + SLOW_DEBUG_DO(assert(check_row_satisfied(row_i))); + + //adjusting + (*rowI).setZero(); // reset this row all zero + row_to_var_non_resp.push_back(numeric_limits::max()); + var_has_resp_row[tmp_clause[0].var()] = 0; + return gret::prop; + } + + //Binary XOR (i.e. toplevel binary XOR) + case 2: { + VERBOSE_PRINT("Binary XOR during init_adjust_matrix, vars: " << tmp_clause); + bool xorEqualFalse = !mat[row_i].rhs(); + + tmp_clause[0] = tmp_clause[0].unsign(); + tmp_clause[1] = tmp_clause[1].unsign(); + #ifdef USE_TBUDDY + if (solver->frat->enabled()) { + tbdd::xor_constraint* bdd = bdd_create(row_i, 2); + ilist out = ilist_new(2); + ilist_resize(out, 2); + if (mat[row_i].rhs()) { + out[0] = (tmp_clause[0].var()+1); + out[1] = (tmp_clause[1].var()+1); + } else { + out[0] = (tmp_clause[0].var()+1)*-1; + out[1] = (tmp_clause[1].var()+1); + } + const int32_t ID = assert_clause(out); + frat_ids.push_back(BDDCl{out, ID}); + VERBOSE_PRINT("ID of bin XOR found (part 1): " << ID); + + ilist out2 = ilist_new(2); + ilist_resize(out2, 2); + if (mat[row_i].rhs()) { + out2[0] = (tmp_clause[0].var()+1)*-1; + out2[1] = (tmp_clause[1].var()+1)*-1; + } else { + out2[0] = (tmp_clause[0].var()+1); + out2[1] = (tmp_clause[1].var()+1)*-1; + } + const int32_t ID2 = assert_clause(out2); + frat_ids.push_back(BDDCl{out2, ID2}); + VERBOSE_PRINT("ID of bin XOR found (part 2): " << ID2); + delete bdd; + } + #endif + + solver->ok = solver->add_xor_clause_inter(tmp_clause, !xorEqualFalse, true); + release_assert(solver->ok); + VERBOSE_PRINT("-> toplevel bin-xor on row: " << row_i << " cl2: " << tmp_clause); + + // reset this row all zero, no need for this row + (*rowI).rhs() = 0; + (*rowI).setZero(); + + row_to_var_non_resp.push_back(numeric_limits::max()); // delete non-basic value in this row + var_has_resp_row[tmp_clause[0].var()] = 0; // delete basic value in this row + break; + } + + default: // need to update watch list + // printf("%d:need to update watch list n",row_id); + assert(non_resp_var != numeric_limits::max()); + + // insert watch list + VERBOSE_PRINT("-> watch 1: resp var " << tmp_clause[0].var()+1 << " for row " << row_i); + VERBOSE_PRINT("-> watch 2: non-resp var " << non_resp_var+1 << " for row " << row_i); + solver->gwatches[tmp_clause[0].var()].push( + GaussWatched(row_i, matrix_no)); // insert basic variable + solver->gwatches[non_resp_var].push( + GaussWatched(row_i, matrix_no)); // insert non-basic variable + row_to_var_non_resp.push_back(non_resp_var); // record in this row non-basic variable + break; + } + ++rowI; + row_i++; + } + assert(row_to_var_non_resp.size() == row_i - adjust_zero); + + mat.resizeNumRows(row_i - adjust_zero); + num_rows = row_i - adjust_zero; + + *solver->frat << __PRETTY_FUNCTION__ << " end\n"; + return gret::nothing_satisfied; +} + +// Delete this row because we have already add to xor clause, nothing to do anymore +void EGaussian::delete_gausswatch( + const uint32_t row_n +) { + // clear nonbasic value watch list + bool debug_find = false; + vec& ws_t = solver->gwatches[row_to_var_non_resp[row_n]]; + + for (int32_t tmpi = ws_t.size() - 1; tmpi >= 0; tmpi--) { + if (ws_t[tmpi].row_n == row_n + && ws_t[tmpi].matrix_num == matrix_no + ) { + ws_t[tmpi] = ws_t.last(); + ws_t.shrink(1); + debug_find = true; + break; + } + } + #ifdef VERBOSE_DEBUG + cout + << "mat[" << matrix_no << "] " + << "Tried cleaning watch of var: " + << row_to_var_non_resp[row_n]+1 << endl; + #endif + assert(debug_find); +} + +uint32_t EGaussian::get_max_level(const GaussQData& gqd, const uint32_t row_n) +{ + int32_t ID; + auto cl = get_reason(row_n, ID); + uint32_t nMaxLevel = gqd.currLevel; + uint32_t nMaxInd = 1; + + for (uint32_t i = 1; i < cl->size(); i++) { + Lit l = (*cl)[i]; + uint32_t nLevel = solver->varData[l.var()].level; + if (nLevel > nMaxLevel) { + nMaxLevel = nLevel; + nMaxInd = i; + } + } + + //should we?? + if (nMaxInd != 1) { + std::swap((*cl)[1], (*cl)[nMaxInd]); + } + return nMaxLevel; +} + +bool EGaussian::find_truths( + GaussWatched*& i, + GaussWatched*& j, + const uint32_t var, + const uint32_t row_n, + GaussQData& gqd +) { + assert(gqd.ret != gauss_res::confl); + assert(initialized); + + #ifdef LAZY_DELETE_HACK + if (!mat[row_n][var_to_col[var]]) { + //lazy delete + return true; + } + #endif + // printf("dd Watch variable : %d , Wathch row num %d n", p , row_n); + + VERBOSE_PRINT( + "mat[" << matrix_no << "] find_truths" << endl + << "-> row: " << row_n << endl + << "-> var: " << var+1 << endl + << "-> dec lev:" << solver->decisionLevel()); + SLOW_DEBUG_DO(assert(row_n < num_rows)); + SLOW_DEBUG_DO(assert(satisfied_xors.size() > row_n)); + + // this XOR is already satisfied + if (satisfied_xors[row_n]) { + VERBOSE_PRINT("-> xor satisfied as per satisfied_xors[row_n]"); + SLOW_DEBUG_DO(assert(check_row_satisfied(row_n))); + *j++ = *i; + find_truth_ret_satisfied_precheck++; + return true; + } + + // swap resp and non-resp variable + bool was_resp_var = false; + if (var_has_resp_row[var] == 1) { + //var has a responsible row, so THIS row must be it! + //since if a var has a responsible row, only ONE row can have a 1 there + was_resp_var = true; + var_has_resp_row[row_to_var_non_resp[row_n]] = 1; + var_has_resp_row[var] = 0; + } + + uint32_t new_resp_var; + Lit ret_lit_prop; + SLOW_DEBUG_DO(check_cols_unset_vals()); + const gret ret = mat[row_n].propGause( + solver->assigns, + col_to_var, + var_has_resp_row, + new_resp_var, + *tmp_col, + *tmp_col2, + *cols_vals, + *cols_unset, + ret_lit_prop); + find_truth_called_propgause++; + + switch (ret) { + case gret::confl: { + find_truth_ret_confl++; + *j++ = *i; + + xor_reasons[row_n].must_recalc = true; + xor_reasons[row_n].propagated = lit_Undef; + gqd.confl = PropBy(matrix_no, row_n); + gqd.ret = gauss_res::confl; + VERBOSE_PRINT("--> conflict"); + + #ifdef USE_TBUDDY + // have to get reason if toplevel (reason will never be asked) + if (solver->decisionLevel() == 0 && solver->frat->enabled()) { + VERBOSE_PRINT("-> conflict at toplevel during find_truths"); + unsat_bdd = bdd_create(row_n, numeric_limits::max()); + } + #endif + + if (was_resp_var) { // recover + var_has_resp_row[row_to_var_non_resp[row_n]] = 0; + var_has_resp_row[var] = 1; + } + + return false; + } + + case gret::prop: { + find_truth_ret_prop++; + VERBOSE_PRINT("--> propagation"); + *j++ = *i; + + xor_reasons[row_n].must_recalc = true; + xor_reasons[row_n].propagated = ret_lit_prop; + assert(solver->value(ret_lit_prop.var()) == l_Undef); + prop_lit(gqd, row_n, ret_lit_prop); + + update_cols_vals_set(ret_lit_prop); + gqd.ret = gauss_res::prop; + + if (was_resp_var) { // recover + var_has_resp_row[row_to_var_non_resp[row_n]] = 0; + var_has_resp_row[var] = 1; + } + + VERBOSE_PRINT("--> Satisfied XORs set for row: " << row_n); + satisfied_xors[row_n] = 1; + SLOW_DEBUG_DO(assert(check_row_satisfied(row_n))); + return true; + } + + // find new watch list + case gret::nothing_fnewwatch: + VERBOSE_PRINT("--> found new watch: " << new_resp_var+1); + + find_truth_ret_fnewwatch++; + // printf("%d:This row is find new watch:%d => orig %d p:%d n",row_n , + // new_resp_var,orig_basic , p); + + if (was_resp_var) { + /// clear watchlist, because only one responsible value in watchlist + assert(new_resp_var != var); + clear_gwatches(new_resp_var); + VERBOSE_PRINT("Cleared watchlist for new resp var: " << new_resp_var+1); + VERBOSE_PRINT("After clear..."); + VERBOSE_DEBUG_DO(print_gwatches(new_resp_var)); + } + assert(new_resp_var != var); + //VERBOSE_DEBUG_DO(print_gwatches(new_resp_var)); + SLOW_DEBUG_DO(check_row_not_in_watch(new_resp_var, row_n)); + solver->gwatches[new_resp_var].push(GaussWatched(row_n, matrix_no)); + + if (was_resp_var) { + //it was the responsible one, so the newly watched var + //is the new column it's responsible for + //so elimination will be needed + + //clear old one, add new resp + var_has_resp_row[row_to_var_non_resp[row_n]] = 0; + var_has_resp_row[new_resp_var] = 1; + + // store the eliminate variable & row + gqd.new_resp_var = new_resp_var; + gqd.new_resp_row = row_n; + if (solver->gmatrices.size() == 1) { + assert(solver->gwatches[gqd.new_resp_var].size() == 1); + } + gqd.do_eliminate = true; + return true; + } else { + row_to_var_non_resp[row_n] = new_resp_var; + return true; + } + + // this row already true + case gret::nothing_satisfied: + VERBOSE_PRINT("--> satisfied"); + + find_truth_ret_satisfied++; + // printf("%d:This row is nothing( maybe already true) n",row_n); + *j++ = *i; + if (was_resp_var) { // recover + var_has_resp_row[row_to_var_non_resp[row_n]] = 0; + var_has_resp_row[var] = 1; + } + + VERBOSE_PRINT("--> Satisfied XORs set for row: " << row_n); + satisfied_xors[row_n] = 1; + SLOW_DEBUG_DO(assert(check_row_satisfied(row_n))); + return true; + + //error here + default: + assert(false); // cannot be here + break; + } + + assert(false); + return true; +} + +inline void EGaussian::update_cols_vals_set(const Lit lit1) +{ + cols_unset->clearBit(var_to_col[lit1.var()]); + if (!lit1.sign()) { + cols_vals->setBit(var_to_col[lit1.var()]); + } +} + +void EGaussian::update_cols_vals_set(bool force) +{ + assert(initialized); + + //cancelled_since_val_update = true; + if (cancelled_since_val_update || force) { + cols_vals->setZero(); + cols_unset->setOne(); + + for(uint32_t col = 0; col < col_to_var.size(); col++) { + uint32_t var = col_to_var[col]; + if (solver->value(var) != l_Undef) { + cols_unset->clearBit(col); + if (solver->value(var) == l_True) { + cols_vals->setBit(col); + } + } + } + last_val_update = solver->trail.size(); + cancelled_since_val_update = false; + return; + } + + assert(solver->trail.size() >= last_val_update); + for(uint32_t i = last_val_update; i < solver->trail.size(); i++) { + uint32_t var = solver->trail[i].lit.var(); + if (var_to_col.size() <= var) { + continue; + } + uint32_t col = var_to_col[var]; + if (col != unassigned_col) { + assert (solver->value(var) != l_Undef); + cols_unset->clearBit(col); + if (solver->value(var) == l_True) { + cols_vals->setBit(col); + } + } + } + last_val_update = solver->trail.size(); +} + +void EGaussian::prop_lit( + const GaussQData& gqd, const uint32_t row_i, const Lit ret_lit_prop) +{ + uint32_t lev; + if (gqd.currLevel == solver->decisionLevel()) lev = gqd.currLevel; + else lev = get_max_level(gqd, row_i); + #ifdef USE_TBUDDY + if (lev == 0 && solver->frat->enabled()) { + //we produce the reason, because we need it immediately, since it's toplevel + int32_t out_ID; + VERBOSE_PRINT("--> BDD reason needed in prop due to lev 0 enqueue"); + [[maybe_unused]] auto const x = get_reason(row_i, out_ID); + + #ifdef SLOW_DEBUG + VERBOSE_PRINT("--> reason clause: " << *x); + uint32_t num_unset = 0; + for(auto const& a: *x) { + assert(solver->value(a) != l_True); + if (solver->value(a) == l_False) { + assert(solver->varData[a.var()].level == 0); + assert(solver->unit_cl_IDs[a.var()] != 0); + } + if (solver->value(a) == l_Undef) num_unset ++; + } + assert(num_unset == 1); + #endif + } + #endif + solver->enqueue(ret_lit_prop, lev, PropBy(matrix_no, row_i)); +} + +void EGaussian::eliminate_col(uint32_t p, GaussQData& gqd) +{ + const uint32_t new_resp_row_n = gqd.new_resp_row; + PackedMatrix::iterator rowI = mat.begin(); + PackedMatrix::iterator end = mat.end(); + const uint32_t new_resp_col = var_to_col[gqd.new_resp_var]; + uint32_t row_i = 0; + + #ifdef VERBOSE_DEBUG + cout + << "mat[" << matrix_no << "] " + << "** eliminating this column: " << new_resp_col << endl + << "-> row that will be the SOLE one having a 1: " << gqd.new_resp_row << endl + << "-> var associated with col: " << gqd.new_resp_var+1 + << endl; + #endif + elim_called++; + + while (rowI != end) { + //Row has a '1' in eliminating column, and it's not the row responsible + if (new_resp_row_n != row_i && (*rowI)[new_resp_col]) { + + // detect orignal non-basic watch list change or not + uint32_t orig_non_resp_var = row_to_var_non_resp[row_i]; + uint32_t orig_non_resp_col = var_to_col[orig_non_resp_var]; + assert((*rowI)[orig_non_resp_col]); + VERBOSE_PRINT("--> This row " << row_i + << " is being watched on var: " << orig_non_resp_var + 1 + << " i.e. it must contain '1' for this var's column"); + + assert(satisfied_xors[row_i] == 0); + (*rowI).xor_in(*(mat.begin() + new_resp_row_n)); + if (solver->frat->enabled()) TBUDDY_DO(xor_in_bdd(row_i, new_resp_row_n)); + + elim_xored_rows++; + + //NOTE: responsible variable cannot be eliminated of course + // (it's the only '1' in that column). + // But non-responsible can be eliminated. So let's check that + // and then deal with it if we have to + if (!(*rowI)[orig_non_resp_col]) { + + #ifdef VERBOSE_DEBUG + cout + << "--> This row " << row_i + << " can no longer be watched (non-responsible), it has no '1' at col " << orig_non_resp_col + << " (var " << col_to_var[orig_non_resp_col]+1 << ")" + << " fixing up..."<< endl; + #endif + + // Delete orignal non-responsible var from watch list + if (orig_non_resp_var != gqd.new_resp_var) { + #ifndef LAZY_DELETE_HACK + delete_gausswatch(row_i); + #endif + } else { + //this does not need a delete, because during + //find_truths, we already did clear_gwatches of the + //orig_non_resp_var, so there is nothing to delete here + } + + Lit ret_lit_prop; + uint32_t new_non_resp_var = 0; + #ifdef SLOW_DEBUG + check_cols_unset_vals(); + #endif + const gret ret = (*rowI).propGause( + solver->assigns, + col_to_var, + var_has_resp_row, + new_non_resp_var, + *tmp_col, + *tmp_col2, + *cols_vals, + *cols_unset, + ret_lit_prop + ); + elim_called_propgause++; + + switch (ret) { + case gret::confl: { + elim_ret_confl++; + VERBOSE_PRINT("---> conflict during eliminate_col's fixup"); + solver->gwatches[p].push(GaussWatched(row_i, matrix_no)); + + // update in this row non-basic variable + row_to_var_non_resp[row_i] = p; + + xor_reasons[row_i].must_recalc = true; + xor_reasons[row_i].propagated = lit_Undef; + gqd.confl = PropBy(matrix_no, row_i); + gqd.ret = gauss_res::confl; + + #ifdef USE_TBUDDY + // have to get reason if toplevel (reason will never be asked) + if (solver->decisionLevel() == 0 && solver->frat->enabled()) { + VERBOSE_PRINT("-> conflict at toplevel during eliminate_col"); + int32_t ID; + get_reason(row_i, ID); + } + #endif + + break; + } + case gret::prop: { + elim_ret_prop++; + VERBOSE_PRINT("---> propagation during eliminate_col's fixup"); + + // if conflicted already, just update non-basic variable + if (gqd.ret == gauss_res::confl) { + SLOW_DEBUG_DO(check_row_not_in_watch(p, row_i)); + solver->gwatches[p].push(GaussWatched(row_i, matrix_no)); + row_to_var_non_resp[row_i] = p; + break; + } + + // update no_basic information + SLOW_DEBUG_DO(check_row_not_in_watch(p, row_i)); + solver->gwatches[p].push(GaussWatched(row_i, matrix_no)); + row_to_var_non_resp[row_i] = p; + + xor_reasons[row_i].must_recalc = true; + xor_reasons[row_i].propagated = ret_lit_prop; + assert(solver->value(ret_lit_prop.var()) == l_Undef); + prop_lit(gqd, row_i, ret_lit_prop); + + update_cols_vals_set(ret_lit_prop); + gqd.ret = gauss_res::prop; + + VERBOSE_PRINT("---> Satisfied XORs set for row: " << row_i); + satisfied_xors[row_i] = 1; + SLOW_DEBUG_DO(assert(check_row_satisfied(row_i))); + break; + } + + // find new watch list + case gret::nothing_fnewwatch: + elim_ret_fnewwatch++; + #ifdef VERBOSE_DEBUG + cout + << "---> Nothing, clause NOT already satisfied, pushing in " + << new_non_resp_var+1 << " as non-responsible var ( " + << row_i << " row) " + << endl; + #endif + + SLOW_DEBUG_DO(check_row_not_in_watch(new_non_resp_var, row_i)); + solver->gwatches[new_non_resp_var].push(GaussWatched(row_i, matrix_no)); + row_to_var_non_resp[row_i] = new_non_resp_var; + break; + + // this row already satisfied + case gret::nothing_satisfied: + elim_ret_satisfied++; + VERBOSE_PRINT("---> Nothing to do, already satisfied , pushing in " + << p+1 << " as non-responsible var ( " + << row_i << " row) "); + + // printf("%d:This row is nothing( maybe already true) in eliminate col + // n",num_row); + + SLOW_DEBUG_DO(check_row_not_in_watch(p, row_i)); + solver->gwatches[p].push(GaussWatched(row_i, matrix_no)); + row_to_var_non_resp[row_i] = p; + + VERBOSE_PRINT("---> Satisfied XORs set for row: " << row_i); + satisfied_xors[row_i] = 1; + SLOW_DEBUG_DO(assert(check_row_satisfied(row_i))); + break; + default: + // can not here + assert(false); + break; + } + } else { + VERBOSE_PRINT("--> OK, this row " << row_i << " still contains '1', can still be responsible"); + } + } + ++rowI; + row_i++; + } + + // Debug_funtion(); + #ifdef VERBOSE_DEBUG + cout + << "mat[" << matrix_no << "] " + << "eliminate_col - exiting. " << endl; + #endif +} + +void EGaussian::print_matrix() { + uint32_t row = 0; + for (PackedMatrix::iterator it = mat.begin(); it != mat.end(); + ++it, row++) { + cout << *it << " -- row:" << row; + if (row >= num_rows) { + cout << " (considered past the end)"; + } + cout << endl; + } +} + +void EGaussian::print_matrix_stats(uint32_t verbosity) +{ + std::stringstream ss; + ss << "c [g " << matrix_no << "] "; + const std::string pre = ss.str(); + + cout << std::left; + + if (verbosity >= 2) { + cout << pre << "truth-find satisfied : " + << print_value_kilo_mega(find_truth_ret_satisfied_precheck, false) << endl; + } + + if (verbosity >= 1) { + cout << pre << "truth-find prop checks : " + << print_value_kilo_mega(find_truth_called_propgause, false) << endl; + } + + + if (verbosity >= 2) { + cout << pre << "-> of which fnnewat : " + << std::setw(5) << std::setprecision(2) << std::right + << stats_line_percent(find_truth_ret_fnewwatch, find_truth_called_propgause) + << " %" + << endl; + cout << pre << "-> of which sat : " + << std::setw(5) << std::setprecision(2) << std::right + << stats_line_percent(find_truth_ret_satisfied, find_truth_called_propgause) + << " %" + << endl; + } + + if (verbosity >= 1) { + cout << pre << "-> of which prop : " + << std::setw(5) << std::setprecision(2) << std::right + << stats_line_percent(find_truth_ret_prop, find_truth_called_propgause) + << " %" + << endl; + cout << pre << "-> of which confl : " + << std::setw(5) << std::setprecision(2) << std::right + << stats_line_percent(find_truth_ret_confl, find_truth_called_propgause) + << " %" + << endl; + } + + cout << std::left; + cout << pre << "elim called : " + << print_value_kilo_mega(elim_called, false) << endl; + + if (verbosity >= 2) { + cout << pre << "-> lead to xor rows : " + << print_value_kilo_mega(elim_xored_rows, false) << endl; + + cout << pre << "--> lead to prop checks : " + << print_value_kilo_mega(elim_called_propgause, false) << endl; + + cout << pre << "---> of which satsified : " + << std::setw(5) << std::setprecision(2) << std::right + << stats_line_percent(elim_ret_satisfied, elim_called_propgause) + << " %" + << endl; + + cout << pre << "---> of which prop : " + << std::setw(5) << std::setprecision(2) << std::right + << stats_line_percent(elim_ret_prop, elim_called_propgause) + << " %" + << endl; + + cout << pre << "---> of which fnnewat : " + << std::setw(5) << std::setprecision(2) << std::right + << stats_line_percent(elim_ret_fnewwatch, elim_called_propgause) + << " %" + << endl; + + cout << pre << "---> of which confl : " + << std::setw(5) << std::setprecision(2) << std::right + << stats_line_percent(elim_ret_confl, elim_called_propgause) + << " %" + << endl; + } + + if (verbosity == 1) { + cout << pre << "---> which lead to prop : " + << std::setw(5) << std::setprecision(2) << std::right + << stats_line_percent(elim_ret_prop, elim_called) + << " %" + << endl; + + cout << pre << "---> which lead to confl: " + << std::setw(5) << std::setprecision(2) << std::right + << stats_line_percent(elim_ret_confl, elim_called) + << " %" + << endl; + } + + cout << std::left; + cout << pre << "size: " + << std::setw(5) << num_rows << " x " + << std::setw(5) << num_cols << endl; + + double density = get_density(); + + if (verbosity >= 2) { + cout << pre << "density before init: " + << std::setprecision(4) << std::left << before_init_density + << endl; + cout << pre << "density after init: " + << std::setprecision(4) << std::left << after_init_density + << endl; + cout << pre << "density : " + << std::setprecision(4) << std::left << density + << endl; + } + cout << std::setprecision(2); +} + +////////////////// +// Checking functions below +////////////////// + +void EGaussian::check_row_not_in_watch(const uint32_t v, const uint32_t row_num) const +{ + for(const auto& x: solver->gwatches[v]) { + if (x.matrix_num == matrix_no && x.row_n == row_num) { + cout << "OOOps, row ID " << row_num << " already in watch for var: " << v+1 << endl; + assert(false); + } + } +} + +void EGaussian::print_gwatches(const uint32_t var) const +{ + vec mycopy; + for(const auto& x: solver->gwatches[var]) { + mycopy.push(x); + } + + std::sort(mycopy.begin(), mycopy.end()); + cout << "Watch for var " << var+1 << ": "; + for(const auto& x: mycopy) { + cout + << "(Mat num: " << x.matrix_num + << " row_n: " << x.row_n << ") "; + } + cout << endl; +} + + +void EGaussian::check_no_prop_or_unsat_rows() +{ + VERBOSE_PRINT("mat[" << matrix_no << "] checking invariants..."); + + for(uint32_t row = 0; row < num_rows; row++) { + uint32_t bits_unset = 0; + bool val = mat[row].rhs(); + for(uint32_t col = 0; col < num_cols; col++) { + if (mat[row][col]) { + uint32_t var = col_to_var[col]; + if (solver->value(var) == l_Undef) { + bits_unset++; + } else { + val ^= (solver->value(var) == l_True); + } + } + } + + bool error = false; + if (bits_unset == 1) { + cout << "ERROR: row " << row << " is PROP but did not propagate!!!" << endl; + error = true; + } + if (bits_unset == 0 && val != false) { + cout << "ERROR: row " << row << " is UNSAT but did not conflict!" << endl; + error = true; + } + if (error) { + for(uint32_t var = 0; var < solver->nVars(); var++) { + const auto& ws = solver->gwatches[var]; + for(const auto& w: ws) { + if (w.matrix_num == matrix_no && w.row_n == row) { + cout << " gauss watched at var: " << var+1 + << " val: " << solver->value(var) << endl; + } + } + } + + cout << " matrix no: " << matrix_no << endl; + cout << " row: " << row << endl; + uint32_t var = row_to_var_non_resp[row]; + cout << " non-resp var: " << var+1 << endl; + cout << " dec level: " << solver->decisionLevel() << endl; + } + assert(bits_unset > 1 || (bits_unset == 0 && val == 0)); + } +} + +void EGaussian::check_watchlist_sanity() +{ + for(size_t i = 0; i < solver->nVars(); i++) { + for(auto w: solver->gwatches[i]) { + if (w.matrix_num == matrix_no) { + assert(i < var_to_col.size()); + } + } + } +} + +void EGaussian::check_tracked_cols_only_one_set() +{ + vector row_resp_for_var(num_rows, var_Undef); + for(uint32_t col = 0; col < num_cols; col++) { + uint32_t var = col_to_var[col]; + if (var_has_resp_row[var]) { + uint32_t num_ones = 0; + uint32_t found_row = var_Undef; + for(uint32_t row = 0; row < num_rows; row++) { + if (mat[row][col]) { + num_ones++; + found_row = row; + } + } + if (num_ones == 0) { + cout + << "mat[" << matrix_no << "] " + << "WARNING: Tracked col " << col + << " var: " << var+1 + << " has 0 rows' bit set to 1..." + << endl; + } + if (num_ones > 1) { + cout + << "mat[" << matrix_no << "] " + << "ERROR: Tracked col " << col + << " var: " << var+1 + << " has " << num_ones << " rows' bit set to 1!!" + << endl; + assert(num_ones <= 1); + } + if (num_ones == 1) { + if (row_resp_for_var[found_row] != var_Undef) { + cout << "ERROR One row can only be responsible for one col" + << " but row " << found_row << " is responsible for" + << " var: " << row_resp_for_var[found_row]+1 + << " and var: " << var+1 + << endl; + assert(false); + } + row_resp_for_var[found_row] = var; + } + } + } +} + +void CMSat::EGaussian::check_invariants() +{ + if (!initialized) return; + check_tracked_cols_only_one_set(); + check_no_prop_or_unsat_rows(); + VERBOSE_PRINT("mat[" << matrix_no << "] " + << "Checked invariants. Dec level: " << solver->decisionLevel()); +} + +bool EGaussian::check_row_satisfied(const uint32_t row) +{ + bool ret = true; + bool fin = mat[row].rhs(); + for(uint32_t i = 0; i < num_cols; i++) { + if (mat[row][i]) { + uint32_t var = col_to_var[i]; + auto val = solver->value(var); + if (val == l_Undef) { + cout << "Var " << var+1 << " col: " << i << " is undef!" << endl; + ret = false; + } + fin ^= val == l_True; + } + } + return ret && fin == false; +} + +void EGaussian::check_cols_unset_vals() +{ + for(uint32_t i = 0; i < num_cols; i ++) { + uint32_t var = col_to_var[i]; + if (solver->value(var) == l_Undef) { + assert((*cols_unset)[i] == 1); + } else { + assert((*cols_unset)[i] == 0); + } + + if (solver->value(var) == l_True) { + assert((*cols_vals)[i] == 1); + } else { + assert((*cols_vals)[i] == 0); + } + } +} + +bool EGaussian::must_disable(GaussQData& gqd) +{ + assert(initialized); + gqd.engaus_disable_checks++; + if ((gqd.engaus_disable_checks & 0x3ff) == 0x3ff //only check once in a while + ) { + uint64_t egcalled = elim_called + find_truth_ret_satisfied_precheck+find_truth_called_propgause; + uint32_t limit = (double)egcalled*solver->conf.gaussconf.min_usefulness_cutoff; + uint32_t useful = find_truth_ret_prop+find_truth_ret_confl+elim_ret_prop+elim_ret_confl; + //cout << "CHECKING - limit: " << limit << " useful:" << useful << endl; + if (egcalled > 200 && useful < limit) { + if (solver->conf.verbosity) { + const double perc = + stats_line_percent(useful, egcalled); + cout << "c [g <" << matrix_no << "] Disabling GJ-elim in this round. " + " Usefulness was: " + << std::setprecision(4) << std::fixed << perc + << "%" + << std::setprecision(2) + << " over " << egcalled << " calls" + << endl; + } + return true; + } + } + + return false; +} + +void CMSat::EGaussian::move_back_xor_clauses() +{ + for(const auto& x: xorclauses) { + TBUDDY_DO(assert(x.bdd == NULL && "Should have finalized matrix first")); + solver->xorclauses.push_back(std::move(x)); + } +} + +#ifdef USE_TBUDDY +void CMSat::EGaussian::finalize_frat() +{ + assert(solver->frat->enabled()); + *solver->frat << __PRETTY_FUNCTION__ << " start\n"; + solver->frat->flush(); + delete unsat_bdd; + + // clean frat_ids + auto todel = ilist_new(frat_ids.size()); + ilist_resize(todel, frat_ids.size()); + uint32_t i = 0; + for(auto const& bdd_cl: frat_ids) { + VERBOSE_PRINT("calling tbuddy to delete clause ID " << bdd_cl.ID); + todel[i] = bdd_cl.ID; + i++; + } + delete_clauses(todel); + + for(auto const& bdd_cl: frat_ids) ilist_free(bdd_cl.cl); + frat_ids.clear(); + ilist_free(todel); + + // clean xor_reasons + ilist todel1 = ilist_new(xor_reasons.size()); + ilist_resize(todel1, xor_reasons.size()); + uint32_t at = 0; + for(auto const& x: xor_reasons) if (x.ID != 0) { + VERBOSE_PRINT("calling tbuddy to delete clause ID " << x.ID); + delete x.constr; + todel1[at++] = x.ID; + } + ilist_resize(todel1, at); + delete_clauses(todel1); + ilist_free(todel1); + + // clean BDDs in xorclauses + for(auto& x2: xorclauses) { + delete x2.bdd; + x2.bdd = NULL; + } + + *solver->frat << __PRETTY_FUNCTION__ << " end\n"; +} +#endif diff --git a/cryptominisat/cppsrc/src/gaussian.h b/cryptominisat/cppsrc/src/gaussian.h new file mode 100644 index 00000000..fafa2103 --- /dev/null +++ b/cryptominisat/cppsrc/src/gaussian.h @@ -0,0 +1,260 @@ +/****************************************** +Copyright (c) 2012 Cheng-Shen Han +Copyright (c) 2012 Jie-Hong Roland Jiang +Copyright (C) 2009-2020 Authors of CryptoMiniSat, see AUTHORS file + +For more information, see " When Boolean Satisfiability Meets Gaussian +Elimination in a Simplex Way." by Cheng-Shen Han and Jie-Hong Roland Jiang +in CAV (Computer Aided Verification), 2012: 410-426 + + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. +***********************************************/ + +#ifndef ENHANCEGAUSSIAN_H +#define ENHANCEGAUSSIAN_H + +#include +#include +#include +#include + +#include "solvertypes.h" +#include "packedmatrix.h" +#include "bitarray.h" +#include "propby.h" +#include "xor.h" +#include "gausswatched.h" +#include "gqueuedata.h" + +//#define VERBOSE_DEBUG +//#define DEBUG_GAUSS + +using std::string; +using std::pair; +using std::vector; + +namespace CMSat { + +class Solver; + +struct XorReason +{ + bool must_recalc = true; + Lit propagated = lit_Undef; + int32_t ID = 0; + vector reason; + #ifdef USE_TBUDDY + tbdd::xor_constraint* constr = NULL; + ilist list = NULL; + #endif +}; + +class EGaussian { + public: + EGaussian( + Solver* solver, + const uint32_t matrix_no, + const vector& xorclauses + ); + ~EGaussian(); + bool is_initialized() const; + + ///returns FALSE in case of conflict + bool find_truths( + GaussWatched*& i, + GaussWatched*& j, + const uint32_t var, + const uint32_t row_n, + GaussQData& gqd + ); + + vector* get_reason(const uint32_t row, int32_t& out_ID); + + // when basic variable is touched , eliminate one col + void eliminate_col( + uint32_t p, + GaussQData& gqd + ); + void canceling(); + bool full_init(bool& created); + void update_cols_vals_set(bool force = false); + void print_matrix_stats(uint32_t verbosity); + bool must_disable(GaussQData& gqd); + void check_invariants(); + void update_matrix_no(uint32_t n); + void check_watchlist_sanity(); + uint32_t get_matrix_no(); + void finalize_frat(); + void move_back_xor_clauses(); + + vector xorclauses; + + private: + Solver* solver; // orignal sat solver + + //Cleanup + void clear_gwatches(const uint32_t var); + void delete_gauss_watch_this_matrix(); + void delete_gausswatch(const uint32_t row_n); + + //Invariant checks, debug + void check_no_prop_or_unsat_rows(); + void check_tracked_cols_only_one_set(); + bool check_row_satisfied(const uint32_t row); + void print_gwatches(const uint32_t var) const; + void check_row_not_in_watch( + const uint32_t v, const uint32_t row_num) const; + + //Reason generation + vector xor_reasons; + vector tmp_clause; + uint32_t get_max_level(const GaussQData& gqd, const uint32_t row_n); + + //Initialisation + void eliminate(); + void fill_matrix(); + void select_columnorder(); + gret init_adjust_matrix(); // adjust matrix, include watch, check row is zero, etc. + double get_density(); + + //Helper functions + void prop_lit( + const GaussQData& gqd, const uint32_t row_i, const Lit ret_lit_prop); + + #ifdef USE_TBUDDY + struct BDDCl { + ilist cl; + int32_t ID; + }; + void xor_in_bdd(const uint32_t a, const uint32_t b); + tbdd::xor_constraint* bdd_create(const uint32_t row_n, const uint32_t expected_size); + ilist one_len_ilist = NULL; + ilist ilist_tmp = NULL; + void create_unit_bdd_reason(const uint32_t row_n); + vector frat_ids; + tbdd::xor_constraint* unsat_bdd = NULL; //set if UNSAT is from GJ + #endif + + + /////////////// + // stats + /////////////// + uint64_t find_truth_ret_satisfied_precheck = 0; + uint64_t find_truth_called_propgause = 0; + uint64_t find_truth_ret_fnewwatch = 0; + uint64_t find_truth_ret_confl = 0; + uint64_t find_truth_ret_satisfied = 0; + uint64_t find_truth_ret_prop = 0; + + uint64_t elim_called = 0; + uint64_t elim_xored_rows = 0; + uint64_t elim_called_propgause = 0; + uint64_t elim_ret_prop = 0; + uint64_t elim_ret_confl = 0; + uint64_t elim_ret_satisfied = 0; + uint64_t elim_ret_fnewwatch = 0; + double before_init_density = 0; + double after_init_density = 0; + + /////////////// + // Internal data + /////////////// + uint32_t matrix_no; + bool initialized = false; + bool cancelled_since_val_update = true; + uint32_t last_val_update = 0; + + //Is the clause at this ROW satisfied already? + //satisfied_xors[decision_level][row] tells me that + vector satisfied_xors; + + // Someone is responsible for this column if TRUE + ///we always WATCH this variable + vector var_has_resp_row; + + ///row_to_var_non_resp[ROW] gives VAR it's NOT responsible for + ///we always WATCH this variable + vector row_to_var_non_resp; + + + PackedMatrix mat; + vector> bdd_matrix; + vector var_to_col; ///var->col mapping. Index with VAR + vector col_to_var; ///col->var mapping. Index with COL + uint32_t num_rows = 0; + uint32_t num_cols = 0; + + //quick lookup + PackedRow *cols_vals = NULL; + PackedRow *cols_unset = NULL; + PackedRow *tmp_col = NULL; + PackedRow *tmp_col2 = NULL; + void update_cols_vals_set(const Lit lit1); + + //Data to free (with delete[] x) + vector tofree; + + + /////////////// + // Debug + /////////////// + void print_matrix(); + void check_cols_unset_vals(); +}; + +inline void EGaussian::canceling() { + cancelled_since_val_update = true; + + //TODO this is an overstatement, coudl be improved + memset(satisfied_xors.data(), 0, satisfied_xors.size()); +} + +inline double EGaussian::get_density() +{ + if (num_rows*num_cols == 0) { + return 0; + } + + uint32_t pop = 0; + for (const auto& row: mat) { + pop += row.popcnt(); + } + return (double)pop/(double)(num_rows*num_cols); +} + +inline void EGaussian::update_matrix_no(uint32_t n) +{ + matrix_no = n; +} + +inline uint32_t EGaussian::get_matrix_no() +{ + return matrix_no; +} + +inline bool EGaussian::is_initialized() const +{ + return initialized; +} + + +} + +#endif //ENHANCEGAUSSIAN_H diff --git a/cryptominisat/cppsrc/src/gausswatched.h b/cryptominisat/cppsrc/src/gausswatched.h new file mode 100644 index 00000000..08b33ca2 --- /dev/null +++ b/cryptominisat/cppsrc/src/gausswatched.h @@ -0,0 +1,56 @@ +/****************************************** +Copyright (c) 2012 Cheng-Shen Han +Copyright (c) 2012 Jie-Hong Roland Jiang +Copyright (C) 2009-2020 Authors of CryptoMiniSat, see AUTHORS file + +For more information, see " When Boolean Satisfiability Meets Gaussian +Elimination in a Simplex Way." by Cheng-Shen Han and Jie-Hong Roland Jiang +in CAV (Computer Aided Verification), 2012: 410-426 + + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. +***********************************************/ + +#ifndef GAUSSWATCHED_H +#define GAUSSWATCHED_H + +namespace CMSat { + struct GaussWatched{ + GaussWatched(uint32_t r ,uint32_t m): + row_n(r) , matrix_num(m) + {} + + uint32_t row_n; // watch row + uint32_t matrix_num; // watch matrix + + bool operator<(const GaussWatched& other) const { + if (matrix_num < other.matrix_num) { + return true; + } + + if (matrix_num > other.matrix_num) { + return false; + } + + return row_n < other.row_n; + } + }; +} + +#endif //GAUSSWATCHED_H diff --git a/cryptominisat/cppsrc/src/get_clause_query.cpp b/cryptominisat/cppsrc/src/get_clause_query.cpp new file mode 100644 index 00000000..a07a2c47 --- /dev/null +++ b/cryptominisat/cppsrc/src/get_clause_query.cpp @@ -0,0 +1,366 @@ +/****************************************** +Copyright (C) 2009-2020 Authors of CryptoMiniSat, see AUTHORS file + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. +***********************************************/ + +#include + +#include "get_clause_query.h" +#include "solver.h" +#include "occsimplifier.h" +#include "varreplacer.h" + +using namespace CMSat; + +GetClauseQuery::GetClauseQuery(Solver* _solver) : + solver(_solver) +{} + +void GetClauseQuery::start_getting_small_clauses( + const uint32_t _max_len, const uint32_t _max_glue, bool _red, + bool _bva_vars, bool _simplified) +{ + if (!outer_to_without_bva_map.empty()) { + std::cerr << "ERROR: You forgot to call end_getting_small_clauses() last time!" <::max()); + assert(watched_at == numeric_limits::max()); + assert(watched_at_sub == numeric_limits::max()); + assert(max_len >= 2); + + if (!red) { + //We'd need to implement getting elimed clauses + assert(solver->occsimplifier->get_num_elimed_vars() == 0); + } + red = _red; + at = 0; + at_lev[0] = 0; + at_lev[1] = 0; + at_lev[2] = 0; + watched_at = 0; + watched_at_sub = 0; + max_len = _max_len; + max_glue = _max_glue; + varreplace_at = 0; + units_at = 0; + comp_at = 0; + comp_at_sum = 0; + elimed_at = 0; + elimed_at2 = 0; + undef_at = 0; + xor_detached_at = 0; + bva_vars = _bva_vars; + simplified = _simplified; + if (simplified) { + bva_vars = true; + if (solver->get_num_bva_vars() != 0) { + cout << "ERRROR! You must not have BVA variables for simplified CNF getting" << endl; + exit(-1); + } + release_assert(solver->get_num_bva_vars() == 0); + } + if (bva_vars) { + outer_to_without_bva_map = solver->build_outer_to_without_bva_map_extended(); + } else { + outer_to_without_bva_map = solver->build_outer_to_without_bva_map(); + } + tmp_cl.clear(); +} + +vector GetClauseQuery::translate_sampl_set( + const vector& sampl_set) +{ + if (simplified) { + assert(solver->get_num_bva_vars() == 0); + vector ret; + for(uint32_t v: sampl_set) { + v = solver->varReplacer->get_var_replaced_with_outer(v); + v = solver->map_outer_to_inter(v); + if (solver->value(v) != l_Undef) continue; + assert(solver->varData[v].removed == Removed::none); + if (!solver->seen[v]) { + ret.push_back(v); + solver->seen[v] = 1; + } + } + for(uint32_t v: sampl_set) { + v = solver->varReplacer->get_var_replaced_with_outer(v); + v = solver->map_outer_to_inter(v); + solver->seen[v] = 0; + } + return ret; + } else { + return sampl_set; + } +} + +void GetClauseQuery::get_all_irred_clauses(vector& out) +{ + start_getting_small_clauses( + numeric_limits::max(), + numeric_limits::max(), + false); + bool ret = get_next_small_clause(out, true); + assert(ret == false); //we must get all clauses, so nothing left + end_getting_small_clauses(); +} + +bool GetClauseQuery::get_next_small_clause(vector& out, bool all_in_one_go) +{ + out.clear(); + if (!solver->okay()) { + if (at == 0) { + at++; + if (!all_in_one_go) { + return true; + } else { + out.push_back(lit_Undef); + } + } + return false; + } + + //Adding units + while (!red &&( + (!simplified && units_at < solver->nVarsOuter()) || + (simplified && units_at < solver->nVars())) + ) { + const uint32_t v = units_at; + if (solver->value(v) != l_Undef) { + tmp_cl.clear(); + tmp_cl.push_back(Lit(v, solver->value(v) == l_False)); + if (!simplified) { + tmp_cl = solver->clause_outer_numbered(tmp_cl); + } + if (bva_vars || all_vars_outside(tmp_cl)) { + map_without_bva(tmp_cl); + out.insert(out.end(), tmp_cl.begin(), tmp_cl.end()); + if (!all_in_one_go) { + units_at++; + return true; + } else { + out.push_back(lit_Undef); + } + } + } + units_at++; + } + + //Adding binaries + while(watched_at < solver->nVars()*2) { + Lit l = Lit::toLit(watched_at); + watch_subarray_const ws = solver->watches[l]; + while(watched_at_sub < ws.size()) { + const Watched& w = ws[watched_at_sub]; + if (w.isBin() && + w.lit2() < l && + (w.red() == red) + ) { + tmp_cl.clear(); + tmp_cl.push_back(l); + tmp_cl.push_back(w.lit2()); + if (!simplified) { + tmp_cl = solver->clause_outer_numbered(tmp_cl); + } + if (bva_vars || all_vars_outside(tmp_cl)) { + map_without_bva(tmp_cl); + out.insert(out.end(), tmp_cl.begin(), tmp_cl.end()); + if (!all_in_one_go) { + watched_at_sub++; + return true; + } else { + out.push_back(lit_Undef); + } + } + } + watched_at_sub++; + } + watched_at++; + watched_at_sub = 0; + } + + //Replaced variables + while (varreplace_at < solver->nVarsOuter()*2 && !simplified) { + Lit l = Lit::toLit(varreplace_at); + Lit l2 = solver->varReplacer->get_lit_replaced_with_outer(l); + if (l2 != l) { + tmp_cl.clear(); + tmp_cl.push_back(l); + tmp_cl.push_back(~l2); + if (bva_vars || all_vars_outside(tmp_cl)) { + map_without_bva(tmp_cl); + out.insert(out.end(), tmp_cl.begin(), tmp_cl.end()); + if (!all_in_one_go) { + varreplace_at++; + return true; + } else { + out.push_back(lit_Undef); + } + } + } + varreplace_at++; + } + + if (red) { + for(uint32_t lev = 0; lev < 3; lev++) + while(at_lev[lev] < solver->longRedCls[lev].size()) { + const ClOffset offs = solver->longRedCls[lev][at_lev[lev]]; + const Clause* cl = solver->cl_alloc.ptr(offs); + if (cl->size() <= max_len + && cl->stats.glue <= max_glue + ) { + if (!simplified) tmp_cl = solver->clause_outer_numbered(*cl); + else {tmp_cl.clear(); for(const auto& l: *cl) tmp_cl.push_back(l);} + if (bva_vars || all_vars_outside(tmp_cl)) { + map_without_bva(tmp_cl); + out.insert(out.end(), tmp_cl.begin(), tmp_cl.end()); + if (!all_in_one_go) { + at_lev[lev]++; + return true; + } else { + out.push_back(lit_Undef); + } + } + } + at_lev[lev]++; + } + } else { + //Irred long clauses + while(at < solver->longIrredCls.size()) { + const ClOffset offs = solver->longIrredCls[at]; + const Clause* cl = solver->cl_alloc.ptr(offs); + if (cl->size() <= max_len) { + if (!simplified) { + tmp_cl = solver->clause_outer_numbered(*cl); + } else { + tmp_cl.clear(); + for(const auto& l: *cl) { + tmp_cl.push_back(l); + } + } + if (bva_vars || all_vars_outside(tmp_cl)) { + map_without_bva(tmp_cl); + out.insert(out.end(), tmp_cl.begin(), tmp_cl.end()); + if (!all_in_one_go) { + at++; + return true; + } else { + out.push_back(lit_Undef); + } + } + } + at++; + } + + //Detached XOR clauses + if (solver->detached_xor_clauses) { + while(xor_detached_at < solver->detached_xor_repr_cls.size()) { + Clause* cl = solver->cl_alloc.ptr( + solver->detached_xor_repr_cls[xor_detached_at]); + assert(cl->_xor_is_detached); + assert(cl->used_in_xor() && cl->used_in_xor_full()); + if (cl->size() <= max_len) { + if (!simplified) { + tmp_cl = solver->clause_outer_numbered(*cl); + } else { + tmp_cl.clear(); + for(const auto& l: *cl) { + tmp_cl.push_back(l); + } + } + if (bva_vars || all_vars_outside(tmp_cl)) { + map_without_bva(tmp_cl); + out.insert(out.end(), tmp_cl.begin(), tmp_cl.end()); + if (!all_in_one_go) { + xor_detached_at++; + return true; + } else { + out.push_back(lit_Undef); + } + } + } + xor_detached_at++; + } + } + + //Elimed clauses (already in OUTER notation) + bool ret = true; + while (ret && solver->occsimplifier && !simplified) { + ret = solver->occsimplifier->get_elimed_clause_at(elimed_at, elimed_at2, tmp_cl); + if (ret && all_vars_outside(tmp_cl)) { + map_without_bva(tmp_cl); + out.insert(out.end(), tmp_cl.begin(), tmp_cl.end()); + if (!all_in_one_go) { + return true; + } else { + out.push_back(lit_Undef); + } + } + } + + //Clauses that have a variable like a V ~a which means the variable MUST take a value + //These are already in OUTER notation + while (undef_at < solver->undef_must_set_vars.size() && !simplified) { + uint32_t v = undef_at; + if (solver->undef_must_set_vars[v]) { + tmp_cl.clear(); + tmp_cl.push_back(Lit(v, false)); + tmp_cl.push_back(Lit(v, true)); + if (bva_vars || all_vars_outside(tmp_cl)) { + map_without_bva(tmp_cl); + out.insert(out.end(), tmp_cl.begin(), tmp_cl.end()); + if (!all_in_one_go) { + undef_at++; + return true; + } else { + out.push_back(lit_Undef); + } + } + } + undef_at++; + } + + } + return false; +} + +void GetClauseQuery::end_getting_small_clauses() +{ + outer_to_without_bva_map.clear(); + outer_to_without_bva_map.shrink_to_fit(); +} + +bool GetClauseQuery::all_vars_outside(const vector& cl) const +{ + for(const auto& l: cl) { + if (solver->varData[solver->map_outer_to_inter(l.var())].is_bva) + return false; + } + return true; +} + +void GetClauseQuery::map_without_bva(vector& cl) +{ + for(auto& l: cl) { + l = Lit(outer_to_without_bva_map[l.var()], l.sign()); + } +} diff --git a/cryptominisat/cppsrc/src/get_clause_query.h b/cryptominisat/cppsrc/src/get_clause_query.h new file mode 100644 index 00000000..59a363f2 --- /dev/null +++ b/cryptominisat/cppsrc/src/get_clause_query.h @@ -0,0 +1,77 @@ +/****************************************** +Copyright (C) 2009-2020 Authors of CryptoMiniSat, see AUTHORS file + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. +***********************************************/ + +#pragma once + +#include "constants.h" +#include +#include +#include +#include + +#include "constants.h" +#include "solvertypes.h" + +using std::numeric_limits; + +namespace CMSat { + +class Solver; + +class GetClauseQuery { +public: + GetClauseQuery(Solver* solver); + void start_getting_small_clauses( + uint32_t max_len, uint32_t max_glue, bool red = true, + bool bva_vars = false, bool simplified = false); + bool get_next_small_clause(std::vector& out, bool all_in_one_go = false); + void end_getting_small_clauses(); + void get_all_irred_clauses(vector& out); + vector translate_sampl_set(const vector& sampl_set); + +private: + Solver* solver; + + bool red = true; + uint32_t max_len = numeric_limits::max(); + uint32_t max_glue = numeric_limits::max(); + uint32_t at = numeric_limits::max(); + uint32_t at_lev[3]; + uint32_t varreplace_at = numeric_limits::max(); + uint32_t units_at = numeric_limits::max(); + uint32_t watched_at = numeric_limits::max(); + uint32_t watched_at_sub = numeric_limits::max(); + uint32_t comp_at = numeric_limits::max(); + uint32_t comp_at_sum = numeric_limits::max(); + uint32_t elimed_at = numeric_limits::max(); + uint32_t elimed_at2 = numeric_limits::max(); + uint32_t xor_detached_at = numeric_limits::max(); + uint32_t undef_at = numeric_limits::max(); + bool simplified = false; + bool bva_vars = false; + + vector outer_to_without_bva_map; + bool all_vars_outside(const vector& cl) const; + void map_without_bva(vector& cl); + vector tmp_cl; +}; +} diff --git a/cryptominisat/cppsrc/src/gqueuedata.h b/cryptominisat/cppsrc/src/gqueuedata.h new file mode 100644 index 00000000..bc1270c4 --- /dev/null +++ b/cryptominisat/cppsrc/src/gqueuedata.h @@ -0,0 +1,51 @@ +/****************************************** +Copyright (C) 2009-2020 Authors of CryptoMiniSat, see AUTHORS file + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. +***********************************************/ + +#ifndef GQUEUEDATA_H__ +#define GQUEUEDATA_H__ + +namespace CMSat { + +struct GaussQData { + bool do_eliminate; // we do elimination when basic variable is invoked + uint32_t new_resp_var; // do elimination variable + uint32_t new_resp_row ; // do elimination row + PropBy confl; // returning conflict + gauss_res ret; //final return value to Searcher + uint32_t currLevel; //level at which the variable was decided on + + + uint32_t num_props = 0; // total gauss propogation time for DPLL + uint32_t num_conflicts = 0; // total gauss conflict time for DPLL + uint32_t engaus_disable_checks = 0; + bool disabled = false; // decide to do gaussian elimination + + void reset() + { + do_eliminate = false; + ret = gauss_res::none; + } +}; + +} + +#endif diff --git a/cryptominisat/cppsrc/src/hasher.h b/cryptominisat/cppsrc/src/hasher.h new file mode 100644 index 00000000..5ef95f79 --- /dev/null +++ b/cryptominisat/cppsrc/src/hasher.h @@ -0,0 +1,61 @@ +/****************************************** +Copyright (C) 2009-2020 Authors of CryptoMiniSat, see AUTHORS file + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. +***********************************************/ + +#include "solvertypes.h" + +namespace CMSat +{ + +// Use 1G extra for clause re-learning bitmap. +static const uint32_t hash_bits = 28; +static const uint32_t hash_size = 1 << hash_bits; +static const uint32_t hash_mask = hash_size - 1; + +static inline uint64_t rotl(uint64_t x, uint64_t n) +{ + return (x << n) | (x >> (8 * sizeof(x) - n)); +} + +#define HASH_MULT_CONST 0x61C8864680B583EBULL + +static inline uint64_t clause_hash(vector &clause) +{ + //assert((sizeof(Lit) * clause.size()) % sizeof(unsigned long) == 0); + + uint64_t x = 0; + uint64_t y = 0; + + for (const Lit l: clause) { + x = x ^ l.toInt(); + y = x ^ y; + x = rotl(x, 12); + x = x + y; + y = rotl(y, 45); + y = 9 * y; + } + + y = y ^ (x * HASH_MULT_CONST); + y = y * HASH_MULT_CONST; + return y; +} + +} diff --git a/cryptominisat/cppsrc/src/heap.h b/cryptominisat/cppsrc/src/heap.h new file mode 100644 index 00000000..9176106a --- /dev/null +++ b/cryptominisat/cppsrc/src/heap.h @@ -0,0 +1,228 @@ +/******************************************************************************************[Heap.h] +Copyright (c) 2003-2006, Niklas Een, Niklas Sorensson +Copyright (c) 2007-2010, Niklas Sorensson + +Permission is hereby granted, free of charge, to any person obtaining a copy of this software and +associated documentation files (the "Software"), to deal in the Software without restriction, +including without limitation the rights to use, copy, modify, merge, publish, distribute, +sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all copies or +substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT +NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, +DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT +OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +**************************************************************************************************/ + +#ifndef Glucose_Heap_h +#define Glucose_Heap_h + +#include +#include "Vec.h" + +namespace CMSat { + +//================================================================================================= +// A heap implementation with support for decrease/increase key. + + +template +class Heap { + Comp lt; // The heap is a minimum-heap with respect to this comparator + vec heap; // Heap of integers + vec indices; // Each integers position (index) in the Heap + + // Index "traversal" functions + static inline int left (int i) + { + return i * 2 + 1; + } + static inline int right (int i) + { + return (i + 1) * 2; + } + static inline int parent(int i) + { + return (i - 1) >> 1; + } + + + void percolateUp(int i) + { + int x = heap[i]; + int p = parent(i); + + while (i != 0 && lt(x, heap[p])) { + heap[i] = heap[p]; + indices[heap[p]] = i; + i = p; + p = parent(p); + } + heap [i] = x; + indices[x] = i; + } + + + void percolateDown(int i) + { + int x = heap[i]; + while (left(i) < (int)heap.size()) { + int child = right(i) < (int)heap.size() && lt(heap[right(i)], heap[left(i)]) ? right(i) : left(i); + if (!lt(heap[child], x)) { + break; + } + heap[i] = heap[child]; + indices[heap[i]] = i; + i = child; + } + heap [i] = x; + indices[x] = i; + } + + +public: + Heap(const Comp& c) : lt(c) { } + + void print_heap() { + std::cout << "heap:"; + for(auto x: heap) { + std::cout << x << " "; + } + std::cout << std::endl; + + std::cout << "ind:"; + for(auto x: indices) { + std::cout << x << " "; + } + std::cout << std::endl; + } + + uint32_t size () const + { + return heap.size(); + } + bool empty () const + { + return heap.size() == 0; + } + bool inHeap (int n) const + { + return n < (int)indices.size() && indices[n] >= 0; + } + int operator[](int index) const + { + assert(index < (int)heap.size()); + return heap[index]; + } + + void decrease (int n) + { + assert(inHeap(n)); + percolateUp (indices[n]); + } + void increase (int n) + { + assert(inHeap(n)); + percolateDown(indices[n]); + } + + + // Safe variant of insert/decrease/increase: + void update(int n) + { + if (!inHeap(n)) { + insert(n); + } else { + percolateUp(indices[n]); + percolateDown(indices[n]); + } + } + + + void insert(int n) + { + indices.growTo(n + 1, -1); + assert(!inHeap(n)); + + indices[n] = heap.size(); + heap.push(n); + percolateUp(indices[n]); + } + + + int removeMin() + { + int x = heap[0]; + heap[0] = heap.last(); + indices[heap[0]] = 0; + indices[x] = -1; + heap.pop(); + if (heap.size() > 1) { + percolateDown(0); + } + return x; + } + + + // Rebuild the heap from scratch, using the elements in 'ns': + template + void build(const T& ns) + { + for (int i = 0; i < (int)ns.size(); i++) { + indices.growTo(ns[i]+1, -1); + } + + for (int i = 0; i < (int)heap.size(); i++) { + indices[heap[i]] = -1; + } + heap.clear(); + + for (uint32_t i = 0; i < ns.size(); i++) { + indices[ns[i]] = i; + heap.push(ns[i]); + } + + for (int i = (int)heap.size() / 2 - 1; i >= 0; i--) { + percolateDown(i); + } + } + + void clear(bool dealloc = false) + { + for (int i = 0; i < (int)heap.size(); i++) { + indices[heap[i]] = -1; + } + heap.clear(dealloc); + } + + size_t mem_used() const + { + size_t mem = 0; + mem += heap.capacity()*sizeof(uint32_t); + mem += indices.capacity()*sizeof(uint32_t); + return mem; + } + + bool heap_property (uint32_t i) const { + return i >= heap.size() + || ( (i == 0 || !lt(heap[i], heap[parent(i)])) + && heap_property( left(i) ) + && heap_property( right(i) ) + ); + } + + bool heap_property() const { + return heap_property(0); + } + +}; + + +//================================================================================================= +} + +#endif diff --git a/cryptominisat/cppsrc/src/hyperengine.cpp b/cryptominisat/cppsrc/src/hyperengine.cpp new file mode 100644 index 00000000..4065eca8 --- /dev/null +++ b/cryptominisat/cppsrc/src/hyperengine.cpp @@ -0,0 +1,684 @@ +/****************************************** +Copyright (C) 2009-2020 Authors of CryptoMiniSat, see AUTHORS file + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. +***********************************************/ + +#include "hyperengine.h" +#include "clauseallocator.h" + +using namespace CMSat; + +HyperEngine::HyperEngine( + const SolverConf *_conf + , Solver* _solver + , std::atomic* _must_interrupt_inter) : + PropEngine(_conf, _solver, _must_interrupt_inter) +{ +} + +HyperEngine::~HyperEngine() = default; + +Lit HyperEngine::propagate_bfs(const uint64_t timeout) +{ + timedOutPropagateFull = false; + propStats.otfHyperPropCalled++; + #ifdef VERBOSE_DEBUG_FULLPROP + cout << "Prop full BFS started" << endl; + #endif + + PropBy confl; + assert(uselessBin.empty()); + + //The toplevel decision has to be set specifically + //If we came here as part of a backtrack to decision level 1, then + //this is already set, and there is no need to set it + if (trail.size() - trail_lim.back() == 1) { + //Set up root node + Lit root = trail[qhead].lit; + varData[root.var()].reason = PropBy(~lit_Undef, false, false, false, 0); + } + + uint32_t nlBinQHead = qhead; + uint32_t lBinQHead = qhead; + + needToAddBinClause.clear(); + PropResult ret = PROP_NOTHING; + start: + + //Early-abort if too much time was used (from prober) + if (propStats.otfHyperTime + propStats.bogoProps > timeout) { + timedOutPropagateFull = true; + return lit_Undef; + } + + //Propagate binary irred + while (nlBinQHead < trail.size()) { + const Lit p = trail[nlBinQHead++].lit; + watch_subarray_const ws = watches[~p]; + propStats.bogoProps += 1; + for(const Watched *k = ws.begin(), *end = ws.end() + ; k != end + ; k++ + ) { + //If something other than irred binary, skip + if (!k->isBin() || k->red()) continue; + ret = prop_bin_with_ancestor_info(p, k, confl); + if (ret == PROP_FAIL) + return analyzeFail(confl); + + } + propStats.bogoProps += ws.size()*4; + } + + //Propagate binary redundant + ret = PROP_NOTHING; + while (lBinQHead < trail.size()) { + const Lit p = trail[lBinQHead].lit; + watch_subarray_const ws = watches[~p]; + propStats.bogoProps += 1; + size_t done = 0; + + for(const Watched *k = ws.begin(), *end = ws.end(); k != end; k++, done++) { + + //If something other than redundant binary, skip + if (!k->isBin() || !k->red()) + continue; + + ret = prop_bin_with_ancestor_info(p, k, confl); + if (ret == PROP_FAIL) { + return analyzeFail(confl); + } else if (ret == PROP_SOMETHING) { + propStats.bogoProps += done*4; + goto start; + } else { + assert(ret == PROP_NOTHING); + } + } + lBinQHead++; + propStats.bogoProps += done*4; + } + + ret = PROP_NOTHING; + while (qhead < trail.size()) { + const Lit p = trail[qhead].lit; + watch_subarray ws = watches[~p]; + propStats.bogoProps += 1; + + Watched* i = ws.begin(); + Watched* j = ws.begin(); + Watched* end = ws.end(); + for(; i != end; i++) { + if (i->isBin()) { + *j++ = *i; + continue; + } + + if (i->isClause()) { + ret = prop_normal_cl_with_ancestor_info(i, j, p, confl); + if (ret == PROP_SOMETHING || ret == PROP_FAIL) { + i++; + break; + } else { + assert(ret == PROP_NOTHING); + continue; + } + } + } + propStats.bogoProps += ws.size()*4; + while(i != end) + *j++ = *i++; + ws.shrink_(end-j); + + if (ret == PROP_FAIL) { + return analyzeFail(confl); + } else if (ret == PROP_SOMETHING) { + propStats.bogoProps += ws.size()*4; + goto start; + } + + qhead++; + propStats.bogoProps += ws.size()*4; + } + + return lit_Undef; +} + +//Add binary clause to deepest common ancestor +void HyperEngine::add_hyper_bin(const Lit p) +{ + propStats.otfHyperTime += 2; + + Lit deepestAncestor = lit_Undef; + bool hyperBinNotAdded = true; + const int32_t ID = ++clauseID; + if (currAncestors.size() > 1) { + deepestAncestor = deepest_common_ancestor(); + + #ifdef VERBOSE_DEBUG_FULLPROP + cout << "Adding hyper-bin clause: " << p << " , " + << ~deepestAncestor << " ID: " << ID << endl; + #endif + needToAddBinClause.insert(BinaryClause(p, ~deepestAncestor, true, ID)); + + hyperBinNotAdded = false; + } else { + //0-level propagation is NEVER made by propFull + assert(currAncestors.size() > 0); + + #ifdef VERBOSE_DEBUG_FULLPROP + cout + << "Not adding hyper-bin because only ONE lit is not set at" + << "level 0 in long clause, but that long clause needs to be cleaned" + << endl; + #endif + deepestAncestor = currAncestors[0]; + hyperBinNotAdded = true; + } + + enqueue_with_acestor_info(p, deepestAncestor, true, ID); + varData[p.var()].reason.setHyperbin(true); + varData[p.var()].reason.setHyperbinNotAdded(hyperBinNotAdded); +} + +/** +We can try both ways: either binary clause can be removed. +Try to remove one, then the other +Return which one is to be removed +*/ +Lit HyperEngine::remove_which_bin_due_to_trans_red( + Lit conflict + , Lit thisAncestor + , bool thisStepRed +) { + propStats.otfHyperTime += 1; + const PropBy& data = varData[conflict.var()].reason; + + bool onlyIrred = !data.isRedStep(); + Lit lookingForAncestor = data.getAncestor(); + + if (thisAncestor == lit_Undef || lookingForAncestor == lit_Undef) + return lit_Undef; + + propStats.otfHyperTime += 1; + bool second_is_deeper = false; + bool ambivalent = true; + if (use_depth_trick) { + ambivalent = depth[thisAncestor.var()] == depth[lookingForAncestor.var()]; + if (depth[thisAncestor.var()] < depth[lookingForAncestor.var()]) { + second_is_deeper = true; + } + } + #ifdef DEBUG_DEPTH + cout + << "1st: " << std::setw(6) << thisAncestor + << " depth: " << std::setw(4) << depth[thisAncestor.var()] + << " 2nd: " << std::setw(6) << lookingForAncestor + << " depth: " << std::setw(4) << depth[lookingForAncestor.var()] + ; + #endif + + + if ((ambivalent || !second_is_deeper) && + is_ancestor_of( + conflict + , thisAncestor + , thisStepRed + , onlyIrred + , lookingForAncestor + ) + ) { + #ifdef DEBUG_DEPTH + cout << " -- OK" << endl; + #endif + //assert(ambivalent || !second_is_deeper); + return thisAncestor; + } + + onlyIrred = !thisStepRed; + thisStepRed = data.isRedStep(); + std::swap(lookingForAncestor, thisAncestor); + if ((ambivalent || second_is_deeper) && + is_ancestor_of( + conflict + , thisAncestor + , thisStepRed + , onlyIrred + , lookingForAncestor + ) + ) { + #ifdef DEBUG_DEPTH + cout << " -- OK" << endl; + #endif + //assert(ambivalent || second_is_deeper); + return thisAncestor; + } + + #ifdef DEBUG_DEPTH + cout << " -- NOTK" << endl; + #endif + + return lit_Undef; +} + +/** +hop backwards from thisAncestor until: +1) we reach ancestor of 'conflict' -- at this point, we return TRUE +2) we reach an invalid point. Either root, or an invalid hop. We return FALSE. +*/ +bool HyperEngine::is_ancestor_of( + const Lit conflict + , Lit thisAncestor + , const bool thisStepRed + , const bool onlyIrred + , const Lit lookingForAncestor +) { + propStats.otfHyperTime += 1; + #ifdef VERBOSE_DEBUG_FULLPROP + cout << "is_ancestor_of." + << "conflict: " << conflict + << " thisAncestor: " << thisAncestor + << " thisStepRed: " << thisStepRed + << " onlyIrred: " << onlyIrred + << " lookingForAncestor: " << lookingForAncestor << endl; + #endif + + //Was propagated at level 0 -- clauseCleaner will remove the clause + if (lookingForAncestor == lit_Undef) + return false; + + if (lookingForAncestor == thisAncestor) { + #ifdef VERBOSE_DEBUG_FULLPROP + cout << "Last position inside prop queue is not saved during propFull" << endl + << "This may be the same exact binary clause -- not removing" << endl; + #endif + return false; + } + + #ifdef VERBOSE_DEBUG_FULLPROP + cout << "Looking for ancestor of " << conflict << " : " << lookingForAncestor << endl; + cout << "This step based on redundant cl? " << (thisStepRed ? "yes" : "false") << endl; + cout << "Only irred is acceptable?" << (onlyIrred ? "yes" : "no") << endl; + cout << "This step would be based on redundant cl?" << (thisStepRed ? "yes" : "no") << endl; + #endif + + if (onlyIrred && thisStepRed) { + #ifdef VERBOSE_DEBUG_FULLPROP + cout << "This step doesn't work -- is redundant but needs irred" << endl; + #endif + return false; + } + + //This is as low as we should search -- we cannot find what we are searchig for lower than this + const size_t bottom = depth[lookingForAncestor.var()]; + + while(thisAncestor != lit_Undef + && (!use_depth_trick || bottom <= depth[thisAncestor.var()]) + ) { + #ifdef VERBOSE_DEBUG_FULLPROP + cout << "Current acestor: " << thisAncestor + << " redundant step? " << varData[thisAncestor.var()].reason.isRedStep() + << endl; + #endif + + if (thisAncestor == conflict) { + #ifdef VERBOSE_DEBUG_FULLPROP + cout << "We are trying to step over the conflict." + << " That would create a loop." << endl; + #endif + return false; + } + + if (thisAncestor == lookingForAncestor) { + #ifdef VERBOSE_DEBUG_FULLPROP + cout << "Ancestor found" << endl; + #endif + return true; + } + + const PropBy& data = varData[thisAncestor.var()].reason; + if ((onlyIrred && data.isRedStep()) + || data.getHyperbinNotAdded() + ) { + #ifdef VERBOSE_DEBUG_FULLPROP + cout << "Wrong kind of hop would be needed" << endl; + #endif + return false; //reached would-be redundant hop (but this is irred) + } + + thisAncestor = data.getAncestor(); + propStats.otfHyperTime += 1; + } + + #ifdef VERBOSE_DEBUG_FULLPROP + cout << "Exit, reached root" << endl; + #endif + + return false; +} + +void HyperEngine::add_hyper_bin(const Lit p, const Clause& cl) +{ + assert(value(p.var()) == l_Undef); + + #ifdef VERBOSE_DEBUG_FULLPROP + cout << "Enqueing " << p + << " with ancestor clause: " << cl + << endl; + #endif + + currAncestors.clear(); + size_t i = 0; + for (Clause::const_iterator + it = cl.begin(), end = cl.end() + ; it != end + ; ++it, i++ + ) { + if (*it != p) { + assert(value(*it) == l_False); + if (varData[it->var()].level != 0) + currAncestors.push_back(~*it); + } + } + + add_hyper_bin(p); +} + +//Analyze why did we fail at decision level 1 +Lit HyperEngine::analyzeFail(const PropBy propBy) +{ + //Clear out the datastructs we will be usin + currAncestors.clear(); + + //First, we set the ancestors, based on the clause + //Each literal in the clause is an ancestor. So just 'push' them inside the + //'currAncestors' variable + switch(propBy.getType()) { + case binary_t: { + const Lit lit = ~propBy.lit2(); + if (varData[lit.var()].level != 0) + currAncestors.push_back(lit); + + if (varData[failBinLit.var()].level != 0) + currAncestors.push_back(~failBinLit); + + break; + } + + case clause_t: { + const uint32_t offset = propBy.get_offset(); + const Clause& cl = *cl_alloc.ptr(offset); + for(size_t i = 0; i < cl.size(); i++) { + if (varData[cl[i].var()].level != 0) + currAncestors.push_back(~cl[i]); + } + break; + } + + case xor_t: + case bnn_t: + case null_clause_t: + assert(false); + break; + } + + Lit foundLit = deepest_common_ancestor(); + + return foundLit; +} + +Lit HyperEngine::deepest_common_ancestor() +{ + //Then, we go back on each ancestor recursively, and exit on the first one + //that unifies ALL the previous ancestors. That is the lowest common ancestor + assert(toClear.empty()); + Lit foundLit = lit_Undef; + while(foundLit == lit_Undef) { + #ifdef VERBOSE_DEBUG_FULLPROP + cout << "LEVEL analyzeFail" << endl; + #endif + size_t num_lit_undef = 0; + for (vector::iterator + it = currAncestors.begin(), end = currAncestors.end() + ; it != end + ; ++it + ) { + propStats.otfHyperTime += 1; + + //We have reached the top of the graph, the other 'threads' that + //are still stepping back will find which literal is the lowest + //common ancestor + if (*it == lit_Undef) { + #ifdef VERBOSE_DEBUG_FULLPROP + cout << "seen lit_Undef" << endl; + #endif + num_lit_undef++; + assert(num_lit_undef != currAncestors.size()); + continue; + } + + //Increase path count + seen[it->toInt()]++; + + //Visited counter has to be cleared later, so add it to the + //to-be-cleared set + if (seen[it->toInt()] == 1) + toClear.push_back(*it); + + #ifdef VERBOSE_DEBUG_FULLPROP + cout << "seen " << *it << " : " << seen[it->toInt()] << endl; + #endif + + //Is this point where all the 'threads' that are stepping backwards + //reach each other? If so, we have found what we were looking for! + //We can exit, and return 'foundLit' + if (seen[it->toInt()] == currAncestors.size()) { + foundLit = *it; + break; + } + + //Update ancestor to its own ancestor, i.e. step up this 'thread' + *it = varData[it->var()].reason.getAncestor(); + } + } + #ifdef VERBOSE_DEBUG_FULLPROP + cout << "END" << endl; + #endif + assert(foundLit != lit_Undef); + + //Clear nodes we have visited + propStats.otfHyperTime += toClear.size()/2; + for(const Lit lit: toClear) { + seen[lit.toInt()] = 0; + } + toClear.clear(); + + return foundLit; +} + +void HyperEngine::remove_bin_clause(Lit lit, const int32_t ID) +{ + //The binary clause we should remove + const BinaryClause clauseToRemove( + ~varData[lit.var()].reason.getAncestor(), + lit, + varData[lit.var()].reason.isRedStep(), + ID); + + //We now remove the clause + //If it's hyper-bin, then we remove the to-be-added hyper-binary clause + //However, if the hyper-bin was never added because only 1 literal was unbound at level 0 (i.e. through + //clause cleaning, the clause would have been 2-long), then we don't do anything. + if (!varData[lit.var()].reason.getHyperbin()) { + #ifdef VERBOSE_DEBUG_FULLPROP + cout << "Normal removing clause " << clauseToRemove << endl; + #endif + propStats.otfHyperTime += 2; + uselessBin.insert(clauseToRemove); + } else if (!varData[lit.var()].reason.getHyperbinNotAdded()) { + #ifdef VERBOSE_DEBUG_FULLPROP + cout << "Removing hyper-bin clause " << clauseToRemove << endl; + #endif + propStats.otfHyperTime += needToAddBinClause.size()/4; + std::set::iterator it = needToAddBinClause.find(clauseToRemove); + + //In case this is called after a backtrack to decisionLevel 1 + //then in fact we might have already cleaned the + //'needToAddBinClause'. When called from probing, the IF below + //must ALWAYS be true + if (it != needToAddBinClause.end()) { + propStats.otfHyperTime += 2; + needToAddBinClause.erase(it); + } + //This will subsume the clause later, so don't remove it + } +} + +PropResult HyperEngine::prop_bin_with_ancestor_info( + const Lit p + , const Watched* k + , PropBy& confl +) { + const Lit lit = k->lit2(); + const lbool val = value(lit); + if (val == l_Undef) { + //Never propagated before + enqueue_with_acestor_info(lit, p, k->red(), k->get_ID()); + return PROP_SOMETHING; + + } else if (val == l_False) { + //Conflict + #ifdef VERBOSE_DEBUG_FULLPROP + cout << "Conflict from " << p << " , " << lit << endl; + #endif + + failBinLit = lit; + confl = PropBy(~p, k->red(), k->get_ID()); + return PROP_FAIL; + + } else if (varData[lit.var()].level != 0 && perform_transitive_reduction) { + //Propaged already + assert(val == l_True); + + #ifdef VERBOSE_DEBUG_FULLPROP + cout << "Lit " << p << " also wants to propagate " << lit << endl; + #endif + Lit remove = remove_which_bin_due_to_trans_red(lit, p, k->red()); + + //Remove this one + if (remove == p) { + const Lit origAnc = varData[lit.var()].reason.getAncestor(); + const int32_t origID = varData[lit.var()].reason.getID(); + assert(origAnc != lit_Undef); + #ifdef VERBOSE_DEBUG_FULLPROP + cout << "ID of k: " << k->get_ID() << " ID of orig: " << origID << " removing latter, origAnc: " << origAnc << endl; + #endif + + remove_bin_clause(lit, origID); + + //Update data indicating what lead to lit + varData[lit.var()].reason = PropBy(~p, k->red(), false, false, k->get_ID()); + assert(varData[p.var()].level != 0); + depth[lit.var()] = depth[p.var()] + 1; + //NOTE: we don't update the levels of other literals... :S + + //for correctness, we would need this, but that would need re-writing of history :S + //if (!onlyIrred) return PropBy(); + + } else if (remove != lit_Undef) { + #ifdef VERBOSE_DEBUG_FULLPROP + cout << "Removing this bin clause, ID: " << k->get_ID() << endl; + #endif + propStats.otfHyperTime += 2; + uselessBin.insert(BinaryClause(~p, lit, k->red(), k->get_ID())); + } + } + + return PROP_NOTHING; +} + + +PropResult HyperEngine::prop_normal_cl_with_ancestor_info( + Watched* i + , Watched*& j + , const Lit p + , PropBy& confl +) { + //Blocked literal is satisfied, so clause is satisfied + if (value(i->getBlockedLit()) == l_True) { + *j++ = *i; + return PROP_NOTHING; + } + + //Dereference pointer + propStats.bogoProps += 4; + const ClOffset offset = i->get_offset(); + Clause& c = *cl_alloc.ptr(offset); + + PropResult ret = prop_normal_helper(c, offset, j, p); + if (ret != PROP_TODO) + return ret; + + // Did not find watch -- clause is unit under assignment: + *j++ = *i; + if (value(c[0]) == l_False) { + return handle_normal_prop_fail(c, offset, confl); + } + + add_hyper_bin(c[0], c); + + return PROP_SOMETHING; +} + +size_t HyperEngine::mem_used() const +{ + size_t mem = 0; + mem += PropEngine::mem_used(); + mem += currAncestors.capacity()*sizeof(Lit); + + return mem; +} + +void HyperEngine::enqueue_with_acestor_info( + const Lit p + , const Lit ancestor + , const bool redStep + , const int32_t ID +) { + //only called at decision level 1 during solving OR + //during intree probing + enqueue(p, decisionLevel(), PropBy(~ancestor, redStep, false, false, ID)); + + assert(varData[ancestor.var()].level != 0); + + if (use_depth_trick) { + depth[p.var()] = depth[ancestor.var()] + 1; + } else { + depth[p.var()] = 0; + } + #if defined(DEBUG_DEPTH) || defined(VERBOSE_DEBUG_FULLPROP) + cout + << "Enqueued " << std::setw(6) << (p) + << " by " << std::setw(6) << (~ancestor) + << " ID: " << ID + << " at depth " << std::setw(4) << depth[p.var()] + << " at dec level: " << decisionLevel() + << endl; + #endif +} diff --git a/cryptominisat/cppsrc/src/hyperengine.h b/cryptominisat/cppsrc/src/hyperengine.h new file mode 100644 index 00000000..2b151279 --- /dev/null +++ b/cryptominisat/cppsrc/src/hyperengine.h @@ -0,0 +1,97 @@ +/****************************************** +Copyright (C) 2009-2020 Authors of CryptoMiniSat, see AUTHORS file + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. +***********************************************/ + +#ifndef HYPERENGINE_H +#define HYPERENGINE_H + +#include "cnf.h" +#include "propby.h" +#include "solvertypes.h" +#include +#include +#include "propengine.h" +#include "mystack.h" + + +using std::vector; +using std::set; + +namespace CMSat { + +class HyperEngine : public PropEngine { +public: + HyperEngine(const SolverConf *_conf, Solver* solver, std::atomic* _must_interrupt_inter); + virtual ~HyperEngine() override; + size_t mem_used() const; + + bool use_depth_trick = true; + bool perform_transitive_reduction = true; + bool timedOutPropagateFull = false; + Lit propagate_bfs( + const uint64_t earlyAborTOut = numeric_limits::max() + ); + set needToAddBinClause; /// uselessBin; + + ///Add hyper-binary clause given this bin clause + void add_hyper_bin(Lit p); + + ///Add hyper-binary clause given this large clause + void add_hyper_bin(Lit p, const Clause& cl); + + void enqueue_with_acestor_info( + const Lit p, const Lit ancestor, const bool redStep, const int32_t ID); + +private: + Lit analyzeFail(PropBy propBy); + Lit remove_which_bin_due_to_trans_red(Lit conflict, Lit thisAncestor, const bool thisStepRed); + void remove_bin_clause(Lit lit, const int32_t ID); + bool is_ancestor_of( + const Lit conflict + , Lit thisAncestor + , const bool thisStepRed + , const bool onlyIrred + , const Lit lookingForAncestor + ); + + //Find lowest common ancestor, once 'currAncestors' has been filled + Lit deepest_common_ancestor(); + + PropResult prop_bin_with_ancestor_info( + const Lit p + , const Watched* k + , PropBy& confl + ); + + PropResult prop_normal_cl_with_ancestor_info( + Watched* i + , Watched*& j + , const Lit p + , PropBy& confl + ); + + vector currAncestors; +}; + +} + +#endif //HYPERENGINE_H diff --git a/cryptominisat/cppsrc/src/intree.cpp b/cryptominisat/cppsrc/src/intree.cpp new file mode 100644 index 00000000..7bf985de --- /dev/null +++ b/cryptominisat/cppsrc/src/intree.cpp @@ -0,0 +1,429 @@ +/****************************************** +Copyright (C) 2009-2020 Authors of CryptoMiniSat, see AUTHORS file + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. +***********************************************/ + +#include "intree.h" +#include "solver.h" +#include "varreplacer.h" +#include "clausecleaner.h" +#include "sqlstats.h" +#include "watchalgos.h" + +#include +#include +#include + +using namespace CMSat; + +InTree::InTree(Solver* _solver) : + solver(_solver) + , seen(_solver->seen) +{} + +bool InTree::replace_until_fixedpoint(bool& aborted) +{ + assert(solver->conf.doFindAndReplaceEqLits); + uint64_t time_limit = + solver->conf.intree_scc_varreplace_time_limitM*1000ULL*1000ULL + *solver->conf.global_timeout_multiplier + *0.5; + time_limit = (double)time_limit * std::min(std::pow((double)(numCalls+1), 0.2), 3.0); + *solver->frat << __PRETTY_FUNCTION__ << " start\n"; + + aborted = false; + uint64_t bogoprops = 0; + uint32_t last_replace = numeric_limits::max(); + uint32_t this_replace = solver->varReplacer->get_num_replaced_vars(); + while(last_replace != this_replace && !aborted) { + last_replace = this_replace; + if (!solver->clauseCleaner->remove_and_clean_all()) { + return false; + } + bool OK = solver->varReplacer->replace_if_enough_is_found(0, &bogoprops); + if (!OK) { + return false; + } + + if (solver->varReplacer->get_scc_depth_warning_triggered()) { + aborted = true; + return solver->okay(); + } + this_replace = solver->varReplacer->get_num_replaced_vars(); + + if (bogoprops > time_limit) { + aborted = true; + return solver->okay(); + } + } + + *solver->frat << __PRETTY_FUNCTION__ << " end\n"; + return true; +} + +bool InTree::watches_only_contains_nonbin(const Lit lit) const +{ + watch_subarray_const ws = solver->watches[lit]; + for(const Watched w: ws) { + if (w.isBin()) { + return false; + } + } + + return true; +} + +bool InTree::check_timeout_due_to_hyperbin() +{ + assert(!(solver->timedOutPropagateFull && solver->frat->enabled())); + assert(!(solver->timedOutPropagateFull && solver->conf.simulate_frat)); + + if (solver->timedOutPropagateFull + && !(solver->frat->enabled() || solver->conf.simulate_frat) + ) { + verb_print(1, "[intree] intra-propagation timeout, turning off OTF hyper-bin&trans-red"); + solver->conf.do_hyperbin_and_transred = false; + return true; + } + + return false; +} + +void InTree::fill_roots() +{ + //l is root if no clause of form (l, l2). + + roots.clear(); + for(uint32_t i = 0; i < solver->nVars()*2; i++) + { + Lit lit(i/2, i%2); + if (solver->varData[lit.var()].removed != Removed::none + || solver->value(lit) != l_Undef + ) { + continue; + } + + if (watches_only_contains_nonbin(lit)) { + roots.push_back(lit); + } + } +} + +bool InTree::intree_probe() +{ + assert(solver->okay()); + queue.clear(); + reset_reason_stack.clear(); + solver->use_depth_trick = false; + solver->perform_transitive_reduction = true; + hyperbin_added = 0; + removedIrredBin = 0; + removedRedBin = 0; + numCalls++; + *solver->frat << __PRETTY_FUNCTION__ << " start\n"; + + if (!solver->conf.doFindAndReplaceEqLits) { + if (solver->conf.verbosity) { + cout << "c [intree] SCC is not allowed, intree cannot work this way, aborting" << endl; + } + return solver->okay(); + } + + bool aborted = false; + if (!replace_until_fixedpoint(aborted)) return solver->okay(); + if (aborted) { + if (solver->conf.verbosity) { + cout + << "c [intree] too expensive or depth exceeded during SCC: aborting" + << endl; + } + solver->use_depth_trick = true; + solver->perform_transitive_reduction = true; + return true; + } + + double myTime = cpuTime(); + bogoprops_to_use = + solver->conf.intree_time_limitM*1000ULL*1000ULL + *solver->conf.global_timeout_multiplier; + bogoprops_to_use = (double)bogoprops_to_use * std::pow((double)(numCalls+1), 0.3); + start_bogoprops = solver->propStats.bogoProps; + + fill_roots(); + //randomize_roots + std::shuffle(roots.begin(), roots.end(), solver->mtrand); + + //Let's enqueue all ~root -s. + for(Lit lit: roots) enqueue(~lit, lit_Undef, false, 0); + + //clear seen + for(QueueElem elem: queue) { + if (elem.propagated != lit_Undef) { + seen[elem.propagated.toInt()] = 0; + } + } + const size_t orig_num_free_vars = solver->get_num_free_vars(); + + tree_look(); + unmark_all_bins(); + + const double time_used = cpuTime() - myTime; + const double time_remain = float_div( + (int64_t)solver->propStats.bogoProps-start_bogoprops, bogoprops_to_use); + const bool time_out = ((int64_t)solver->propStats.bogoProps > start_bogoprops + bogoprops_to_use); + + verb_print(1, + "[intree] Set " + << (orig_num_free_vars - solver->get_num_free_vars()) + << " vars" + << " hyper-added: " << hyperbin_added + << " trans-irred: " << removedIrredBin + << " trans-red: " << removedRedBin + << solver->conf.print_times(time_used, time_out, time_remain)); + + if (solver->sqlStats) { + solver->sqlStats->time_passed( + solver + , "intree" + , time_used + , time_out + , time_remain + ); + } + + *solver->frat << __PRETTY_FUNCTION__ << " end\n"; + solver->use_depth_trick = true; + solver->perform_transitive_reduction = true; + return solver->okay(); +} + +void InTree::unmark_all_bins() +{ + for(watch_subarray wsub: solver->watches) { + for(Watched& w: wsub) { + if (w.isBin()) { + w.unmark_bin_cl(); + } + } + } +} + +void InTree::tree_look() +{ + assert(failed.empty()); + depth_failed.clear(); + depth_failed.push_back(false); + solver->propStats.clear(); + + bool timeout = false; + while(!queue.empty()) + { + if (start_bogoprops + bogoprops_to_use < + (int64_t)solver->propStats.bogoProps + + (int64_t)solver->propStats.otfHyperTime + || timeout + ) { + break; + } + + const QueueElem elem = queue.front(); + queue.pop_front(); + + if (solver->conf.verbosity >= 10) { + cout << "Dequeued [[" << elem << "]] dec lev:" + << solver->decisionLevel() << endl; + } + + if (elem.propagated != lit_Undef) { + timeout = handle_lit_popped_from_queue( + elem.propagated, elem.other_lit, elem.red, elem.ID); + } else { + assert(solver->decisionLevel() > 0); + solver->cancelUntil(solver->decisionLevel()-1); + + depth_failed.pop_back(); + assert(!depth_failed.empty()); + + if (reset_reason_stack.empty()) { + assert(solver->decisionLevel() == 0); + } else { + assert(!reset_reason_stack.empty()); + ResetReason tmp = reset_reason_stack.back(); + reset_reason_stack.pop_back(); + if (tmp.var_reason_changed != var_Undef) { + solver->varData[tmp.var_reason_changed].reason = tmp.orig_propby; + if (solver->conf.verbosity >= 10) { + cout << "RESet reason for VAR " << tmp.var_reason_changed+1 << " to: ????" << /*tmp.orig_propby.lit2() << */ " red: " << (int)tmp.orig_propby.isRedStep() << endl; + } + } + } + } + + if (solver->decisionLevel() == 0) { + if (!empty_failed_list()) { + return; + } + } + } + + solver->cancelUntil(0); + empty_failed_list(); +} + +bool InTree::handle_lit_popped_from_queue( + const Lit lit, const Lit other_lit, const bool red, const int32_t ID) +{ + solver->new_decision_level(); + depth_failed.push_back(depth_failed.back()); + if (other_lit != lit_Undef) { + reset_reason_stack.push_back(ResetReason(var_Undef, PropBy())); + } + + bool timeout = false; + + if (solver->value(lit) == l_False + || depth_failed.back() == 1 + ) { + //l is failed. + failed.push_back(~lit); + verb_print(10,"Failed :" << ~lit << " level: " << solver->decisionLevel()); + return false; + } + + if (other_lit != lit_Undef) { + //update 'other_lit' 's ancestor to 'lit' + assert(solver->value(other_lit) == l_True); + reset_reason_stack.back() = ResetReason(other_lit.var(), solver->varData[other_lit.var()].reason); + solver->varData[other_lit.var()].reason = PropBy(~lit, red, false, false, ID); + verb_print(10, "Set reason for VAR " << other_lit.var()+1 + << " to: " << ~lit << " red: " << (int)red); + } + + if (solver->value(lit) == l_Undef) { + solver->enqueue(lit); + + //Should do HHBR here + bool ok; + if (solver->conf.do_hyperbin_and_transred) { + uint64_t max_hyper_time = numeric_limits::max(); + if (!solver->frat->enabled() && + !solver->conf.simulate_frat + ) { + max_hyper_time = + solver->propStats.otfHyperTime + + solver->propStats.bogoProps + + 1600ULL*1000ULL*1000ULL; + } + + Lit ret = solver->propagate_bfs(max_hyper_time); + ok = (ret == lit_Undef); + timeout = check_timeout_due_to_hyperbin(); + } else { + ok = solver->propagate().isNULL(); + } + + if (!ok && !timeout) { + depth_failed.back() = 1; + failed.push_back(~lit); + if (solver->conf.verbosity >= 10) { + cout << "(timeout?) Failed :" << ~lit << " level: " << solver->decisionLevel() << endl; + } + } else { + hyperbin_added += solver->hyper_bin_res_all(false); + auto [a, b] = solver->remove_useless_bins(true); + removedIrredBin += a; + removedRedBin += b; + } + solver->uselessBin.clear(); + solver->needToAddBinClause.clear(); + } + + return timeout; +} + +bool InTree::empty_failed_list() +{ + assert(solver->decisionLevel() == 0); + for(const Lit lit: failed) { + if (!solver->ok) { + return false; + } + + if (solver->value(lit) == l_Undef) { + solver->enqueue(lit); + solver->ok = solver->propagate().isNULL(); + if (!solver->ok) { + return false; + } + } else if (solver->value(lit) == l_False) { + //*(solver->frat) << add << solver->clauseID++ << ~lit << fin; + solver->unsat_cl_ID = solver->clauseID; + *(solver->frat) << add << solver->clauseID++ <ok = false; + return false; + } + } + failed.clear(); + + return true; +} + + +// (lit V otherlit) exists -> (~otherlit, lit) in queue +// Next: (~otherLit, lit2) exists -> (~lit2, ~otherLit) in queue +// --> original ~otherlit got enqueued by lit2 = False (--> PropBy(lit2) ). + +void InTree::enqueue(const Lit lit, const Lit other_lit, const bool red_cl, const int32_t ID) +{ + queue.push_back(QueueElem(lit, other_lit, red_cl, ID)); + assert(!seen[lit.toInt()]); + seen[lit.toInt()] = 1; + assert(solver->value(lit) == l_Undef); + + watch_subarray ws = solver->watches[lit]; + for(Watched& w: ws) { + if (w.isBin() + && seen[(~w.lit2()).toInt()] == 0 + && solver->value(w.lit2()) == l_Undef + ) { + //Mark both + w.mark_bin_cl(); + Watched& other_w = findWatchedOfBin( + solver->watches, w.lit2(), lit, w.red(), w.get_ID()); + other_w.mark_bin_cl(); + + enqueue(~w.lit2(), lit, w.red(), w.get_ID()); + } + } + queue.push_back(QueueElem(lit_Undef, lit_Undef, false, 0)); +} + + +double InTree::mem_used() const +{ + double mem = 0; + mem += sizeof(InTree); + mem += roots.size()*sizeof(Lit); + mem += failed.size()*sizeof(Lit); + mem += reset_reason_stack.size()*sizeof(ResetReason); + mem += queue.size()*sizeof(QueueElem); + mem += depth_failed.size()*sizeof(char); + return mem; +} diff --git a/cryptominisat/cppsrc/src/intree.h b/cryptominisat/cppsrc/src/intree.h new file mode 100644 index 00000000..a8590f42 --- /dev/null +++ b/cryptominisat/cppsrc/src/intree.h @@ -0,0 +1,123 @@ +/****************************************** +Copyright (C) 2009-2020 Authors of CryptoMiniSat, see AUTHORS file + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. +***********************************************/ + +#include "cloffset.h" +#include "solvertypes.h" +#include "propby.h" + +#include +#include +using std::vector; +using std::deque; + +namespace CMSat { + +class Solver; + +class InTree +{ +public: + InTree(Solver* _solver); + bool intree_probe(); + + struct QueueElem + { + QueueElem( + const Lit _propagated, + const Lit _other_lit, + const bool _red, + const int32_t _ID) : + propagated(_propagated), + other_lit(_other_lit), + red(_red), + ID(_ID) + {} + + Lit propagated; + Lit other_lit; + bool red; + int32_t ID; + }; + + struct ResetReason + { + ResetReason(uint32_t _var_reason_changed, PropBy _orig_propby) : + var_reason_changed(_var_reason_changed) + , orig_propby(_orig_propby) + {} + + uint32_t var_reason_changed; + PropBy orig_propby; + }; + + double mem_used() const; + +private: + + bool check_timeout_due_to_hyperbin(); + void unmark_all_bins(); + bool handle_lit_popped_from_queue( + const Lit lit, const Lit propagating, const bool red, const int32_t ID); + bool empty_failed_list(); + void fill_roots(); + bool watches_only_contains_nonbin(const Lit lit) const; + bool replace_until_fixedpoint(bool& aborted); + void enqueue(const Lit lit, const Lit other_lit, const bool red_cl, const int32_t ID); + + void setup(); + void build_intree(); + void do_one(); + void tree_look(); + + vector roots; + vector failed; + vector reset_reason_stack; + deque queue; + vector depth_failed; + int64_t bogoprops_to_use; + int64_t start_bogoprops; + + size_t hyperbin_added; + size_t removedIrredBin; + size_t removedRedBin; + size_t numCalls = 0; + + Solver* solver; + vector& seen; +}; + +inline std::ostream& operator<<(std::ostream& os, const InTree::QueueElem& elem) +{ + if (elem.propagated == lit_Undef) { + os << "NONE"; + } else { + os << "prop:" << elem.propagated + << " other_lit:" << elem.other_lit + << " red: " << elem.red + << " ID: " << elem.ID; + } + + return os; +} + +} + diff --git a/cryptominisat/cppsrc/src/ipasir.cpp b/cryptominisat/cppsrc/src/ipasir.cpp new file mode 100644 index 00000000..03581925 --- /dev/null +++ b/cryptominisat/cppsrc/src/ipasir.cpp @@ -0,0 +1,262 @@ +/****************************************** +Copyright (c) 2014, Tomas Balyo, Karlsruhe Institute of Technology. +Copyright (c) 2014, Armin Biere, Johannes Kepler University. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to +deal in the Software without restriction, including without limitation the +rights to use, copy, modify, merge, publish, distribute, sublicense, and/or +sell copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS +IN THE SOFTWARE. +***********************************************/ + +/** + * Return the name and the version of the incremental SAT + * solving library. + */ + +#include "cryptominisat.h" +#include +#include +#include +#include +#include "constants.h" + +using std::vector; +using namespace CMSat; +struct MySolver { + ~MySolver() + { + delete solver; + } + + MySolver() + { + solver = new SATSolver; + } + + SATSolver* solver; + vector clause; + vector assumptions; + vector last_conflict; + vector conflict_cl_map; +}; + +extern "C" { + +DLL_PUBLIC const char * ipasir_signature () +{ + static char tmp[200]; + std::string tmp2 = "cryptominisat-"; + tmp2 += SATSolver::get_version(); + memcpy(tmp, tmp2.c_str(), tmp2.length()+1); + return tmp; +} + +/** + * Construct a new solver and return a pointer to it. + * Use the returned pointer as the first parameter in each + * of the following functions. + * + * Required state: N/A + * State after: INPUT + */ +DLL_PUBLIC void * ipasir_init () +{ + MySolver *s = new MySolver; + return (void*)s; +} + +/** + * Release the solver, i.e., all its resoruces and + * allocated memory (destructor). The solver pointer + * cannot be used for any purposes after this call. + * + * Required state: INPUT or SAT or UNSAT + * State after: undefined + */ +DLL_PUBLIC void ipasir_release (void * solver) +{ + MySolver* s = (MySolver*)solver; + delete s; +} + +namespace +{ +void ensure_var_created(MySolver& s, Lit lit) +{ + if (lit.var() >= s.solver->nVars()) { + const uint32_t toadd = lit.var() - s.solver->nVars() + 1; + s.solver->new_vars(toadd); + } +} +} + +/** + * Add the given literal into the currently added clause + * or finalize the clause with a 0. Clauses added this way + * cannot be removed. The addition of removable clauses + * can be simulated using activation literals and assumptions. + * + * Required state: INPUT or SAT or UNSAT + * State after: INPUT + * + * Literals are encoded as (non-zero) integers as in the + * DIMACS formats. They have to be smaller or equal to + * INT_MAX and strictly larger than INT_MIN (to avoid + * negation overflow). This applies to all the literal + * arguments in API functions. + */ +DLL_PUBLIC void ipasir_add (void * solver, int lit_or_zero) +{ + MySolver* s = (MySolver*)solver; + + if (lit_or_zero == 0) { + s->solver->add_clause(s->clause); + s->clause.clear(); + } else { + Lit lit(std::abs(lit_or_zero)-1, lit_or_zero < 0); + ensure_var_created(*s, lit); + s->clause.push_back(lit); + } +} + +/** + * Add an assumption for the next SAT search (the next call + * of ipasir_solve). After calling ipasir_solve all the + * previously added assumptions are cleared. + * + * Required state: INPUT or SAT or UNSAT + * State after: INPUT + */ +DLL_PUBLIC void ipasir_assume (void * solver, int lit) +{ + MySolver* s = (MySolver*)solver; + Lit lit_cms(std::abs(lit)-1, lit < 0); + ensure_var_created(*s, lit_cms); + s->assumptions.push_back(lit_cms); +} + +/** + * Solve the formula with specified clauses under the specified assumptions. + * If the formula is satisfiable the function returns 10 and the state of the solver is changed to SAT. + * If the formula is unsatisfiable the function returns 20 and the state of the solver is changed to UNSAT. + * If the search is interrupted (see ipasir_set_terminate) the function returns 0 and the state of the solver remains INPUT. + * This function can be called in any defined state of the solver. + * + * Required state: INPUT or SAT or UNSAT + * State after: INPUT or SAT or UNSAT + */ +DLL_PUBLIC int ipasir_solve (void * solver) +{ + MySolver* s = (MySolver*)solver; + + //Cleanup last_conflict + for(auto x: s->last_conflict) { + s->conflict_cl_map[x.toInt()] = 0; + } + s->last_conflict.clear(); + + //solve + lbool ret = s->solver->solve(&(s->assumptions)); + s->assumptions.clear(); + + if (ret == l_True) { + return 10; + } + if (ret == l_False) { + s->conflict_cl_map.resize(s->solver->nVars()*2, 0); + s->last_conflict = s->solver->get_conflict(); + for(auto x: s->last_conflict) { + s->conflict_cl_map[x.toInt()] = 1; + } + return 20; + } + if (ret == l_Undef) { + return 0; + } + assert(false); + exit(-1); +} + +/** + * Get the truth value of the given literal in the found satisfying + * assignment. Return 'lit' if True, '-lit' if False, and 0 if not important. + * This function can only be used if ipasir_solve has returned 10 + * and no 'ipasir_add' nor 'ipasir_assume' has been called + * since then, i.e., the state of the solver is SAT. + * + * Required state: SAT + * State after: SAT + */ +DLL_PUBLIC int ipasir_val (void * solver, int lit) +{ + MySolver* s = (MySolver*)solver; + assert(s->solver->okay()); + + const int ipasirVar = std::abs(lit); + const uint32_t cmVar = ipasirVar-1; + lbool val = s->solver->get_model()[cmVar]; + + if (val == l_Undef) { + return 0; + } + if (val == l_False) { + return -ipasirVar; + } + return ipasirVar; +} + +/** + * Check if the given assumption literal was used to prove the + * unsatisfiability of the formula under the assumptions + * used for the last SAT search. Return 1 if so, 0 otherwise. + * This function can only be used if ipasir_solve has returned 20 and + * no ipasir_add or ipasir_assume has been called since then, i.e., + * the state of the solver is UNSAT. + * + * Required state: UNSAT + * State after: UNSAT + */ +DLL_PUBLIC int ipasir_failed (void * solver, int lit) +{ + MySolver* s = (MySolver*)solver; + const Lit tofind(std::abs(lit)-1, lit < 0); + return s->conflict_cl_map[(~tofind).toInt()]; //yeah, it's reveresed, it's weird +} + +/** + * Set a callback function used to indicate a termination requirement to the + * solver. The solver will periodically call this function and check its return + * value during the search. The ipasir_set_terminate function can be called in any + * state of the solver, the state remains unchanged after the call. + * The callback function is of the form "int terminate(void * state)" + * - it returns a non-zero value if the solver should terminate. + * - the solver calls the callback function with the parameter "state" + * having the value passed in the ipasir_set_terminate function (2nd parameter). + * + * Required state: INPUT or SAT or UNSAT + * State after: INPUT or SAT or UNSAT + */ +DLL_PUBLIC void ipasir_set_terminate (void * /*solver*/, void * /*state*/, int (* /*terminate*/)(void * state)) +{ + //this is complicated. +} + +DLL_PUBLIC void ipasir_set_learn (void * /*solver*/, void * /*state*/, int /*max_length*/, void (* /*learn*/)(void * state, int * clause)) +{ + //this is complicated +} + +} diff --git a/cryptominisat/cppsrc/src/ipasir.h b/cryptominisat/cppsrc/src/ipasir.h new file mode 100644 index 00000000..30cd490c --- /dev/null +++ b/cryptominisat/cppsrc/src/ipasir.h @@ -0,0 +1,164 @@ +/****************************************** +Copyright (c) 2014, Tomas Balyo, Karlsruhe Institute of Technology. +Copyright (c) 2014, Armin Biere, Johannes Kepler University. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to +deal in the Software without restriction, including without limitation the +rights to use, copy, modify, merge, publish, distribute, sublicense, and/or +sell copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS +IN THE SOFTWARE. +***********************************************/ + + +/* Part of the generic incremental SAT API called 'ipasir'. + * See 'LICENSE' for rights to use this software. + */ +#ifndef ipasir_h_INCLUDED +#define ipasir_h_INCLUDED + +/*------------------------------------------------------------------------*/ +#ifdef __cplusplus +extern "C" { +#endif +/*------------------------------------------------------------------------*/ + +/** + * Return the name and the version of the incremental SAT + * solving library. + */ +const char * ipasir_signature (); + +/** + * Construct a new solver and return a pointer to it. + * Use the returned pointer as the first parameter in each + * of the following functions. + * + * Required state: N/A + * State after: INPUT + */ +void * ipasir_init (); + +/** + * Release the solver, i.e., all its resoruces and + * allocated memory (destructor). The solver pointer + * cannot be used for any purposes after this call. + * + * Required state: INPUT or SAT or UNSAT + * State after: undefined + */ +void ipasir_release (void * solver); + +/** + * Add the given literal into the currently added clause + * or finalize the clause with a 0. Clauses added this way + * cannot be removed. The addition of removable clauses + * can be simulated using activation literals and assumptions. + * + * Required state: INPUT or SAT or UNSAT + * State after: INPUT + * + * Literals are encoded as (non-zero) integers as in the + * DIMACS formats. They have to be smaller or equal to + * INT_MAX and strictly larger than INT_MIN (to avoid + * negation overflow). This applies to all the literal + * arguments in API functions. + */ +void ipasir_add (void * solver, int lit_or_zero); + +/** + * Add an assumption for the next SAT search (the next call + * of ipasir_solve). After calling ipasir_solve all the + * previously added assumptions are cleared. + * + * Required state: INPUT or SAT or UNSAT + * State after: INPUT + */ +void ipasir_assume (void * solver, int lit); + +/** + * Solve the formula with specified clauses under the specified assumptions. + * If the formula is satisfiable the function returns 10 and the state of the solver is changed to SAT. + * If the formula is unsatisfiable the function returns 20 and the state of the solver is changed to UNSAT. + * If the search is interrupted (see ipasir_set_terminate) the function returns 0 and the state of the solver remains INPUT. + * This function can be called in any defined state of the solver. + * + * Required state: INPUT or SAT or UNSAT + * State after: INPUT or SAT or UNSAT + */ +int ipasir_solve (void * solver); + +/** + * Get the truth value of the given literal in the found satisfying + * assignment. Return 'lit' if True, '-lit' if False, and 0 if not important. + * This function can only be used if ipasir_solve has returned 10 + * and no 'ipasir_add' nor 'ipasir_assume' has been called + * since then, i.e., the state of the solver is SAT. + * + * Required state: SAT + * State after: SAT + */ +int ipasir_val (void * solver, int lit); + +/** + * Check if the given assumption literal was used to prove the + * unsatisfiability of the formula under the assumptions + * used for the last SAT search. Return 1 if so, 0 otherwise. + * This function can only be used if ipasir_solve has returned 20 and + * no ipasir_add or ipasir_assume has been called since then, i.e., + * the state of the solver is UNSAT. + * + * Required state: UNSAT + * State after: UNSAT + */ +int ipasir_failed (void * solver, int lit); + +/** + * Set a callback function used to indicate a termination requirement to the + * solver. The solver will periodically call this function and check its return + * value during the search. The ipasir_set_terminate function can be called in any + * state of the solver, the state remains unchanged after the call. + * The callback function is of the form "int terminate(void * state)" + * - it returns a non-zero value if the solver should terminate. + * - the solver calls the callback function with the parameter "state" + * having the value passed in the ipasir_set_terminate function (2nd parameter). + * + * Required state: INPUT or SAT or UNSAT + * State after: INPUT or SAT or UNSAT + */ +void ipasir_set_terminate (void * solver, void * state, int (*terminate)(void * state)); + +/** + * Set a callback function used to extract learned clauses up to a given lenght from the + * solver. The solver will call this function for each learned clause that satisfies + * the maximum length (literal count) condition. The ipasir_set_learn function can be called in any + * state of the solver, the state remains unchanged after the call. + * The callback function is of the form "void learn(void * state, int * clause)" + * - the solver calls the callback function with the parameter "state" + * having the value passed in the ipasir_set_terminate function (2nd parameter). + * - the argument "clause" is a pointer to a null terminated integer array containing the learned clause. + * the solver can change the data at the memory location that "clause" points to after the function call. + * + * Required state: INPUT or SAT or UNSAT + * State after: INPUT or SAT or UNSAT + */ +void ipasir_set_learn (void * solver, void * state, int max_length, void (*learn)(void * state, int * clause)); + +/*------------------------------------------------------------------------*/ +#ifdef __cplusplus +} +#endif +/*------------------------------------------------------------------------*/ + +#endif diff --git a/cryptominisat/cppsrc/src/lucky.cpp b/cryptominisat/cppsrc/src/lucky.cpp new file mode 100644 index 00000000..090ebce9 --- /dev/null +++ b/cryptominisat/cppsrc/src/lucky.cpp @@ -0,0 +1,327 @@ +/****************************************** +Copyright (C) 2009-2020 Authors of CryptoMiniSat, see AUTHORS file +Originally from CaDiCaL's "lucky.cpp", Copyright by Armin Biere, 2019 + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. +***********************************************/ + +#include "lucky.h" +#include "solver.h" +#include "sqlstats.h" +#include "time_mem.h" + +using namespace CMSat; + + +Lucky::Lucky(Solver* _solver) : + solver(_solver) +{ +} + +void CMSat::Lucky::doit() +{ + assert(solver->okay()); + assert(solver->decisionLevel() == 0); + + double myTime = cpuTime(); + + if (check_all(true)) goto end; + if (check_all(false)) goto end; + if (search_fwd_sat(true)) goto end; + if (search_fwd_sat(false)) goto end; + if (search_backw_sat(true)) goto end; + if (search_backw_sat(false)) goto end; + if (horn_sat(true)) goto end; + if (horn_sat(false)) goto end; + + end: + double time_used = cpuTime() - myTime; + if (solver->conf.verbosity) { + cout << "c [lucky] finished " + << solver->conf.print_times(time_used) + << endl; + } + if (solver->sqlStats) { + solver->sqlStats->time_passed_min( + solver + , "lucky" + , time_used + ); + } + assert(solver->decisionLevel() == 0); +} + +bool CMSat::Lucky::check_all(bool polar) +{ + for(uint32_t i = 0; i < solver->nVars()*2; i++) { + Lit lit = Lit::toLit(i); + + if (solver->value(lit) == l_True) { + continue; + } + if (!lit.sign() == polar) { + continue; + } + for(const auto& w: solver->watches[lit]) { + if (w.isBin() && solver->value(w.lit2()) == l_True) + continue; + if (w.isBin() && solver->value(w.lit2()) == l_False) + return false; + if (w.isBin() && !w.lit2().sign() != polar) + return false; + } + } + + for(const auto off: solver->longIrredCls) { + Clause* cl = solver->cl_alloc.ptr(off); + bool ok = false; + for(const Lit l: *cl) { + if (solver->value(l) == l_True) { + ok = true; + break; + } + if (!l.sign() == polar) { + ok = true; + break; + } + } + if (!ok) { + return false; + } + } + + if (solver->conf.verbosity) { + cout << "c [lucky] all " << (int)polar << " worked. Saving phases." << endl; + } + for(auto& x: solver->varData) { + x.best_polarity = polar; + } + return true; +} + + +void Lucky::set_polarities_to_enq_val() +{ + for(uint32_t i = 0; i < solver->nVars(); i++) { + solver->varData[i].stable_polarity = solver->value(i) == l_True; + } +} + +bool CMSat::Lucky::search_fwd_sat(bool polar) +{ + for(uint32_t i = 0; i < solver->nVars(); i++) { + if (solver->varData[i].removed != Removed::none) { + continue; + } + + if (solver->value(i) != l_Undef) { + continue; + } + solver->new_decision_level(); + + Lit lit = Lit(i, !polar); + solver->enqueue(lit); + auto p = solver->propagate(); + if (!p.isNULL()) { + solver->cancelUntil(0); + return false; + } + } + + if (solver->conf.verbosity) { + cout << "c [lucky] Forward polar " << (int)polar << " worked. Saving phases." << endl; + } + + set_polarities_to_enq_val(); + solver->cancelUntil(0); + + return true; +} + +bool CMSat::Lucky::enqueue_and_prop_assumptions() +{ + assert(solver->decisionLevel() == 0); + while (solver->decisionLevel() < solver->assumptions.size()) { + const Lit p = solver->map_outer_to_inter( + solver->assumptions[solver->decisionLevel()].lit_outer); + + if (solver->value(p) == l_True) { + // Dummy decision level: + solver->new_decision_level(); + continue; + } else if (solver->value(p) == l_False) { + solver->cancelUntil(0); + return false; + } else { + assert(p.var() < solver->nVars()); + solver->new_decision_level(); + solver->enqueue(p); + auto prop = solver->propagate(); + if (!prop.isNULL()) { + solver->cancelUntil(0); + return false; + } + } + } + return true; +} + +bool CMSat::Lucky::search_backw_sat(bool polar) +{ + if (!enqueue_and_prop_assumptions()) { + return false; + } + + for(int i = (int)solver->nVars() - 1; i >= 0; i--) { + if (solver->varData[i].removed != Removed::none) { + continue; + } + + if (solver->value(i) != l_Undef) { + continue; + } + solver->new_decision_level(); + + Lit lit = Lit(i, !polar); + solver->enqueue(lit); + auto p = solver->propagate(); + if (!p.isNULL()) { + solver->cancelUntil(0); + return false; + } + } + + if (solver->conf.verbosity) { + cout << "c [lucky] Backward polar " << (int)polar << " worked. Saving phases." << endl; + } + + set_polarities_to_enq_val(); + solver->cancelUntil(0); + return true; +} + +bool CMSat::Lucky::horn_sat(bool polar) +{ + if (!enqueue_and_prop_assumptions()) { + return false; + } + + for(const auto off: solver->longIrredCls) { + Clause* cl = solver->cl_alloc.ptr(off); + bool satisfied = false; + Lit to_set = lit_Undef; + for(const Lit l: *cl) { + if (!l.sign() == polar && solver->value(l) == l_Undef) { + to_set = l; + } + if (solver->value(l) == l_True) { + satisfied = true; + break; + } + } + if (satisfied) { + continue; + } + + if (to_set == lit_Undef) { + //no unassigned literal of correct polarity + solver->cancelUntil(0); + return false; + } + solver->new_decision_level(); + solver->enqueue(to_set); + auto p = solver->propagate(); + if (!p.isNULL()) { + solver->cancelUntil(0); + return false; + } + } + + //NOTE: propagating WHILE going through a watchlist will SEGFAULT + vector toset; + for(uint32_t i = 0; i < solver->nVars()*2; i++) { + Lit lit = Lit::toLit(i); + if (solver->value(lit) == l_True) { + continue; + } + if (!lit.sign() == polar) { + bool must_set = false; + for(const auto& w: solver->watches[lit]) { + if (w.isBin() && + solver->value(w.lit2()) != l_True) + { + must_set = true; + break; + } + } + if (must_set) { + solver->new_decision_level(); + solver->enqueue(lit); + auto p = solver->propagate(); + if (!p.isNULL()) { + solver->cancelUntil(0); + return false; + } + } + } else { + toset.clear(); + bool ok = true; + for(const auto& w: solver->watches[lit]) { + if (w.isBin() && + solver->value(w.lit2()) != l_True) + { + if (w.lit2().sign() != polar) { + ok = false; + break; + } else { + toset.push_back(w.lit2()); + } + } + } + if (!ok) { + solver->cancelUntil(0); + return false; + } + for(const auto& x: toset) { + if (solver->value(x) == l_False) { + solver->cancelUntil(0); + return false; + } + if (solver->value(x) == l_True) { + continue; + } + solver->new_decision_level(); + solver->enqueue(x); + auto p = solver->propagate(); + if (!p.isNULL()) { + solver->cancelUntil(0); + return false; + } + } + } + } + + if (solver->conf.verbosity) { + cout << "c [lucky] Horn polar " << (int)polar << " worked. Saving phases." << endl; + } + + set_polarities_to_enq_val(); + solver->cancelUntil(0); + return true; +} diff --git a/cryptominisat/cppsrc/src/lucky.h b/cryptominisat/cppsrc/src/lucky.h new file mode 100644 index 00000000..f0469063 --- /dev/null +++ b/cryptominisat/cppsrc/src/lucky.h @@ -0,0 +1,51 @@ +/****************************************** +Copyright (C) 2009-2020 Authors of CryptoMiniSat, see AUTHORS file +Originally from CaDiCaL's "lucky.cpp", Copyright by Armin Biere, 2019 + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. +***********************************************/ + +#ifndef LUCKY_PHASES_H_ +#define LUCKY_PHASES_H_ + +namespace CMSat { + +class Solver; + +class Lucky +{ +public: + Lucky(Solver* solver); + void doit(); + +//private: + bool check_all(bool polar); + bool search_fwd_sat(bool polar); + bool search_backw_sat(bool polar); + bool horn_sat(bool polar); + +private: + bool enqueue_and_prop_assumptions(); + void set_polarities_to_enq_val(); + Solver* solver; +}; + +} + +#endif diff --git a/cryptominisat/cppsrc/src/main.cpp b/cryptominisat/cppsrc/src/main.cpp new file mode 100644 index 00000000..02c33b2d --- /dev/null +++ b/cryptominisat/cppsrc/src/main.cpp @@ -0,0 +1,1608 @@ +/* +Copyright (C) 2009-2022 Authors of CryptoMiniSat, see AUTHORS file + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. +*/ + +#if defined(__GNUC__) && defined(__linux__) + +#ifndef _GNU_SOURCE +#define _GNU_SOURCE +#endif + +#include +#endif + +#define DEBUG_DIMACSPARSER_CMS + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "main.h" +#include "main_common.h" +#include "time_mem.h" +#include "dimacsparser.h" +#include "cryptominisat.h" +#include "signalcode.h" +#include "argparse.hpp" + +using namespace CMSat; + +using std::cout; +using std::cerr; +using std::endl; +using std::map; +double wallclock_time_started = 0.0; + +struct WrongParam { + WrongParam(const string& _param, const string& _msg) : param(_param) , msg(_msg) {} + const string& getMsg() const { return msg; } + const string& getParam() const { return param; } + string param; + string msg; +}; + +Main::Main(int _argc, char** _argv) : + argc(_argc) + , argv(_argv) + , fileNamePresent (false) +{ +} + +void Main::readInAFile(SATSolver* solver2, const string& filename) +{ + solver2->add_sql_tag("filename", filename); + if (conf.verbosity) cout << "c Reading file '" << filename << "'" << endl; + #ifndef USE_ZLIB + FILE * in = fopen(filename.c_str(), "rb"); + DimacsParser, SATSolver> parser(solver2, &debugLib, conf.verbosity); + #else + gzFile in = gzopen(filename.c_str(), "rb"); + DimacsParser, SATSolver> parser(solver2, &debugLib, conf.verbosity); + #endif + + if (in == NULL) { + std::cerr + << "ERROR! Could not open file '" + << filename + << "' for reading: " << strerror(errno) << endl; + + std::exit(1); + } + + bool strict_header = false; + if (!parser.parse_DIMACS(in, strict_header)) { + exit(-1); + } + + if (!sampling_vars_str.empty() && !parser.sampling_vars.empty()) { + cerr << "ERROR! Sampling vars set in console but also in CNF." << endl; + exit(-1); + } + + if (!sampling_vars_str.empty()) { + assert(sampling_vars.empty()); + + std::stringstream ss(sampling_vars_str); + uint32_t i; + while (ss >> i) { + const uint32_t var = i-1; + sampling_vars.push_back(var); + if (ss.peek() == ',' || ss.peek() == ' ') ss.ignore(); + } + } else { + sampling_vars.swap(parser.sampling_vars); + } + + if (sampling_vars.empty()) { + if (only_sampling_solution) { + cout << "ERROR: only sampling vars are requested in the solution, but no sampling vars have been set!" << endl; + exit(-1); + } + } else { + solver2->set_sampling_vars(&sampling_vars); + if (sampling_vars.size() > 100) { + cout + << "c Sampling var set contains over 100 variables, not displaying" + << endl; + } else { + if (conf.verbosity) { + cout << "c Sampling vars set (total num: " + << sampling_vars.size() << " ) : "; + for(size_t i = 0; i < sampling_vars.size(); i++) { + const uint32_t v = sampling_vars[i]; + cout << v+1; + if (i+1 != sampling_vars.size()) + cout << ","; + } + cout << endl; + } + } + } + + call_after_parse(); + + #ifndef USE_ZLIB + fclose(in); + #else + gzclose(in); + #endif +} + +void Main::readInStandardInput(SATSolver* solver2) +{ + if (conf.verbosity) cout << "c Reading from standard input... Use '-h' or '--help' for help." << endl; + + #ifndef USE_ZLIB + FILE * in = stdin; + #else + gzFile in = gzdopen(0, "rb"); //opens stdin, which is 0 + #endif + + if (in == NULL) { + std::cerr << "ERROR! Could not open standard input for reading" << endl; + std::exit(1); + } + + #ifndef USE_ZLIB + DimacsParser, SATSolver> parser(solver2, &debugLib, conf.verbosity); + #else + DimacsParser, SATSolver> parser(solver2, &debugLib, conf.verbosity); + #endif + + if (!parser.parse_DIMACS(in, false)) { + exit(-1); + } + + #ifdef USE_ZLIB + gzclose(in); + #endif +} + +void Main::parseInAllFiles(SATSolver* solver2) +{ + const double myTimeTotal = cpuTimeTotal(); + const double myTime = cpuTime(); + + //First read normal extra files + solver->add_sql_tag("stdin", fileNamePresent ? "False" : "True"); + if (!fileNamePresent) readInStandardInput(solver2); + else readInAFile(solver2, input_file); + + if (conf.verbosity) { + if (num_threads > 1) { + cout + << "c Sum parsing time among all threads (wall time will differ): " + << std::fixed << std::setprecision(2) + << (cpuTimeTotal() - myTimeTotal) + << " s" << endl; + } else { + cout + << "c Parsing time: " + << std::fixed << std::setprecision(2) + << (cpuTime() - myTime) + << " s" << endl; + } + } +} + +void Main::printResultFunc( + std::ostream* os + , const bool toFile + , const lbool ret +) { + if (ret == l_True) { + if(toFile) { + *os << "SAT" << endl; + } + else if (!printResult) *os << "s SATISFIABLE" << endl; + else *os << "s SATISFIABLE" << endl; + } else if (ret == l_False) { + if(toFile) { + *os << "UNSAT" << endl; + } + else if (!printResult) *os << "s UNSATISFIABLE" << endl; + else *os << "s UNSATISFIABLE" << endl; + } else { + *os << "s INDETERMINATE" << endl; + } + if (ret == l_True && !printResult && !toFile) + { + cout << "c Not printing satisfying assignment. " + "Use the '--printsol 1' option for that" << endl; + } + + if (ret == l_True && (printResult || toFile)) { + if (toFile) { + auto fun = [&](uint32_t var) { + if (solver->get_model()[var] != l_Undef) { + *os << ((solver->get_model()[var] == l_True)? "" : "-") << var+1 << " "; + } + }; + + if (sampling_vars.empty() || !only_sampling_solution) { + for (uint32_t var = 0; var < solver->nVars(); var++) { + fun(var); + } + + } else { + for (uint32_t var: sampling_vars) { + fun(var); + } + } + *os << "0" << endl; + } else { + uint32_t num_undef; + if (sampling_vars.empty() || !only_sampling_solution) { + num_undef = print_model(solver, os); + } else { + num_undef = print_model(solver, os, &sampling_vars); + } + if (num_undef && !toFile && conf.verbosity) { + cout << "c NOTE: " << num_undef << " variables are NOT set." << endl; + } + } + } +} + +/* clang-format off */ +void Main::add_supported_options() +{ + // Declare the supported options. + program.add_argument("-h", "--help") + .help("Print extensive help") + .default_value(false); + program.add_argument("-v", "--version") + .help("Print version info") + .flag(); + program.add_argument("--verb") + .action([&](const auto& a) {conf.verbosity = std::atoi(a.c_str());}) + .default_value(conf.verbosity) + .help("[0-10] Verbosity of solver. 0 = only solution"); + program.add_argument("--maxtime") + .help("Stop solving after this much time (s)") + .scan<'g', double>(); + program.add_argument("--maxconfl") + .help("Stop solving after this many conflicts") + .scan<'d', uint64_t>(); + program.add_argument("-r", "--random") + .action([&](const auto& a) {conf.origSeed = std::atoi(a.c_str());}) + .default_value(conf.origSeed) + .help("[0..] Random seed"); + program.add_argument("-t", "--threads") + .default_value(1) + .action([&](const auto& a) {num_threads = std::atoi(a.c_str());}) + .help("Number of threads"); + program.add_argument("-m", "--mult") + .action([&](const auto& a) {conf.orig_global_timeout_multiplier = std::atof(a.c_str());}) + .default_value(conf.orig_global_timeout_multiplier) + .help("Time multiplier for all simplification cutoffs"); + program.add_argument("--nextm") + .action([&](const auto& a) {conf.global_next_multiplier = std::atof(a.c_str());}) + .default_value(conf.global_next_multiplier) + .help("Global multiplier when the next inprocessing should take place"); + program.add_argument("--memoutmult") + .action([&](const auto& a) {conf.var_and_mem_out_mult = std::atof(a.c_str());}) + .default_value(conf.var_and_mem_out_mult) + .help("Multiplier for memory-out checks on inprocessing functions. It limits things such as clause-link-in. Useful when you have limited memory but still want to do some inprocessing"); + program.add_argument("--maxsol") + .action([&](const auto& a) {max_nr_of_solutions = std::atoll(a.c_str());}) + .default_value(max_nr_of_solutions) + .help("Search for given amount of solutions. Thanks to Jannis Harder for the decision-based banning idea"); + program.add_argument("--polar") + .default_value("auto") + .help("{true,false,rnd,auto,stable} Selects polarity mode. 'true' -> selects only positive polarity when branching. 'false' -> selects only negative polarity when branching. 'auto' -> selects last polarity used (also called 'caching')"); + program.add_argument("--scc") + .action([&](const auto& a) {conf.doFindAndReplaceEqLits = std::atoi(a.c_str());}) + .default_value(conf.doFindAndReplaceEqLits) + .help("Find equivalent literals through SCC and replace them"); + + #ifdef STATS_NEEDED + program.add_argument("--clid"). + .flag() + .action([&](const auto& a) {clause_ID_needed = true;}) + .help("Add clause IDs to FRAT output") + #endif + + #ifdef FINAL_PREDICTOR + po::options_description predictOptions("Predict options"); + predictOptions.add_options() + program.add_argument("--predloc") + .action([&](const auto& a) {conf.pred_conf_location = std::atoi(a.c_str());}) + .default_value(conf.pred_conf_location) + .help("Directory where predictor_short.json, predictor_long.json, predictor_forever.json are") + program.add_argument("--predtype") + .action([&](const auto& a) {conf.predictor_type = std::atoi(a.c_str());}) + .default_value(conf.predictor_type) + .help("Type of predictor. Supported: py, xgb, lgbm") + program.add_argument("--predtables") + .action([&](const auto& a) {conf.pred_tables = std::atoi(a.c_str());}) + .default_value(conf.pred_tables) + .help("000 = normal for all, 111 = ancestor for all") + program.add_argument("--predbestfeats") + .action([&](const auto& a) {conf.predict_best_feat_fname = a);}) + .default_value(conf.predict_best_feat_fname) + .help("Model python file name") + + //size + program.add_argument("--predshortsize") + .action([&](const auto& a) {conf.pred_short_size = std::atoi(a.c_str());}) + .default_value(conf.pred_short_size) + .help("Pred short multiplier") + program.add_argument("--predlongsize") + .action([&](const auto& a) {conf.pred_long_size = std::atoi(a.c_str());}) + .default_value(conf.pred_long_size) + .help("Pred long multiplier") + program.add_argument("--predforeversize") + .action([&](const auto& a) {conf.pred_forever_size = std::atoi(a.c_str());}) + .default_value(conf.pred_forever_size) + .help("Pred forever multiplier") + program.add_argument("--predforevercutoff") + .action([&](const auto& a) {conf.pred_forever_cutoff = std::atoi(a.c_str());}) + .default_value(conf.pred_forever_cutoff) + .help("If non-zero, ONLY this determines what's MOVED to or KEPT IN 'forever'.") + program.add_argument("--predforeverpow") + .action([&](const auto& a) {conf.pred_forever_size_pow = std::atof(a.c_str());}) + .default_value(conf.pred_forever_size_pow) + .help("Pred forever power to raise the conflicts to") + program.add_argument("--ordertier2by") + .action([&](const auto& a) {conf.order_tier2_by = std::atoi(a.c_str());}) + .default_value(conf.order_tier2_by) + .help("Order Tier 2 by Tier 2/1/0 prediction") + + //move or del? + program.add_argument("--movefromtier0") + .action([&](const auto& a) {conf.move_from_tier0 = std::atoi(a.c_str());}) + .default_value(conf.move_from_tier0) + .help("Move from tier0 to tier1? If set to 0, then it's deleted instead of moved.") + program.add_argument("--movefromtier1") + .action([&](const auto& a) {conf.move_from_tier1 = std::atoi(a.c_str());}) + .default_value(conf.move_from_tier1) + .help("Move from tier1 to tier2? If set to 0, then it's deleted instead of moved.") + + //printing + program.add_argument("--dumppreddistrib") + .action([&](const auto& a) {conf.dump_pred_distrib = std::atoi(a.c_str());}) + .default_value(conf.dump_pred_distrib) + .help("Dump predict distirution to pred_distrib.csv") + + //chunk + program.add_argument("--predlongchunk") + .action([&](const auto& a) {conf.pred_long_chunk = std::atoi(a.c_str());}) + .default_value(conf.pred_long_chunk) + help("Pred long chunk multiplier") + program.add_argument("--predforeverchunk") + .action([&](const auto& a) {conf.pred_forever_chunk = std::atoi(a.c_str());}) + .default_value(conf.pred_forever_chunk) + help("Pred forever chunk multiplier") + program.add_argument("--predforeverchunkmult") + .action([&](const auto& a) {conf.pred_forever_chunk_mult = std::atof(a.c_str());}) + .default_value(conf.pred_forever_chunk_mult) + help("Pred forever chunk should be POW multiplied just like forever. 0/1 (i.e. true/false) option") + + //Check intervals for LONG and FOREVER + program.add_argument("--predlongcheckn") + .action([&](const auto& a) {conf.pred_long_check_every_n = std::atoi(a.c_str());}) + .default_value(conf.pred_long_check_every_n) + .help("Pred long check over limit every N") + program.add_argument("--predforevercheckn") + .action([&](const auto& a) {conf.pred_forever_check_every_n = std::atoi(a.c_str());}) + .default_value(conf.pred_forever_check_every_n) + .help("Pred forever check over limit every N") + + // Some old stuff + program.add_argument("--preddistillsmallgue") + .action([&](const auto& a) {conf.pred_distill_only_smallgue = std::atoi(a.c_str());}) + .default_value(conf.pred_distill_only_smallgue) + .help("Only distill small glue clauses") + + // Lock clauses in + program.add_argument("--preddontmovetime") + .action([&](const auto& a) {conf.pred_dontmove_until_timeinside = std::atoi(a.c_str());}) + .default_value(conf.pred_dontmove_until_timeinside) + .help("Don't move clause until it's time has passed. For lev0 and lev1 only. If 1 = half time needs to pass (e.g. if we check every 50k conflicts, it must have been in the solver for 25k or it's force-kept). If 2 = the full time is needed, in the example, 25k.") + #endif + + + /* po::options_description restartOptions("Restart options"); */ + /* restartOptions.add_options() */ + std::ostringstream s_local_glue_multiplier; + s_local_glue_multiplier << std::setprecision(4) << conf.local_glue_multiplier; + program.add_argument("--restart") + .default_value("auto") + .help("{geom, glue, luby} Restart strategy to follow."); + program.add_argument("--rstfirst") + .action([&](const auto& a) {conf.restart_first = std::atoi(a.c_str());}) + .default_value(conf.restart_first) + .help("The size of the base restart"); + program.add_argument("--gluehist") + .action([&](const auto& a) {conf.shortTermHistorySize = std::atoi(a.c_str());}) + .default_value(conf.shortTermHistorySize) + .help("The size of the moving window for short-term glue history of redundant clauses. If higher, the minimal number of conflicts between restarts is longer"); + program.add_argument("--lwrbndblkrest") + .action([&](const auto& a) {conf.lower_bound_for_blocking_restart = std::atoi(a.c_str());}) + .default_value(conf.lower_bound_for_blocking_restart) + .help("Lower bound on blocking restart -- don't block before this many conflicts"); + program.add_argument("--locgmult" ) + .action([&](const auto& a) {conf.local_glue_multiplier = std::atof(a.c_str());}) + .default_value(conf.local_glue_multiplier) + /* .s_local_glue_multiplier.str()*/ + .help("The multiplier used to determine if we should restart during glue-based restart"); + program.add_argument("--ratiogluegeom") + .action([&](const auto& a) {conf.ratio_glue_geom = std::atof(a.c_str());}) + .default_value(conf.ratio_glue_geom) + .help("Ratio of glue vs geometric restarts -- more is more glue"); + program.add_argument("--blockingglue") + .action([&](const auto& a) {conf.do_blocking_restart = std::atoi(a.c_str());}) + .default_value(conf.do_blocking_restart) + .help("Do blocking restart for glues"); + + std::ostringstream s_incclean; + std::ostringstream s_adjust_low; + s_adjust_low << std::setprecision(2) << conf.adjust_glue_if_too_many_tier0; + + /* po::options_description reduceDBOptions("Redundant clause options"); */ + /* reduceDBOptions.add_options() */ + program.add_argument("--gluecut0") + .action([&](const auto& a) {conf.glue_put_lev0_if_below_or_eq = std::atoi(a.c_str());}) + .default_value(conf.glue_put_lev0_if_below_or_eq) + .help("Glue value for lev 0 ('keep') cut"); + program.add_argument("--gluecut1") + .action([&](const auto& a) {conf.glue_put_lev1_if_below_or_eq = std::atoi(a.c_str());}) + .default_value(conf.glue_put_lev1_if_below_or_eq) + .help("Glue value for lev 1 cut ('give another shot'"); + program.add_argument("--adjustglue") + .action([&](const auto& a) {conf.adjust_glue_if_too_many_tier0 = std::atof(a.c_str());}) + .default_value(conf.adjust_glue_if_too_many_tier0) + //, s_adjust_low.str() + .help("If more than this % of clauses is LOW glue (level 0) then lower the glue cutoff by 1 -- once and never again"); + program.add_argument("--everylev1") + .action([&](const auto& a) {conf.every_lev1_reduce = std::atoi(a.c_str());}) + .default_value(conf.every_lev1_reduce) + .help("Reduce lev1 clauses every N"); + program.add_argument("--everylev2") + .action([&](const auto& a) {conf.every_lev2_reduce = std::atoi(a.c_str());}) + .default_value(conf.every_lev2_reduce) + .help("Reduce lev2 clauses every N"); + #if defined(STATS_NEEDED) || defined(FINAL_PREDICTOR) + program.add_argument("--everypred") + .action([&](const auto& a) {conf.every_pred_reduce = std::atoi(a.c_str());}) + .default_value(conf.every_pred_reduce) + .help("Reduce final predictor (lev3) clauses every N, and produce data at every N in case of STATS_NEEDED"); + #endif + program.add_argument("--lev1usewithin") + .action([&](const auto& a) {conf.must_touch_lev1_within = std::atoi(a.c_str());}) + .default_value(conf.must_touch_lev1_within) + .help("Learnt clause must be used in lev1 within this timeframe or be dropped to lev2"); + + /* po::options_description varPickOptions("Variable branching options"); */ + /* varPickOptions.add_options() */ + program.add_argument("--branchstr") + .action([&](const auto& a) {conf.branch_strategy_setup = a;}) + .default_value(conf.branch_strategy_setup) + .help("Branch strategy string that switches between different branch strategies while solving e.g. 'vsids1+vsids2'"); + + program.add_argument("--nobansol") + .flag() + .action([&](const auto&) {dont_ban_solutions = true;}) + .help("Don't ban the solution once it's found"); + program.add_argument("--debuglib") + .action([&](const auto& a) {debugLib = a;}) + .help("Parse special comments to run solve/simplify during parsing of CNF"); + + /* po::options_description breakid_options("Breakid options"); */ + /* breakid_options.add_options() */ + program.add_argument("--breakid") + .action([&](const auto& a) {conf.doBreakid = std::atoi(a.c_str());}) + .default_value(conf.doBreakid) + .help("Run BreakID to break symmetries."); + program.add_argument("--breakideveryn") + .action([&](const auto& a) {conf.breakid_every_n = std::atoi(a.c_str());}) + .default_value(conf.breakid_every_n) + .help("Run BreakID every N simplification iterations"); + program.add_argument("--breakidmaxlits") + .action([&](const auto& a) {conf.breakid_lits_limit_K = std::atoll(a.c_str());}) + .default_value(conf.breakid_lits_limit_K) + .help("Maximum number of literals in thousands. If exceeded, BreakID will not run"); + program.add_argument("--breakidmaxcls") + .action([&](const auto& a) {conf.breakid_cls_limit_K = std::atoll(a.c_str());}) + .default_value(conf.breakid_cls_limit_K) + .help("Maximum number of clauses in thousands. If exceeded, BreakID will not run"); + program.add_argument("--breakidmaxvars") + .action([&](const auto& a) {conf.breakid_vars_limit_K = std::atoll(a.c_str());}) + .default_value(conf.breakid_vars_limit_K) + .help("Maximum number of variables in thousands. If exceeded, BreakID will not run");; + program.add_argument("--breakidtime") + .action([&](const auto& a) {conf.breakid_time_limit_K = std::atoll(a.c_str());}) + .default_value(conf.breakid_time_limit_K) + .help("Maximum number of steps taken during automorphism finding."); + program.add_argument("--breakidcls") + .action([&](const auto& a) {conf.breakid_max_constr_per_permut = std::atoi(a.c_str());}) + .default_value(conf.breakid_max_constr_per_permut) + .help("Maximum number of breaking clauses per permutation.");; + program.add_argument("--breakidmatrix") + .action([&](const auto& a) {conf.breakid_matrix_detect = std::atoi(a.c_str());}) + .default_value(conf.breakid_matrix_detect) + .help("Detect matrix row interchangability"); + ; + + /* po::options_description sls_options("Stochastic Local Search options"); */ + /* sls_options.add_options() */ + program.add_argument("--sls") + .action([&](const auto& a) {conf.doSLS = std::atoi(a.c_str());}) + .default_value(conf.doSLS) + .help("Run SLS during simplification"); + program.add_argument("--slstype") + .action([&](const auto& a) {conf.which_sls = a;}) + .default_value(conf.which_sls) + .help("Which SLS to run. Allowed values: walksat, yalsat, ccnr, ccnr_yalsat"); + program.add_argument("--slsmaxmem") + .action([&](const auto& a) {conf.sls_memoutMB = std::atoi(a.c_str());}) + .default_value(conf.sls_memoutMB) + .help("Maximum number of MB to give to SLS solver. Doesn't run SLS solver if the memory usage would be more than this."); + program.add_argument("--slseveryn") + .action([&](const auto& a) {conf.sls_every_n = std::atoi(a.c_str());}) + .default_value(conf.sls_every_n) + .help("Run SLS solver every N simplifications only"); + program.add_argument("--yalsatmems") + .action([&](const auto& a) {conf.yalsat_max_mems = std::atoi(a.c_str());}) + .default_value(conf.yalsat_max_mems) + .help("Run Yalsat with this many mems*million timeout. Limits time of yalsat run"); + program.add_argument("--walksatruns") + .action([&](const auto& a) {conf.walksat_max_runs = std::atoi(a.c_str());}) + .default_value(conf.walksat_max_runs) + .help("Max 'runs' for WalkSAT. Limits time of WalkSAT run"); + program.add_argument("--slsgetphase") + .action([&](const auto& a) {conf.sls_get_phase = std::atoi(a.c_str());}) + .default_value(conf.sls_get_phase) + .help("Get phase from SLS solver, set as new phase for CDCL"); + program.add_argument("--slsccnraspire") + .action([&](const auto& a) {conf.sls_ccnr_asipire = std::atoi(a.c_str());}) + .default_value(conf.sls_ccnr_asipire) + .help("Turn aspiration on/off for CCANR"); + program.add_argument("--slstobump") + .action([&](const auto& a) {conf.sls_how_many_to_bump = std::atoi(a.c_str());}) + .default_value(conf.sls_how_many_to_bump) + .help("How many variables to bump in CCNR"); + program.add_argument("--slstobumpmaxpervar") + .action([&](const auto& a) {conf.sls_bump_var_max_n_times = std::atoi(a.c_str());}) + .default_value(conf.sls_bump_var_max_n_times) + .help("How many times to bump an individual variable's activity in CCNR"); + program.add_argument("--slsbumptype") + .action([&](const auto& a) {conf.sls_bump_type = std::atoi(a.c_str());}) + .default_value(conf.sls_bump_type) + .help("How to calculate what variable to bump. 1 = clause-based, 2 = var-flip-based, 3 = var-score-based"); + + /* po::options_description probeOptions("Probing options"); */ + /* probeOptions.add_options() */ + program.add_argument("--transred") + .action([&](const auto& a) {conf.doTransRed = std::atoi(a.c_str());}) + .default_value(conf.doTransRed) + .help("Remove useless binary clauses (transitive reduction)"); + program.add_argument("--intree") + .action([&](const auto& a) {conf.doIntreeProbe = std::atoi(a.c_str());}) + .default_value(conf.doIntreeProbe) + .help("Carry out intree-based probing"); + program.add_argument("--intreemaxm") + .action([&](const auto& a) {conf.intree_time_limitM = std::atoll(a.c_str());}) + .default_value(conf.intree_time_limitM) + .help("Time in mega-bogoprops to perform intree probing"); + program.add_argument("--otfhyper") + .action([&](const auto& a) {conf.do_hyperbin_and_transred = std::atoi(a.c_str());}) + .default_value(conf.do_hyperbin_and_transred) + .help("Perform hyper-binary resolution during probing"); + + /* po::options_description simp_schedules("Simplification schedules"); */ + /* simp_schedules.add_options() */ + std::ostringstream ssERatio; + ssERatio << std::setprecision(4) << conf.varElimRatioPerIter; + std::ostringstream s_num_conflicts_of_search_inc; + s_num_conflicts_of_search_inc << std::setprecision(4) << conf.num_conflicts_of_search_inc; + program.add_argument("--schedsimp") + .action([&](const auto& a) {conf.do_simplify_problem = std::atoi(a.c_str());}) + .default_value(conf.do_simplify_problem) + .help("Perform simplification rounds. If 0, we never perform any."); + program.add_argument("--presimp") + .action([&](const auto& a) {conf.simplify_at_startup = std::atoi(a.c_str());}) + .default_value(conf.simplify_at_startup) + .help("Perform simplification at the very start"); + program.add_argument("--allpresimp") + .action([&](const auto& a) {conf.simplify_at_every_startup = std::atoi(a.c_str());}) + .default_value(conf.simplify_at_every_startup) + .help("Perform simplification at EVERY start -- only matters in library mode"); + program.add_argument("-n", "--nonstop") + .action([&](const auto& a) {conf.never_stop_search = std::atoi(a.c_str());}) + .default_value(conf.never_stop_search) + .help("Never stop the search() process in class SATSolver"); + program.add_argument("--maxnumsimppersolve") + .action([&](const auto& a) {conf.max_num_simplify_per_solve_call = std::atoi(a.c_str());}) + .default_value(conf.max_num_simplify_per_solve_call) + .help("Maximum number of simplifiactions to perform for every solve() call. After this, no more inprocessing will take place."); + + program.add_argument("--schedule") + .action([&](const auto& a) {conf.simplify_schedule_nonstartup = a;}) + .help("Schedule for simplification during run"); + program.add_argument("--preschedule") + .action([&](const auto& a) {conf.simplify_schedule_startup = a;}) + .help("Schedule for simplification at startup"); + program.add_argument("--occsimp") + .action([&](const auto& a) {conf.perform_occur_based_simp = std::atoi(a.c_str());}) + .default_value(conf.perform_occur_based_simp) + .help("Perform occurrence-list-based optimisations (variable elimination, subsumption, bounded variable addition...)"); + program.add_argument("--confbtwsimp") + .action([&](const auto& a) {conf.num_conflicts_of_search = std::atoll(a.c_str());}) + .default_value(conf.num_conflicts_of_search) + .help("Start first simplification after this many conflicts"); + program.add_argument("--confbtwsimpinc") + .action([&](const auto& a) {conf.num_conflicts_of_search_inc = std::atof(a.c_str());}) + .default_value(conf.num_conflicts_of_search_inc) + //s_num_conflicts_of_search_inc.str() + .help("Simp rounds increment by this power of N"); + + /* po::options_description tern_res_options("Ternary resolution"); */ + /* tern_res_options.add_options() */ + std::ostringstream tern_keep; + tern_keep << std::setprecision(2) << conf.ternary_keep_mult; + std::ostringstream tern_max_create; + tern_max_create << std::setprecision(2) << conf.ternary_max_create; + program.add_argument("--tern") + .action([&](const auto& a) {conf.doTernary = std::atoi(a.c_str());}) + .default_value(conf.doTernary) + .help("Perform Ternary resolution"); + program.add_argument("--terntimelim") + .action([&](const auto& a) {conf.ternary_res_time_limitM = std::atoll(a.c_str());}) + .default_value(conf.ternary_res_time_limitM) + .help("Time-out in bogoprops M of ternary resolution as per paper 'Look-Ahead Versus Look-Back for Satisfiability Problems'"); + program.add_argument("--ternkeep") + .action([&](const auto& a) {conf.ternary_keep_mult = std::atof(a.c_str());}) + .default_value(conf.ternary_keep_mult) + //, tern_keep.str() + .help("Keep ternary resolution clauses only if they are touched within this multiple of 'lev1usewithin'"); + program.add_argument("--terncreate") + .action([&](const auto& a) {conf.ternary_max_create = std::atof(a.c_str());}) + .default_value(conf.ternary_max_create) + //, tern_max_create.str() + .help("Create only this multiple (of linked in cls) ternary resolution clauses per simp run"); + program.add_argument("--ternbincreate") + .action([&](const auto& a) {conf.allow_ternary_bin_create = std::atoi(a.c_str());}) + .default_value(conf.allow_ternary_bin_create) + //, tern_max_create.str() + .help("Allow ternary resolving to generate binary clauses"); + + /* po::options_description occ_mem_limits("Occ-based simplification memory limits"); */ + /* occ_mem_limits.add_options() */ + program.add_argument("--occredmax") + .action([&](const auto& a) {conf.maxRedLinkInSize = std::atoi(a.c_str());}) + .default_value(conf.maxRedLinkInSize) + .help("Don't add to occur list any redundant clause larger than this"); + program.add_argument("--occredmaxmb") + .action([&](const auto& a) {conf.maxOccurRedMB = std::atof(a.c_str());}) + .default_value(conf.maxOccurRedMB) + .help("Don't allow redundant occur size to be beyond this many MB"); + program.add_argument("--occirredmaxmb") + .action([&](const auto& a) {conf.maxOccurIrredMB = std::atof(a.c_str());}) + .default_value(conf.maxOccurIrredMB) + .help("Don't allow irredundant occur size to be beyond this many MB"); + ; + + /* po::options_description sub_str_time_limits("Occ-based subsumption and strengthening time limits"); */ + /* sub_str_time_limits.add_options() */ + program.add_argument("--strengthen") + .action([&](const auto& a) {conf.do_strengthen_with_occur = std::atoi(a.c_str());}) + .default_value(conf.do_strengthen_with_occur) + .help("Perform clause contraction through self-subsuming resolution as part of the occurrence-subsumption system"); + program.add_argument("--weakentimelim") + .action([&](const auto& a) {conf.weaken_time_limitM = std::atoll(a.c_str());}) + .default_value(conf.weaken_time_limitM) + .help("Time-out in bogoprops M of weakeaning used"); + program.add_argument("--substimelim") + .action([&](const auto& a) {conf.subsumption_time_limitM = std::atoll(a.c_str());}) + .default_value(conf.subsumption_time_limitM) + .help("Time-out in bogoprops M of subsumption of long clauses with long clauses, after computing occur"); + program.add_argument("--substimelimbinratio") + .action([&](const auto& a) {conf.subsumption_time_limit_ratio_sub_str_w_bin = std::atof(a.c_str());}) + .default_value(conf.subsumption_time_limit_ratio_sub_str_w_bin) + .help("Ratio of subsumption time limit to spend on sub&str long clauses with bin"); + program.add_argument("--substimelimlongratio") + .action([&](const auto& a) {conf.subsumption_time_limit_ratio_sub_w_long = std::atof(a.c_str());}) + .default_value(conf.subsumption_time_limit_ratio_sub_w_long) + .help("Ratio of subsumption time limit to spend on sub long clauses with long"); + program.add_argument("--strstimelim") + .action([&](const auto& a) {conf.strengthening_time_limitM = std::atoll(a.c_str());}) + .default_value(conf.strengthening_time_limitM) + .help("Time-out in bogoprops M of strengthening of long clauses with long clauses, after computing occur"); + program.add_argument("--sublonggothrough") + .action([&](const auto& a) {conf.subsume_gothrough_multip = std::atof(a.c_str());}) + .default_value(conf.subsume_gothrough_multip) + .help("How many times go through subsume"); + ; + + /* po::options_description bva_options("BVA options"); */ + /* bva_options.add_options() */ + program.add_argument("--bva") + .action([&](const auto& a) {conf.do_bva = std::atoi(a.c_str());}) + .default_value(conf.do_bva) + .help("Perform bounded variable addition"); + program.add_argument("--bvaeveryn") + .action([&](const auto& a) {conf.bva_every_n = std::atoi(a.c_str());}) + .default_value(conf.bva_every_n) + .help("Perform BVA only every N occ-simplify calls"); + program.add_argument("--bvalim") + .action([&](const auto& a) {conf.bva_limit_per_call = std::atoi(a.c_str());}) + .default_value(conf.bva_limit_per_call) + .help("Maximum number of variables to add by BVA per call"); + program.add_argument("--bva2lit") + .action([&](const auto& a) {conf.bva_also_twolit_diff = std::atoi(a.c_str());}) + .default_value(conf.bva_also_twolit_diff) + .help("BVA with 2-lit difference hack, too. Beware, this reduces the effectiveness of 1-lit diff"); + program.add_argument("--bvato") + .action([&](const auto& a) {conf.bva_time_limitM = std::atoll(a.c_str());}) + .default_value(conf.bva_time_limitM) + .help("BVA time limit in bogoprops M"); + ; + + /* po::options_description bve_options("BVE options"); */ + /* bve_options.add_options() */ + program.add_argument("--varelim") + .action([&](const auto& a) {conf.doVarElim = std::atoi(a.c_str());}) + .default_value(conf.doVarElim) + .help("Perform variable elimination as per Een and Biere"); + program.add_argument("--varelimto") + .action([&](const auto& a) {conf.varelim_time_limitM = std::atoll(a.c_str());}) + .default_value(conf.varelim_time_limitM) + .help("Var elimination bogoprops M time limit"); + program.add_argument("--varelimover") + .action([&](const auto& a) {conf.min_bva_gain = std::atoi(a.c_str());}) + .default_value(conf.min_bva_gain) + .help("Do BVE until the resulting no. of clause increase is less than X. Only power of 2 makes sense, i.e. 2,4,8..."); + program.add_argument("--emptyelim") + .action([&](const auto& a) {conf.do_empty_varelim = std::atoi(a.c_str());}) + .default_value(conf.do_empty_varelim) + .help("Perform empty resolvent elimination using bit-map trick"); + program.add_argument("--varelimmaxmb") + .action([&](const auto& a) {conf.var_linkin_limit_MB = std::atoi(a.c_str());}) + .default_value(conf.var_linkin_limit_MB) + .help("Maximum extra MB of memory to use for new clauses during varelim"); + program.add_argument("--eratio") + .action([&](const auto& a) {conf.varElimRatioPerIter = std::atof(a.c_str());}) + .default_value(conf.varElimRatioPerIter) + //, ssERatio.str() + .help("Eliminate this ratio of free variables at most per variable elimination iteration"); + program.add_argument("--varelimcheckres") + .action([&](const auto& a) {conf.varelim_check_resolvent_subs = std::atoi(a.c_str());}) + .default_value(conf.varelim_check_resolvent_subs) + .help("BVE should check whether resolvents subsume others and check for exact size increase"); + + /* po::options_description xorOptions("XOR-related options"); */ + /* xorOptions.add_options() */ + program.add_argument("--xor") + .action([&](const auto& a) {conf.doFindXors = std::atoi(a.c_str());}) + .default_value(conf.doFindXors) + .help("Discover long XORs"); + program.add_argument("--maxxorsize") + .action([&](const auto& a) {conf.maxXorToFind = std::atoi(a.c_str());}) + .default_value(conf.maxXorToFind) + .help("Maximum XOR size to find"); + program.add_argument("--xorfindtout") + .action([&](const auto& a) {conf.xor_finder_time_limitM = std::atoll(a.c_str());}) + .default_value(conf.xor_finder_time_limitM) + .help("Time limit for finding XORs"); + program.add_argument("--varsperxorcut") + .action([&](const auto& a) {conf.xor_var_per_cut = std::atoi(a.c_str());}) + .default_value(conf.xor_var_per_cut) + .help("Number of _real_ variables per XOR when cutting them. So 2 will have XORs of size 4 because 1 = connecting to previous, 1 = connecting to next, 2 in the midde. If the XOR is 4 long, it will be just one 4-long XOR, no connectors"); + program.add_argument("--maxxormat") + .action([&](const auto& a) {conf.maxXORMatrix = std::atoll(a.c_str());}) + .default_value(conf.maxXORMatrix) + .help("Maximum matrix size (=num elements) that we should try to echelonize"); + program.add_argument("--forcepreservexors") + .action([&](const auto& a) {conf.force_preserve_xors = std::atoi(a.c_str());}) + .default_value(conf.force_preserve_xors) + .help("Force preserving XORs when they have been found. Easier to make sure XORs are not lost through simplifiactions such as strenghtening"); + + /* po::options_description gateOptions("Gate-related options"); */ + /* gateOptions.add_options() */ + program.add_argument("--gates") + .action([&](const auto& a) {conf.doGateFind = std::atoi(a.c_str());}) + .default_value(conf.doGateFind) + .help("Find gates."); + program.add_argument("--printgatedot") + .action([&](const auto& a) {conf.doPrintGateDot = std::atoi(a.c_str());}) + .default_value(conf.doPrintGateDot) + .help("Print gate structure regularly to file 'gatesX.dot'"); + program.add_argument("--gatefindto") + .action([&](const auto& a) {conf.gatefinder_time_limitM = std::atoll(a.c_str());}) + .default_value(conf.gatefinder_time_limitM) + .help("Max time in bogoprops M to find gates"); + + /* po::options_description conflOptions("Conflict options"); */ + /* conflOptions.add_options() */ + program.add_argument("--recur") + .action([&](const auto& a) {conf.doRecursiveMinim = std::atoi(a.c_str());}) + .default_value(conf.doRecursiveMinim) + .help("Perform recursive minimisation"); + program.add_argument("--moreminim") + .action([&](const auto& a) {conf.doMinimRedMore = std::atoi(a.c_str());}) + .default_value(conf.doMinimRedMore) + .help("Perform strong minimisation at conflict gen."); + program.add_argument("--moremoreminim") + .action([&](const auto& a) {conf.doMinimRedMoreMore = std::atoi(a.c_str());}) + .default_value(conf.doMinimRedMoreMore) + .help("Perform even stronger minimisation at conflict gen."); + program.add_argument("--moremorealways") + .action([&](const auto& a) {conf.doAlwaysFMinim = std::atoi(a.c_str());}) + .default_value(conf.doAlwaysFMinim) + .help("Always strong-minimise clause"); + program.add_argument("--decbased") + .action([&](const auto& a) {conf.do_decision_based_cl = std::atoi(a.c_str());}) + .default_value(conf.do_decision_based_cl) + .help("Create decision-based conflict clauses when the UIP clause is too large"); + + /* po::options_description propOptions("Glue options"); */ + /* propOptions.add_options() */ + program.add_argument("--updateglueonanalysis") + .action([&](const auto& a) {conf.update_glues_on_analyze = std::atoi(a.c_str());}) + .default_value(conf.update_glues_on_analyze) + .help("Update glues while analyzing"); + program.add_argument("--maxgluehistltlimited") + .action([&](const auto& a) {conf.max_glue_cutoff_gluehistltlimited = std::atoi(a.c_str());}) + .default_value(conf.max_glue_cutoff_gluehistltlimited) + .help("Maximum glue used by glue-based restart strategy when populating glue history."); + + /* po::options_description chrono_bt_opts("Propagation options"); */ + /* chrono_bt_opts.add_options() */ + program.add_argument("--diffdeclevelchrono") + .action([&](const auto& a) {conf.diff_declev_for_chrono = std::atoi(a.c_str());}) + .default_value(conf.diff_declev_for_chrono) + .help("Difference in decision level is more than this, perform chonological backtracking instead of non-chronological backtracking. Giving -1 means it is never turned on (overrides '--confltochrono -1' in this case)."); + +#ifdef USE_SQLITE3 + /* po::options_description sqlOptions("SQL options"); */ + /* sqlOptions.add_options() */ + program.add_argument("--sql") + .action([&](const auto& a) {sql = std::atoi(a.c_str());}) + .default_value(0) + .help("Write to SQL. 0 = no SQL, 1 or 2 = sqlite"); + program.add_argument("--sqlitedb") + .action([&](const auto& a) {sqlite_filename = a;}) + .default_value(conf.verbosity) + .help("[0-10] Verbosity of solver. 0 = only solution");; + program.add_argument("--sqlitedboverwrite") + .action([&](const auto& a) {conf.sql_overwrite_file = std::atoi(a.c_str());}) + .default_value(conf.sql_overwrite_file) + .help("Overwrite the SQLite database file if it exists"); + program.add_argument("--cldatadumpratio") + .action([&](const auto& a) {conf.dump_individual_cldata_ratio = std::atof(a.c_str());}) + .default_value(conf.dump_individual_cldata_ratio) + .help("Only dump this ratio of clauses' data, randomly selected. Since machine learning doesn't need that much data, this can reduce the data you have to deal with."); + program.add_argument("--cllockdatagen") + .action([&](const auto& a) {conf.lock_for_data_gen_ratio = std::atof(a.c_str());}) + .default_value(conf.lock_for_data_gen_ratio) + .help("Lock for data generation into lev0, setting locked_for_data_gen. Only works when clause is marked for dumping ('--cldatadumpratio' )"); +#endif + + /* po::options_description printOptions("Printing options"); */ + /* printOptions.add_options() */ + program.add_argument("--verbstat") + .action([&](const auto& a) {conf.verbStats = std::atoi(a.c_str());}) + .default_value(conf.verbStats) + .help("Change verbosity of statistics at the end of the solving [0..3]"); + program.add_argument("--verbrestart") + .action([&](const auto& a) {conf.print_full_restart_stat = std::atoi(a.c_str());}) + .default_value(conf.print_full_restart_stat) + .help("Print more thorough, but different stats"); + program.add_argument("--verballrestarts") + .action([&](const auto& a) {conf.print_all_restarts = std::atoi(a.c_str());}) + .default_value(conf.print_all_restarts) + .help("Print a line for every restart"); + program.add_argument("--printsol,s") + .action([&](const auto& a) {printResult = std::atoi(a.c_str());}) + .default_value(printResult) + .help("Print assignment if solution is SAT"); + program.add_argument("--restartprint") + .action([&](const auto& a) {conf.print_restart_line_every_n_confl = std::atoi(a.c_str());}) + .default_value(conf.print_restart_line_every_n_confl) + .help("Print restart status lines at least every N conflicts"); + + + /* po::options_description distillOptions("Distill options"); */ + /* distillOptions.add_options() */ + program.add_argument("--distill") + .action([&](const auto& a) {conf.do_distill_clauses = std::atoi(a.c_str());}) + .default_value(conf.do_distill_clauses) + .help("Regularly execute clause distillation"); + program.add_argument("--distillbin") + .action([&](const auto& a) {conf.do_distill_bin_clauses = std::atoi(a.c_str());}) + .default_value(conf.do_distill_bin_clauses) + .help("Regularly execute clause distillation"); + program.add_argument("--distillmaxm") + .action([&](const auto& a) {conf.distill_long_cls_time_limitM = std::atoll(a.c_str());}) + .default_value(conf.distill_long_cls_time_limitM) + .help("Maximum number of Mega-bogoprops(~time) to spend on vivifying/distilling long cls by enqueueing and propagating"); + program.add_argument("--distillincconf") + .action([&](const auto& a) {conf.distill_increase_conf_ratio = std::atof(a.c_str());}) + .default_value(conf.distill_increase_conf_ratio) + .help("Multiplier for current number of conflicts OTF distill"); + program.add_argument("--distillminconf") + .action([&](const auto& a) {conf.distill_min_confl = std::atoll(a.c_str());}) + .default_value(conf.distill_min_confl) + .help("Minimum number of conflicts between OTF distill"); + program.add_argument("--distilltier0ratio") + .action([&](const auto& a) {conf.distill_red_tier0_ratio = std::atof(a.c_str());}) + .default_value(conf.distill_red_tier0_ratio) + .help("How much of tier 0 to distill"); + program.add_argument("--distilltier1ratio") + .action([&](const auto& a) {conf.distill_red_tier1_ratio = std::atof(a.c_str());}) + .default_value(conf.distill_red_tier1_ratio) + .help("How much of tier 1 to distill"); + program.add_argument("--distillirredalsoremratio") + .action([&](const auto& a) {conf.distill_irred_alsoremove_ratio = std::atof(a.c_str());}) + .default_value(conf.distill_irred_alsoremove_ratio) + .help("How much of irred to distill when doing also removal"); + program.add_argument("--distillirrednoremratio") + .action([&](const auto& a) {conf.distill_irred_noremove_ratio = std::atof(a.c_str());}) + .default_value(conf.distill_irred_noremove_ratio) + .help("How much of irred to distill when doing no removal"); + program.add_argument("--distillshuffleeveryn") + .action([&](const auto& a) {conf.distill_rand_shuffle_order_every_n = std::atoi(a.c_str());}) + .default_value(conf.distill_rand_shuffle_order_every_n) + .help("Shuffle to-be-distilled clauses every N cases randomly"); + program.add_argument("--distillsort") + .action([&](const auto& a) {conf.distill_sort = std::atoi(a.c_str());}) + .default_value(conf.distill_sort) + .help("Distill sorting type"); + ; + + /* po::options_description mem_save_opts("Memory saving options"); */ + /* mem_save_opts.add_options() */ + program.add_argument("--renumber") + .action([&](const auto& a) {conf.doRenumberVars = std::atoi(a.c_str());}) + .default_value(conf.doRenumberVars) + .help("Renumber variables to increase CPU cache efficiency"); + program.add_argument("--mustconsolidate") + .action([&](const auto& a) {conf.must_always_conslidate = std::atoi(a.c_str());}) + .default_value(conf.must_always_conslidate) + .help("Always consolidate, even if not useful. This is used for debugging ONLY"); + program.add_argument("--savemem") + .action([&](const auto& a) {conf.doSaveMem = std::atoi(a.c_str());}) + .default_value(conf.doSaveMem) + .help("Save memory by deallocating variable space after renumbering. Only works if renumbering is active."); + program.add_argument("--mustrenumber") + .action([&](const auto& a) {conf.must_renumber = std::atoi(a.c_str());}) + .default_value(conf.must_renumber) + .help("Treat all 'renumber' strategies as 'must-renumber'"); + program.add_argument("--fullwatchconseveryn") + .action([&](const auto& a) {conf.full_watch_consolidate_every_n_confl = std::atoll(a.c_str());}) + .default_value(conf.full_watch_consolidate_every_n_confl) + .help("Consolidate watchlists fully once every N conflicts. Scheduled during simplification rounds."); + + /* po::options_description miscOptions("Misc options"); */ + /* miscOptions.add_options() */ + program.add_argument("--strmaxt") + .action([&](const auto& a) {conf.watch_based_str_time_limitM = std::atoll(a.c_str());}) + .default_value(conf.watch_based_str_time_limitM) + .help("Maximum MBP to spend on distilling long irred cls through watches"); + program.add_argument("--implicitmanip") + .action([&](const auto& a) {conf.doStrSubImplicit = std::atoi(a.c_str());}) + .default_value(conf.doStrSubImplicit) + .help("Subsume and strengthen implicit clauses with each other"); + program.add_argument("--implsubsto") + .action([&](const auto& a) {conf.subsume_implicit_time_limitM = std::atoll(a.c_str());}) + .default_value(conf.subsume_implicit_time_limitM) + .help("Timeout (in bogoprop Millions) of implicit subsumption"); + program.add_argument("--implstrto") + .action([&](const auto& a) {conf.distill_implicit_with_implicit_time_limitM = std::atoll(a.c_str());}) + .default_value(conf.distill_implicit_with_implicit_time_limitM) + .help("Timeout (in bogoprop Millions) of implicit strengthening"); + program.add_argument("--cardfind") + .action([&](const auto& a) {conf.doFindCard = std::atoi(a.c_str());}) + .default_value(conf.doFindCard) + .help("Find cardinality constraints"); + + /* hiddenOptions.add_options() */ + program.add_argument("--sync") + .action([&](const auto& a) {conf.sync_every_confl = std::atoll(a.c_str());}) + .default_value(conf.sync_every_confl) + .help("Sync threads every N conflicts"); + program.add_argument("--clearinter") + .action([&](const auto& a) {need_clean_exit = std::atoi(a.c_str());}) + .default_value(0) + .help("Interrupt threads cleanly, all the time"); + program.add_argument("--zero-exit-status") + .flag() + .action([&](const auto&) {zero_exit_status = true;}) + .help("Exit with status zero in case the solving has finished without an issue"); + program.add_argument("--printtimes") + .action([&](const auto& a) {conf.do_print_times = std::atoi(a.c_str());}) + .default_value(conf.do_print_times) + .help("Print time it took for each simplification run. If set to 0, logs are easier to compare"); + program.add_argument("--maxsccdepth") + .action([&](const auto& a) {conf.max_scc_depth = std::atoi(a.c_str());}) + .default_value(conf.max_scc_depth) + .help("The maximum for scc search depth"); + program.add_argument("--simfrat") + .action([&](const auto& a) {conf.simulate_frat = std::atoi(a.c_str());}) + .default_value(conf.simulate_frat) + .help("Simulate FRAT"); + program.add_argument("--sampling") + .action([&](const auto& a) {sampling_vars_str = a;}) + .default_value(sampling_vars_str) + .help("Sampling vars, separated by comma"); + program.add_argument("--onlysampling") + .flag() + .action([&](const auto&) {only_sampling_solution = true;}) + .help("Print and ban(!) solutions' vars only in 'c ind' or as --sampling '...'"); + program.add_argument("--assump") + .action([&](const auto& a) {assump_filename = a;}) + .default_value(assump_filename) + .help("Assumptions file"); + +#ifdef USE_BOSPHORUS + po::options_description bosph_options("Gauss options"); + bosph_options.add_options() + program.add_argument("--bosph") + .action([&](const auto& a) {conf.do_bosphorus = std::atoi(a.c_str());}) + .default_value(conf.do_bosphorus) + .help("Execute bosphorus"); + program.add_argument("--bospheveryn") + .action([&](const auto& a) {conf.bosphorus_every_n = std::atoi(a.c_str());}) + .default_value(conf.bosphorus_every_n) + .help("Execute bosphorus only every Nth iteration -- starting at Nth iter."); + ; +#endif + +/* po::options_description gaussOptions("Gauss options"); */ +/* gaussOptions.add_options() */ + program.add_argument("--maxmatrixrows") + .action([&](const auto& a) {conf.gaussconf.max_matrix_rows = std::atoi(a.c_str());}) + .default_value(conf.gaussconf.max_matrix_rows) + .help("Set maximum no. of rows for gaussian matrix. Too large matrices" + "should bee discarded for reasons of efficiency"); + program.add_argument("--maxmatrixcols") + .action([&](const auto& a) {conf.gaussconf.max_matrix_columns = std::atoi(a.c_str());}) + .default_value(conf.gaussconf.max_matrix_columns) + .help("Set maximum no. of columns for gaussian matrix. Too large matrices" + "should bee discarded for reasons of efficiency"); + program.add_argument("--autodisablegauss") + .action([&](const auto& a) {conf.gaussconf.autodisable = std::atoi(a.c_str());}) + .default_value(conf.gaussconf.autodisable) + .help("Automatically disable gauss when performing badly"); + program.add_argument("--minmatrixrows") + .action([&](const auto& a) {conf.gaussconf.min_matrix_rows = std::atoi(a.c_str());}) + .default_value(conf.gaussconf.min_matrix_rows) + .help("Set minimum no. of rows for gaussian matrix. Normally, too small" + " matrices are discarded for reasons of efficiency"); + program.add_argument("--maxnummatrices") + .action([&](const auto& a) {conf.gaussconf.max_num_matrices = std::atoi(a.c_str());}) + .default_value(conf.gaussconf.max_num_matrices) + .help("Maximum number of matrices to treat."); + program.add_argument("--detachxor") + .action([&](const auto& a) {conf.xor_detach_reattach = std::atoi(a.c_str());}) + .default_value(conf.xor_detach_reattach) + .help("Detach and reattach XORs"); + program.add_argument("--useallmatrixes") + .action([&](const auto& a) {conf.force_use_all_matrixes = std::atoi(a.c_str());}) + .default_value(conf.force_use_all_matrixes) + .help("Force using all matrices"); + program.add_argument("--detachverb") + .action([&](const auto& a) {conf.xor_detach_verb = std::atoi(a.c_str());}) + .default_value(conf.xor_detach_verb) + .help("If set, verbosity for XOR detach code is upped, ignoring normal verbosity"); + program.add_argument("--gaussusefulcutoff") + .action([&](const auto& a) {conf.gaussconf.min_usefulness_cutoff = std::atof(a.c_str());}) + .default_value(conf.gaussconf.min_usefulness_cutoff) + .help("Turn off Gauss if less than this many usefulenss ratio is recorded"); + program.add_argument("--dumpresult") + .action([&](const auto& a) {result_fname = a;}) + .help("Write solution(s) to this file"); + + //these a kind of special and determine positional options' meanings + program.add_argument("files").remaining().help("input file and FRAT output"); + +} +/* clang-format on */ + +string remove_last_comma_if_exists(std::string s) +{ + std::string s2 = s; + if (s[s.length()-1] == ',') + s2.resize(s2.length()-1); + return s2; +} + +void Main::check_options_correctness() +{ + try { + program.parse_args(argc, argv); + if (program.is_used("--help")) { + cout + << "A universal, fast SAT solver with XOR and Gaussian Elimination support. " << endl + << "Input " + #ifndef USE_ZLIB + << "must be plain" + #else + << "can be either plain or gzipped" + #endif + << " DIMACS with XOR extension" << endl << endl; + + cout + << "cryptominisat5 [options] inputfile [frat-file]" << endl << endl; + + cout << program << endl; + cout << "Normal run schedules:" << endl; + cout << " Default schedule: " + << remove_last_comma_if_exists(conf.simplify_schedule_nonstartup) << endl<< endl; + cout << " Schedule at startup: " + << remove_last_comma_if_exists(conf.simplify_schedule_startup) << endl << endl; + std::exit(0); + } + + /* if (vm.count("help")) */ + /* { */ + /* cout */ + /* << "USAGE: " << argv[0] << " [options] inputfile [frat-trim-file]" << endl */ + + /* << " where input is " */ + /* #ifndef USE_ZLIB */ + /* << "plain" */ + /* #else */ + /* << "plain or gzipped" */ + /* #endif */ + /* << " DIMACS." << endl; */ + + /* cout << help_options_simple << endl; */ + /* std::exit(0); */ + /* } */ + } + catch (const std::exception& err) { + std::cerr << err.what() << std::endl; + std::cerr << program; + exit(-1); + } + + /* } catch (boost::exception_detail::clone_impl< */ + /* boost::exception_detail::error_info_injector >& c */ + /* ) { */ + /* cerr */ + /* << "ERROR: Some option you gave was wrong. Please give '--help' to get help" << endl */ + /* << " Unknown option: " << c.what() << endl; */ + /* std::exit(-1); */ + /* } catch (boost::bad_any_cast &e) { */ + /* std::cerr */ + /* << "ERROR! You probably gave a wrong argument type" << endl */ + /* << " Bad cast: " << e.what() */ + /* << endl; */ + + /* std::exit(-1); */ + /* } catch (boost::exception_detail::clone_impl< */ + /* boost::exception_detail::error_info_injector >& what */ + /* ) { */ + /* cerr */ + /* << "ERROR: Invalid value '" << what.what() << "'" << endl */ + /* << " given to option '" << what.get_option_name() << "'" */ + /* << endl; */ + + /* std::exit(-1); */ + /* } catch (boost::exception_detail::clone_impl< */ + /* boost::exception_detail::error_info_injector >& what */ + /* ) { */ + /* cerr */ + /* << "ERROR: " << what.what() << " of option '" */ + /* << what.get_option_name() << "'" */ + /* << endl; */ + + /* std::exit(-1); */ + /* } catch (boost::exception_detail::clone_impl< */ + /* boost::exception_detail::error_info_injector >& what */ + /* ) { */ + /* cerr */ + /* << "ERROR: You forgot to give a required option '" */ + /* << what.get_option_name() << "'" */ + /* << endl; */ + + /* std::exit(-1); */ + /* } catch (boost::exception_detail::clone_impl< */ + /* boost::exception_detail::error_info_injector >& what */ + /* ) { */ + /* cerr */ + /* << "ERROR: You gave too many positional arguments. Only at most two can be given:" << endl */ + /* << " the 1st the CNF file input, and optionally, the 2nd the FRAT file output" << endl */ + /* << " OR (pre-processing) 1st for the input CNF, 2nd for the simplified CNF" << endl */ + /* << " OR (post-processing) 1st for the solution file" << endl */ + /* ; */ + + /* std::exit(-1); */ + /* } catch (boost::exception_detail::clone_impl< */ + /* boost::exception_detail::error_info_injector >& what */ + /* ) { */ + /* cerr */ + /* << "ERROR: The option you gave was not fully written and matches" << endl */ + /* << " more than one option. Please give the full option name." << endl */ + /* << " The option you gave: '" << what.get_option_name() << "'" < >& what */ + /* ) { */ + /* cerr */ + /* << "ERROR: The option you gave is missing the argument or the" << endl */ + /* << " argument is given with space between the equal sign." << endl */ + /* << " detailed error message: " << what.what() << endl */ + /* ; */ + /* std::exit(-1); */ + /* } */ +} + +void Main::parse_restart_type() +{ + string type = program.get("restart"); + if (type == "geom") + conf.restartType = Restart::geom; + else if (type == "luby") + conf.restartType = Restart::luby; + else if (type == "glue") + conf.restartType = Restart::glue; + else if (type == "auto") + conf.restartType = Restart::automatic; + else throw WrongParam("restart", "unknown restart type"); +} + +void Main::parse_polarity_type() +{ + string mode = program.get("polar"); + if (mode == "true") conf.polarity_mode = PolarityMode::polarmode_pos; + else if (mode == "false") conf.polarity_mode = PolarityMode::polarmode_neg; + else if (mode == "rnd") conf.polarity_mode = PolarityMode::polarmode_rnd; + else if (mode == "auto") conf.polarity_mode = PolarityMode::polarmode_automatic; + else if (mode == "stable") conf.polarity_mode = PolarityMode::polarmode_best; + else if (mode == "weight") conf.polarity_mode = PolarityMode::polarmode_weighted; + else throw WrongParam(mode, "unknown polarity-mode"); +} + +void Main::manually_parse_some_options() +{ + #ifndef USE_BREAKID + if (conf.doBreakid) { + if (conf.verbosity) { + cout << "c BreakID not compiled in, disabling" << endl; + } + conf.doBreakid = false; + } + #endif + + if (conf.max_glue_cutoff_gluehistltlimited > 1000) { + cout << "ERROR: 'Maximum supported glue size is currently 100000" << endl; + exit(-1); + } + + if (conf.which_sls != "yalsat" && + conf.which_sls != "walksat" && + conf.which_sls != "ccnr_yalsat" && + conf.which_sls != "ccnr") + { + cout << "ERROR: you gave '" << conf.which_sls << " for SLS with the option '--slstype'." + << " This is incorrect, we only accept 'yalsat' and 'walksat'" + << endl; + } + + + if (conf.yalsat_max_mems < 1) { + cout << "ERROR: '--walkmems' must be at least 1" << endl; + exit(-1); + } + + if (conf.sls_every_n < 1) { + cout << "ERROR: '--walkeveryn' must be at least 1" << endl; + exit(-1); + } + + if (conf.maxXorToFind > MAX_XOR_RECOVER_SIZE) { + cout << "ERROR: The '--maxxorsize' parameter cannot be larger than " << MAX_XOR_RECOVER_SIZE << endl; + exit(-1); + } + + if (conf.shortTermHistorySize <= 0) { + cout + << "You MUST give a short term history size (\"--gluehist\")" << endl + << " greater than 0!" + << endl; + + std::exit(-1); + } + + if (!result_fname.empty()) { + resultfile = new std::ofstream; + resultfile->open(result_fname.c_str()); + if (!(*resultfile)) { + cout << "ERROR: Couldn't open file '" << result_fname << "' for writing result!" << endl; + std::exit(-1); + } + } + + parse_polarity_type(); + parse_restart_type(); + + try { + auto files = program.get>("files"); + if (files.size() > 2) { + cerr << "ERROR: you can only have at most two files as positional options:" + "the input file and the output FRAT file" << endl; + exit(-1); + } + if (!files.empty()) { + input_file = files[0]; +#ifdef USE_SQLITE3 + if (!program.is_used("sqlitedb")) sqlite_filename = input_file + ".sqlite"; + else sqlite_filename = program.get("sqlitedb"); +#endif + fileNamePresent = true; + } else assert(false && "The try() should not have succeeded"); + if (files.size() > 1 || conf.simulate_frat) { + if (files.size() > 1) { + assert(!conf.simulate_frat && "You can't have both simulation of FRAT and frat"); + frat_fname = files[1]; + } + handle_frat_option(); + } + } catch (std::logic_error& e) { + fileNamePresent = false; + } + if (conf.verbosity >= 3) cout << "c Outputting solution to console" << endl; +} + +void Main::parseCommandLine() { + need_clean_exit = 0; + + //Reconstruct the command line so we can emit it later if needed + for(int i = 0; i < argc; i++) { + commandLine += string(argv[i]); + if (i+1 < argc) { + commandLine += " "; + } + } + + add_supported_options(); + /* all_options.add(help_options_complicated); */ + /* all_options.add(hiddenOptions); */ + + /* help_options_simple */ + /* .add(generalOptions) */ + /* ; */ + + check_options_correctness(); + if (program["version"] == true) { + printVersionInfo(); + std::exit(0); + } + + try { + manually_parse_some_options(); + } catch(WrongParam& wp) { + cerr << "ERROR: " << wp.getMsg() << endl; + exit(-1); + } +} + +void Main::check_num_threads_sanity(const unsigned thread_num) const +{ + const unsigned num_cores = std::thread::hardware_concurrency(); + if (num_cores == 0) { + //Library doesn't know much, we can't do any checks. + return; + } + + if (thread_num > num_cores && conf.verbosity) { + std::cout + << "c WARNING: Number of threads requested is more than the number of" + << " cores reported by the system.\n" + << "c WARNING: This is not a good idea in general. It's best to set the" + << " number of threads to the number of real cores" << endl; + } +} + +int Main::solve() +{ + wallclock_time_started = real_time_sec(); + solver = new SATSolver((void*)&conf); + solverToInterrupt = solver; + if (fratf) solver->set_frat(fratf); + if (program.is_used("maxtime")) solver->set_max_time(program.get("maxtime")); + if (program.is_used("maxconfl")) solver->set_max_confl(program.get("maxconfl")); + + check_num_threads_sanity(num_threads); + solver->set_num_threads(num_threads); + if (sql != 0) solver->set_sqlite(sqlite_filename); + + //Print command line used to execute the solver: for options and inputs + if (conf.verbosity) { + printVersionInfo(); + cout + << "c Executed with command line: " + << commandLine + << endl; + } + + solver->add_sql_tag("commandline", commandLine); + solver->add_sql_tag("verbosity", std::to_string(conf.verbosity)); + solver->add_sql_tag("threads", std::to_string(num_threads)); + solver->add_sql_tag("version", solver->get_version()); + solver->add_sql_tag("SHA-revision", solver->get_version_sha1()); + solver->add_sql_tag("env", solver->get_compilation_env()); + #ifdef __GNUC__ + solver->add_sql_tag("compiler", "gcc-" __VERSION__); + #else + solver->add_sql_tag("compiler", "non-gcc"); + #endif + + //Parse in DIMACS (maybe gzipped) files + //solver->log_to_file("mydump.cnf"); + parseInAllFiles(solver); + if (!assump_filename.empty()) { + std::ifstream* tmp = new std::ifstream; + tmp->open(assump_filename.c_str()); + std::string temp; + while(std::getline(*tmp, temp)) { + //Do with temp + int x = std::stoi(temp); + cout << "Assume: " << x << endl; + Lit l = Lit(std::abs(x)-1, x < 0); + assumps.push_back(l); + } + + delete tmp; + } + + lbool ret = multi_solutions(); + if (ret == l_Undef && conf.verbosity) { + cout + << "c Not finished running -- signal caught or some maximum reached" + << endl; + } + if (conf.verbosity) { + solver->print_stats(wallclock_time_started); + } + + printResultFunc(&cout, false, ret); + if (resultfile) { + printResultFunc(resultfile, true, ret); + } + if (ret == l_True && max_nr_of_solutions > 1) { + // If ret is l_True then we must have hit the solution limit. + // Print final number of solutions when we hit the limit here + // as multi_solutions() doesn't. Don't print for a single solution. + if (conf.verbosity) { + cout + << "c Number of solutions found until now: " + << std::setw(6) << max_nr_of_solutions + << endl + << "c maxsol reached" + << endl; + } + } + + return correctReturnValue(ret); +} + +lbool Main::multi_solutions() +{ + if (max_nr_of_solutions == 1 + && fratf == NULL + && !conf.simulate_frat + && debugLib.empty() + ) { + solver->set_single_run(); + } + + unsigned long current_nr_of_solutions = 0; + lbool ret = l_True; + while(current_nr_of_solutions < max_nr_of_solutions && ret == l_True) { + ret = solver->solve(&assumps, only_sampling_solution); + current_nr_of_solutions++; + + if (ret == l_True && current_nr_of_solutions < max_nr_of_solutions) { + printResultFunc(&cout, false, ret); + if (resultfile) { + printResultFunc(resultfile, true, ret); + } + + if (conf.verbosity) { + cout + << "c Number of solutions found until now: " + << std::setw(6) << current_nr_of_solutions + << endl; + } + + if (!dont_ban_solutions) { + ban_found_solution(); + } + } + } + return ret; +} + +void Main::ban_found_solution() +{ + vector lits; + if (sampling_vars.empty()) { + //all of the solution + for (uint32_t var = 0; var < solver->nVars(); var++) { + if (solver->get_model()[var] != l_Undef) { + lits.push_back( Lit(var, (solver->get_model()[var] == l_True)? true : false) ); + } + } + } else { + for (const uint32_t var: sampling_vars) { + if (solver->get_model()[var] != l_Undef) { + lits.push_back( Lit(var, (solver->get_model()[var] == l_True)? true : false) ); + } + } + } + solver->add_clause(lits); +} + +/////////// +// Useful helper functions +/////////// + +void Main::printVersionInfo() +{ + cout << solver->get_text_version_info(); +} + +int Main::correctReturnValue(const lbool ret) const +{ + int retval = -1; + if (ret == l_True) { + retval = 10; + } else if (ret == l_False) { + retval = 20; + } else if (ret == l_Undef) { + retval = 15; + } else { + std::cerr << "Something is very wrong, output is neither l_Undef, nor l_False, nor l_True" << endl; + exit(-1); + } + + if (zero_exit_status) { + return 0; + } else { + return retval; + } +} diff --git a/cryptominisat/cppsrc/src/main.h b/cryptominisat/cppsrc/src/main.h new file mode 100644 index 00000000..eff7e245 --- /dev/null +++ b/cryptominisat/cppsrc/src/main.h @@ -0,0 +1,120 @@ +/****************************************** +Copyright (C) 2009-2020 Authors of CryptoMiniSat, see AUTHORS file + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. +***********************************************/ + +#ifndef MAIN_H +#define MAIN_H + +#include +#include +#include +#include + +#include "argparse.hpp" +#include "main_common.h" +#include "solverconf.h" +#include "cryptominisat.h" + +using std::string; +using std::vector; + +using namespace CMSat; + +class Main: public MainCommon +{ + public: + Main(int argc, char** argv); + ~Main() + { + if (fratf) { + fflush(fratf); + fclose(fratf); + } + + delete solver; + } + + void parseCommandLine(); + virtual int solve(); + + private: + //arguments + int argc; + char** argv; + string var_elim_strategy; + void check_options_correctness(); + void manually_parse_some_options(); + void parse_restart_type(); + void parse_polarity_type(); + void check_num_threads_sanity(const unsigned thread_num) const; + argparse::ArgumentParser program = argparse::ArgumentParser("cryptominisat5"); + + protected: + //Options + virtual void add_supported_options(); + virtual void call_after_parse() {} + SATSolver* solver = NULL; + + //File reading + void readInAFile(SATSolver* solver2, const string& filename); + void readInStandardInput(SATSolver* solver2); + void parseInAllFiles(SATSolver* solver2); + + //Helper functions + void printResultFunc( + std::ostream* os + , const bool toFile + , const lbool ret + ); + void printVersionInfo(); + int correctReturnValue(const lbool ret) const; + lbool multi_solutions(); + void ban_found_solution(); + + //Config + std::string debugLib; + int printResult = true; + string commandLine; + uint32_t max_nr_of_solutions = 1; + bool dont_ban_solutions = false; + int sql = 0; + string sqlite_filename; + uint64_t maxconfl; + + //Sampling vars + vector sampling_vars; + std::string sampling_vars_str = ""; + bool only_sampling_solution = false; + std::string assump_filename; + vector assumps; + + + //Files to read & write + bool fileNamePresent; + string result_fname; + string input_file; + std::ofstream* resultfile = NULL; + + //Drat checker + bool clause_ID_needed = false; +}; + +#endif //MAIN_H diff --git a/cryptominisat/cppsrc/src/main_common.cpp b/cryptominisat/cppsrc/src/main_common.cpp new file mode 100644 index 00000000..255de6a5 --- /dev/null +++ b/cryptominisat/cppsrc/src/main_common.cpp @@ -0,0 +1,82 @@ +/************************************************************* +MiniSat --- Copyright (c) 2003-2006, Niklas Een, Niklas Sorensson +CryptoMiniSat --- Copyright (C) 2009-2020 Authors of CryptoMiniSat, see AUTHORS file + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. +***************************************************************/ + +#include "main_common.h" +#include "solverconf.h" +#include +#include + +using std::endl; + +using namespace CMSat; + +void MainCommon::handle_frat_option() +{ + if (!conf.simulate_frat) { + FILE* fratfTmp = fopen(frat_fname.c_str(), "wb"); + if (fratfTmp == NULL) { + std::cerr + << "ERROR: Could not open FRAT file " + << frat_fname + << " for writing" + << endl; + + std::exit(-1); + } + fratf = fratfTmp; + } +} + +uint32_t MainCommon::print_model(CMSat::SATSolver* solver, std::ostream* os, std::vector* only) +{ + *os << "v "; + size_t line_size = 2; + size_t num_undef = 0; + + auto fun = [&](uint32_t var) { + if (solver->get_model()[var] != CMSat::l_Undef) { + const bool value_is_positive = (solver->get_model()[var] == CMSat::l_True); + const size_t this_var_size = std::ceil(std::log10(var+1)) + 1 + !value_is_positive; + line_size += this_var_size; + if (line_size > 80) { + *os << std::endl << "v "; + line_size = 2 + this_var_size; + } + *os << (value_is_positive? "" : "-") << var+1 << " "; + } else { + num_undef++; + } + }; + + if (only == NULL) { + for (uint32_t var = 0; var < solver->nVars(); var++) { + fun(var); + } + } else { + for(uint32_t var: *only) { + fun(var); + } + } + *os << "0" << std::endl; + return num_undef; +} diff --git a/cryptominisat/cppsrc/src/main_common.h b/cryptominisat/cppsrc/src/main_common.h new file mode 100644 index 00000000..b6e6b4ff --- /dev/null +++ b/cryptominisat/cppsrc/src/main_common.h @@ -0,0 +1,47 @@ +/************************************************************* +MiniSat --- Copyright (c) 2003-2006, Niklas Een, Niklas Sorensson +CryptoMiniSat --- Copyright (C) 2009-2020 Authors of CryptoMiniSat, see AUTHORS file + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. +***************************************************************/ + +#ifndef __MAIN_COMMON_H__ +#define __MAIN_COMMON_H__ + +#include "cryptominisat.h" +#include "solverconf.h" +#include +#include + +class MainCommon +{ +public: + static uint32_t print_model(CMSat::SATSolver* solver, + std::ostream* os, + std::vector* only = NULL); + void handle_frat_option(); + + string frat_fname; + FILE* fratf = NULL; + bool zero_exit_status = false; + CMSat::SolverConf conf; + unsigned num_threads = 1; +}; + +#endif //__MAIN_COMMON_H__ diff --git a/cryptominisat/cppsrc/src/main_emscripten.cpp b/cryptominisat/cppsrc/src/main_emscripten.cpp new file mode 100644 index 00000000..a445fdad --- /dev/null +++ b/cryptominisat/cppsrc/src/main_emscripten.cpp @@ -0,0 +1,139 @@ +/************************************************************* +MiniSat --- Copyright (c) 2003-2006, Niklas Een, Niklas Sorensson +CryptoMiniSat --- Copyright (C) 2009-2020 Authors of CryptoMiniSat, see AUTHORS file + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. +***************************************************************/ + +#include +#include +#include +#include "constants.h" + +using std::cout; +using std::endl; + +#include "main_common.h" + +#include "solverconf.h" +#include "cryptominisat.h" +#include "dimacsparser.h" +#include "streambuffer.h" + +using namespace CMSat; + +SATSolver* solver = NULL; +DLL_PUBLIC void printVersionInfo() +{ + cout << "c CryptoMiniSat version " << solver->get_version() << endl; + cout << "c CryptoMiniSat SHA revision " << solver->get_version_sha1() << endl; +} + +DLL_PUBLIC int start_solve(const char* input) +{ + SolverConf conf; + conf.max_confl = 500; + conf.verbosity = 1; + conf.do_print_times = 0; + conf.simplify_at_startup = 0; + + delete solver; + solver = new SATSolver(&conf); + + if (conf.verbosity) { + printVersionInfo(); + } + + DimacsParser, SATSolver> parser(solver, NULL, conf.verbosity); + if (!parser.parse_DIMACS(input, false)) { + exit(-1); + } + + solver->set_max_confl(500); + lbool ret = solver->simplify(); + + if (ret == l_True) { + cout << "c "<< endl << "c "<< endl; + cout << "s SATISFIABLE" << endl; + cout << "c conflicts: " << solver->get_sum_conflicts() << endl; + } else if (ret == l_False) { + cout << "c "<< endl << "c "<< endl; + cout << "s UNSATISFIABLE"<< endl; + cout << "c conflicts: " << solver->get_sum_conflicts() << endl; + } + + if (ret == l_True) { + return 0; + } else if (ret == l_False) { + return 1; + } else { + return 2; + } +} + +DLL_PUBLIC int continue_solve() +{ + solver->set_max_confl(500); + lbool ret = solver->solve(); + + if (ret == l_True) { + cout << "c "<< endl << "c "<< endl; + cout << "s SATISFIABLE" << endl; + cout << "c conflicts: " << solver->get_sum_conflicts() << endl; + } else if (ret == l_False) { + cout << "c "<< endl << "c "<< endl; + cout << "s UNSATISFIABLE"<< endl; + cout << "c conflicts: " << solver->get_sum_conflicts() << endl; + } + + if (ret == l_True) { + MainCommon::print_model(solver, &std::cout); + } + + if (ret == l_True) { + return 0; + } else if (ret == l_False) { + return 1; + } else { + return 2; + } +} + +DLL_PUBLIC int get_num_conflicts() +{ + uint64_t num = solver->get_sum_conflicts(); + return num; +} + + +extern "C" { + +DLL_PUBLIC int cstart_solve(const char *input) { + return start_solve(input); +} + +DLL_PUBLIC int ccontinue_solve() { + return continue_solve(); +} + +DLL_PUBLIC int cget_num_conflicts() { + return get_num_conflicts(); +} + +} diff --git a/cryptominisat/cppsrc/src/main_exe.cpp b/cryptominisat/cppsrc/src/main_exe.cpp new file mode 100644 index 00000000..42755947 --- /dev/null +++ b/cryptominisat/cppsrc/src/main_exe.cpp @@ -0,0 +1,56 @@ +/* +Copyright (C) 2009-2020 Authors of CryptoMiniSat, see AUTHORS file + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. +*/ + +#include "main.h" +#include "signalcode.h" +#include +#include + +int main(int argc, char** argv) +{ +// --> HAD to be disabled due to python module +// #if defined(__GNUC__) && defined(__linux__) +// feenableexcept(FE_INVALID | +// FE_DIVBYZERO | +// FE_OVERFLOW +// ); +// #endif + + int ret = -1; + try { + Main main(argc, argv); + main.conf.verbosity = 1; + main.conf.verbStats = 2; + main.parseCommandLine(); + + signal(SIGINT, SIGINT_handler); + ret = main.solve(); + } catch (CMSat::TooManyVarsError& e) { + std::cerr << "ERROR! Variable requested is far too large" << std::endl; + exit(-1); + } catch (CMSat::TooLongClauseError& e) { + std::cerr << "ERROR! Too long clause inserted" << std::endl; + exit(-1); + } + + return ret; +} diff --git a/cryptominisat/cppsrc/src/main_mpi.cpp b/cryptominisat/cppsrc/src/main_mpi.cpp new file mode 100644 index 00000000..c29e0d15 --- /dev/null +++ b/cryptominisat/cppsrc/src/main_mpi.cpp @@ -0,0 +1,266 @@ +/****************************************** +Copyright (C) 2020 Authors of CryptoMiniSat, see AUTHORS file + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. +***********************************************/ + +#include +#include +#include +#include "datasyncserver.h" +#include "cryptominisat.h" +#include "solverconf.h" +#include "zlib.h" +#include "dimacsparser.h" + + +using std::cout; +using std::endl; + + +int num_threads = 2; + +vector solve(lbool& solution_val) +{ + int err, mpiRank, mpiSize; + err = MPI_Comm_rank(MPI_COMM_WORLD, &mpiRank); + assert(err == MPI_SUCCESS); + err = MPI_Comm_size(MPI_COMM_WORLD, &mpiSize); + assert(err == MPI_SUCCESS); + CMSat::SolverConf conf; + conf.verbosity = 0; //(mpiRank == 1); + conf.is_mpi = true; + conf.do_bva = false; + + if (mpiSize > 1 && mpiRank > 1) { + conf.origSeed = mpiRank*2000; //this will be added T that is the thread number within the MPI + if (mpiRank % 6 == 3) { + conf.polarity_mode = CMSat::PolarityMode::polarmode_pos; + conf.restartType = CMSat::Restart::geom; + } + if (mpiRank % 6 == 4) { + conf.polarity_mode = CMSat::PolarityMode::polarmode_neg; + conf.restartType = CMSat::Restart::glue; + } + } + + CMSat::SATSolver solver(&conf); + solver.set_num_threads(num_threads); + + //Receive the num variables, and all the claues + Lit data[1024]; + vector clause; + uint32_t num_msgs = 0; + uint32_t num_clauses = 0; + bool done = false; + + + #ifdef VERBOSE_DEBUG_MPI_SENDRCV + cout << "c created solver " << mpiRank << " reading in file..." << endl; + #endif + while(!done) { + MPI_Bcast(&data, 1024, MPI_UNSIGNED, 0, MPI_COMM_WORLD); + //cout << "c solver " << mpiRank << " got file msg " << num_msgs << endl; + + uint32_t i = 0; + if (num_msgs == 0) { + solver.new_vars(data[0].var()); + #ifdef VERBOSE_DEBUG_MPI_SENDRCV + cout << "c Solver " << mpiRank + << " was told by MPI there are " << solver.nVars() << " variables" << endl; + #endif + i++; + } + num_msgs++; + + for(; i < 1024; i ++) { + if (data[i] == lit_Error) { + done = true; + break; + } else if (data[i] == lit_Undef) { + solver.add_clause(clause); + num_clauses++; + clause.clear(); + } else { + assert(data[i].var() < solver.nVars()); + clause.push_back(data[i]); + } + } + } + #ifdef VERBOSE_DEBUG_MPI_SENDRCV + cout << "c Solver " << mpiRank + << " finished getting all of the file." + << " nvars: " << solver.nVars() + << " num_clauses: " << num_clauses << endl; + #endif + + solution_val = solver.solve(); + vector model; + if (solution_val == l_True) { + model = solver.get_model(); + } + return model; +} + + +int main(int argc, char** argv) +{ + int err; + err = MPI_Init(&argc, &argv); + assert(err == MPI_SUCCESS); + + int mpiRank, mpiSize; + err = MPI_Comm_rank(MPI_COMM_WORLD, &mpiRank); + assert(err == MPI_SUCCESS); + + err = MPI_Comm_size(MPI_COMM_WORLD, &mpiSize); + assert(err == MPI_SUCCESS); + + if (mpiSize <= 1) { + cout << "ERROR: you must run on at least 2 MPI nodes" << endl; + cout << "NOTE: If using mpirun, use: mpirun -c NUM_PROCESSES ./cryptominisat5_mpi FILENAME NUM_THREADS" << endl; + exit(-1); + } + + if (argc != 3) { + cout << "ERROR: You MUST give 2 position parameters: FILENAME and NUM_THREADS" << endl; + exit(-1); + } + + assert(argc == 3); + for(uint32_t i = 0; i < strlen(argv[2]); i++) { + if (argv[2][i]-'0' < 0 || argv[2][i]-'0' > '9') { + cout << "ERROR: You MUST give a thread number that's an integer!" << endl; + exit(-1); + } + } + num_threads = atoi(argv[2]); + if (num_threads < 2) { + cout << "ERROR: you must have at least 2 threads per MPI node" << endl; + exit(-1); + } + + + if (mpiRank == 0) { + std::string filename(argv[1]); + cout << "c Filename is: " << filename << endl; + cout << "c num threads used: " << num_threads << endl; + + CMSat::DataSyncServer server; + gzFile in = gzopen(filename.c_str(), "rb"); + DimacsParser, CMSat::DataSyncServer> parser(&server, NULL, 0); + if (in == NULL) { + std::cerr + << "ERROR! Could not open file '" + << filename + << "' for reading: " << strerror(errno) << endl; + + std::exit(1); + } + + bool strict_header = false; + if (!parser.parse_DIMACS(in, strict_header)) { + exit(-1); + } + gzclose(in); + + cout << "c read in file" << endl;; + + server.send_cnf_to_solvers(); + + lbool sol = server.actAsServer(); + if (sol == l_True) { + cout << "s SATISFIABLE" << endl; + server.print_solution(); + } else if (sol == l_False) { + cout << "s UNSATISFIABLE" << endl; + } else { + assert(false); + } + } else { + lbool solution_val; + const vector model = solve(solution_val); + #ifdef VERBOSE_DEBUG_MPI_SENDRCV + cout << "c --> MPI Slave Rank " << mpiRank + << " Solved " << << " with value: " << solution_val << std::endl; + #endif + + if (solution_val != l_Undef) { + //Send tag 1 to 0 that indicates we solved + MPI_Request req; + vector solution_dat; + solution_dat.push_back(toInt(solution_val)); + if (solution_val == l_True) { + solution_dat.push_back(model.size()); + for(uint32_t i = 0; i < model.size(); i++) { + solution_dat.push_back(toInt(model[i])); + } + } + + err = MPI_Isend(solution_dat.data(), solution_dat.size(), MPI_UNSIGNED, 0, 1, MPI_COMM_WORLD, &req); + assert(err == MPI_SUCCESS); + #ifdef VERBOSE_DEBUG_MPI_SENDRCV + cout << "c --> MPI Slave Rank " << mpiRank + << " sent tag 1 to master to indicate finished" << std::endl; + #endif + + //Either we should we get an acknowledgement of receipt, or we get an interrupt + int flag; + MPI_Status status; + while(true) { + err = MPI_Iprobe(0, 1, MPI_COMM_WORLD, &flag, &status); + assert(err == MPI_SUCCESS); + + //We received an interrupt, let's cancel the send and exit + if (flag == true) { + unsigned buf; + err = MPI_Recv(&buf, 0, MPI_UNSIGNED, 0, 1, MPI_COMM_WORLD, &status); + assert(err == MPI_SUCCESS); + #ifdef VERBOSE_DEBUG_MPI_SENDRCV + cout << "c --> MPI Slave Rank " << mpiRank + << " got tag 1 from master. Let's cancel our send & exit." << std::endl; + #endif + + err = MPI_Cancel(&req); + assert(err == MPI_SUCCESS); + break; + } + + int op_completed; + err = MPI_Test(&req, &op_completed, &status); + assert(err == MPI_SUCCESS); + + //OK, server got our message, we can exit + if (op_completed) { + #ifdef VERBOSE_DEBUG_MPI_SENDRCV + cout << "c --> MPI Slave Rank " << mpiRank + << " completed sending solution & tag 1 to master. Let's exit." << std::endl; + #endif + break; + } + + usleep(50); + } + } + } + + err = MPI_Finalize(); + assert(err == MPI_SUCCESS); + return 0; +} diff --git a/cryptominisat/cppsrc/src/matrixfinder.cpp b/cryptominisat/cppsrc/src/matrixfinder.cpp new file mode 100644 index 00000000..d8733a3f --- /dev/null +++ b/cryptominisat/cppsrc/src/matrixfinder.cpp @@ -0,0 +1,426 @@ +/****************************************** +Copyright (C) 2009-2020 Authors of CryptoMiniSat, see AUTHORS file + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. +***********************************************/ + +#include "matrixfinder.h" +#include "solver.h" +#include "gaussian.h" +#include "clausecleaner.h" +#include "time_mem.h" +#include "sqlstats.h" +#include "xorfinder.h" +#include "varreplacer.h" + +#include +#include +#include +#include + +//#define VERBOSE_DEBUG +//#define PART_FINDING + +using namespace CMSat; + +using std::set; +using std::map; + +MatrixFinder::MatrixFinder(Solver* _solver) : + solver(_solver) +{ +} + +inline uint32_t MatrixFinder::fingerprint(const Xor& x) const +{ + uint32_t fingerprint = 0; + + for (uint32_t v: x) + fingerprint |= v; + + return fingerprint; +} + +inline bool MatrixFinder::firstPartOfSecond(const Xor& c1, const Xor& c2) const +{ + uint32_t i1, i2; + for (i1 = 0, i2 = 0; i1 < c1.size() && i2 < c2.size();) { + if (c1[i1] != c2[i2]) + i2++; + else { + i1++; + i2++; + } + } + + return (i1 == c1.size()); +} + +inline bool MatrixFinder::belong_same_matrix(const Xor& x) +{ + uint32_t comp_num = numeric_limits::max(); + for (uint32_t v : x) { + if (table[v] == var_Undef) { + //Belongs to none, abort + return false; + } + + if (comp_num == numeric_limits::max()) { + //Belongs to this one + comp_num = table[v]; + } else { + if (comp_num != table[v]) { + //Another var in this XOR belongs to another component + return false; + } + } + } + return true; +} + +bool MatrixFinder::find_matrices(bool& can_detach) +{ + assert(solver->decisionLevel() == 0); + assert(solver->ok); + assert(solver->gmatrices.empty()); + can_detach = true; + + table.clear(); + table.resize(solver->nVars(), var_Undef); + reverseTable.clear(); + clash_vars_unused.clear(); + matrix_no = 0; + double myTime = cpuTime(); + + XorFinder finder(NULL, solver); + + for(auto& x: solver->xorclauses_unused) solver->xorclauses.push_back(std::move(x)); + solver->xorclauses_unused.clear(); + solver->clauseCleaner->clean_xor_clauses(solver->xorclauses); + + finder.grab_mem(); + finder.move_xors_without_connecting_vars_to_unused(); + if (!finder.xor_together_xors(solver->xorclauses)) return false; + + finder.move_xors_without_connecting_vars_to_unused(); + finder.clean_equivalent_xors(solver->xorclauses); + verb_print(1, "[matrix] unused xors from cleaning: " << solver->xorclauses_unused.size()); + for(const auto& x: solver->xorclauses_unused) + clash_vars_unused.insert(x.clash_vars.begin(), x.clash_vars.end()); + + if (solver->xorclauses.size() < solver->conf.gaussconf.min_gauss_xor_clauses) { + can_detach = false; + verb_print(4, "c [matrix] too few xor clauses for GJ: " << solver->xorclauses.size()); + return true; + } + + if (solver->xorclauses.size() > solver->conf.gaussconf.max_gauss_xor_clauses + && solver->conf.sampling_vars != NULL + ) { + can_detach = false; + verb_print(1, + "c WARNING sampling vars have been given but there" + "are too many XORs and it would take too much time to put them" + "into matrices. Skipping!"); + return true; + } + + //Just one giant matrix. + if (!solver->conf.gaussconf.doMatrixFind) { + verb_print(1,"c Matrix finding disabled through switch. Putting all xors into matrix."); + solver->gmatrices.push_back(new EGaussian(solver, 0, solver->xorclauses)); + solver->gqueuedata.resize(solver->gmatrices.size()); + return true; + } + + vector newSet; + set tomerge; + for (const Xor& x : solver->xorclauses) { + if (belong_same_matrix(x)) { + continue; + } + + tomerge.clear(); + newSet.clear(); + for (uint32_t v : x) { + if (table[v] != var_Undef) + tomerge.insert(table[v]); + else + newSet.push_back(v); + } + if (tomerge.size() == 1) { + const uint32_t into = *tomerge.begin(); + auto intoReverse = reverseTable.find(into); + for (uint32_t i = 0; i < newSet.size(); i++) { + intoReverse->second.push_back(newSet[i]); + table[newSet[i]] = into; + } + continue; + } + + for (uint32_t v: tomerge) { + newSet.insert(newSet.end(), reverseTable[v].begin(), reverseTable[v].end()); + reverseTable.erase(v); + } + for (uint32_t i = 0; i < newSet.size(); i++) + table[newSet[i]] = matrix_no; + reverseTable[matrix_no] = newSet; + matrix_no++; + } + + #ifdef VERBOSE_DEBUG + for (map >::iterator it = reverseTable.begin() + , end = reverseTable.end() + ; it != end + ; ++it + ) { + cout << "XOR table set: " << endl; + for (vector::iterator it2 = it->second.begin(), end2 = it->second.end() + ; it2 != end2 + ; it2++ + ) { + cout << *it2 << ", "; + } + cout << "-------" << endl; + } + #endif + + uint32_t numMatrixes = setMatrixes(); + + const bool time_out = false; + const double time_used = cpuTime() - myTime; + verb_print(1, "[matrix] Using " << numMatrixes + << " matrices recovered from " << solver->xorclauses.size() << " xors" + << solver->conf.print_times(time_used, time_out)); + + if (solver->sqlStats) { + solver->sqlStats->time_passed_min( + solver + , "matrix find" + , time_used + ); + } + + return solver->okay(); +} + +uint32_t MatrixFinder::setMatrixes() +{ + if (solver->conf.sampling_vars) { + uint32_t size_at_least = (double)solver->conf.sampling_vars->size()*3; + if (solver->conf.gaussconf.max_matrix_rows < size_at_least) { + solver->conf.gaussconf.max_matrix_rows = size_at_least; + verb_print(1,"c [matrix] incrementing max number of rows to " << size_at_least); + } + } + + vector matrix_shape; + vector > xorsInMatrix(matrix_no); + + for (uint32_t i = 0; i < matrix_no; i++) { + matrix_shape.push_back(MatrixShape(i)); + matrix_shape[i].num = i; + matrix_shape[i].cols = reverseTable[i].size(); + } + + for (const Xor& x : solver->xorclauses) { + TBUDDY_DO(if (solver->frat->enabled()) assert(x.bdd)); + + //take 1st variable to check which matrix it's in. + const uint32_t matrix = table[x[0]]; + assert(matrix < matrix_no); + + //for stats + matrix_shape[matrix].rows ++; + matrix_shape[matrix].sum_xor_sizes += x.size(); + xorsInMatrix[matrix].push_back(x); + } + solver->xorclauses.clear(); + + for(auto& m: matrix_shape) { + if (m.tot_size() > 0) { + m.density = (double)m.sum_xor_sizes / (double)(m.tot_size()); + } + } + + std::sort(matrix_shape.begin(), matrix_shape.end(), mysorter()); + + uint32_t realMatrixNum = 0; + uint32_t unusedMatrix = 0; + uint32_t too_few_rows_matrix = 0; + uint32_t unused_matrix_printed = 0; + for (int a = matrix_no-1; a >= 0; a--) { + MatrixShape& m = matrix_shape[a]; + uint32_t i = m.num; + if (m.rows == 0) { + continue; + } + + bool use_matrix = true; + + + //Over- or undersized + if (use_matrix && m.rows > solver->conf.gaussconf.max_matrix_rows) { + use_matrix = false; + verb_print(1,"[matrix] Too many rows in matrix: " << m.rows << " -> set usage to NO"); + } + if (use_matrix && m.cols > solver->conf.gaussconf.max_matrix_columns) { + use_matrix = false; + verb_print(1,"[matrix] Too many columns in matrix: " << m.cols << " -> set usage to NO"); + } + + if (use_matrix && m.rows < solver->conf.gaussconf.min_matrix_rows) { + use_matrix = false; + too_few_rows_matrix++; + verb_print(2,"[matrix] Too few rows in matrix: " << m.rows << " -> set usage to NO"); + } + + //calculate sampling var ratio + //for statistics ONLY + double ratio_sampling; + if (solver->conf.sampling_vars) { + //'seen' with what is in Matrix + for(uint32_t int_var: reverseTable[i]) { + solver->seen[int_var] = 1; + } + + uint32_t tot_sampling_vars = 0; + uint32_t sampling_var_inside_matrix = 0; + for(uint32_t outside_var: *solver->conf.sampling_vars) { + uint32_t outer_var = solver->map_to_with_bva(outside_var); + outer_var = solver->varReplacer->get_var_replaced_with_outer(outer_var); + uint32_t int_var = solver->map_outer_to_inter(outer_var); + tot_sampling_vars++; + if (solver->value(int_var) != l_Undef) { + sampling_var_inside_matrix++; + } else if (int_var < solver->nVars() + && solver->seen[int_var] + ) { + sampling_var_inside_matrix++; + } + } + + //Clear 'seen' + for(uint32_t int_var: reverseTable[i]) solver->seen[int_var] = 0; + ratio_sampling = (double)sampling_var_inside_matrix/(double)tot_sampling_vars; + } + + //Over the max number of matrixes + if (use_matrix && realMatrixNum >= solver->conf.gaussconf.max_num_matrices) { + verb_print(3, "c [matrix] above max number of matrixes -> set usage to NO"); + use_matrix = false; + } + + if (m.rows > solver->conf.gaussconf.min_matrix_rows) { + //Override in case sampling vars ratio is high + if (solver->conf.sampling_vars) { + verb_print(2, "[matrix] ratio_sampling: " << ratio_sampling); + if (ratio_sampling >= 0.6) { //TODO Magic constant + verb_print(1, "[matrix] sampling ratio good -> set usage to YES"); + use_matrix = true; + } else { + verb_print(2, "[matrix] sampling ratio bad -> set usage to NO"); + use_matrix = false; + } + } + } + + //if already detached, we MUST use the matrix + for(const auto& x: xorsInMatrix[i]) { + if (x.detached) { + use_matrix = true; + if (solver->conf.verbosity) { + cout << "c we MUST use the matrix, it contains a previously detached XOR" + << " -> set usage to YES" << endl; + } + break; + } + } + + if (solver->conf.force_use_all_matrixes) { + use_matrix = true; + if (solver->conf.verbosity) { + cout << "c solver configured to force use all matrixes" + << " -> set usage to YES" << endl; + } + } + + if (use_matrix) { + solver->gmatrices.push_back( + new EGaussian(solver, realMatrixNum, xorsInMatrix[i])); + solver->gqueuedata.resize(solver->gmatrices.size()); + + if (solver->conf.verbosity) { + cout << "c [matrix] Good matrix " << std::setw(2) << realMatrixNum; + } + realMatrixNum++; + assert(solver->gmatrices.size() == realMatrixNum); + } else { + for(auto& x: xorsInMatrix[i]) { + solver->xorclauses_unused.push_back(x); + //cout<< "c [matrix]xor not in matrix, now unused_xors size: " << unused_xors.size() << endl; + clash_vars_unused.insert(x.clash_vars.begin(), x.clash_vars.end()); + } + if (solver->conf.verbosity && unused_matrix_printed < 10) { + if (m.rows >= solver->conf.gaussconf.min_matrix_rows || + solver->conf.verbosity >= 2) + { + cout << "c [matrix] UNused matrix "; + } + } + unusedMatrix++; + } + + if (solver->conf.verbosity) { + double avg = (double)m.sum_xor_sizes/(double)m.rows; + if (!use_matrix && + ((m.rows < solver->conf.gaussconf.min_matrix_rows && + solver->conf.verbosity < 2) || + (unused_matrix_printed >= 10)) + ) + { + continue; + } + + if (!use_matrix) { + unused_matrix_printed++; + } + + cout << std::setw(7) << m.rows << " x" + << std::setw(5) << reverseTable[i].size() + << " density:" + << std::setw(5) << std::fixed << std::setprecision(4) << m.density + << " xorlen avg: " + << std::setw(5) << std::fixed << std::setprecision(2) << avg; + if (solver->conf.sampling_vars) { + cout << " perc of sampl vars: " + << std::setw(5) << std::fixed << std::setprecision(3) + << ratio_sampling*100.0 << " %"; + } + cout << endl; + } + } + + if (solver->conf.verbosity && unusedMatrix > 0) { + cout << "c [matrix] unused matrices: " << unusedMatrix + << " of which too few rows: " << too_few_rows_matrix << endl; + } + + return realMatrixNum; +} diff --git a/cryptominisat/cppsrc/src/matrixfinder.h b/cryptominisat/cppsrc/src/matrixfinder.h new file mode 100644 index 00000000..9dcecbce --- /dev/null +++ b/cryptominisat/cppsrc/src/matrixfinder.h @@ -0,0 +1,94 @@ +/****************************************** +Copyright (C) 2009-2020 Authors of CryptoMiniSat, see AUTHORS file + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. +***********************************************/ + +#ifndef MATRIXFINDER_H +#define MATRIXFINDER_H + +#include +#include +#include +#include "xor.h" +#include "constants.h" + +namespace CMSat { + +class Solver; + +using std::map; +using std::vector; +using std::pair; +using std::set; + +class MatrixFinder { + + public: + MatrixFinder(Solver* solver); + + //NOTE "simplify_xors" should always be true except during testing + bool find_matrices(bool& can_detach); + set clash_vars_unused; + + private: + uint32_t setMatrixes(); + struct MatrixShape + { + MatrixShape(uint32_t matrix_num) : + num(matrix_num) + {} + + MatrixShape() + {} + + uint32_t num; + uint32_t rows = 0; + uint32_t cols = 0; + uint32_t sum_xor_sizes = 0; + double density = 0; + + uint64_t tot_size() const + { + return (uint64_t)rows*(uint64_t)cols; + } + }; + + struct mysorter + { + bool operator () (const MatrixShape& left, const MatrixShape& right) + { + return left.sum_xor_sizes < right.sum_xor_sizes; + } + }; + + inline uint32_t fingerprint(const Xor& c) const; + inline bool firstPartOfSecond(const Xor& c1, const Xor& c2) const; + inline bool belong_same_matrix(const Xor& x); + + map > reverseTable; //matrix -> vars + vector table; //var -> matrix + uint32_t matrix_no; + + Solver* solver; +}; + +} + +#endif //MATRIXFINDER_H diff --git a/cryptominisat/cppsrc/src/msvc/stdint.h b/cryptominisat/cppsrc/src/msvc/stdint.h new file mode 100644 index 00000000..d02608a5 --- /dev/null +++ b/cryptominisat/cppsrc/src/msvc/stdint.h @@ -0,0 +1,247 @@ +// ISO C9x compliant stdint.h for Microsoft Visual Studio +// Based on ISO/IEC 9899:TC2 Committee draft (May 6, 2005) WG14/N1124 +// +// Copyright (c) 2006-2008 Alexander Chemeris +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// +// 1. Redistributions of source code must retain the above copyright notice, +// this list of conditions and the following disclaimer. +// +// 2. Redistributions in binary form must reproduce the above copyright +// notice, this list of conditions and the following disclaimer in the +// documentation and/or other materials provided with the distribution. +// +// 3. The name of the author may be used to endorse or promote products +// derived from this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED +// WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO +// EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, +// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; +// OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, +// WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR +// OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF +// ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +/////////////////////////////////////////////////////////////////////////////// + +#ifndef _MSC_VER // [ +#error "Use this header only with Microsoft Visual C++ compilers!" +#endif // _MSC_VER ] + +#ifndef _MSC_STDINT_H_ // [ +#define _MSC_STDINT_H_ + +#if _MSC_VER > 1000 +#pragma once +#endif + +#include + +// For Visual Studio 6 in C++ mode and for many Visual Studio versions when +// compiling for ARM we should wrap include with 'extern "C++" {}' +// or compiler give many errors like this: +// error C2733: second C linkage of overloaded function 'wmemchr' not allowed +#ifdef __cplusplus +extern "C" { +#endif +# include +#ifdef __cplusplus +} +#endif + +// Define _W64 macros to mark types changing their size, like intptr_t. +#ifndef _W64 +# if !defined(__midl) && (defined(_X86_) || defined(_M_IX86)) && _MSC_VER >= 1300 +# define _W64 __w64 +# else +# define _W64 +# endif +#endif + + +// 7.18.1 Integer types + +// 7.18.1.1 Exact-width integer types + +// Visual Studio 6 and Embedded Visual C++ 4 doesn't +// realize that, e.g. char has the same size as __int8 +// so we give up on __intX for them. +#if (_MSC_VER < 1300) + typedef signed char int8_t; + typedef signed short int16_t; + typedef signed int int32_t; + typedef unsigned char uint8_t; + typedef unsigned short uint16_t; + typedef unsigned int uint32_t; +#else + typedef signed __int8 int8_t; + typedef signed __int16 int16_t; + typedef signed __int32 int32_t; + typedef unsigned __int8 uint8_t; + typedef unsigned __int16 uint16_t; + typedef unsigned __int32 uint32_t; +#endif +typedef signed __int64 int64_t; +typedef unsigned __int64 uint64_t; + + +// 7.18.1.2 Minimum-width integer types +typedef int8_t int_least8_t; +typedef int16_t int_least16_t; +typedef int32_t int_least32_t; +typedef int64_t int_least64_t; +typedef uint8_t uint_least8_t; +typedef uint16_t uint_least16_t; +typedef uint32_t uint_least32_t; +typedef uint64_t uint_least64_t; + +// 7.18.1.3 Fastest minimum-width integer types +typedef int8_t int_fast8_t; +typedef int16_t int_fast16_t; +typedef int32_t int_fast32_t; +typedef int64_t int_fast64_t; +typedef uint8_t uint_fast8_t; +typedef uint16_t uint_fast16_t; +typedef uint32_t uint_fast32_t; +typedef uint64_t uint_fast64_t; + +// 7.18.1.4 Integer types capable of holding object pointers +#ifdef _WIN64 // [ + typedef signed __int64 intptr_t; + typedef unsigned __int64 uintptr_t; +#else // _WIN64 ][ + typedef _W64 signed int intptr_t; + typedef _W64 unsigned int uintptr_t; +#endif // _WIN64 ] + +// 7.18.1.5 Greatest-width integer types +typedef int64_t intmax_t; +typedef uint64_t uintmax_t; + + +// 7.18.2 Limits of specified-width integer types + +#if !defined(__cplusplus) || defined(__STDC_LIMIT_MACROS) // [ See footnote 220 at page 257 and footnote 221 at page 259 + +// 7.18.2.1 Limits of exact-width integer types +#define INT8_MIN ((int8_t)_I8_MIN) +#define INT8_MAX _I8_MAX +#define INT16_MIN ((int16_t)_I16_MIN) +#define INT16_MAX _I16_MAX +#define INT32_MIN ((int32_t)_I32_MIN) +#define INT32_MAX _I32_MAX +#define INT64_MIN ((int64_t)_I64_MIN) +#define INT64_MAX _I64_MAX +#define UINT8_MAX _UI8_MAX +#define UINT16_MAX _UI16_MAX +#define UINT32_MAX _UI32_MAX +#define UINT64_MAX _UI64_MAX + +// 7.18.2.2 Limits of minimum-width integer types +#define INT_LEAST8_MIN INT8_MIN +#define INT_LEAST8_MAX INT8_MAX +#define INT_LEAST16_MIN INT16_MIN +#define INT_LEAST16_MAX INT16_MAX +#define INT_LEAST32_MIN INT32_MIN +#define INT_LEAST32_MAX INT32_MAX +#define INT_LEAST64_MIN INT64_MIN +#define INT_LEAST64_MAX INT64_MAX +#define UINT_LEAST8_MAX UINT8_MAX +#define UINT_LEAST16_MAX UINT16_MAX +#define UINT_LEAST32_MAX UINT32_MAX +#define UINT_LEAST64_MAX UINT64_MAX + +// 7.18.2.3 Limits of fastest minimum-width integer types +#define INT_FAST8_MIN INT8_MIN +#define INT_FAST8_MAX INT8_MAX +#define INT_FAST16_MIN INT16_MIN +#define INT_FAST16_MAX INT16_MAX +#define INT_FAST32_MIN INT32_MIN +#define INT_FAST32_MAX INT32_MAX +#define INT_FAST64_MIN INT64_MIN +#define INT_FAST64_MAX INT64_MAX +#define UINT_FAST8_MAX UINT8_MAX +#define UINT_FAST16_MAX UINT16_MAX +#define UINT_FAST32_MAX UINT32_MAX +#define UINT_FAST64_MAX UINT64_MAX + +// 7.18.2.4 Limits of integer types capable of holding object pointers +#ifdef _WIN64 // [ +# define INTPTR_MIN INT64_MIN +# define INTPTR_MAX INT64_MAX +# define UINTPTR_MAX UINT64_MAX +#else // _WIN64 ][ +# define INTPTR_MIN INT32_MIN +# define INTPTR_MAX INT32_MAX +# define UINTPTR_MAX UINT32_MAX +#endif // _WIN64 ] + +// 7.18.2.5 Limits of greatest-width integer types +#define INTMAX_MIN INT64_MIN +#define INTMAX_MAX INT64_MAX +#define UINTMAX_MAX UINT64_MAX + +// 7.18.3 Limits of other integer types + +#ifdef _WIN64 // [ +# define PTRDIFF_MIN _I64_MIN +# define PTRDIFF_MAX _I64_MAX +#else // _WIN64 ][ +# define PTRDIFF_MIN _I32_MIN +# define PTRDIFF_MAX _I32_MAX +#endif // _WIN64 ] + +#define SIG_ATOMIC_MIN INT_MIN +#define SIG_ATOMIC_MAX INT_MAX + +#ifndef SIZE_MAX // [ +# ifdef _WIN64 // [ +# define SIZE_MAX _UI64_MAX +# else // _WIN64 ][ +# define SIZE_MAX _UI32_MAX +# endif // _WIN64 ] +#endif // SIZE_MAX ] + +// WCHAR_MIN and WCHAR_MAX are also defined in +#ifndef WCHAR_MIN // [ +# define WCHAR_MIN 0 +#endif // WCHAR_MIN ] +#ifndef WCHAR_MAX // [ +# define WCHAR_MAX _UI16_MAX +#endif // WCHAR_MAX ] + +#define WINT_MIN 0 +#define WINT_MAX _UI16_MAX + +#endif // __STDC_LIMIT_MACROS ] + + +// 7.18.4 Limits of other integer types + +#if !defined(__cplusplus) || defined(__STDC_CONSTANT_MACROS) // [ See footnote 224 at page 260 + +// 7.18.4.1 Macros for minimum-width integer constants + +#define INT8_C(val) val##i8 +#define INT16_C(val) val##i16 +#define INT32_C(val) val##i32 +#define INT64_C(val) val##i64 + +#define UINT8_C(val) val##ui8 +#define UINT16_C(val) val##ui16 +#define UINT32_C(val) val##ui32 +#define UINT64_C(val) val##ui64 + +// 7.18.4.2 Macros for greatest-width integer constants +#define INTMAX_C INT64_C +#define UINTMAX_C UINT64_C + +#endif // __STDC_CONSTANT_MACROS ] + + +#endif // _MSC_STDINT_H_ ] diff --git a/cryptominisat/cppsrc/src/mystack.h b/cryptominisat/cppsrc/src/mystack.h new file mode 100644 index 00000000..393c1899 --- /dev/null +++ b/cryptominisat/cppsrc/src/mystack.h @@ -0,0 +1,77 @@ +/****************************************** +Copyright (C) 2009-2020 Authors of CryptoMiniSat, see AUTHORS file + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. +***********************************************/ + +#ifndef __MYSTACK_H__ +#define __MYSTACK_H__ + +#include +using std::vector; + +namespace CMSat { + +template +class MyStack +{ +public: + void clear() + { + inter.clear(); + } + + bool empty() const + { + return inter.empty(); + } + + void pop() + { + assert(!inter.empty()); + inter.resize(inter.size()-1); + } + + const T top() const + { + return inter.back(); + } + + void push(const T& data) + { + inter.push_back(data); + } + + size_t capacity() const + { + return inter.capacity(); + } + + size_t mem_used() const + { + return capacity()*sizeof(T); + } + +private: + vector inter; +}; + +} + +#endif //__MYSTACK_H__ diff --git a/cryptominisat/cppsrc/src/nomutex.h b/cryptominisat/cppsrc/src/nomutex.h new file mode 100644 index 00000000..f74f17d7 --- /dev/null +++ b/cryptominisat/cppsrc/src/nomutex.h @@ -0,0 +1,60 @@ +/****************************************** +Copyright (C) 2009-2020 Authors of CryptoMiniSat, see AUTHORS file + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. +***********************************************/ + +#ifndef NO_MUTEX_H +#define NO_MUTEX_H + +namespace std { + struct mutex { + void lock() {} + void unlock() {} + }; + + static const bool memory_order_relaxed = true; + static const bool memory_order_acquire = true; + + inline void atomic_thread_fence(bool) + {} + + template + struct atomic { + atomic() + {} + + atomic(bool _val) : + val(_val) + {} + + void store(bool _val, bool) { + val = _val; + } + bool load(bool) const { + return val; + } + operator bool() { + return val; + } + T val; + }; +} + +#endif //NO_MUTEX_H diff --git a/cryptominisat/cppsrc/src/occsimplifier.cpp b/cryptominisat/cppsrc/src/occsimplifier.cpp new file mode 100644 index 00000000..141a387f --- /dev/null +++ b/cryptominisat/cppsrc/src/occsimplifier.cpp @@ -0,0 +1,5574 @@ +/****************************************** +Copyright (C) 2009-2020 Authors of CryptoMiniSat, see AUTHORS file + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. +***********************************************/ + +#include "constants.h" +#include "time_mem.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "occsimplifier.h" +#include "clause.h" +#include "solver.h" +#include "clausecleaner.h" +#include "constants.h" +#include "solutionextender.h" +#include "varreplacer.h" +#include "varupdatehelper.h" +#include "completedetachreattacher.h" +#include "subsumestrengthen.h" +#include "watchalgos.h" +#include "clauseallocator.h" +#include "subsumeimplicit.h" +#include "sqlstats.h" +#include "datasync.h" +#include "xorfinder.h" +#include "gatefinder.h" +#include "bva.h" +#include "trim.h" +extern "C" { +#include "picosat/picosat.h" +} + +//#define VERBOSE_DEBUG +#ifdef VERBOSE_DEBUG +#define BIT_MORE_VERBOSITY +#define VERBOSE_ORGATE_REPLACE +#define VERBOSE_ASYMTE +#define VERBOSE_GATE_REMOVAL +#define VERBOSE_XORGATE_MIX +#define VERBOSE_DEBUG_XOR_FINDER +#define VERBOSE_DEBUG_VARELIM +#endif + +using namespace CMSat; +using std::cout; +using std::endl; +using std::unique; + +//#define VERBOSE_DEBUG_VARELIM +//#define VERBOSE_DEBUG_XOR_FINDER +//#define BIT_MORE_VERBOSITY +//#define TOUCH_LESS +//#define VERBOSE_ORGATE_REPLACE +//#define VERBOSE_DEBUG_ASYMTE +//#define VERBOSE_GATE_REMOVAL +//#define VERBOSE_XORGATE_MIX +//#define CHECK_N_OCCUR +//#define DEBUG_VARELIM + +OccSimplifier::OccSimplifier(Solver* _solver): + solver(_solver) + , seen(solver->seen) + , seen2(solver->seen2) + , toClear(solver->toClear) + , velim_order(VarOrderLt(varElimComplexity)) + , gateFinder(NULL) + , anythingHasBeenElimed(false) + , elimedMapBuilt(false) +{ + bva = new BVA(solver, this); + sub_str = new SubsumeStrengthen(this, solver); + + tmp_bin_cl.resize(2); +} + +OccSimplifier::~OccSimplifier() +{ + delete bva; + delete sub_str; + delete gateFinder; +} + +void OccSimplifier::new_var(const uint32_t /*orig_outer*/) +{ + n_occurs.insert(n_occurs.end(), 2, 0); + if (solver->conf.sampling_vars) { + sampling_vars_occsimp.insert(sampling_vars_occsimp.end(), 1, 0); + } +} + +void OccSimplifier::new_vars(size_t n) +{ + n_occurs.insert(n_occurs.end(), n*2ULL, 0); + if (solver->conf.sampling_vars) { + sampling_vars_occsimp.insert(sampling_vars_occsimp.end(), n, 0); + } +} + +void OccSimplifier::save_on_var_memory() +{ + clauses.clear(); + clauses.shrink_to_fit(); + eClsLits.shrink_to_fit(); + + cl_to_free_later.shrink_to_fit(); + + elim_calc_need_update.shrink_to_fit(); + elimedClauses.shrink_to_fit(); +} + +void OccSimplifier::print_elimed_clauses_reverse() const +{ + for(vector::const_reverse_iterator + it = elimedClauses.rbegin(), end = elimedClauses.rend() + ; it != end + ; ++it + ) { + size_t at = 1; + vector lits; + while(at < it->size()) { + Lit l = it->at(at, eClsLits); + if (l == lit_Undef) { + cout + << "elimed clause (internal number):"; + for(size_t i = 0; i < it->size(); i++) { + cout << it->at(i, eClsLits) << " "; + } + cout << endl; + lits.clear(); + } else { + lits.push_back(l); + } + at++; + } + + cout + << "dummy elimed clause for var (internal number) " << it->at(0, eClsLits).var() + << endl; + + } +} + +uint32_t OccSimplifier::dump_elimed_clauses(std::ostream* outfile) const +{ + uint32_t num_cls = 0; + for (ElimedClauses elimed: elimedClauses) { + if (elimed.toRemove) + continue; + + for (size_t i = 0; i < elimed.size(); i++) { + //It's elimed on this variable + if (i == 0) { + continue; + } + Lit l = elimed.at(i, eClsLits); + if (outfile != NULL) { + if (l == lit_Undef) { + *outfile + << " 0" + << endl; + } else { + *outfile + << l << " "; + } + } + if (l == lit_Undef) { + num_cls++; + } + } + } + return num_cls; +} + +bool OccSimplifier::get_elimed_clause_at(uint32_t& at,uint32_t& at2, vector& out) const +{ + out.clear(); + while(at < elimedClauses.size()) { + const auto& elimed = elimedClauses[at]; + if (elimed.toRemove) { + at++; + continue; + } + + while(at2 < elimed.size()) { + //It's elimed on this variable + if (at2 == 0) { + at2++; + continue; + } + Lit l = elimed.at(at2, eClsLits); + if (l == lit_Undef) { + at2++; + return true; + //nothing, return? + } else { + out.push_back(l); + } + at2++; + } + at2 = 0; + at++; + } + return false; +} + +void OccSimplifier::extend_model(SolutionExtender* extender) +{ + //Either a variable is not eliminated, or its value is undef + for(size_t i = 0; i < solver->nVarsOuter(); i++) { + const uint32_t outer = solver->map_inter_to_outer(i); + assert(solver->varData[i].removed != Removed::elimed + || (solver->value(i) == l_Undef && solver->model_value(outer) == l_Undef) + ); + } + + #ifdef VERBOSE_DEBUG_RECONSTRUCT + cout << "Number of elimed clauses: " << elimedClauses.size() << endl; + print_elimed_clauses_reverse(); + #endif + + //go through in reverse order + vector lits; + for (long int i = (int)elimedClauses.size()-1; i >= 0; i--) { + ElimedClauses* it = &elimedClauses[i]; + if (it->toRemove) { + continue; + } + + Lit elimedOn = solver->varReplacer->get_lit_replaced_with_outer(it->at(0, eClsLits)); + size_t at = 1; + bool satisfied = false; + lits.clear(); + while(at < it->size()) { + //built clause, reached marker, "lits" is now valid + if (it->at(at, eClsLits) == lit_Undef) { + if (!satisfied) { + [[maybe_unused]] bool var_set = extender->addClause(lits, elimedOn.var()); + + #ifndef DEBUG_VARELIM + //all should be satisfied in fact + //no need to go any further + if (var_set) break; + #endif + } + satisfied = false; + lits.clear(); + + //Building clause, "lits" is not yet valid + } else if (!satisfied) { + Lit l = it->at(at, eClsLits); + l = solver->varReplacer->get_lit_replaced_with_outer(l); + lits.push_back(l); + + //Elimed clause can be skipped, it's satisfied + if (solver->model_value(l) == l_True) { + satisfied = true; + } + } + at++; + } + extender->dummyElimed(elimedOn.var()); + } + if (solver->conf.verbosity >= 2) { + cout << "c [extend] Extended " << elimedClauses.size() << " var-elim clauses" << endl; + } +} + +void OccSimplifier::unlink_clause( + const ClOffset offset + , bool doDrat + , bool allow_empty_watch + , bool only_set_is_removed +) { + Clause& cl = *solver->cl_alloc.ptr(offset); + if (doDrat && (solver->frat->enabled() || solver->conf.simulate_frat)) { + (*solver->frat) << del << cl << fin; + } + + if (!cl.red()) { + for (const Lit lit: cl) { + elim_calc_need_update.touch(lit.var()); + #ifdef CHECK_N_OCCUR + assert(n_occurs[lit.toInt()]>0); + #endif + n_occurs[lit.toInt()]--; + removed_cl_with_var.touch(lit.var()); + } + } + + if (!only_set_is_removed) { + for (const Lit lit: cl) { + if (!(allow_empty_watch && solver->watches[lit].empty())) { + *limit_to_decrease -= 2*(long)solver->watches[lit].size(); + removeWCl(solver->watches[lit], offset); + } + } + } else { + for (const Lit lit: cl) { + solver->watches.smudge(lit); + } + } + cl.setRemoved(); + + if (cl.red()) { + solver->litStats.redLits -= cl.size(); + } else { + solver->litStats.irredLits -= cl.size(); + } + + if (!only_set_is_removed) { + solver->free_cl(&cl); + } else { + cl_to_free_later.push_back(offset); + } +} + +bool OccSimplifier::clean_clause( + ClOffset offset, + bool only_set_is_removed) +{ + assert(!solver->frat->something_delayed()); + assert(solver->okay()); + + bool satisfied = false; + Clause& cl = *solver->cl_alloc.ptr(offset); + assert(!cl.getRemoved()); + assert(!cl.freed()); + (*solver->frat) << deldelay << cl << fin; + + Lit* i = cl.begin(); + Lit* j = cl.begin(); + const Lit* end = cl.end(); + *limit_to_decrease -= (long)cl.size(); + for(; i != end; i++) { + if (solver->value(*i) == l_Undef) { + //clean_clause() is called when the clause changed, so this is relevant + added_cl_to_var.touch(i->var()); + *j++ = *i; + continue; + } + + if (solver->value(*i) == l_True) + satisfied = true; + + if (solver->value(*i) == l_True + || solver->value(*i) == l_False + ) { + removeWCl(solver->watches[*i], offset); + if (!cl.red()) { + removed_cl_with_var.touch(i->var()); + elim_calc_need_update.touch(i->var()); + n_occurs[i->toInt()]--; + } + } + } + cl.shrink(i-j); + cl.recalc_abst_if_needed(); + + //Update lits stat + if (cl.red()) { + solver->litStats.redLits -= i-j; + } else { + solver->litStats.irredLits -= i-j; + } + + if (satisfied) { + (*solver->frat) << findelay; + unlink_clause(offset, false, false, only_set_is_removed); + return true; + } + + if (solver->conf.verbosity >= 6) { + cout << "-> Clause became after cleaning:" << cl << endl; + } + + if (i-j > 0) { + INC_ID(cl); + (*solver->frat) << add << cl << fin << findelay; + } else { + solver->frat->forget_delay(); + } + + switch(cl.size()) { + case 0: + unlink_clause(offset, false, false, only_set_is_removed); + solver->ok = false; + return false; + + case 1: { + solver->enqueue(cl[0]); + *solver->frat << del << cl << fin; // double unit delete + unlink_clause(offset, false, false, only_set_is_removed); + solver->ok = solver->propagate_occur(limit_to_decrease); + return solver->okay(); + } + + case 2: { + solver->attach_bin_clause(cl[0], cl[1], cl.red(), cl.stats.ID); + if (!cl.red()) { + std::pair tmp = {cl[0], cl[1]}; + added_irred_bin.push_back(tmp); + n_occurs[tmp.first.toInt()]++; + n_occurs[tmp.second.toInt()]++; + } + unlink_clause(offset, false, false, only_set_is_removed); + return true; + } + default: + if (i-j > 0) { + cl.setStrenghtened(); + cl.recalc_abst_if_needed(); + if (!cl.red()) { + added_long_cl.push_back(offset); + } + } + return true; + } +} + + +bool OccSimplifier::complete_clean_clause(Clause& cl) +{ + assert(solver->okay()); + assert(!solver->frat->something_delayed()); + assert(cl.size() > 2); + + (*solver->frat) << deldelay << cl << fin; + + //Remove all lits from stats + //we will re-attach the clause either way + if (cl.red()) { + solver->litStats.redLits -= cl.size(); + } else { + solver->litStats.irredLits -= cl.size(); + } + + Lit *i = cl.begin(); + Lit *j = i; + for (Lit *end = cl.end(); i != end; i++) { + if (solver->value(*i) == l_True) { + (*solver->frat) << findelay; + return false; + } + + if (solver->value(*i) == l_Undef) { + *j++ = *i; + } + } + cl.shrink(i-j); + cl.recalc_abst_if_needed(); + + //Drat + if (i - j > 0) { + INC_ID(cl); + (*solver->frat) << add << cl << fin << findelay; + } else { + solver->frat->forget_delay(); + } + + switch (cl.size()) { + case 0: + solver->ok = false; + return false; + + case 1: { + solver->enqueue(cl[0]); + *solver->frat << del << cl << fin; // double unit delete + return false; + } + case 2: + solver->attach_bin_clause(cl[0], cl[1], cl.red(), cl.stats.ID); + return false; + + default: + return true; + } +} + +struct sort_smallest_first { + sort_smallest_first(ClauseAllocator& _cl_alloc) : + cl_alloc(_cl_alloc) + {} + + bool operator()(const Watched& first, const Watched& second) + { + if (second.isBin() && first.isClause()) { + //wrong order + return false; + } + if (first.isBin() && second.isClause()) { + //this is the right order + return true; + } + + if (first.isBin() && second.isBin()) { + //correct order if first has lit2() smaller. + if (first.lit2() != second.lit2()) { + return first.lit2() < second.lit2(); + } + return first.get_ID() < second.get_ID(); + } + + if (first.isClause() && second.isClause()) { + Clause& cl1 = *cl_alloc.ptr(first.get_offset()); + Clause& cl2 = *cl_alloc.ptr(second.get_offset()); + if (cl1.size() != cl2.size()) { + //Smaller clause size first is correct order + return cl1.size() < cl2.size(); + } + + //we don't care, let's use offset as a distinguisher + return first.get_offset() < second.get_offset(); + } + + assert(false && "This cannot happen"); + return false; + } + + ClauseAllocator& cl_alloc; +}; + +uint64_t OccSimplifier::calc_mem_usage_of_occur(const vector& toAdd) const +{ + uint64_t memUsage = 0; + for (const ClOffset offs: toAdd) { + Clause* cl = solver->cl_alloc.ptr(offs); + + //*2 because of the overhead of allocation + memUsage += cl->size()*sizeof(Watched)*2; + } + + //Estimate malloc overhead + memUsage += solver->num_active_vars()*2*40; + + return memUsage; +} + +void OccSimplifier::print_mem_usage_of_occur(uint64_t memUsage) const +{ + verb_print(1, "[occ] mem usage for occur " + << std::setw(6) << memUsage/(1024ULL*1024ULL) << " MB"); +} + +void OccSimplifier::print_linkin_data(const LinkInData link_in_data) const +{ + if (solver->conf.verbosity < 2) + return; + + double val; + if (link_in_data.cl_linked + link_in_data.cl_not_linked == 0) { + val = 0; + } else { + val = float_div(link_in_data.cl_not_linked, link_in_data.cl_linked+link_in_data.cl_not_linked)*100.0; + } + + cout + << "c [occ] Not linked in " + << link_in_data.cl_not_linked << "/" + << (link_in_data.cl_linked + link_in_data.cl_not_linked) + << " (" + << std::setprecision(2) << std::fixed + << val + << " %)" + << endl; +} + + +OccSimplifier::LinkInData OccSimplifier::link_in_clauses( + const vector& toAdd + , bool alsoOccur + , uint32_t max_size + , int64_t link_in_lit_limit +) { + LinkInData link_in_data; + for (const ClOffset offs: toAdd) { + Clause* cl = solver->cl_alloc.ptr(offs); + cl->recalc_abst_if_needed(); + assert(cl->abst == calcAbstraction(*cl)); + assert(!cl->red() || cl->stats.glue > 0); + + if (alsoOccur + && cl->size() < max_size + && link_in_lit_limit > 0 + ) { + link_in_clause(*cl); + link_in_data.cl_linked++; + link_in_lit_limit -= cl->size(); + clause_lits_added += cl->size(); + } else { + /*cout << "alsoOccur: " << alsoOccur + << " cl->size() < max_size: " << (cl->size() < max_size) + << " link_in_lit_limit: " << link_in_lit_limit << endl;*/ + //assert(cl->red()); + cl->setOccurLinked(false); + link_in_data.cl_not_linked++; + std::sort(cl->begin(), cl->end()); + } + + clauses.push_back(offs); + } + + return link_in_data; +} + +bool OccSimplifier::check_varelim_when_adding_back_cl(const Clause* cl) const +{ + bool notLinkedNeedFree = false; + for (const Lit& l: *cl) { + //The clause was too long, and wasn't linked in + //but has been var-elimed, so remove it + if (!cl->getOccurLinked() + && solver->varData[l.var()].removed == Removed::elimed + ) { + notLinkedNeedFree = true; + } + + if (cl->getOccurLinked() + && solver->varData[l.var()].removed != Removed::none + ) { + std::cerr + << "ERROR! Clause " << *cl + << " red: " << cl->red() + << " contains lit " << l + << " which has removed status" + << removed_type_to_string(solver->varData[l.var()].removed) + << endl; + + assert(false); + std::exit(-1); + } + } + + return notLinkedNeedFree; +} + +void OccSimplifier::check_cls_sanity() { + if (!solver->okay()) return; + for (const ClOffset offs: clauses) { + Clause* cl = solver->cl_alloc.ptr(offs); + if (cl->getRemoved() || cl->freed()) continue; + assert(!cl->stats.marked_clause); + if (cl->size() <= 2) cout << "ERROR: too short cl: " << *cl << endl; + assert(cl->size() > 2); + } +} + +void OccSimplifier::add_back_to_solver() +{ + solver->clean_occur_from_removed_clauses_only_smudged(); + free_clauses_to_free(); + + for (const ClOffset offs: clauses) { + Clause* cl = solver->cl_alloc.ptr(offs); + if (cl->getRemoved() || cl->freed()) continue; + assert(!cl->stats.marked_clause); + assert(cl->size() > 2); + + if (check_varelim_when_adding_back_cl(cl)) { + //The clause wasn't linked in but needs removal now + if (cl->red()) { + solver->litStats.redLits -= cl->size(); + } else { + solver->litStats.irredLits -= cl->size(); + } + *solver->frat << del << *cl << fin; + solver->free_cl(cl); + continue; + } + + if (solver->okay() && complete_clean_clause(*cl)) { + solver->attachClause(*cl); + if (cl->red()) { + assert(cl->stats.glue > 0); + assert(cl->stats.which_red_array < solver->longRedCls.size()); + solver->longRedCls[cl->stats.which_red_array].push_back(offs); + } else { + solver->longIrredCls.push_back(offs); + } + } else { + solver->free_cl(cl); + } + } +} + +void OccSimplifier::remove_all_longs_from_watches() +{ + for (watch_array::iterator + it = solver->watches.begin(), end = solver->watches.end() + ; it != end + ; ++it + ) { + watch_subarray ws = *it; + + Watched* i = ws.begin(); + Watched* j = i; + for (Watched *end2 = ws.end(); i != end2; i++) { + if (i->isClause()) { + continue; + } else { + assert(i->isBin() || i->isBNN()); + *j++ = *i; + } + } + ws.shrink(i - j); + } +} + +void OccSimplifier::eliminate_empty_resolvent_vars() +{ + assert(added_long_cl.empty()); + assert(solver->okay()); + assert(solver->prop_at_head()); + assert(added_irred_bin.empty()); + + uint32_t var_elimed = 0; + double myTime = cpuTime(); + const int64_t orig_empty_varelim_time_limit = empty_varelim_time_limit; + auto old_limit_to_decrease = limit_to_decrease; + limit_to_decrease = &empty_varelim_time_limit; + assert(cl_to_free_later.empty()); + assert(solver->watches.get_smudged_list().empty()); + if (solver->nVars() == 0) goto end; + + for(size_t var = rnd_uint(solver->mtrand,solver->nVars()-1), num = 0 + ; num < solver->nVars() && *limit_to_decrease > 0 + ; var = (var + 1) % solver->nVars(), num++ + ) { + assert(var == var % solver->nVars()); + if (!can_eliminate_var(var)) continue; + const Lit lit = Lit(var, false); + if (!check_empty_resolvent(lit)) continue; + + create_dummy_elimed_clause(lit); + rem_cls_from_watch_due_to_varelim(lit); + rem_cls_from_watch_due_to_varelim(~lit); + set_var_as_eliminated(var); + var_elimed++; + } + + end: + solver->clean_occur_from_removed_clauses_only_smudged(); + free_clauses_to_free(); + + const double time_used = cpuTime() - myTime; + const bool time_out = (*limit_to_decrease <= 0); + const double time_remain = float_div(*limit_to_decrease, orig_empty_varelim_time_limit); + if (solver->conf.verbosity) { + cout + << "c [occ-empty-res] Empty resolvent elimed: " << var_elimed + << solver->conf.print_times(time_used, time_out) + << endl; + } + if (solver->sqlStats) { + solver->sqlStats->time_passed( + solver + , "empty resolvent" + , time_used + , time_out + , time_remain + ); + } + limit_to_decrease = old_limit_to_decrease; +} + +bool OccSimplifier::can_eliminate_var(const uint32_t var) const +{ + #ifdef SLOW_DEBUG + if (solver->conf.sampling_vars) { + assert(var < solver->nVars()); + assert(var < sampling_vars_occsimp.size()); + } + #endif + + assert(var < solver->nVars()); + if (solver->value(var) != l_Undef || + solver->varData[var].removed != Removed::none || + solver->var_inside_assumptions(var) != l_Undef || + ((solver->conf.sampling_vars || solver->fast_backw.fast_backw_on) && + sampling_vars_occsimp[var]) + ) { + return false; + } + + return true; +} + +uint32_t OccSimplifier::sum_irred_cls_longs() const +{ + uint32_t sum = 0; + for (ClOffset offs: clauses) { + Clause* cl = solver->cl_alloc.ptr(offs); + if (cl->freed() || cl->getRemoved() || cl->red()) + continue; + + assert(cl->size() > 2); + sum++; + } + return sum; +} + +uint32_t OccSimplifier::sum_irred_cls_longs_lits() const +{ + uint32_t sum = 0; + for (ClOffset offs: clauses) { + Clause* cl = solver->cl_alloc.ptr(offs); + if (cl->freed() || cl->getRemoved() || cl->red()) + continue; + + assert(cl->size() > 2); + sum += cl->size(); + } + return sum; +} + +//backward subsumes & strengthens with added long and bin +bool OccSimplifier::sub_str_with_added_long_and_bin(const bool verbose) +{ + assert(solver->okay()); + assert(solver->prop_at_head()); + + while (!added_long_cl.empty() || !added_irred_bin.empty()) + { + if (!sub_str->handle_added_long_cl(verbose)) return false; + assert(solver->okay()); + assert(solver->prop_at_head()); + + //NOTE: added_irred_bin CAN CHANGE while this is running!! + for (size_t i = 0; i < added_irred_bin.size(); i++) { + tmp_bin_cl[0] = added_irred_bin[i].first; + tmp_bin_cl[1] = added_irred_bin[i].second; + + Sub1Ret ret; //TODO use this in the stats + if (!sub_str->backw_sub_str_with_impl(tmp_bin_cl, ret)) return false; + } + added_irred_bin.clear(); + } + assert(added_long_cl.empty()); + assert(added_irred_bin.empty()); + + return solver->okay(); +} + +bool OccSimplifier::clear_vars_from_cls_that_have_been_set() +{ + assert(solver->okay()); + assert(solver->decisionLevel() == 0); + assert(solver->prop_at_head()); + + //This only matters in terms of var elim complexity + //solver->clauseCleaner->clean_implicit_clauses(); + cls_to_clean_tmp.clear(); + while(last_trail_cleared < solver->trail_size()) { + Lit l = solver->trail_at(last_trail_cleared++); + elim_calc_need_update.touch(l.var()); + watch_subarray ws = solver->watches[l]; + + //Everything here is satisfied + uint32_t j = 0; + for (uint32_t i = 0; i < ws.size(); i ++) { + Watched& w = ws[i]; + if (w.isBin()) { + removeWBin(solver->watches, w.lit2(), l, w.red(), w.get_ID()); + if (w.red()) { + solver->binTri.redBins--; + } else { + n_occurs[l.toInt()]--; + n_occurs[w.lit2().toInt()]--; + elim_calc_need_update.touch(w.lit2()); + solver->binTri.irredBins--; + } + *(solver->frat) << del << w.get_ID() << l << w.lit2() << fin; + continue; + } + + assert(w.isClause()); + ws[j++] = w; + ClOffset offs = w.get_offset(); + Clause* cl = solver->cl_alloc.ptr(offs); + if (cl->getRemoved() || cl->freed()) { + //Satisfied and removed + continue; + } + //We'll need to set removed, etc. + cls_to_clean_tmp.push_back(offs); + } + ws.resize(j); + + l = ~l; + watch_subarray ws2 = solver->watches[l]; + + //Remove literal + j = 0; + for (uint32_t i = 0; i < ws2.size(); i ++) { + Watched& w = ws2[i]; + if (w.isBin()) { + assert(solver->value(w.lit2()) == l_True); //we propagate and it'd be UNSAT otherwise + removeWBin(solver->watches, w.lit2(), l, w.red(), w.get_ID()); + if (w.red()) { + solver->binTri.redBins--; + } else { + n_occurs[l.toInt()]--; + n_occurs[w.lit2().toInt()]--; + elim_calc_need_update.touch(w.lit2()); + solver->binTri.irredBins--; + } + *(solver->frat) << del << w.get_ID() << l << w.lit2() << fin; + continue; + } + + ws2[j++] = w; + assert(w.isClause()); + ClOffset offs = w.get_offset(); + Clause* cl = solver->cl_alloc.ptr(offs); + if (cl->getRemoved() || cl->freed()) { + continue; + } + cls_to_clean_tmp.push_back(offs); + } + ws2.resize(j); + } + + for(ClOffset offs: cls_to_clean_tmp) { + Clause* cl = solver->cl_alloc.ptr(offs); + if (!cl->getRemoved() && !cl->freed()) { + if (!clean_clause(offs, true)) { + return false; + } + } + } + + if (!sub_str_with_added_long_and_bin(false)) { + return false; + } + + return solver->okay(); +} + +bool OccSimplifier::mark_and_push_to_added_long_cl_cls_containing(const Lit lit) +{ + watch_subarray_const cs = solver->watches[lit]; + *limit_to_decrease -= (long)cs.size()*2+ 40; + for (const Watched *it = cs.begin(), *end = cs.end() + ; it != end + ; ++it + ) { + if (it->isClause()) { + ClOffset offs = it->get_offset(); + Clause* cl = solver->cl_alloc.ptr(offs); + + //Has already been removed or added to "added_long_cl" + if (cl->freed() || cl->getRemoved() || cl->stats.marked_clause) + continue; + + cl->stats.marked_clause = 1; + added_long_cl.push_back(offs); + } + } + return true; +} + +bool OccSimplifier::simulate_frw_sub_str_with_added_cl_to_var() +{ + auto old_limit_to_decrease = limit_to_decrease; + limit_to_decrease = &varelim_sub_str_limit; + + //during the mark_and_push_to_added_long_cl_cls_containing() below, we mark the clauses + //so we don't add the same clause twice + for(uint32_t i = 0 + ; i < added_cl_to_var.getTouchedList().size() + && *limit_to_decrease > 0 + && !solver->must_interrupt_asap() + ; i++ + ) { + uint32_t var = added_cl_to_var.getTouchedList()[i]; + Lit lit = Lit(var, true); + if (!sub_str->backw_sub_str_long_with_bins_watch(lit, true)) goto end; + if (!mark_and_push_to_added_long_cl_cls_containing(lit)) goto end; + + lit = ~lit; + if (!sub_str->backw_sub_str_long_with_bins_watch(lit, true)) goto end; + if (!mark_and_push_to_added_long_cl_cls_containing(lit)) goto end; + } + added_cl_to_var.clear(); + + //here, we clean the marks on the clauses, even in case of timeout/abort + if (!sub_str_with_added_long_and_bin(false)) goto end; + SLOW_DEBUG_DO(check_no_marked_clauses()); + + end: + limit_to_decrease = old_limit_to_decrease; + return solver->okay(); +} + +void OccSimplifier::check_no_marked_clauses() +{ + for(const auto& off: clauses) { + Clause* cl = solver->cl_alloc.ptr(off); + if (!cl->getRemoved()) { + assert(!cl->stats.marked_clause); + } + } +} + +void OccSimplifier::strengthen_dummy_with_bins(const bool avoid_redundant) +{ + auto old_limit_to_decrease = limit_to_decrease; + limit_to_decrease = &dummy_str_time_limit; + uint32_t j; + + if (*limit_to_decrease < 0) goto end; + for(auto const&l: dummy) seen[l.toInt()] = 1; + for(auto const&l: dummy) { + if (!seen[l.toInt()]) continue; //avoid loops + *limit_to_decrease -= 1; + for(auto const& w: solver->watches[l]) { + if (!w.isBin()) continue; + if (avoid_redundant && w.red()) continue; + const Lit lit2 = w.lit2(); + if (seen[(~lit2).toInt()]) seen[(~lit2).toInt()] = 0; + } + } + + j = 0; + for(uint32_t i = 0; i < dummy.size(); i++) { + if (seen[dummy[i].toInt()]) { + dummy[j++] = dummy[i]; + } + seen[dummy[i].toInt()] = 0; + } + dummy.resize(j); + + end: + limit_to_decrease = old_limit_to_decrease; +} + +void OccSimplifier::subs_with_resolvent_clauses() +{ + assert(solver->okay()); + assert(solver->prop_at_head()); + double myTime = cpuTime(); + uint64_t removed = 0; + uint64_t resolvents_checked = 0; + auto old_limit_to_decrease = limit_to_decrease; + limit_to_decrease = &norm_varelim_time_limit; + + for(uint32_t var = 0; var < solver->nVars(); var++) { + if (solver->value(var) != l_Undef || solver->varData[var].removed != Removed::none) continue; + + const Lit lit(var, false); + const auto& tmp_poss = solver->watches[lit]; + const auto& tmp_negs = solver->watches[~lit]; + int32_t ID1; + int32_t ID2; + for (auto const& pos: tmp_poss) { + *limit_to_decrease -= 3; + if (pos.isBin()) { + if (pos.red()) continue; + ID1 = pos.get_ID(); + } + else if (pos.isClause()) { + const Clause *cl = solver->cl_alloc.ptr(pos.get_offset()); + if (cl->getRemoved() || cl->red()) continue; + ID1 = cl->stats.ID; + } + + for (auto const& neg: tmp_negs) { + *limit_to_decrease -= 3; + if (*limit_to_decrease < 0) goto end; + if (neg.isBin()) { + if (neg.red()) continue; + ID2 = neg.get_ID(); + } else if (neg.isClause()) { + const Clause *cl = solver->cl_alloc.ptr(neg.get_offset()); + if (cl->getRemoved() || cl->red()) continue; + ID2 = cl->stats.ID; + } + + //Resolve the two clauses + bool tautological = resolve_clauses(pos, neg, lit); + if (tautological) continue; + if (solver->satisfied(dummy)) continue; + if (dummy.size() == 1) { + // could remove binary subsumed, which would lead watchlist manipulated + // which would lead to memory error, since we are going thorugh it + // just skip. + continue; + } + if (*limit_to_decrease < -10LL*1000LL) return; +// if (dummy.size() > 10) continue; //likely not useful + + resolvents_checked++; + tmp_subs.clear(); + std::sort(dummy.begin(), dummy.end()); +// strengthen_dummy_with_bins(true); //too expensive + + sub_str->find_subsumed( + CL_OFFSET_MAX, + dummy, + calcAbstraction(dummy), + tmp_subs, + true //only irred + ); + for(const auto& sub: tmp_subs) { + if (sub.ws.isBin()) { + const auto ID3 = sub.ws.get_ID(); + if (ID3 == ID1 || ID3 == ID2 || sub.ws.red()) continue; + sub_str->remove_binary_cl(sub); + removed++; + } else if (sub.ws.isClause()) { + const Clause* cl = solver->cl_alloc.ptr(sub.ws.get_offset()); + const auto ID3 = cl->stats.ID; + if (ID3 == ID1 || ID3 == ID2 || cl->red()) continue; + unlink_clause(sub.ws.get_offset(), true, false, true); + removed++; + } + } + } + } + } + + end: + solver->clean_occur_from_removed_clauses_only_smudged(); + free_clauses_to_free(); + verb_print(1, "[occ-resolv-subs] removed: " << removed + << " checked: " << resolvents_checked + << " T: " << (cpuTime()-myTime)); + limit_to_decrease = old_limit_to_decrease; +} + +bool OccSimplifier::eliminate_vars() +{ + assert(solver->okay()); + assert(solver->prop_at_head()); + assert(added_irred_bin.empty()); + assert(added_long_cl.empty()); + assert(picovars_used.empty()); + var_to_picovar.clear(); + var_to_picovar.resize(solver->nVars(), 0); + picolits_added = 0; + turned_off_irreg_gate = false; + + //Set-up + double myTime = cpuTime(); + size_t vars_elimed = 0; + size_t wenThrough = 0; + time_spent_on_calc_otf_update = 0; + num_otf_update_until_now = 0; + int64_t orig_norm_varelim_time_limit = norm_varelim_time_limit; + auto old_limit_to_decrease = limit_to_decrease; + limit_to_decrease = &norm_varelim_time_limit; + assert(cl_to_free_later.empty()); + assert(solver->watches.get_smudged_list().empty()); + bvestats.clear(); + bvestats.numCalls = 1; + + //Go through the ordered list of variables to eliminate + int64_t last_elimed = 1; + grow = 0; + uint32_t n_cls_last = sum_irred_cls_longs() + solver->binTri.irredBins; + uint32_t n_cls_init = n_cls_last; + uint32_t n_vars_last = solver->get_num_free_vars(); + + //For debug ONLY + // subsume with bins everywhere first +// for(uint32_t i = 0; i < solver->nVars(); i++) { +// Lit lit = Lit(i, false); +// if (!sub_str->backw_sub_str_long_with_bins_watch(lit, false)) { +// goto end; +// } +// +// lit = Lit(i, true); +// if (!sub_str->backw_sub_str_long_with_bins_watch(lit, false)) { +// goto end; +// } +// if (*limit_to_decrease <= 0) +// break; +// } + // + + if (!clear_vars_from_cls_that_have_been_set()) { + goto end; + } + + while(varelim_num_limit > 0 + && varelim_linkin_limit_bytes > 0 + && *limit_to_decrease > 0 + ) { + if (solver->conf.verbosity >= 2) { + cout << "c x n vars : " << solver->get_num_free_vars() << endl; + #ifdef DEBUG_VARELIM + cout << "c x cls long : " << sum_irred_cls_longs() << endl; + cout << "c x cls bin : " << solver->binTri.irredBins << endl; + cout << "c x long cls lits: " << sum_irred_cls_longs_lits() << endl; + #endif + } + + last_elimed = 0; + limit_to_decrease = &norm_varelim_time_limit; + order_vars_for_elim(); + if (velim_order.size() < 400) { + for(auto& v: solver->varData) { + v.occ_simp_tried = 0; + } + } + + added_cl_to_var.clear(); + removed_cl_with_var.touch(Lit(0, false)); + while(!removed_cl_with_var.getTouchedList().empty() + && *limit_to_decrease > 0 + && !solver->must_interrupt_asap() + && solver->okay() + ) { + assert(solver->prop_at_head()); + removed_cl_with_var.clear(); + update_varelim_complexity_heap(); + while(!velim_order.empty() + && *limit_to_decrease > 0 + && varelim_num_limit > 0 + && varelim_linkin_limit_bytes > 0 + && solver->okay() + && !solver->must_interrupt_asap() + ) { + assert(solver->prop_at_head()); + assert(limit_to_decrease == &norm_varelim_time_limit); + uint32_t var = velim_order.removeMin(); + + //Stats + *limit_to_decrease -= 20; + wenThrough++; + + if (!can_eliminate_var(var)) continue; + if (maybe_eliminate(var)) { + vars_elimed++; + varelim_num_limit--; + last_elimed++; + } + if (!solver->okay()) goto end; + assert(solver->prop_at_head()); + + if (!clear_vars_from_cls_that_have_been_set()) goto end; + + //SUB and STR for newly added long and short cls + if (!sub_str_with_added_long_and_bin(false)) goto end; + + // This is expensive, only do it if we are in Arjun's E mode + if (solver->conf.varelim_check_resolvent_subs + && !simulate_frw_sub_str_with_added_cl_to_var()) goto end; + + assert(solver->okay()); + assert(solver->prop_at_head()); + update_varelim_complexity_heap(); + } + assert(solver->prop_at_head()); + assert(added_long_cl.empty()); + assert(added_irred_bin.empty()); + + solver->clean_occur_from_removed_clauses_only_smudged(); + + if (solver->conf.verbosity >= 2) { + cout <<"c size of added_cl_to_var : " << added_cl_to_var.getTouchedList().size() << endl; + cout <<"c size of removed_cl_with_var: " << removed_cl_with_var.getTouchedList().size() << endl; + } + + if (!simulate_frw_sub_str_with_added_cl_to_var()) goto end; + + //These WILL ADD VARS BACK even though it's not changed. + for(uint32_t var: removed_cl_with_var.getTouchedList()) { + if (!can_eliminate_var(var)) continue; + varElimComplexity[var] = heuristicCalcVarElimScore(var); + velim_order.update(var); + } + + if (solver->conf.verbosity >= 2) { + cout << "c x n vars : " << solver->get_num_free_vars() << endl; + #ifdef DEBUG_VARELIM + cout << "c x cls long : " << sum_irred_cls_longs() << endl; + cout << "c x cls bin : " << solver->binTri.irredBins << endl; + cout << "c x long cls lits: " << sum_irred_cls_longs_lits() << endl; + #endif + cout << "c another run ?"<< endl; + } + } + #ifdef DEBUG_VARELIM + if (solver->conf.verbosity >= 2) { + cout << "c finished here" << endl; + } + #endif + solver->clean_occur_from_removed_clauses_only_smudged(); + + //For debug ONLY + /////////////// +// free_clauses_to_free(); +// // backward_sub_str(); +// // limit_to_decrease = &norm_varelim_time_limit; +// solver->clauseCleaner->clean_implicit_clauses(); +// solver->clean_occur_from_removed_clauses(); + /////////////// + + uint32_t n_cls_now = sum_irred_cls_longs() + solver->binTri.irredBins; + uint32_t n_vars_now = solver->get_num_free_vars(); + double cl_inc_rate = 2.0; + if (n_cls_last != 0) { + cl_inc_rate = (double)n_cls_now / n_cls_last; + } + + double var_dec_rate = 1.0; + if (n_vars_now != 0) { + var_dec_rate = (double)n_vars_last / n_vars_now; + } + if (solver->conf.verbosity) { + cout << "c [occ-bve] iter v-elim " << last_elimed << endl; + cout << "c cl_inc_rate=" << cl_inc_rate + << ", var_dec_rate=" << var_dec_rate + << " (grow=" << grow << ")" << endl; + + cout << "c Reduced to " << solver->get_num_free_vars() << " vars" + << ", " << sum_irred_cls_longs() + solver->binTri.irredBins + << " cls (grow=" << grow << ")" << endl; + + if (varelim_num_limit < 0 + || varelim_linkin_limit_bytes < 0 + || *limit_to_decrease < 0 + ) { + cout << "c [occ-bve] stopped varelim due to outage. " + << " varelim_num_limit: " << print_value_kilo_mega(varelim_num_limit) + << " varelim_linkin_limit_bytes: " << print_value_kilo_mega(varelim_linkin_limit_bytes) + << " *limit_to_decrease: " << print_value_kilo_mega(*limit_to_decrease) + << endl; + } + } + + if (n_cls_now > n_cls_init || cl_inc_rate > (var_dec_rate)) { + break; + } + n_cls_last = n_cls_now; + n_vars_last = n_vars_now; + + if ((int)grow == solver->conf.min_bva_gain) break; + if (grow == 0) grow = 8; + else grow *= 2; + grow = std::min(grow, solver->conf.min_bva_gain); + assert(solver->prop_at_head()); + assert(added_long_cl.empty()); + assert(added_irred_bin.empty()); + } + + if (solver->conf.verbosity) { + cout << "c x n vars : " << solver->get_num_free_vars() << endl; + #ifdef DEBUG_VARELIM + cout << "c x cls long : " << sum_irred_cls_longs() << endl; + cout << "c x cls bin : " << solver->binTri.irredBins << endl; + cout << "c x long cls lits: " << sum_irred_cls_longs_lits() << endl; + #endif + } + +end: + if (solver->okay()) { + assert(solver->prop_at_head()); + assert(added_long_cl.empty()); + assert(added_irred_bin.empty()); + #ifdef SLOW_DEBUG + check_no_marked_clauses(); + #endif + } + solver->clean_occur_from_removed_clauses_only_smudged(); + free_clauses_to_free(); + + assert(solver->watches.get_smudged_list().empty()); + const double time_used = cpuTime() - myTime; + const bool time_out = (*limit_to_decrease <= 0); + const double time_remain = float_div(*limit_to_decrease, orig_norm_varelim_time_limit); + + verb_print(1, "#try to eliminate: "<< print_value_kilo_mega(wenThrough)); + verb_print(1, "#var-elim : "<< print_value_kilo_mega(vars_elimed)); + verb_print(1, "#T-o: " << (time_out ? "Y" : "N")); + verb_print(1, "#T-r: " << std::fixed << std::setprecision(2) << (time_remain*100.0) << "%"); + verb_print(1, "#T : " << time_used); + if (solver->conf.verbosity) { + if (solver->conf.verbosity >= 3) + runStats.print(solver->nVarsOuter(), this); + else + runStats.print_extra_times(); + } + if (solver->sqlStats) { + solver->sqlStats->time_passed( + solver + , "bve" + , time_used + , time_out + , time_remain + ); + } + assert(limit_to_decrease == &norm_varelim_time_limit); + limit_to_decrease = old_limit_to_decrease; + + bvestats.varElimTimeOut += time_out; + bvestats.timeUsed = cpuTime() - myTime; + bvestats_global += bvestats; + + return solver->okay(); +} + +void OccSimplifier::free_clauses_to_free() +{ + for(ClOffset off: cl_to_free_later) { + Clause* cl = solver->cl_alloc.ptr(off); + solver->free_cl(cl); + } + cl_to_free_later.clear(); +} + +bool OccSimplifier::fill_occur_and_print_stats() +{ + double myTime = cpuTime(); + remove_all_longs_from_watches(); + if (!fill_occur()) { + return false; + } + sanityCheckElimedVars(); + const double linkInTime = cpuTime() - myTime; + runStats.linkInTime += linkInTime; + if (solver->sqlStats) { + solver->sqlStats->time_passed_min( + solver + , "occur build" + , linkInTime + ); + } + + //Print memory usage after occur link-in + if (solver->conf.verbosity) { + double vm_usage = 0; + solver->print_watch_mem_used(memUsedTotal(vm_usage)); + } + + return true; +} + +struct OrderByDecreasingIncidence { + OrderByDecreasingIncidence(const vector& _n_occurs): + n_occurs(_n_occurs) + { + } + bool operator()(const uint32_t v1, const uint32_t v2) + { + uint32_t v1_occ = n_occurs[Lit(v1, false).toInt()] + n_occurs[Lit(v1, true).toInt()]; + uint32_t v2_occ = n_occurs[Lit(v2, false).toInt()] + n_occurs[Lit(v2, true).toInt()]; + + return v1_occ > v2_occ; + } + + const vector& n_occurs; +}; + +struct MyOccSorter +{ + MyOccSorter(const Solver* _solver) : + solver(_solver) + { + } + bool operator()(const Watched& w1, const Watched& w2) + { + if (w2.isBin()) + return false; + + if (w1.isBin() && !w2.isBin()) + return true; + + //both are non-bin + const Clause* cl1 = solver->cl_alloc.ptr(w1.get_offset()); + const Clause* cl2 = solver->cl_alloc.ptr(w2.get_offset()); + + //The other is at least as good, this is removed + if (cl1->freed() || cl1->getRemoved()) + return false; + + //The other is not removed, so it's better + if (cl2->freed() || cl2->getRemoved()) + return true; + + const uint32_t sz1 = cl1->size(); + const uint32_t sz2 = cl2->size(); + return sz1 < sz2; + } + + const Solver* solver; +}; + +void OccSimplifier::sort_occurs_and_set_abst() +{ + for(auto& ws: solver->watches) { + std::sort(ws.begin(), ws.end(), MyOccSorter(solver)); + + for(Watched& w: ws) { + if (w.isClause()) { + Clause* cl = solver->cl_alloc.ptr(w.get_offset()); + if (cl->freed() || cl->getRemoved()) { + w.setElimedLit(lit_Error); + } else if (cl->size() >solver->conf.maxXorToFind) { + w.setElimedLit(lit_Undef); + } else { + w.setElimedLit(Lit::toLit(cl->abst)); + } + } + } + } +} + +vector OccSimplifier::recover_or_gates() +{ + vector or_gates; + auto origTrailSize = solver->trail_size(); + gateFinder = new GateFinder(this, solver); + + startup = false; + double backup = solver->conf.maxOccurRedMB; + solver->conf.maxOccurRedMB = 0; + if (!setup()) { + delete gateFinder; + gateFinder = NULL; + return or_gates; + } + + gateFinder->find_all(); + or_gates = gateFinder->get_gates(); + gateFinder->cleanup(); + + solver->conf.maxOccurRedMB = backup; + delete gateFinder; + gateFinder = NULL; + finishUp(origTrailSize); + return or_gates; +} + +int OccSimplifier::lit_to_picolit(const Lit l) { + picolits_added++; + auto f = var_to_picovar[l.var()]; + int picolit = 0; + if (f == 0) { + int v = picosat_inc_max_var(picosat); + var_to_picovar[l.var()] = v; + picovars_used.push_back(l.var()); + picolit = v * (l.sign() ? -1 : 1); + } else { + picolit = f * (l.sign() ? -1 : 1); + } + return picolit; +} + +uint32_t OccSimplifier::add_cls_to_picosat_definable(const Lit wsLit) { + assert(seen[wsLit.var()] == 1); + + uint32_t added = 0; + for(const auto& w: solver->watches[wsLit]) { + if (w.isClause()) { + Clause& cl = *solver->cl_alloc.ptr(w.get_offset()); + assert(!cl.getRemoved()); + assert(!cl.red()); + bool only_sampl = true; + for(const auto& l: cl) { + if (!seen[l.var()]) { + only_sampl = false; + break; + } + } + if (only_sampl) { + added++; + for(const auto& l: cl) { + if (l != wsLit) picosat_add(picosat, lit_to_picolit(l)); + } +// cout << "Added cl: " << cl << endl; + picosat_add(picosat, 0); + } + } else if (w.isBin()) { + if (!w.red()) { + bool only_sampl = seen[w.lit2().var()]; + if (only_sampl) { + added++; + picosat_add(picosat, lit_to_picolit(w.lit2())); + picosat_add(picosat, 0); + // cout << "Added cl: " << w.lit2() << " " << wsLit << endl; + } + } + } else { + assert(false); + } + } + return added; +} + +bool OccSimplifier::elim_var_by_str(uint32_t var, const vector>& cls) +{ + Lit l(var, false); + + // Remove binaries, add units. + solver->watches[l].copyTo(poss); + for(auto const& w: poss) { + if (!w.isBin()) continue; + + auto val = solver->value(w.lit2()); + assert(val == l_Undef); + solver->enqueue(w.lit2()); + solver->ok = solver->propagate_occur(limit_to_decrease); + if (!solver->okay()) goto end; + + if (!solver->okay()) goto end; + + sub_str->remove_binary_cl(OccurClause(l, w)); + if (w.red()) continue; + } + solver->watches[~l].copyTo(negs); + for(auto const& w: negs) { + if (!w.isBin()) continue; + + sub_str->remove_binary_cl(OccurClause(~l, w)); + if (w.red()) continue; + // No need to add the unit, already added above. + } + + // Add resolvent, remove pair of cls + for(auto const& p: cls) { + dummy.clear(); + Clause* cl = solver->cl_alloc.ptr(p.first); + for(auto const& lit: *cl) { + if (lit.var() != var) dummy.push_back(lit); + } + if (!full_add_clause(dummy, weaken_dummy, NULL, false)) goto end; + unlink_clause(p.first); + unlink_clause(p.second); + } + + //Remove remaining redundant clauses + solver->watches[l].copyTo(poss); + for(auto const& w: poss) { + assert(w.isClause()); + Clause* cl = solver->cl_alloc.ptr(w.get_offset()); + assert(cl->red()); + unlink_clause(w.get_offset()); + } + solver->watches[~l].copyTo(negs); + for(auto const& w: negs) { + assert(w.isClause()); + Clause* cl = solver->cl_alloc.ptr(w.get_offset()); + assert(cl->red()); + unlink_clause(w.get_offset()); + } + assert(solver->watches[l].empty()); + assert(solver->watches[~l].empty()); + + end: + return solver->okay(); +} + +// Returns new set that doesn't contain variables that are definable +vector OccSimplifier::remove_definable_by_irreg_gate(const vector& vars) +{ + assert(solver->okay()); + assert(solver->prop_at_head()); + assert(picovars_used.empty()); + var_to_picovar.clear(); + var_to_picovar.resize(solver->nVars(), 0); + + vector ret; + auto origTrailSize = solver->trail_size(); + + startup = false; + double backup = solver->conf.maxOccurRedMB; + solver->conf.maxOccurRedMB = 0; + if (!setup()) return vars; + assert(picosat == NULL); + + uint32_t unsat = 0; + uint32_t picosat_ran = 0; + uint32_t no_cls_matching_filter = 0; + uint32_t no_occ = 0; + uint32_t too_many_occ = 0; + uint32_t equiv_subformula = 0; + + vector vars2; + for(const uint32_t& v: vars) { + auto rem_val = solver->varData[v].removed; + assert(rem_val == Removed::none || rem_val == Removed::replaced); + const uint32_t v2 = solver->varReplacer->get_var_replaced_with(v); + + rem_val = solver->varData[v2].removed; + assert(rem_val == Removed::none); + assert(v2 < seen.size()); + + if (seen[v2]) continue; + seen[v2] = 1; + vars2.push_back(v2); + } + + std::reverse(vars2.begin(), vars2.end()); + for(const auto& v: vars2) { + assert(solver->varData[v].removed == Removed::none); + if (solver->value(v) != l_Undef) continue; + const Lit l = Lit(v, false); + + uint32_t total = solver->watches[l].size() + solver->watches[~l].size(); + bool empty_occ = total == 0 || + (solver->zero_irred_cls(l) && solver->zero_irred_cls(~l)); + if (empty_occ) { + no_occ++; + ret.push_back(v); + continue; + } + + // too expensive? + if (total > 500) { + too_many_occ++; + ret.push_back(v); + continue; + } + + if (picosat == NULL) { + picosat = picosat_init(); + } + + assert(picovars_used.empty()); + uint32_t added = add_cls_to_picosat_definable(l); + added += add_cls_to_picosat_definable(~l); + for(const auto x: picovars_used) var_to_picovar[x] = 0; + picovars_used.clear(); + + if (added == 0) { + no_cls_matching_filter++; + ret.push_back(v); + continue; + } + + int picoret = picosat_sat(picosat, 100); + picosat_ran++; + if (picoret == PICOSAT_UNSATISFIABLE) { + unsat++; + seen[v] = 0; + } else { + ret.push_back(v); + } + picosat_reset(picosat); + picosat = NULL; + } + if (picosat) { + picosat_reset(picosat); + picosat = NULL; + } + for(const uint32_t v: vars2) seen[v] = 0; + + verb_print(1, "[gate-definable] no-cls-match-filt: " << no_cls_matching_filter + << " pico ran: " << picosat_ran << " unsat: " << unsat + << " 0-occ: " << no_occ << " too-many-occ: " << too_many_occ + << " empty-res: " << equiv_subformula); + + solver->conf.maxOccurRedMB = backup; + finishUp(origTrailSize); + return ret; +} + +void OccSimplifier::clean_sampl_and_get_empties( + vector& sampl_vars, vector& empty_vars) +{ + assert(solver->okay()); + assert(solver->prop_at_head()); + release_assert(empty_vars.empty()); + if (!setup()) return; + + auto origTrailSize = solver->trail_size(); + startup = false; + const double backup = solver->conf.maxOccurRedMB; + solver->conf.maxOccurRedMB = 0; + const double myTime = cpuTime(); + + set empty_vars_set; + + // Clean up sampl_vars from replaced and set variables + set sampl_vars_set; + for(uint32_t& v: sampl_vars) { + v = solver->varReplacer->get_var_replaced_with(v); + auto rem_val = solver->varData[v].removed; + assert(rem_val == Removed::none); + if (solver->value(v) != l_Undef) continue; + assert(v < solver->nVars()); + sampl_vars_set.insert(v); + } + + // Find empties + uint32_t mirror = 0; + uint32_t empty_occ = 0; + for(auto& v: sampl_vars_set) { + if (!solver->okay()) goto end; + const Lit l = Lit(v, false); + + uint32_t irred_and_red = solver->watches[l].size() + solver->watches[~l].size(); + if (irred_and_red == 0 || (solver->zero_irred_cls(l) && solver->zero_irred_cls(~l))) { + empty_occ++; + empty_vars_set.insert(v); + elim_var_by_str(l.var(), {}); + assert(solver->watches[l].empty() && solver->watches[~l].empty()); + continue; + } + } + + // Replace what we were given with cleaned + empty removed + sampl_vars.clear(); + for(auto const& v: sampl_vars_set) { + if (empty_vars_set.find(v) == empty_vars_set.end()) + sampl_vars.push_back(v); + } + empty_vars.clear(); + for(auto const& v: empty_vars_set) empty_vars.push_back(v); + + end: + double time_used = cpuTime() - myTime; + verb_print(1, "[cms-equiv-sub] equiv_subformula: " << mirror + << " empty_occ: " << empty_occ << solver->conf.print_times(time_used)); + + solver->conf.maxOccurRedMB = backup; + finishUp(origTrailSize); +} + +vector OccSimplifier::recover_ite_gates() +{ + vector or_gates; + auto origTrailSize = solver->trail_size(); + + startup = false; + double backup = solver->conf.maxOccurRedMB; + solver->conf.maxOccurRedMB = 0; + if (!setup()) { + delete gateFinder; + gateFinder = NULL; + return or_gates; + } + + vec out_a_all; + for(uint32_t i = 0; i < solver->nVars()*2; i++) { + const Lit lit = Lit::toLit(i); + out_a_all.clear(); + gates_poss.clear(); //temps, not needed + gates_negs.clear(); //temps, not needed + find_ite_gate(lit, solver->watches[lit], solver->watches[~lit], + gates_poss, gates_negs, //temporaries, actually not used + &out_a_all); // what we are looking for + + if (out_a_all.empty()) { + continue; + } + + //out_a_all contains N*2 clauses, every 2 make up an ITE + //For each of 2: + // x -> (a=f) + // -x -> (a=g) + // and we get back 2x 3-long clauses: + // -a V f V -x + // -a V g V x + // i.e. lhs[0] = f, lhs[2] = g, lhs[1] --> if TRUE selects lhs[2] otherwise lhs[1] + //cout << "out_a_all.s: " << out_a_all.size() << endl; + for(uint32_t i2 = 0; i2 < out_a_all.size(); i2+=2) { + ITEGate gate; + gate.rhs = lit; + seen[lit.var()] = 1; + uint32_t at = 0; + + for(uint32_t x = 0; x < 2; x++) { + Watched& w = out_a_all[i2+x]; + assert(w.isClause()); + Clause* cl = solver->cl_alloc.ptr(w.get_offset()); + //cout << "c: " << *cl << endl; + for(const auto&l : *cl) { + if (!seen[l.var()]) { + gate.lhs[at++] = l; + seen[l.var()] = 1; + } + } + } + assert(at == 3); + + //Cleanup + for(const auto& l: gate.get_all()) seen[l.var()] = 0; + or_gates.push_back(gate); + } + } + + solver->conf.maxOccurRedMB = backup; + finishUp(origTrailSize); + return or_gates; +} + +struct OrGateSorterLHS { + bool operator()(const OrGate& a, const OrGate& b) + { + if (a.lits.size() != b.lits.size()) return a.lits.size() < b.lits.size(); + for(uint32_t i = 0; i < a.lits.size(); i++) { + if (a.lits[i] != b.lits[i]) return a.lits[i] < b.lits[i]; + } + return a.rhs < b.rhs; + } +}; + +struct GateLHSEq { + bool operator()(const OrGate& a, const OrGate& b) + { + if (a.lits.size() != b.lits.size()) return false; + for(uint32_t i = 0; i < a.lits.size(); i++) { + if (a.lits[i] != b.lits[i]) return false; + } + return true; + } +}; + +bool OccSimplifier::cl_rem_with_or_gates() +{ + assert(solver->okay()); + assert(solver->prop_at_head()); + assert(added_irred_bin.empty()); + assert(added_long_cl.empty()); + + double myTime = cpuTime(); + gateFinder = new GateFinder(this, solver); + gateFinder->find_all(); + auto gates = gateFinder->get_gates(); + gateFinder->cleanup(); + delete gateFinder; + gateFinder = NULL; + + uint64_t removed = 0; + + for(auto const&g: gates) { + if (g.lits.size() != 2) continue; + + solver->watches[~g.lits[0]].copyTo(poss); + for(const auto& w: poss) { + if (!w.isClause()) continue; + Clause* cl1 = solver->cl_alloc.ptr(w.get_offset()); + if (cl1->getRemoved() || cl1->red()) continue; + if (cl1->size() <= 3) continue; // we could mess with definition of gates + if (cl1->stats.ID == g.ID) continue; + + bool found = false; + for(auto const&l: *cl1) { + if (l == ~g.lits[0]) {found = true; continue;} + seen[l.toInt()] = 1; + } + assert(found); + + solver->watches[~g.lits[1]].copyTo(negs); + for(const auto& w2: negs) { + if (!w2.isClause()) continue; + Clause* cl2 = solver->cl_alloc.ptr(w2.get_offset()); + if (cl1->getRemoved()) continue; // COULD HAVE BEEN REMOVED BELOW + if (cl2->getRemoved() || cl2->red()) continue; + if (cl2->stats.ID == g.ID) continue; + if (cl2->size() != cl1->size()) continue; + auto myabst1 = cl1->abst | abst_var(g.lits[1].var()); + auto myabst2 = cl2->abst | abst_var(g.lits[0].var()); + if (myabst1 != myabst2) continue; + + bool ok = true; + found = false; + for(auto const&l: *cl2) { + if (l == ~g.lits[1]) {found = true; continue;} + if (!seen[l.toInt()]) {ok = false; break;} + } + if (ok) { + assert(found); + dummy.clear(); + for(auto const&l: *cl2) { + if (l == ~g.lits[1]) {dummy.push_back(~g.rhs); continue;} + dummy.push_back(l); + } + + auto s = ClauseStats::combineStats(cl1->stats, cl2->stats); + full_add_clause(dummy, weaken_dummy, &s, false); + unlink_clause(w.get_offset(), true, false, true); + unlink_clause(w2.get_offset(), true, false, true); + removed++; + verb_print(2,"[cl-rem-gates] We could remove clauses: " + << *cl1 << " -- " << *cl2 << " based on gate: " << g); + if (!solver->okay()) goto end; + break; + } + } + for(auto const&l: *cl1) seen[l.toInt()] = 0; + } + } + + if (!sub_str_with_added_long_and_bin(true)) goto end; + + end: + solver->clean_occur_from_removed_clauses_only_smudged(); + free_clauses_to_free(); + + SLOW_DEBUG_DO(check_n_occur()); + SLOW_DEBUG_DO(check_clauses_lits_ordered()); + + //Update global stats + const double time_used = cpuTime() - myTime; + //const bool time_out = (*limit_to_decrease <= 0); + verb_print(1, "[occ-cl-rem-gates] removed: " << removed << " T: " << cpuTime()-myTime); + + + if (solver->sqlStats) { + solver->sqlStats->time_passed_min( + solver + , "occ-cl-rem-gates" + , time_used + ); + } + + assert(solver->okay()); + assert(solver->prop_at_head()); + return solver->okay(); +} + +// Checks that both inputs l1 & l2 are in the Clause. If so, replaces it with the RHS +bool OccSimplifier::lit_rem_with_or_gates() +{ + assert(solver->okay()); + assert(solver->prop_at_head()); + assert(added_irred_bin.empty()); + assert(added_long_cl.empty()); + + double myTime = cpuTime(); + gateFinder = new GateFinder(this, solver); + gateFinder->find_all(); + auto gates = gateFinder->get_gates(); + gateFinder->cleanup(); + delete gateFinder; + gateFinder = NULL; + + // we can't have 2 definitions of the same gate with different RHS + // Otherwise, we have a V b = c --> i.e. a V b V -c exists + // and have a V b = d --> i.e. a V b V -d exists + // and we could replace (a V b V -c) with d V -c + // and we could replace (a V b V -d) with c V -d + // which would loose the definiton of c->a V b and d-> a V b + std::sort(gates.begin(), gates.end(), OrGateSorterLHS()); + gates.erase(unique(gates.begin(), gates.end(), GateLHSEq()),gates.end()); + + uint64_t shortened = 0; + uint64_t removed = 0; + for(const auto& gate: gates) { + if (!solver->okay()) goto end; + if (solver->value(gate.rhs) != l_Undef) continue; + for(auto const& l: gate.lits) seen[l.toInt()] = 1; + + Lit smallest = gate.lits[0]; + uint32_t smallest_val = solver->watches[gate.lits[0]].size(); + for(uint32_t i = 1; i < gate.lits.size(); i++) { + const Lit l = gate.lits[i]; + const uint32_t sz = solver->watches[l].size(); + if (sz < smallest_val) { + smallest = l; + smallest_val = sz; + } + } + solver->watches[smallest].copyTo(poss); + + VERBOSE_PRINT("Checking to shorten with gate: " << gate); + for(const auto& w: poss) { + if (!solver->okay()) break; + if (w.isBin() || w. isBNN()) continue; + assert(w.isClause()); + const auto off = w.get_offset(); + Clause* cl = solver->cl_alloc.ptr(w.get_offset()); + if (cl->stats.ID == gate.ID || //the gate definition, skip + cl->red() || //no need, slow + cl->getRemoved()) + { + continue; + } + assert(!cl->freed()); + assert(cl->getOccurLinked()); + + //TODO check calcAbst! + bool contains_rhs = false; + bool contains_inv_rhs = false; + uint32_t found = 0; + for(auto const& l: *cl) { + if (l == gate.rhs) contains_rhs = true; + if (l == ~gate.rhs) contains_inv_rhs = true; + if (seen[l.toInt()]) found++; + } + if (found < gate.lits.size()) continue; + assert(found == gate.lits.size()); +// cout << "Gate LHS matches clause: " << *cl << " gate: " << gate << endl; + + if (contains_inv_rhs) { +// cout << "Removing cl: " << *cl << endl; + unlink_clause(off, true, false, true); + removed++; + continue; + } + shortened++; + (*solver->frat) << deldelay << *cl << fin; + +// cout << "Shortening cl: " << *cl << endl; + for(auto const& l: gate.lits) { + solver->watches.smudge(l); + removeWCl(solver->watches[l], off); + n_occurs[l.toInt()]--; + elim_calc_need_update.touch(l); + removed_cl_with_var.touch(l); + cl->strengthen(l); + } + + solver->litStats.irredLits-=gate.lits.size(); + if (!contains_rhs) { + cl->enlarge_one(); + (*cl)[cl->size()-1] = gate.rhs; + cl->reCalcAbstraction(); + solver->watches[gate.rhs].push(Watched(off, cl->abst)); + n_occurs[gate.rhs.toInt()]++; + elim_calc_need_update.touch(gate.rhs); + solver->litStats.irredLits++; + } else { + cl->reCalcAbstraction(); + } + std::sort(cl->begin(), cl->end()); + INC_ID(*cl); + (*solver->frat) << add << *cl << fin << findelay; +// cout << "Shortened cl: " << *cl << endl; + + if (cl->size() == 2) { + n_occurs[(*cl)[0].toInt()]++; + n_occurs[(*cl)[1].toInt()]++; + solver->attach_bin_clause((*cl)[0], (*cl)[1], false, cl->stats.ID, false); + unlink_clause(off, false, false, true); +// cout << "Became bin." << endl; + } else if (cl->size() == 1) { + tmp_tern_res.clear(); tmp_tern_res.push_back((*cl)[0]); + Clause* newCl = full_add_clause(tmp_tern_res, finalLits_ternary, NULL, false); + assert(newCl == NULL); + unlink_clause(off, true, false, true); + } else assert(cl->size() > 2); + } + for(auto const& l: gate.lits) seen[l.toInt()] = 0; + } + if (!sub_str_with_added_long_and_bin(true)) goto end; + + end: + solver->clean_occur_from_removed_clauses_only_smudged(); + free_clauses_to_free(); + + SLOW_DEBUG_DO(check_n_occur()); + SLOW_DEBUG_DO(check_clauses_lits_ordered()); + + //Update global stats + const double time_used = cpuTime() - myTime; + //const bool time_out = (*limit_to_decrease <= 0); + verb_print(1, "[occ-gate-based-lit-rem]" + << " lit-rem: " << shortened + << " cl-rem: " << removed + << solver->conf.print_times(time_used, false)); + + if (solver->sqlStats) { + solver->sqlStats->time_passed_min( + solver + , "occ-gate-based-lit-rem" + , time_used + ); + } + + return solver->okay(); +} + +bool OccSimplifier::execute_simplifier_strategy(const string& strategy) +{ + std::istringstream ss(strategy); + std::string token; + + while(std::getline(ss, token, ',')) { + if (cpuTime() > solver->conf.maxTime + || solver->must_interrupt_asap() + || solver->nVars() == 0 + || !solver->okay() + ) { + return solver->okay(); + } + assert(added_long_cl.empty()); + assert(solver->prop_at_head()); + assert(solver->decisionLevel() == 0); + assert(cl_to_free_later.empty()); + set_limits(); + + #ifdef SLOW_DEBUG + #if defined(STATS_NEEDED) || defined(FINAL_PREDICTOR) + for (ClOffset offs: clauses) { + Clause* cl = solver->cl_alloc.ptr(offs); + if (cl->freed()) + continue; + if (!cl->red()) { + continue; + } + assert(solver->red_stats_extra[cl->stats.extra_pos].introduced_at_conflict != 0); + } + #endif + solver->check_implicit_stats(true); + solver->check_assumptions_sanity(); + check_no_marked_clauses(); + check_clauses_lits_ordered(); + #endif + + token = trim(token); + std::transform(token.begin(), token.end(), token.begin(), ::tolower); + if (token != "" && solver->conf.verbosity) { + cout << "c --> Executing OCC strategy token: " << token << '\n'; + *solver->frat << __PRETTY_FUNCTION__ << " Executing OCC strategy token:" << token.c_str() << "\n"; + } + + if (token == "occ-backw-sub-str") { + backward_sub_str(); + } else if (token == "occ-backw-sub") { + backward_sub(); + } else if (token == "occ-del-elimed") { + } else if (token == "occ-rem-unconn-assumps") { + delete_component_unconnected_to_assumps(); + } else if (token == "occ-ternary-res") { + if (solver->conf.doTernary) { + ternary_res(); + } + } else if (token == "occ-xor") { + if (solver->conf.doFindXors && + #ifdef USE_TBUDDY + true) + #else + !solver->frat->enabled()) + #endif + { + XorFinder finder(this, solver); + finder.find_xors(); + runStats.xorTime += finder.get_stats().findTime; + } + } else if (token == "occ-lit-rem") { + if (!solver->frat->enabled()) all_occ_based_lit_rem(); + } else if (token == "occ-bce") { + blocked_clause_elim(); + } else if (token == "occ-clean-implicit") { + //BUG TODO + //solver->clauseCleaner->clean_implicit_clauses(); + } else if (token == "occ-bve-empty") { + //Get rid of XOR clauses + if (solver->frat->enabled()) { + TBUDDY_DO(solver->free_bdds(solver->xorclauses_orig)); + TBUDDY_DO(solver->free_bdds(solver->xorclauses)); + TBUDDY_DO(solver->free_bdds(solver->xorclauses_unused)); + } + if (solver->conf.do_empty_varelim) eliminate_empty_resolvent_vars(); + } else if (token == "occ-bve") { + if (solver->conf.doVarElim) { + solver->removed_xorclauses_clash_vars.clear(); + solver->xor_clauses_updated = true; + + //Get rid of XOR clauses + if (solver->frat->enabled()) { + TBUDDY_DO(solver->free_bdds(solver->xorclauses_orig)); + TBUDDY_DO(solver->free_bdds(solver->xorclauses)); + TBUDDY_DO(solver->free_bdds(solver->xorclauses_unused)); + } + solver->xorclauses.clear(); + solver->xorclauses_orig.clear(); + solver->xorclauses_unused.clear(); + + if (solver->conf.do_empty_varelim) eliminate_empty_resolvent_vars(); + if (solver->conf.do_full_varelim) { + if (!eliminate_vars()) continue; + } + } + } else if (token == "occ-rem-with-orgates") { + lit_rem_with_or_gates(); + } else if (token == "occ-cl-rem-with-orgates") { + cl_rem_with_or_gates(); + } else if (token == "occ-bva") { + if (solver->conf.do_bva && false) { //TODO due to IDs, this is BROKEN + assert(false && "due to clause IDs this is broken"); + if (solver->conf.verbosity) { + cout << "c [occ-bva] global numcalls: " << globalStats.numCalls << endl; + } + if ((globalStats.numCalls % solver->conf.bva_every_n) == (solver->conf.bva_every_n-1)) { + if (!bva->bounded_var_addition()) { + continue; + } + added_irred_bin.clear(); + added_cl_to_var.clear(); + added_long_cl.clear(); + } + } + } else if (token == "occ-resolv-subs") { + subs_with_resolvent_clauses(); + } else if (token == "") { + //nothing, ignore empty token + } else { + cout << "ERROR: occur strategy '" << token << "' not recognised!" << endl; + exit(-1); + } + + #ifdef CHECK_N_OCCUR + check_n_occur(); + #endif //CHECK_N_OCCUR + SLOW_DEBUG_DO(check_cls_sanity()); + } + + if (solver->okay()) { + assert(solver->prop_at_head()); + } + + return solver->okay(); +} + +bool OccSimplifier::setup() +{ + *solver->frat << __PRETTY_FUNCTION__ << " start\n"; + assert(solver->okay()); + assert(toClear.empty()); + added_long_cl.clear(); + added_irred_bin.clear(); + added_cl_to_var.clear(); + n_occurs.clear(); + n_occurs.resize(solver->nVars()*2, 0); + + //Test & debug + #ifdef DEBUG_ATTACH_MORE + solver->test_all_clause_attached(); + solver->check_wrong_attach(); + #endif + + //Clean the clauses before playing with them + if (!solver->clauseCleaner->remove_and_clean_all()) { + return false; + } + + //If too many clauses, don't do it + if (solver->get_num_long_cls() > 40ULL*1000ULL*1000ULL*solver->conf.var_and_mem_out_mult + || solver->litStats.irredLits > 100ULL*1000ULL*1000ULL*solver->conf.var_and_mem_out_mult + ) { + if (solver->conf.verbosity) { + cout << "c [occ] will not link in occur, CNF has too many clauses/irred lits" << endl; + } + return false; + } + + //Setup + clause_lits_added = 0; + runStats.clear(); + runStats.numCalls++; + clauses.clear(); + set_limits(); //to calculate strengthening_time_limit + limit_to_decrease = &strengthening_time_limit; + if (!fill_occur_and_print_stats()) { + return false; + } + + set_limits(); + return solver->okay(); +} + +bool OccSimplifier::simplify(const bool _startup, const std::string& schedule) +{ + if (!solver->bnns.empty()) { + return solver->okay(); + } + #ifdef DEBUG_MARKED_CLAUSE + assert(solver->no_marked_clauses()); + #endif + + assert(solver->detached_xor_repr_cls.empty()); + assert(solver->gmatrices.empty()); + assert(solver->gqueuedata.empty()); + + startup = _startup; + if (!setup()) return solver->okay(); + + const size_t origElimedSize = elimedClauses.size(); + const size_t origTrailSize = solver->trail_size(); + + sampling_vars_occsimp.clear(); + if (solver->conf.sampling_vars) { + // sampling vars should not be eliminated + assert(!solver->fast_backw.fast_backw_on); + sampling_vars_occsimp.resize(solver->nVars(), false); + for(uint32_t outside_var: *solver->conf.sampling_vars) { + uint32_t outer_var = solver->map_to_with_bva(outside_var); + outer_var = solver->varReplacer->get_var_replaced_with_outer(outer_var); + uint32_t int_var = solver->map_outer_to_inter(outer_var); + if (int_var < solver->nVars()) { + sampling_vars_occsimp[int_var] = true; + } + } + } else if (solver->fast_backw.fast_backw_on) { + // fast backward arjun system + sampling_vars_occsimp.resize(solver->nVars(), false); + for(Lit p: *solver->fast_backw._assumptions) { + uint32_t var = solver->fast_backw.indic_to_var->at(p.var()); + p = solver->varReplacer->get_lit_replaced_with_outer(p); + p = solver->map_outer_to_inter(p); + assert(solver->varData[p.var()].removed == Removed::none); + sampling_vars_occsimp[p.var()] = true; + + //Deal with indicators: var, var + orig_num_vars + if (var == var_Undef) { + continue; + } + uint32_t var2 = var + solver->fast_backw.orig_num_vars; + var = solver->varReplacer->get_var_replaced_with_outer(var); + var = solver->map_outer_to_inter(var); + assert(solver->varData[var].removed == Removed::none); + if (sampling_vars_occsimp.size() > var) { + sampling_vars_occsimp[var] = true; + } + + var2 = solver->varReplacer->get_var_replaced_with_outer(var2); + var2 = solver->map_outer_to_inter(var2); + assert(solver->varData[var2].removed == Removed::none); + if (sampling_vars_occsimp.size() > var2) { + sampling_vars_occsimp[var2] = true; + } + } + + //Deal with test_indic + uint32_t v = *(solver->fast_backw.test_indic); + if (v != var_Undef) { + v = solver->varReplacer->get_var_replaced_with_outer(v); + v = solver->map_outer_to_inter(v); + if (sampling_vars_occsimp.size() > v) { + sampling_vars_occsimp[v] = true; + } + } + } else { + sampling_vars_occsimp.shrink_to_fit(); + } + + last_trail_cleared = solver->getTrailSize(); + execute_simplifier_strategy(schedule); + + remove_by_frat_recently_elimed_clauses(origElimedSize); + finishUp(origTrailSize); + + return solver->okay(); +} + +bool OccSimplifier::ternary_res() +{ + assert(solver->okay()); + assert(cl_to_add_ternary.empty()); + assert(solver->prop_at_head()); + assert(cl_to_free_later.empty()); + if (clauses.empty()) return solver->okay(); + + double myTime = cpuTime(); + int64_t orig_ternary_res_time_limit = ternary_res_time_limit; + auto old_limit_to_decrease = limit_to_decrease; + limit_to_decrease = &ternary_res_time_limit; + Sub1Ret sub1_ret; + + //NOTE: the "clauses" here will change in size as we add resolvents + size_t at = rnd_uint(solver->mtrand, clauses.size()-1); + for(size_t i = 0; i < clauses.size(); i++) { + ClOffset offs = clauses[(at+i) % clauses.size()]; + Clause * cl = solver->cl_alloc.ptr(offs); + *limit_to_decrease -= 10; + if (!cl->freed() + && !cl->getRemoved() + && !cl->is_ternary_resolved + && cl->size() == 3 + && !cl->red() + && *limit_to_decrease > 0 + && ternary_res_cls_limit > 0 + ) { + if (!perform_ternary(cl, offs, sub1_ret)) + goto end; + } + } + + if (!sub_str_with_added_long_and_bin(false)) { + goto end; + } + assert(added_long_cl.empty()); + + end: + //Update global stats + const double time_used = cpuTime() - myTime; + const bool time_out = (*limit_to_decrease <= 0); + const double time_remain = float_div(*limit_to_decrease, orig_ternary_res_time_limit); + if (solver->conf.verbosity) { + cout + << "c [occ-ternary-res] Ternary" + << " res-tri: " << runStats.ternary_added_tri + << " res-bin: " << runStats.ternary_added_bin + << " sub: " << sub1_ret.sub + << " str: " << sub1_ret.str + << solver->conf.print_times(time_used, time_out, time_remain) + << endl; + } + if (solver->sqlStats) { + solver->sqlStats->time_passed( + solver + , "ternary res" + , time_used + , time_out + , time_remain + ); + } + runStats.triresolveTime += time_used; + solver->clean_occur_from_removed_clauses_only_smudged(); + free_clauses_to_free(); + limit_to_decrease = old_limit_to_decrease; + + return solver->okay(); +} + +bool OccSimplifier::perform_ternary(Clause* cl, ClOffset offs, Sub1Ret& sub1_ret) +{ + assert(cl->size() == 3); + assert(!cl->red()); + assert(solver->okay()); + + cl->is_ternary_resolved = 1; + *limit_to_decrease -= 3; + for(const Lit l: *cl) { + seen[l.toInt()] = 1; + } + + size_t largest = 0; + Lit dont_check = lit_Undef; + for(const Lit l: *cl) { + size_t sz = n_occurs[l.toInt()] + n_occurs[(~l).toInt()]; + if (sz > largest) { + largest = sz; + dont_check = l; + } + } + + assert(cl_to_add_ternary.empty()); + for(const Lit l: *cl) { + if (l == dont_check) { + continue; + } + check_ternary_cl(cl, offs, solver->watches[l]); + check_ternary_cl(cl, offs, solver->watches[~l]); + } + + //clean up + for(const Lit l: *cl) { + seen[l.toInt()] = 0; + } + + //Add new ternary resolvents + for(const Tri& newcl: cl_to_add_ternary) { + ClauseStats stats; + stats.last_touched_any = solver->sumConflicts; + stats.is_ternary_resolvent = true; + #if defined(STATS_NEEDED) || defined(FINAL_PREDICTOR) + ClauseStatsExtra stats_extra; + stats_extra.introduced_at_conflict = solver->sumConflicts; + stats_extra.orig_size = 3; + #endif + + #ifdef FINAL_PREDICTOR + stats.which_red_array = 2; + #else + stats.which_red_array = 1; + #endif + + #ifdef STATS_NEEDED + double myrnd = solver->mtrand.randDblExc(); + if (myrnd <= solver->conf.dump_individual_cldata_ratio) { + //TODO mark clause for dumping + } + #endif + + tmp_tern_res.clear(); + for(uint32_t i = 0; i < newcl.size; i++) { + tmp_tern_res.push_back(newcl.lits[i]); + } + + Clause* newCl = full_add_clause(tmp_tern_res, finalLits_ternary, &stats, true); + if (newCl) { + #ifdef STATS_NEEDED + newCl->stats.locked_for_data_gen = + solver->mtrand.randDblExc() < solver->conf.lock_for_data_gen_ratio; + if (newCl->stats.locked_for_data_gen) { + newCl->stats.which_red_array = 0; + } + #endif + #if defined(STATS_NEEDED) || defined(FINAL_PREDICTOR) + solver->red_stats_extra.push_back(stats_extra); + newCl->stats.extra_pos = solver->red_stats_extra.size()-1; + #endif + ClOffset off = solver->cl_alloc.get_offset(newCl); + if (!sub_str->backw_sub_str_with_long(off, sub1_ret)) { + return false; + } + } else { + if (!solver->okay()) return false; + //We'd need to check sub1_ret and see if it subsumed an irred + // then fix it up. Can't be bothered. +// if (!sub_str->backw_sub_str_with_impl(finalLits_ternary, sub1_ret)) { +// return false; +// } + } + *limit_to_decrease-=20; + ternary_res_cls_limit--; + } + cl_to_add_ternary.clear(); + + return solver->okay(); +} + +void OccSimplifier::check_ternary_cl(Clause* cl, ClOffset offs, watch_subarray ws) +{ + *limit_to_decrease -= ws.size()*2; + for (const Watched& w: ws) { + if (!w.isClause() || w.get_offset() == offs) + continue; + + ClOffset offs2 = w.get_offset(); + Clause * cl2 = solver->cl_alloc.ptr(offs2); + *limit_to_decrease -= 10; + if (!cl2->freed() + && !cl2->getRemoved() + && cl2->size() == 3 + && !cl2->red() + ) { + uint32_t num_lits = 0; + uint32_t num_vars = 0; + Lit lit_clash = lit_Undef; + for(Lit l2: *cl2) { + num_vars += (seen[l2.toInt()] || seen[(~l2).toInt()]); + num_lits += seen[l2.toInt()]; + if (seen[(~l2).toInt()]) { + lit_clash = l2; + + //It's symmetric so only do it one way + // I can resolve + // "a b c" with "a -b d" OR + // "a -b d" with "a b c" + // This ensures we only do it one way. + if (!lit_clash.sign()) { + lit_clash = lit_Error; + break; + } + } + } + + //Not tri resolveeable or the wrong side of the symmetry + if (lit_clash == lit_Error) { + continue; + } + + //Becomes tri + if ((num_vars == 2 && num_lits == 1) || + (solver->conf.allow_ternary_bin_create && + num_vars == 3 && num_lits == 2) + ) { + *limit_to_decrease-=20; + + Tri newcl; + for(Lit l: *cl) { + if (l.var() != lit_clash.var()) + newcl.lits[newcl.size++] = l; + } + for(Lit l: *cl2) { + if (l.var() != lit_clash.var() + && !seen[l.toInt()] + ) { + newcl.lits[newcl.size++] = l; + } + } + + assert(newcl.size < 4 && newcl.size > 1); + if (newcl.size == 2 || newcl.size == 3) { + if (newcl.size == 2) { + runStats.ternary_added_bin++; + } else { + assert(newcl.size == 3); + runStats.ternary_added_tri++; + } + cl_to_add_ternary.push_back(newcl); + } + } + } + } +} + +void OccSimplifier::fill_tocheck_seen(const vec& ws, vector& tocheck) +{ + for(const auto& w: ws) { + assert(!w.isBNN()); + if (w.isBin()) { + if (w.red()) continue; + const uint32_t v = w.lit2().var(); + if (!seen[v]) { + tocheck.push_back(v); + seen[v] = 1; + } + } else if (w.isClause()) { + const Clause& cl2 = *solver->cl_alloc.ptr(w.get_offset()); + if (cl2.getRemoved() || cl2.red()) continue; + for(auto const& l: cl2) { + if (!seen[l.var()]) { + tocheck.push_back(l.var()); + seen[l.var()] = 1; + } + } + } + } +} + +//WARNING we MUST be sure there is at least ONE solution! +void OccSimplifier::delete_component_unconnected_to_assumps() +{ + assert(solver->okay()); + uint64_t removed = 0; + + vector tocheck; + for(uint32_t i = 0; i < solver->nVars(); i++) { + if (solver->varData[i].assumption != l_Undef) { + tocheck.push_back(i); + seen[i] = 1; + } + } + + vector tocheck2; + while(!tocheck.empty()) { + verb_print(3, __PRETTY_FUNCTION__ << "-- tocheck size: " << tocheck.size()); + std::swap(tocheck, tocheck2); + tocheck.clear(); + for(auto const& v: tocheck2) { + Lit l = Lit(v, true); + fill_tocheck_seen(solver->watches[l], tocheck); + fill_tocheck_seen(solver->watches[~l], tocheck); + } + } + + for(uint32_t i = 0; i < solver->nVars()*2; i++) { + Lit l = Lit::toLit(i); + if (seen[l.var()]) continue; + + vec tmp; + solver->watches[l].copyTo(tmp); + for(auto const& w: tmp) { + assert(!w.isBNN()); + if (w.isBin()) { + if (w.red()) continue; + if (!seen[w.lit2().var()]) { + solver->detach_bin_clause(l, w.lit2(), w.red(), w.get_ID(), false, true); + removed++; + } + } else if (w.isClause()) { + const Clause& cl2 = *solver->cl_alloc.ptr(w.get_offset()); + if (cl2.getRemoved() || cl2.red()) continue; + bool ok = true; + for(auto const&l2: cl2) { + if (seen[l2.var()]) {ok = false; break;} + } + if (ok) { + unlink_clause(w.get_offset(), true, false, true); + removed++; + } + } + } + } + + for(uint32_t i = 0; i < solver->nVars(); i++) seen[i] = 0; + + solver->clean_occur_from_removed_clauses_only_smudged(); + free_clauses_to_free(); + + verb_print(1, "[occ-rem-unconn-assumps] Removed cls: " << removed); +} + +void OccSimplifier::backward_sub() +{ + auto backup = subsumption_time_limit; + subsumption_time_limit = 0; + auto old_limit_to_decrease = limit_to_decrease; + limit_to_decrease = &subsumption_time_limit; + assert(cl_to_free_later.empty()); + + subsumption_time_limit += (int64_t) + ((double)backup*solver->conf.subsumption_time_limit_ratio_sub_str_w_bin); + + assert(cl_to_free_later.empty()); + assert(solver->watches.get_smudged_list().empty()); + +// if (!sub_str->backw_sub_str_long_with_bins() +// || solver->must_interrupt_asap() +// ) { +// goto end; +// } + + subsumption_time_limit += (int64_t) + ((double)backup*solver->conf.subsumption_time_limit_ratio_sub_w_long); + sub_str->backw_sub_long_with_long(); + + solver->clean_occur_from_removed_clauses_only_smudged(); + free_clauses_to_free(); + limit_to_decrease = old_limit_to_decrease; +} + +bool OccSimplifier::backward_sub_str() +{ + assert(cl_to_free_later.empty()); + assert(solver->watches.get_smudged_list().empty()); + + auto backup = subsumption_time_limit; + subsumption_time_limit = 0; + auto old_limit_to_decrease = limit_to_decrease; + limit_to_decrease = &subsumption_time_limit; + + //Sub-str long with bins + subsumption_time_limit += (int64_t) + ((double)backup*solver->conf.subsumption_time_limit_ratio_sub_str_w_bin); + if (!sub_str->backw_sub_str_long_with_bins() + || solver->must_interrupt_asap() + ) { + goto end; + } + + //Sub long with long + subsumption_time_limit += (int64_t) + ((double)backup*solver->conf.subsumption_time_limit_ratio_sub_w_long); + sub_str->backw_sub_long_with_long(); + if (solver->must_interrupt_asap()) + goto end; + + //Sub+Str long with long + limit_to_decrease = &strengthening_time_limit; + if (!sub_str->backw_str_long_with_long() + || solver->must_interrupt_asap() + ) { + goto end; + } + + //Deal with added long and bin + if (!sub_str_with_added_long_and_bin(true) + || solver->must_interrupt_asap() + ) { + goto end; + } + + end: + solver->clean_occur_from_removed_clauses_only_smudged(); + free_clauses_to_free(); + limit_to_decrease = old_limit_to_decrease; + + return solver->okay(); +} + +bool OccSimplifier::fill_occur() +{ + //Calculate binary clauses' contribution to n_occurs + size_t wsLit = 0; + for (watch_array::const_iterator + it = solver->watches.begin(), end = solver->watches.end() + ; it != end + ; ++it, wsLit++ + ) { + Lit lit = Lit::toLit(wsLit); + watch_subarray_const ws = *it; + for (const Watched* it2 = ws.begin(), *end2 = ws.end() + ; it2 != end2 + ; it2++ + ) { + if (it2->isBin() && !it2->red() && lit < it2->lit2()) { + n_occurs[lit.toInt()]++; + n_occurs[it2->lit2().toInt()]++; + } + } + } + + //Add irredundant to occur + uint64_t memUsage = calc_mem_usage_of_occur(solver->longIrredCls); + print_mem_usage_of_occur(memUsage); + if (memUsage > solver->conf.maxOccurIrredMB*1000ULL*1000ULL*solver->conf.var_and_mem_out_mult) { + if (solver->conf.verbosity) { + cout << "c [occ] Memory usage of occur is too high, unlinking and skipping occur" << endl; + } + CompleteDetachReatacher detRet(solver); + detRet.reattachLongs(true); + return false; + } + + link_in_data_irred = link_in_clauses( + solver->longIrredCls + , true //add to occur list + , numeric_limits::max() + , numeric_limits::max() + ); + solver->longIrredCls.clear(); + if (solver->conf.verbosity) { + cout << "c [occ] Linked in IRRED BIN by default: " << solver->binTri.irredBins << endl; + cout << "c [occ] Linked in RED BIN by default: " << solver->binTri.redBins << endl; + } + print_linkin_data(link_in_data_irred); + + //Add redundant to occur + if (solver->conf.maxRedLinkInSize > 0) { + memUsage = calc_mem_usage_of_occur(solver->longRedCls[0]); + print_mem_usage_of_occur(memUsage); + bool linkin = true; + if (memUsage > solver->conf.maxOccurRedMB*1000ULL*1000ULL*solver->conf.var_and_mem_out_mult) { + linkin = false; + } + //Sort, so we get the shortest ones in at least + uint32_t arr_to_link = 0; + std::sort(solver->longRedCls[arr_to_link].begin(), solver->longRedCls[arr_to_link].end() + , ClauseSizeSorter(solver->cl_alloc)); + + link_in_data_red = link_in_clauses( + solver->longRedCls[arr_to_link] + , linkin + , solver->conf.maxRedLinkInSize + , solver->conf.maxOccurRedLitLinkedM*1000ULL*1000ULL*solver->conf.var_and_mem_out_mult + ); + solver->longRedCls[arr_to_link].clear(); + } + + //Don't really link in the rest + for(auto& lredcls: solver->longRedCls) { + link_in_clauses(lredcls, false, 0, 0); + } + for(auto& lredcls: solver->longRedCls) { + lredcls.clear(); + } + + LinkInData combined(link_in_data_irred); + combined.combine(link_in_data_red); + print_linkin_data(combined); + + return true; +} + +//This must NEVER be called during solve. Only JUST BEFORE Solver::solve() is called +//otherwise, uneliminated_vars_since_last_solve will be wrong +bool OccSimplifier::uneliminate(uint32_t var) +{ + #ifdef VERBOSE_DEBUG_RECONSTRUCT + cout << "calling uneliminate() on var" << var+1 << endl; + #endif + assert(solver->decisionLevel() == 0); + assert(solver->okay()); + + //Check that it was really eliminated + assert(solver->varData[var].removed == Removed::elimed); + assert(solver->value(var) == l_Undef); + + if (!elimedMapBuilt) { + cleanElimedClauses(); + buildElimedMap(); + } + + //Uneliminate it in theory + bvestats_global.numVarsElimed--; + solver->varData[var].removed = Removed::none; +// cout << " solver->set_decision_var called with var: " << var << endl; + solver->set_decision_var(var); + + //Find if variable is really needed to be eliminated + var = solver->map_inter_to_outer(var); + uint32_t at_elimed_cls = blk_var_to_cls[var]; + if (at_elimed_cls == numeric_limits::max()) + return solver->okay(); + + //Eliminate it in practice + //NOTE: Need to eliminate in theory first to avoid infinite loops + + //Mark for removal from elimed list + elimedClauses[at_elimed_cls].toRemove = true; + can_remove_elimed_clauses = true; + assert(elimedClauses[at_elimed_cls].at(0, eClsLits).var() == var); + + //Re-insert into Solver + #ifdef VERBOSE_DEBUG_RECONSTRUCT + cout + << "Uneliminating cl "; + for(size_t i=0; i< elimedClauses[at_elimed_cls].size(); i++){ + cout << elimedClauses[at_elimed_cls].at(i, eClsLits) << " "; + } + cout << " on var " << var+1 + << endl; + #endif + + vector lits; + size_t bat = 1; + while(bat < elimedClauses[at_elimed_cls].size()) { + Lit l = elimedClauses[at_elimed_cls].at(bat, eClsLits); + if (l == lit_Undef) { + solver->add_clause_outer_copylits(lits); + if (!solver->okay()) { + return false; + } + lits.clear(); + } else { + lits.push_back(l); + } + bat++; + } + + return solver->okay(); +} + +void OccSimplifier::remove_by_frat_recently_elimed_clauses(size_t origElimedSize) +{ + if (! (solver->frat->enabled() || solver->conf.simulate_frat) ) + return; + + if (solver->conf.verbosity >= 6) { + cout << "c Deleting elimed clauses for FRAT" << endl; + } + + uint32_t at_ID = 0; + vector lits; + for(size_t i = origElimedSize; i < elimedClauses.size(); i++) { + lits.clear(); + size_t at = 1; + while(at < elimedClauses[i].size()) { + const Lit l = elimedClauses[i].at(at, eClsLits); + if (l == lit_Undef) { + const int32_t ID = newly_elimed_cls_IDs[at_ID++]; + (*solver->frat) << del << ID << lits << fin; + lits.clear(); + } else { + lits.push_back(solver->map_outer_to_inter(l)); + } + at++; + } + } + newly_elimed_cls_IDs.clear(); +} + +void OccSimplifier::buildElimedMap() +{ + blk_var_to_cls.clear(); + blk_var_to_cls.resize(solver->nVarsOuter(), numeric_limits::max()); + for(size_t i = 0; i < elimedClauses.size(); i++) { + const ElimedClauses& elimed = elimedClauses[i]; + uint32_t elimedon = elimed.at(0, eClsLits).var(); + assert(elimedon < blk_var_to_cls.size()); + blk_var_to_cls[elimedon] = i; + } + elimedMapBuilt = true; +} + +void OccSimplifier::finishUp( + size_t origTrailSize +) { + bool somethingSet = (solver->trail_size() - origTrailSize) > 0; + runStats.zeroDepthAssings = solver->trail_size() - origTrailSize; + const double myTime = cpuTime(); + + //Add back clauses to solver + remove_all_longs_from_watches(); + if (solver->ok) { + assert(solver->prop_at_head()); + add_back_to_solver(); + if (solver->okay()) { + solver->ok = solver->propagate().isNULL(); + } + } else { + for(const auto& offs: clauses) { + Clause* cl = solver->cl_alloc.ptr(offs); + if (cl->getRemoved() || cl->freed()) { + continue; + } + *solver->frat << del << *cl << fin; + solver->free_cl(cl); + } + } + + //Update global stats + const double time_used = cpuTime() - myTime; + runStats.finalCleanupTime += time_used; + if (solver->sqlStats) { + solver->sqlStats->time_passed_min( + solver + , "occur cleanup" + , time_used + ); + } + globalStats += runStats; + sub_str->finishedRun(); + *solver->frat << __PRETTY_FUNCTION__ << " start\n"; + + //Sanity checks + if (solver->okay() + #ifndef SLOW_DEBUG + && somethingSet + #endif + ) { + #ifdef SLOW_DEBUG + solver->test_all_clause_attached(); + solver->check_wrong_attach(); + solver->check_stats(); + solver->check_implicit_propagated(); + #endif + } + + if (solver->ok) check_elimed_vars_are_unassignedAndStats(); + + //Let's just clean up ourselves a bit + clauses.clear(); +} + +void OccSimplifier::sanityCheckElimedVars() const +{ + //First, sanity-check the long clauses + for (vector::const_iterator + it = clauses.begin(), end = clauses.end() + ; it != end + ; ++it + ) { + const Clause* cl = solver->cl_alloc.ptr(*it); + + //Already removed + if (cl->freed()) + continue; + + for (const Lit lit: *cl) { + if (solver->varData[lit.var()].removed == Removed::elimed) { + cout + << "Error: elimed var -- Lit " << lit << " in clause" + << endl + << "wrongly left in clause: " << *cl + << endl; + std::exit(-1); + } + } + } + + //Then, sanity-check the binary clauses + size_t wsLit = 0; + for (watch_array::const_iterator + it = solver->watches.begin(), end = solver->watches.end() + ; it != end + ; ++it, wsLit++ + ) { + Lit lit = Lit::toLit(wsLit); + watch_subarray_const ws = *it; + for (const Watched* it2 = ws.begin(), *end2 = ws.end() + ; it2 != end2 + ; it2++ + ) { + if (it2->isBin()) { + if (solver->varData[lit.var()].removed == Removed::elimed + || solver->varData[it2->lit2().var()].removed == Removed::elimed + ) { + cout + << "Error: A var is elimed in a binary clause: " + << lit << " , " << it2->lit2() + << endl; + std::exit(-1); + } + } + } + } +} + +void OccSimplifier::set_limits() +{ + subsumption_time_limit = 450LL*1000LL*solver->conf.subsumption_time_limitM + *solver->conf.global_timeout_multiplier; + strengthening_time_limit = 200LL*1000LL*solver->conf.strengthening_time_limitM + *solver->conf.global_timeout_multiplier; + norm_varelim_time_limit = 4ULL*1000LL*1000LL*solver->conf.varelim_time_limitM + *solver->conf.global_timeout_multiplier; + empty_varelim_time_limit = 200LL*1000LL*solver->conf.empty_varelim_time_limitM + *solver->conf.global_timeout_multiplier; + varelim_sub_str_limit = 1000ULL*1000ULL*solver->conf.varelim_sub_str_limitM + *solver->conf.global_timeout_multiplier; + ternary_res_time_limit = 1000ULL*1000ULL*solver->conf.ternary_res_time_limitM + *solver->conf.global_timeout_multiplier; + occ_based_lit_rem_time_limit = 1000ULL*1000ULL*solver->conf.occ_based_lit_rem_time_limitM + *solver->conf.global_timeout_multiplier; + ternary_res_cls_limit = link_in_data_irred.cl_linked * solver->conf.ternary_max_create; + weaken_time_limit = 1000ULL*1000ULL*solver->conf.weaken_time_limitM + *solver->conf.global_timeout_multiplier; + dummy_str_time_limit = 1000ULL*1000ULL*solver->conf.dummy_str_time_limitM + *solver->conf.global_timeout_multiplier; + + //If variable elimination isn't going so well + if (bvestats_global.testedToElimVars > 0 + && float_div(bvestats_global.numVarsElimed, bvestats_global.testedToElimVars) < 0.1 + ) { + norm_varelim_time_limit /= 2; + } + + #ifdef BIT_MORE_VERBOSITY + cout << "c clause_lits_added: " << clause_lits_added << endl; + #endif + + norm_varelim_time_limit *= 4; + empty_varelim_time_limit *= 4; + subsumption_time_limit *= 2; + strengthening_time_limit *= 2; + varelim_sub_str_limit *= 10; + + varelim_num_limit = ((double)solver->get_num_free_vars() * solver->conf.varElimRatioPerIter); + varelim_linkin_limit_bytes = solver->conf.var_linkin_limit_MB *1000LL*1000LL*solver->conf.var_and_mem_out_mult; + + if (!solver->conf.do_strengthen_with_occur) { + strengthening_time_limit = 0; + } + + //For debugging +// subsumption_time_limit = 0; +// strengthening_time_limit = 0; +// norm_varelim_time_limit = 0; +// empty_varelim_time_limit = 0; +// varelim_num_limit = 0; +// subsumption_time_limit = numeric_limits::max(); +// strengthening_time_limit = numeric_limits::max(); +// norm_varelim_time_limit = numeric_limits::max(); +// empty_varelim_time_limit = numeric_limits::max(); +// varelim_num_limit = numeric_limits::max(); +// varelim_sub_str_limit = numeric_limits::max(); +} + +void OccSimplifier::cleanElimedClauses() +{ + assert(solver->decisionLevel() == 0); + vector::iterator i = elimedClauses.begin(); + vector::iterator j = elimedClauses.begin(); + + uint64_t i_eClsLits = 0; + uint64_t j_eClsLits = 0; + for (vector::iterator + end = elimedClauses.end() + ; i != end + ; ++i + ) { + const uint32_t elimedOn = solver->map_outer_to_inter(i->at(0, eClsLits).var()); + if (solver->varData[elimedOn].removed == Removed::elimed + && solver->value(elimedOn) != l_Undef + ) { + std::cerr + << "ERROR: var " << Lit(elimedOn, false) << " elimed," + << " value: " << solver->value(elimedOn) + << endl; + assert(false); + std::exit(-1); + } + + if (i->toRemove) { + elimedMapBuilt = false; + i_eClsLits += i->size(); + assert(i_eClsLits == i->end); + i->start = numeric_limits::max(); + i->end = numeric_limits::max(); + } else { + assert(solver->varData[elimedOn].removed == Removed::elimed); + + //beware we might change this + const size_t sz = i->size(); + + //don't copy if we don't need to + if (!elimedMapBuilt) { + for(size_t x = 0; x < sz; x++) { + eClsLits[j_eClsLits++] = eClsLits[i_eClsLits++]; + } + } else { + i_eClsLits += sz; + j_eClsLits += sz; + } + assert(i_eClsLits == i->end); + i->start = j_eClsLits-sz; + i->end = j_eClsLits; + *j++ = *i; + } + } + eClsLits.resize(j_eClsLits); + elimedClauses.resize(elimedClauses.size()-(i-j)); + can_remove_elimed_clauses = false; +} + +void OccSimplifier::rem_cls_from_watch_due_to_varelim( + const Lit lit + , bool add_to_block +) { + elimedMapBuilt = false; + + //Copy&clear i.e. MOVE + solver->watches[lit].moveTo(tmp_rem_cls_copy); + assert(solver->watches[lit].empty()); + + vector& lits = tmp_rem_lits; + for (const Watched watch :tmp_rem_cls_copy) { + lits.clear(); + bool red = false; + + if (watch.isClause()) { + const ClOffset offset = watch.get_offset(); + const Clause& cl = *solver->cl_alloc.ptr(offset); + if (cl.getRemoved()) { + continue; + } + assert(!cl.freed()); + + //Put clause into elimed status + if (add_to_block) { + if (!cl.red()) { + bvestats.clauses_elimed_long++; + bvestats.clauses_elimed_sumsize += cl.size(); + + lits.resize(cl.size()); + std::copy(cl.begin(), cl.end(), lits.begin()); + add_clause_to_blck(lits, cl.stats.ID); + } else { + red = true; + } + } + + //Remove -- only FRAT the ones that are redundant + //The irred will be removed thanks to 'elimed' system + unlink_clause(offset, cl.red(), true, true); + } else if (watch.isBin()) { + //Update stats + if (!watch.red()) { + bvestats.clauses_elimed_bin++; + bvestats.clauses_elimed_sumsize += 2; + } else { + red = true; + } + + //Put clause into elimed status + lits.resize(2); + lits[0] = lit; + lits[1] = watch.lit2(); + if (!watch.red()) { + if (add_to_block) { + add_clause_to_blck(lits, watch.get_ID()); + } + n_occurs[lits[0].toInt()]--; + n_occurs[lits[1].toInt()]--; + removed_cl_with_var.touch(lits[0]); + removed_cl_with_var.touch(lits[1]); + elim_calc_need_update.touch(lits[0]); + elim_calc_need_update.touch(lits[1]); + } else { + //If redundant, delayed elimed-based FRAT deletion will not work + //so delete explicitly + (*solver->frat) << del << watch.get_ID() << lits[0] << lits[1] << fin; + } + + //Remove + //*limit_to_decrease -= (long)solver->watches[lits[0]].size()/4; //This is zero + *limit_to_decrease -= (long)solver->watches[lits[1]].size()/4; + solver->detach_bin_clause(lits[0], lits[1], red, watch.get_ID(), true, true); + } else { + assert(false); + } + + if (solver->conf.verbosity >= 3 && !lits.empty()) { + cout + << "Eliminated clause " << lits << " (red: " << red << ")" + << " on var " << lit.var()+1 + << endl; + } + } +} + +void OccSimplifier::add_clause_to_blck(const vector& lits, const uint64_t ID) +{ + for(const Lit& l: lits) { + removed_cl_with_var.touch(l.var()); + elim_calc_need_update.touch(l.var()); + } + + vector lits_outer = lits; + solver->map_inter_to_outer(lits_outer); + for(Lit l: lits_outer) { + eClsLits.push_back(l); + } + eClsLits.push_back(lit_Undef); + elimedClauses.back().end = eClsLits.size(); + newly_elimed_cls_IDs.push_back(ID); +} + +void OccSimplifier::add_picosat_cls( + const vec& ws, const Lit elim_lit, + map& picosat_cl_to_cms_cl) +{ + picosat_cl_to_cms_cl.clear(); + for(const auto& w: ws) { + if (w.isClause()) { + Clause& cl = *solver->cl_alloc.ptr(w.get_offset()); + assert(!cl.getRemoved()); + assert(!cl.red()); + for(const auto& l: cl) { + if (l.var() != elim_lit.var()) + picosat_add(picosat, lit_to_picolit(l)); + } +// cout << "Added cl (except " << elim_lit.unsign() << "): " << cl << endl; + int pico_cl_id = picosat_add(picosat, 0); + picosat_cl_to_cms_cl[pico_cl_id] = w; + } else if (w.isBin()) { + assert(!w.red()); + picosat_add(picosat, lit_to_picolit(w.lit2())); + int pico_cl_id = picosat_add(picosat, 0); + picosat_cl_to_cms_cl[pico_cl_id] = w; +// cout << "Added cl: " << w.lit2() << endl; + } else { + assert(false); + } + } +} + +bool OccSimplifier::find_irreg_gate( + Lit elim_lit + , watch_subarray_const a + , watch_subarray_const b + , vec& out_a + , vec& out_b +) { + // Too expensive + if (turned_off_irreg_gate || picolits_added > (double)solver->conf.global_timeout_multiplier * (double)solver->conf.picosat_gate_limitK * (double)1000) { + if (solver->conf.verbosity && !turned_off_irreg_gate) { + cout << "c [occ-bve] turning off picosat-based irreg gate detection, added lits: " << print_value_kilo_mega(picolits_added) << endl; + } + turned_off_irreg_gate = true; + return false; + } + if (a.size() + b.size() > 100) return false; + + bool found = false; + out_a.clear(); + out_b.clear(); + + assert(picosat == NULL); + picosat = picosat_init(); + int ret = picosat_enable_trace_generation(picosat); + assert(ret != 0 && "Traces cannot be generated in PicoSAT, wrongly configured&built"); + + map a_map; + map b_map; + assert(picovars_used.empty()); + add_picosat_cls(a, elim_lit, a_map); + add_picosat_cls(b, elim_lit, b_map); + for(const auto v: picovars_used) var_to_picovar[v] = 0; + picovars_used.clear(); + + ret = picosat_sat(picosat, 300); + if (ret == PICOSAT_UNSATISFIABLE) { + for(const auto& m: a_map) { + if (picosat_coreclause(picosat, m.first)) { + out_a.push(m.second); + } + } + for(const auto& m: b_map) { + if (picosat_coreclause(picosat, m.first)) { + out_b.push(m.second); + } + } +// cout << "PicoSAT UNSAT for var: " << elim_lit << " core size: " << out_a.size() + out_b.size() << " vs: " << a.size()+b.size() << endl; + found = true; + resolve_gate = true; + } + picosat_reset(picosat); + picosat = NULL; + + return found; +} + +bool OccSimplifier::find_or_gate( + Lit elim_lit + , watch_subarray_const a + , watch_subarray_const b + , vec& out_a + , vec& out_b +) { + bool found = false; + out_a.clear(); + out_b.clear(); + + assert(toClear.empty()); + for(const Watched w: a) { + if (w.isBin()) { + SLOW_DEBUG_DO(assert(!w.red())); + seen[(~w.lit2()).toInt()] = w.get_ID(); + toClear.push_back(~w.lit2()); + } + } + + //Have to find the corresponding gate. Finding one is good enough + for(const Watched w: b) { + if (w.isBin()) { + continue; + } + + if (w.isClause()) { + SLOW_DEBUG_DO(assert(!solver->redundant_or_removed(w))); + Clause* cl = solver->cl_alloc.ptr(w.get_offset()); + + assert(cl->size() > 2); + bool OK = true; + for(const Lit lit: *cl) { + if (lit != ~elim_lit) { + if (!seen[lit.toInt()]) { + OK = false; + break; + } + } + } + + //Found all lits inside + if (OK) { + out_b.push(w); + for(const Lit lit: *cl) { + if (lit != ~elim_lit) { + out_a.push(Watched(~lit, false, seen[lit.toInt()])); + } + } + found = true; + break; + } + } + } + + for(Lit l: toClear) { + seen[l.toInt()] = 0; + } + toClear.clear(); + + return found; +} + +bool OccSimplifier::find_ite_gate( + Lit elim_lit + , watch_subarray_const a + , watch_subarray_const b + , vec& out_a + , vec& out_b + , vec* out_a_all +) { + int limit = solver->conf.varelim_gate_find_limit; + bool found = false; + out_a.clear(); + out_b.clear(); + + //gate description we are looking for where "a" is being defineed + // as x -> (a=f) + // -x -> (a=g) + // these translate to: + // -a V f V -x + // -a V g V x + // a V -f V -x + // a V -g V x + //where elim_lit = -a + // lits[0] = f + // lits[1] = -x + // lits[2] = g + Lit lits[3]; + assert(toClear.empty()); + for(uint32_t i = 0; i < a.size() && limit >= 0; i++, limit--) { + const Watched& w = a[i]; + if (w.isBin() || w.isBNN()) { + SLOW_DEBUG_DO(if (w.isBin()) assert(!w.red())); + continue; + } + + assert(w.isClause()); + SLOW_DEBUG_DO(assert(!solver->redundant_or_removed(w))); + Clause* cl = solver->cl_alloc.ptr(w.get_offset()); + if (cl->size() != 3) { + continue; + } + + //Clear seen + for(const auto& l: toClear) { + seen[l.var()] = 0; + } + toClear.clear(); + out_a.push(w); + + //Set up base + uint32_t at = 0; + for(const auto& l: *cl) { + if (l == elim_lit) { + continue; + } + lits[at++] = l; + seen[l.var()] = 1; + toClear.push_back(l); + } + assert(at == 2); + + //Find 2nd base: -a V g V x + for(uint32_t j = i+1; j < a.size(); j++, limit--) { + const Watched& w2 = a[j]; + if (w2.isBin()) { + continue; + } + Clause* cl2 = solver->cl_alloc.ptr(w2.get_offset()); + if (cl2->size() != 3) { + continue; + } + + uint32_t match = 0; + bool ok = false; + bool ok2 = false; + for(const auto& l: *cl2) { + match += seen[l.var()]; + if (l == ~lits[1]) { + ok = true; + } + if (l == ~lits[2]) { + ok2 = true; + } + } + if (match != 1) { + continue; + } + + if (!ok && !ok2) { + continue; + } + if (!ok && ok2) { +// cout << "Swapped" << endl; + std::swap(lits[0], lits[1]); + } + + //Make elim_lit 1st position + if (elim_lit == (*cl2)[1]) { + std::swap((*cl2)[0], (*cl2)[1]); + } + if (elim_lit == (*cl2)[2]) { + std::swap((*cl2)[0], (*cl2)[2]); + } + + //Make ~lits[1] (i.e. x) 2nd position + if (~lits[1] == (*cl2)[2]) { + std::swap((*cl2)[2], (*cl2)[1]); + } + lits[2] = (*cl2)[2]; + + std::sort(cl2->begin(), cl2->end()); + seen[lits[2].var()] = 1; + toClear.push_back(lits[2]); + out_a.push(w2); + break; + } + + if (out_a.size() != 2) { + continue; + } + +// cout << "Start" << endl; + out_b.clear(); + bool got_mf_v_mx = false; + bool got_mg_v_x = false; + for(uint32_t j = 0; j < b.size(); j++, limit--) { + const Watched& w2 = b[j]; + if (w2.isBin()) { + continue; + } + Clause* cl2 = solver->cl_alloc.ptr(w2.get_offset()); + if (cl2->size() != 3) { + continue; + } + uint32_t match = 0; + for(const auto& l: *cl2) { + match += seen[l.var()]; + } + if (match != 2) { + continue; + } +// cout << "base: " << *cl << endl; +// cout << "elim lit: " << elim_lit << endl; +// cout << "lits[0]: " << lits[0] << endl; +// cout << "lits[1]: " << lits[1] << endl; +// cout << "lits[1]: " << lits[2] << endl; +// cout << "check " << *cl2 << endl; + + + //Make ~elim_lit 1st position + if (~elim_lit == (*cl2)[1]) { + std::swap((*cl2)[0], (*cl2)[1]); + } + if (~elim_lit == (*cl2)[2]) { + std::swap((*cl2)[0], (*cl2)[2]); + } + + //Make lits[1].var() (i.e. (~)x) 2nd position + if (lits[1].var() == (*cl2)[2].var()) { + std::swap((*cl2)[1], (*cl2)[2]); + } + + //it's -x here, so must have -f i.e. ~lits[0] + // a V -f V -x + if ((*cl2)[1] == lits[1] && + (*cl2)[2] == ~lits[0] && + !got_mf_v_mx) + { + std::sort(cl2->begin(), cl2->end()); + out_b.push(w2); + got_mf_v_mx = true; + continue; + } + + //it's x here, so must have -g i.e. ~lits[2] + if ((*cl2)[1] == ~lits[1] && + (*cl2)[2] == ~lits[2] && + !got_mg_v_x) + { + std::sort(cl2->begin(), cl2->end()); + out_b.push(w2); + got_mg_v_x = true; + continue; + } + std::sort(cl2->begin(), cl2->end()); + + if (got_mf_v_mx && got_mg_v_x) { + break; + } + } + if (got_mf_v_mx && got_mg_v_x) { + found = true; + if (out_a_all == NULL) { + break; + } else { + assert(out_a.size() == 2); + out_a_all->push(out_a[0]); + out_a_all->push(out_a[1]); + } + } + } + + if (limit < 0) { + //cout << "ITE Gate find timeout limit reached" << endl; + bvestats.gatefind_timeouts++; + } + + for(Lit l: toClear) { + seen[l.var()] = 0; + } + toClear.clear(); + + if (found && out_a_all == NULL) { + assert(out_a.size() == 2); + assert(out_b.size() == 2); + std::sort(out_a.begin(), out_a.end(), sort_smallest_first(solver->cl_alloc)); + std::sort(out_b.begin(), out_b.end(), sort_smallest_first(solver->cl_alloc)); + } + + if (found) resolve_gate = true; + return found; +} + +bool OccSimplifier::find_equivalence_gate( + [[maybe_unused]] Lit elim_lit + , watch_subarray_const a + , watch_subarray_const b + , vec& out_a + , vec& out_b +) { + assert(toClear.empty()); + + bool found = false; + out_a.clear(); + out_b.clear(); + + for(const Watched& w: a) { + if (w.isBin()) { + SLOW_DEBUG_DO(assert(!w.red())); + seen[w.lit2().toInt()] = w.get_ID(); + toClear.push_back(w.lit2()); + } + } + + for(const Watched& w: b) { + if (w.isBin()) { + SLOW_DEBUG_DO(assert(!w.red())); + if (seen[(~w.lit2()).toInt()]) { + out_b.push(w); + out_a.push(Watched(~w.lit2(), false, seen[(~w.lit2()).toInt()])); + found = true; + break; + } + } + } + + for(const auto& l: toClear) seen[l.toInt()] = 0; + toClear.clear(); + + if (found) VERBOSE_PRINT("EQ gate"); + return found; +} + +bool OccSimplifier::find_xor_gate( + [[maybe_unused]] Lit elim_lit + , watch_subarray_const a + , watch_subarray_const b + , vec& out_a + , vec& out_b +) { + assert(toClear.empty()); + //cout << "Finding xor gate" << endl; + + bool found = false; + int limit = solver->conf.varelim_gate_find_limit; + out_a.clear(); + out_b.clear(); + assert(toclear_marked_cls.empty()); + assert(parities_found.empty()); + + uint32_t maxsize = 7; + maxsize = std::min((int)maxsize, (int)std::log2(a.size())+1); + maxsize = std::min((int)maxsize, (int)std::log2(b.size())+1); + + bool parity; + uint32_t size; + uint32_t tofind; + for(uint32_t j = 0; j < a.size() && limit >= 0; j++, limit--) { + const Watched& w = a[j]; + if (w.isBin()) { + continue; + } + + assert(w.isClause()); + Clause* cl = solver->cl_alloc.ptr(w.get_offset()); + if (cl->size() > maxsize || cl->stats.marked_clause || cl->red()) { + continue; + } + size = cl->size(); + tofind = 1ULL<<(size-1); + + //Clear seen + for(const auto& l: toClear) { + seen[l.var()] = 0; + } + toClear.clear(); + + parity = 0; + for(const auto& l: *cl) { + seen [l.var()] = 1; + toClear.push_back(l); + parity ^= l.sign(); + } + out_a.clear(); + out_a.push(w); + cl->stats.marked_clause = 1; + toclear_marked_cls.push_back(cl); + std::sort(cl->begin(), cl->end()); + uint32_t val = 0; + for(uint32_t i2 = 0; i2 < cl->size(); i2 ++) { + if ((*cl)[i2].sign()) { + val += 1 << i2; + } + } + parities_found.clear(); + parities_found.insert(val); + + for(uint32_t i = j+1; i < a.size(); i++) { + const Watched& w2 = a[i]; + if (w2.isBin()) continue; + + assert(w2.isClause()); + Clause* cl2 = solver->cl_alloc.ptr(w2.get_offset()); + SLOW_DEBUG_DO(assert(!cl2->red())); + if (cl2->size() != size || cl2->stats.marked_clause) continue; + + bool this_cl_ok = true; + bool myparity = 0; + for(const auto& l2: *cl2) { + if (!seen[l2.var()]) { + this_cl_ok = false; + break; + } + myparity ^= l2.sign(); + } + + //cout << "Mypar: " << myparity << " real par: " << parity << " ok: " << this_cl_ok << endl; + if (this_cl_ok && myparity == parity) { + cl2->stats.marked_clause = 1; + toclear_marked_cls.push_back(cl2); + std::sort(cl2->begin(), cl2->end()); + val = 0; + for(uint32_t i2 = 0; i2 < cl2->size(); i2 ++) { + if ((*cl2)[i2].sign()) { + val += 1 << i2; + } + } + if (parities_found.find(val) == parities_found.end()) { + out_a.push(w2); + parities_found.insert(val); + } + } + } + + //Early abort, we should have found 3 by now + //cout << "Here par find s: " << parities_found.size() << endl; + if (parities_found.size() != tofind/2) { + continue; + } + + out_b.clear(); + for(uint32_t i = 0; i < b.size(); i++, limit--) { + const Watched& w2 = b[i]; + if (w2.isBin()) { + continue; + } + assert(w2.isClause()); + Clause* cl2 = solver->cl_alloc.ptr(w2.get_offset()); + SLOW_DEBUG_DO(assert(!cl2->red())); + if (cl2->size() != size || cl2->stats.marked_clause) { + continue; + } + bool this_cl_ok = true; + bool myparity = 0; + for(const auto& l2: *cl2) { + if (!seen[l2.var()]) { + this_cl_ok = false; + break; + } + myparity ^= l2.sign(); + } + //cout << "Mypar: " << myparity << " real par: " << parity << " ok: " << this_cl_ok << endl; + if (this_cl_ok && myparity == parity) { + cl2->stats.marked_clause = 1; + toclear_marked_cls.push_back(cl2); + std::sort(cl2->begin(), cl2->end()); + val = 0; + for(uint32_t i2 = 0; i2 < cl2->size(); i2 ++) { + if ((*cl2)[i2].sign()) { + val += 1 << i2; + } + } + if (parities_found.find(val) == parities_found.end()) { + out_b.push(w2); + parities_found.insert(val); + } + } + uint32_t so_far = parities_found.size(); + + if (so_far == tofind) { + found = true; + break; + } + + //Early abort -- there is not enough left in "b" to be able to do work + if (tofind-so_far > (b.size() - i - 1)) { + break; + } + } + if (found) { + break; + } + } + + if (limit < 0) { + VERBOSE_PRINT("XOR Gate find limit reached"); + bvestats.gatefind_timeouts++; + } + + //Clear seen + for(const auto& l: toClear) { + seen[l.var()] = 0; + } + toClear.clear(); + + //Cleark cl markings + for(const auto& cl: toclear_marked_cls) { + cl->stats.marked_clause = 0; + } + toclear_marked_cls.clear(); + parities_found.clear(); + + + if (found) { + VERBOSE_PRINT("XOR gate"); + assert(out_a.size() == tofind/2); + assert(out_b.size() == tofind/2); + std::sort(out_a.begin(), out_a.end(), sort_smallest_first(solver->cl_alloc)); + std::sort(out_b.begin(), out_b.end(), sort_smallest_first(solver->cl_alloc)); + } else { + out_a.clear(); + out_b.clear(); + } + + return found; +} + +bool OccSimplifier::try_remove_lit_via_occurrence_simpl( + const OccurClause& occ_cl) +{ + assert(solver->decisionLevel() == 0); + assert(solver->prop_at_head()); + if (occ_cl.ws.isBin()) return false; + + solver->new_decision_level(); + *limit_to_decrease -= 1; + Clause* cl = solver->cl_alloc.ptr(occ_cl.ws.get_offset()); + assert(!cl->getRemoved()); + assert(!cl->freed()); + + bool conflicted = false; + bool found_it = false; + bool can_remove_cl = false; + for(Lit l: *cl) { + if (l != occ_cl.lit) l = ~l; + else found_it = true; + + const lbool val = solver->value(l); + if (val == l_False) { + //either it's the ORIG lit -- then the lit can be removed + if (l == occ_cl.lit) { + conflicted = true; + } else { //it's an INVERTED lit -- then the whole clause can be removed. + assert(false && "Not possible, we cleaned up the clauses from satisfied"); + } + break; + } + if (val == l_Undef) { + solver->enqueue(l); + } + } + + //No conflict at decision level 0, let's propagate + if (!conflicted && !can_remove_cl) { + assert(found_it); + conflicted = !solver->propagate_occur(limit_to_decrease); + } + solver->cancelUntil(0); + + assert(solver->decisionLevel() == 0); + return conflicted; +} + +bool OccSimplifier::forward_subsume_irred( + const Lit lit, + cl_abst_type abs, + const uint32_t size) +{ + for(const auto& w: solver->watches[lit]) { + if (w.isBin()) { + if (!w.red() && seen[w.lit2().toInt()]) { + return true; + } + } else { + assert(w.isClause()); + Clause* cl = solver->cl_alloc.ptr(w.get_offset()); + if (cl->freed() || cl->getRemoved() || cl->red()) { + continue; + } + if (cl->size() >= size || !subsetAbst(cl->abst, abs)) { + continue; + } + + bool ok = true; + for(const auto& l: *cl) { + if (!seen[l.toInt()]) { + ok = false; + break; + } + } + if (ok) { + return true; + } + + } + } + return false; +} + +bool OccSimplifier::generate_resolvents_weakened( + vector& tmp_poss, + vector& tmp_negs, + vec& tmp_poss2, + vec& tmp_negs2, + Lit lit, + uint32_t limit) +{ + size_t poss_start = 0; + size_t pos_at = 0; + for (uint32_t i = 0; i < tmp_poss.size(); i++, pos_at++) { + poss_start = i; + while (tmp_poss[i] != lit_Undef) i++; + *limit_to_decrease -= 3; + + size_t negs_start = 0; + size_t negs_at = 0; + for (uint32_t i2 = 0; i2 < tmp_negs.size(); i2++, negs_at++) { + negs_start = i2; + while (tmp_negs[i2] != lit_Undef) i2++; + *limit_to_decrease -= 3; + + //Resolve the two weakened clauses + dummy.clear(); + for (uint32_t x = poss_start; x < i; x++) { + const Lit l = tmp_poss[x]; + if (l == lit) continue; + seen[l.toInt()] = 1; + dummy.push_back(l); + } + + bool tautological = false; + for (uint32_t x = negs_start; x < i2; x++) { + const Lit l = tmp_negs[x]; + if (l == ~lit) continue; + if (seen[(~l).toInt()]) { + tautological = true; + break; + } + + if (!seen[l.toInt()]) { + dummy.push_back(l); + seen[l.toInt()] = 1; + } + } + #ifdef VERBOSE_DEBUG + cout << "Dummy after neg: "; + for(auto const& l: dummy) cout << l << ", "; + cout << " taut: " << tautological << endl; + #endif + + for (uint32_t x = poss_start; x < i; x++) seen[tmp_poss[x].toInt()] = 0; + for (uint32_t x = negs_start; x < i2; x++) seen[tmp_negs[x].toInt()] = 0; + if (tautological) continue; + if (solver->satisfied(dummy)) continue; + + tautological = resolve_clauses(tmp_poss2[pos_at], tmp_negs2[negs_at], lit); + if (tautological) continue; + VERBOSE_PRINT("Adding new varelim resolvent clause: " << dummy); + + //Early-abort or over time + if (resolvents.size()+1 > limit + //Too long resolvent + || (solver->conf.velim_resolvent_too_large != -1 + && ((int)dummy.size() > solver->conf.velim_resolvent_too_large)) + //Over-time + || *limit_to_decrease < -10LL*1000LL + + ) { + return false; + } + + ClauseStats stats; + resolvents.add_resolvent(dummy, stats, false); + } + } + + return true; +} + +bool OccSimplifier::generate_resolvents( + vec& tmp_poss, + vec& tmp_negs, + Lit lit, + uint32_t limit) +{ + size_t at_poss = 0; + for (const Watched* it = tmp_poss.begin(), *end = tmp_poss.end() + ; it != end + ; ++it, at_poss++ + ) { + *limit_to_decrease -= 3; + #ifdef SLOW_DEBUG + assert(!solver->redundant_or_removed(*it)); + #endif + + size_t at_negs = 0; + for (const Watched *it2 = tmp_negs.begin(), *end2 = tmp_negs.end() + ; it2 != end2 + ; it2++, at_negs++ + ) { + *limit_to_decrease -= 3; + assert(!solver->redundant_or_removed(*it2)); + + //Resolve the two clauses + bool tautological = resolve_clauses(*it, *it2, lit); + if (tautological) continue; + if (solver->satisfied(dummy)) continue; +// if (weaken_time_limit > 0 && check_taut_weaken_dummy(lit.var())) continue; + + #ifdef VERBOSE_DEBUG_VARELIM + cout << "Adding new clause due to varelim: " << dummy << endl; + #endif + + //Early-abort or over time + if (resolvents.size()+1 > limit + //Too long resolvent + || (solver->conf.velim_resolvent_too_large != -1 + && ((int)dummy.size() > solver->conf.velim_resolvent_too_large)) + //Over-time + || *limit_to_decrease < -10LL*1000LL + + ) { + return false; + } + + //Calculate new clause stats + ClauseStats stats; + bool is_xor = false; + if (it->isBin() && it2->isClause()) { + Clause* c = solver->cl_alloc.ptr(it2->get_offset()); + stats = c->stats; + is_xor |= c->used_in_xor(); + } else if (it2->isBin() && it->isClause()) { + Clause* c = solver->cl_alloc.ptr(it->get_offset()); + stats = c->stats; + is_xor |= c->used_in_xor(); + } else if (it2->isClause() && it->isClause()) { + Clause* c1 = solver->cl_alloc.ptr(it->get_offset()); + Clause* c2 = solver->cl_alloc.ptr(it2->get_offset()); + //Neither are redundant, this works. + stats = ClauseStats::combineStats(c1->stats, c2->stats); + is_xor |= c1->used_in_xor(); + is_xor |= c2->used_in_xor(); + } + //must clear marking that has been set due to gate + //strengthen_dummy_with_bins(false); + resolvents.add_resolvent(dummy, stats, is_xor); + } + } + + return true; +} + +void OccSimplifier::get_antecedents( + const vec& gates, + const vec& full_set, + vec& output) +{ + //both of gates and full_set are strictly sorted and cleaned from REDundant + output.clear(); + uint32_t j = 0; + for(uint32_t i = 0; i < full_set.size(); i++) { + const Watched& w = full_set[i]; + if (solver->redundant_or_removed(w)) + continue; + if (j < gates.size()) { + if (gates[j] == w) { + j++; + continue; + } + } + output.push(w); + } + + assert(output.size() == full_set.size() - gates.size()); +} + +void OccSimplifier::clean_from_red_or_removed( + const vec& in, + vec& out) +{ + out.clear(); + for(const auto& w: in) { + assert(w.getType() == WatchType::watch_clause_t || w.getType() == WatchType::watch_binary_t); + if (!solver->redundant_or_removed(w)) { + out.push(w); + } + } +} + +void OccSimplifier::clean_from_satisfied(vec& in) +{ + uint32_t j = 0; + uint32_t i = 0; + for(; i < in.size(); i++) { + const Watched& w = in[i]; + if (w.isBin()) { + if (solver->value(w.lit2()) == l_Undef) { + in[j++] = in[i]; + } + continue; + } + + assert(w.isClause()); + if (!solver->satisfied(w.get_offset())) { + in[j++] = in[i]; + } + continue; + } + in.shrink(i-j); +} + +void OccSimplifier::weaken( + const Lit lit, const vec& in, vector& out) +{ + int64_t* old_limit_to_decrease = limit_to_decrease; + limit_to_decrease = &weaken_time_limit; + + out.clear(); + uint32_t at = 0; + for(const auto& c: in) { + if (c.isBin()) { + out.push_back(lit); + out.push_back(c.lit2()); + seen[c.lit2().toInt()] = 1; + toClear.push_back(c.lit2()); + } else if (c.isClause()) { + const Clause* cl = solver->cl_alloc.ptr(c.get_offset()); + for(auto const& l: *cl) { + if (l != lit) { + seen[l.toInt()] = 1; + toClear.push_back(l); + } + out.push_back(l); + } + } else release_assert(false); + for(uint32_t i = at; i < out.size() && *limit_to_decrease > 0; i++) { + const Lit l = out[i]; + if (l == lit) continue; + *limit_to_decrease-=50; + *limit_to_decrease-=solver->watches[l].size(); + for(auto const& w: solver->watches[l]) { + /*if (w.isClause()) { + *limit_to_decrease -= 1; + const Clause& cl = *solver->cl_alloc.ptr(w.get_offset()); + if (cl.getRemoved() || cl.red() || cl.size() >= out.size() || cl.size() > 10) continue; + uint32_t num_inside = 0; + bool wrong = false; + Lit toadd = lit_Undef; + for(auto const& l2: cl) { + if (seen[l2.toInt()]) num_inside++; + else toadd = ~l2; + + if (seen[(~l2).toInt()] || l2.var() == lit.var()) {wrong = true; break;} + } + if (!wrong && num_inside == cl.size()-1) { + out.push_back(toadd); + seen[(toadd).toInt()] = 1; + toClear.push_back(toadd); + } + continue; + }*/ + + if (!w.isBin() || w.red()) continue; + if (w.lit2().var() == lit.var()) continue; + if (seen[(~w.lit2()).toInt()] || seen[w.lit2().toInt()]) continue; + Lit toadd = ~w.lit2(); + out.push_back(toadd); + seen[(toadd).toInt()] = 1; + toClear.push_back(toadd); + } + } + out.push_back(lit_Undef); + for(auto const &l: toClear) seen[l.toInt()] = 0; + toClear.clear(); + at = out.size(); + } + + limit_to_decrease = old_limit_to_decrease; +} + +bool OccSimplifier::check_taut_weaken_dummy(const uint32_t dontuse) +{ + weaken_dummy = dummy; + for(auto const& l: weaken_dummy) seen[l.toInt()] = 1; + + bool taut = false; + for(uint32_t i = 0; i < weaken_dummy.size(); i++) { + const Lit l = weaken_dummy[i]; + assert(l.var() != dontuse); + if (taut) break; + weaken_time_limit-=1; + for(auto const& w: solver->watches[l]) { + if (!w.isBin() || w.red()) continue; + const Lit toadd = ~w.lit2(); + if (seen[toadd.toInt()]) continue; + if (seen[(~toadd).toInt()]) { + taut = true; + break; + } + if (toadd.var() == dontuse) continue; + seen[(toadd).toInt()] = 1; + weaken_dummy.push_back(toadd); + } + } + for(auto const& l: weaken_dummy) seen[l.toInt()] = 0; + return taut; +} + +//Return true if it worked +bool OccSimplifier::test_elim_and_fill_resolvents(const uint32_t var) +{ + assert(solver->ok); + assert(solver->varData[var].removed == Removed::none); + assert(solver->value(var) == l_Undef); + resolvents.clear(); + const Lit lit = Lit(var, false); + + //Gather data + #ifdef CHECK_N_OCCUR + if (n_occurs[Lit(var, false).toInt()] != calc_data_for_heuristic(Lit(var, false))) { + cout << "lit " << Lit(var, false) << endl; + cout << "n_occ is: " << n_occurs[Lit(var, false).toInt()] << endl; + cout << "calc is: " << calc_data_for_heuristic(Lit(var, false)) << endl; + assert(false); + } + + if (n_occurs[Lit(var, true).toInt()] != calc_data_for_heuristic(Lit(var, true))) { + cout << "lit " << Lit(var, true) << endl; + cout << "n_occ is: " << n_occurs[Lit(var, true).toInt()] << endl; + cout << "calc is: " << calc_data_for_heuristic(Lit(var, true)) << endl; + } + #endif + uint32_t pos = n_occurs[Lit(var, false).toInt()]; + uint32_t neg = n_occurs[Lit(var, true).toInt()]; + + //set-up + clean_from_red_or_removed(solver->watches[lit], poss); + clean_from_red_or_removed(solver->watches[~lit], negs); + assert(poss.size() == pos); + assert(negs.size() == neg); + clean_from_satisfied(poss); + clean_from_satisfied(negs); + pos = poss.size(); + neg = negs.size(); + + //Pure literal, no resolvents + //we look at "pos" and "neg" (and not poss&negs) because we don't care about redundant clauses + if (pos == 0 || neg == 0) { + return true; + } + + + // A smaller OR gate will lead to less BIN (and 1 long) clause. + //The total size of the resolvent is + // |G_a|*|R_NOTa| + |G_NOTa|*|R_a|. + // Let's say it's [50,50], gate is short, [1,2] + // 1 * 48 + 2* 49 = 146 + // Let's say it's [50,50], gate is lomg, [1,6] + // 1 * 44 + 6* 49 = 338 + // So must sort smallest first to find the short gate first! + + std::sort(poss.begin(), poss.end(), sort_smallest_first(solver->cl_alloc)); + std::sort(negs.begin(), negs.end(), sort_smallest_first(solver->cl_alloc)); + + //Too expensive to check, it's futile + if ((uint64_t)neg * (uint64_t)pos + >= solver->conf.varelim_cutoff_too_many_clauses + ) { + return false; + } + + // see: http://baldur.iti.kit.edu/sat/files/ex04.pdf + bool gates = false; + resolve_gate = false; + if (find_equivalence_gate(lit, poss, negs, gates_poss, gates_negs)) { + gates = true; + } else if (find_or_gate(lit, poss, negs, gates_poss, gates_negs)) { + gates = true; + } else if (find_or_gate(~lit, negs, poss, gates_negs, gates_poss)) { + gates = true; + } else if (find_ite_gate(lit, poss, negs, gates_poss, gates_negs)) { + gates = true; + } else if (find_ite_gate(~lit, negs, poss, gates_negs, gates_poss)) { + gates = true; + } else if (find_xor_gate(lit, poss, negs, gates_poss, gates_negs)) { + gates = true; + } else if (find_irreg_gate(lit, poss, negs, gates_poss, gates_negs)) { + gates = true; + } + + if (gates && solver->conf.verbosity > 5) { + cout << "Elim on gate, lit: " << lit << " g poss: "; + for(const auto& w: gates_poss) { + if (w.isClause()) { + cout << " [" << *solver->cl_alloc.ptr(w.get_offset()) << "], "; + } else { + cout << w << ", "; + } + } + cout << " -- g negs: "; + for(const auto& w: gates_negs) { + cout << w << ", "; + } + cout << endl; + } + + std::sort(gates_poss.begin(), gates_poss.end(), sort_smallest_first(solver->cl_alloc)); + std::sort(gates_negs.begin(), gates_negs.end(), sort_smallest_first(solver->cl_alloc)); + //TODO We could just filter negs, poss below + get_antecedents(gates_negs, negs, antec_negs); + get_antecedents(gates_poss, poss, antec_poss); + + bool weakened = false; + if (weaken_time_limit > 0) { + weakened = true; + weaken(lit, antec_poss, antec_poss_weakened); + weaken(~lit, antec_negs, antec_negs_weakened); + } + + uint32_t limit = pos+neg+grow; + bool ret = true; + if (gates) { + if (!generate_resolvents(gates_poss, antec_negs, lit, limit)) { + ret = false; + } else if (!generate_resolvents(gates_negs, antec_poss, ~lit, limit)) { + ret = false; + } else if (resolve_gate && + !generate_resolvents(gates_poss, gates_negs, lit, limit)) { + ret = false; + } + } else { + if (weakened) { + if (!generate_resolvents_weakened( + antec_poss_weakened, antec_negs_weakened, + antec_poss, antec_negs, + lit, limit)) { + ret = false; + } + } else { + if (!generate_resolvents(antec_poss, antec_negs, lit, limit)) { + ret = false; + } + } + } + + return ret; +} + +void OccSimplifier::printOccur(const Lit lit) const +{ + for(size_t i = 0; i < solver->watches[lit].size(); i++) { + const Watched& w = solver->watches[lit][i]; + if (w.isBin()) { + cout + << "Bin --> " + << lit << ", " + << w.lit2() + << "(red: " << w.red() + << ")" + << endl; + } + + if (w.isClause()) { + const Clause& cl = *solver->cl_alloc.ptr(w.get_offset()); + if (cl.getRemoved()) + continue; + cout + << "Clause--> " + << cl + << "(red: " << cl.red() + << ")" + << "(rem: " << cl.getRemoved() + << ")" + << endl; + } + } +} + +void OccSimplifier::print_var_eliminate_stat(const Lit lit) const +{ + //Eliminate: + if (solver->conf.verbosity < 5) + return; + + cout + << "Eliminating var " << lit + << " with occur sizes " + << solver->watches[lit].size() << " , " + << solver->watches[~lit].size() + << endl; + + cout << "POS: " << endl; + printOccur(lit); + cout << "NEG: " << endl; + printOccur(~lit); +} + +bool OccSimplifier::add_varelim_resolvent( + vector& finalLits + , const ClauseStats& stats + , const bool is_xor +) { + assert(solver->okay()); + assert(solver->prop_at_head()); + + bvestats.newClauses++; + Clause* newCl = NULL; + + if (solver->conf.verbosity >= 5) { + cout + << "adding v-elim resolvent: " + << finalLits + << endl; + } + + ClauseStats backup_stats(stats); + newCl = solver->add_clause_int( + finalLits //Literals in new clause + , false //Is the new clause redundant? + , &backup_stats//Statistics for this new clause (usage, etc.) + , false //Should clause be attached if long? + , &finalLits //Return final set of literals here + ); + + if (solver->okay()) { + solver->ok = solver->propagate_occur(limit_to_decrease); + } + if (!solver->okay()) { + return false; + } + + if (newCl != NULL) { + newCl->set_used_in_xor(is_xor); + link_in_clause(*newCl); + ClOffset offset = solver->cl_alloc.get_offset(newCl); + clauses.push_back(offset); + added_long_cl.push_back(offset); + + // 4 = clause itself + // 8 = watch (=occur) space + varelim_linkin_limit_bytes -= (int64_t)finalLits.size()*(4+8); + varelim_linkin_limit_bytes -= (int64_t)sizeof(Clause); + } else if (finalLits.size() == 2) { + n_occurs[finalLits[0].toInt()]++; + n_occurs[finalLits[1].toInt()]++; + added_irred_bin.push_back(std::make_pair(finalLits[0], finalLits[1])); + + // 8 = watch space + varelim_linkin_limit_bytes -= (int64_t)finalLits.size()*(8); + } + + //Touch every var of the new clause, so we re-estimate + //elimination complexity for this var + for(Lit lit: finalLits) { + #ifdef CHECK_N_OCCUR + if(n_occurs[lit.toInt()] != calc_data_for_heuristic(lit)) { + cout << "n_occurs[lit.toInt()]:" << n_occurs[lit.toInt()] << endl; + cout << "calc_data_for_heuristic(lit): " << calc_data_for_heuristic(lit) << endl; + cout << "cl: " << finalLits << endl; + cout << "lit: " << lit << endl; + assert(false); + } + #endif + elim_calc_need_update.touch(lit.var()); + added_cl_to_var.touch(lit.var()); + } + + return true; +} + +void OccSimplifier::check_n_occur() +{ + for (size_t i=0; i < solver->nVars(); i++) { + Lit lit(i, false); + const uint32_t pos = calc_occ_data(lit); + if (pos != n_occurs[lit.toInt()]) { + cout << "for lit: " << lit << endl; + cout << "pos is: " << pos + << " n_occurs is:" << n_occurs[lit.toInt()] << endl; + assert(false); + } + + const uint32_t neg = calc_occ_data(~lit); + if (neg != n_occurs[(~lit).toInt()]) { + cout << "for lit: " << lit << endl; + cout << "neg is: " << neg + << " n_occurs is:" << n_occurs[(~lit).toInt()] << endl; + assert(false); + } + } +} + +void OccSimplifier::update_varelim_complexity_heap() +{ + num_otf_update_until_now++; + for(uint32_t var: elim_calc_need_update.getTouchedList()) { + //No point in updating the score of this var + if (!can_eliminate_var(var) || !velim_order.inHeap(var)) { + continue; + } + + auto prev = varElimComplexity[var]; + varElimComplexity[var] = heuristicCalcVarElimScore(var); + + //If different, PUT IT BACK IN, and update the heap + if (prev != varElimComplexity[var]) { + velim_order.update(var); + } + } + elim_calc_need_update.clear(); + + #ifdef CHECK_N_OCCUR + for(uint32_t var = 0; var < solver->nVars(); var++) { + if (!can_eliminate_var(var) || !velim_order.inHeap(var)) { + continue; + } + + auto prev = varElimComplexity[var]; + varElimComplexity[var] = heuristicCalcVarElimScore(var); + if (prev != varElimComplexity[var]) { + cout << "prev: " << prev << " now: " << varElimComplexity[var] << endl; + } + assert(prev == varElimComplexity[var]); + } + #endif +} + +void OccSimplifier::print_var_elim_complexity_stats(const uint32_t var) const +{ + if (solver->conf.verbosity >= 5) { + cout << "var " << var +1 << " trying complexity: " << varElimComplexity[var] << endl; + } +} + +void OccSimplifier::set_var_as_eliminated(const uint32_t var) +{ + const Lit lit = Lit(var, false); + if (solver->conf.verbosity >= 5) { + cout << "Elimination of var " + << solver->map_inter_to_outer(lit) + << " finished " << endl; + } + assert(solver->varData[var].removed == Removed::none); + solver->varData[var].removed = Removed::elimed; + + bvestats_global.numVarsElimed++; +} + +void OccSimplifier::create_dummy_elimed_clause(const Lit lit) +{ + eClsLits.push_back(solver->map_inter_to_outer(lit)); + elimedClauses.push_back( + ElimedClauses(eClsLits.size()-1, eClsLits.size()) + ); + elimedMapBuilt = false; +} + +bool OccSimplifier::occ_based_lit_rem(uint32_t var, uint32_t& removed) { + assert(solver->decisionLevel() == 0); + + int64_t* old_limit_to_decrease = limit_to_decrease; + limit_to_decrease = &occ_based_lit_rem_time_limit; + removed = 0; + for(int i = 0; i < 2; i++) { + Lit lit(var, i); + *limit_to_decrease -= 1; + solver->watches[lit].copyTo(poss); + + for(const auto& w: poss) { + *limit_to_decrease -= 1; + if (!w.isClause()) continue; + + const ClOffset offset = w.get_offset(); + Clause* cl = solver->cl_alloc.ptr(offset); + if (cl->getRemoved() || cl->red()) continue; + assert(!cl->freed()); + + if (solver->satisfied(*cl)) { + unlink_clause(offset, true, true, true); + continue; + } + + if (*limit_to_decrease > 0 && try_remove_lit_via_occurrence_simpl(OccurClause(lit, w))) { + remove_literal(offset, lit, true); + if (!solver->okay()) goto end; + removed++; + } + } + } + + end: + limit_to_decrease = old_limit_to_decrease; + return solver->okay(); +} + +bool OccSimplifier::all_occ_based_lit_rem() +{ + assert(solver->okay()); + assert(solver->prop_at_head()); + + double myTime = cpuTime(); + //TODO this is not being used, bogoprops is not checked here + auto old_limit_to_decrease = limit_to_decrease; + limit_to_decrease = &occ_based_lit_rem_time_limit; + + //Order them for removal + vector vars; + for(uint32_t v = 0; v < solver->nVars(); v++) { + if (solver->varData[v].removed == Removed::none && + solver->value(v) == l_Undef) + { + vars.push_back(v); + } + } + std::sort(vars.begin(), vars.end(), OrderByDecreasingIncidence(n_occurs)); + + //Try to remove + uint32_t removed_all = 0; + for(const auto& v: vars) { + uint32_t all = n_occurs[Lit(v, false).toInt()] + n_occurs[Lit(v, true).toInt()]; + if (all == 0) { + continue; + } + uint32_t removed = 0; + if (!occ_based_lit_rem(v, removed)) { + goto end; + } + removed_all += removed; + if (solver->conf.verbosity >= 5) { + cout << "occ-lit-rem finished var " << v + << " occ_p: " << n_occurs[Lit(v, false).toInt()] + << " occ_n: " << n_occurs[Lit(v, true).toInt()] + << " rem: " << removed + << endl; + } + } + + if (!sub_str_with_added_long_and_bin(false)) goto end; + + end: + solver->clean_occur_from_removed_clauses_only_smudged(); + free_clauses_to_free(); + + if (solver->okay()) { + assert(solver->prop_at_head()); + solver->check_implicit_propagated(); + } + + double time_used = cpuTime() - myTime; + if (solver->conf.verbosity) { + cout + << "c [occ-lit-rem] Occ Lit Rem: " << removed_all + << solver->conf.print_times(time_used) + << endl; + } + if (solver->sqlStats) { + solver->sqlStats->time_passed_min( + solver + , "occ based lit rem" + , time_used + ); + } + limit_to_decrease = old_limit_to_decrease; + + return solver->okay(); +} + +bool OccSimplifier::maybe_eliminate(const uint32_t var) +{ + assert(solver->ok); + assert(solver->prop_at_head()); + + print_var_elim_complexity_stats(var); + bvestats.testedToElimVars++; + const Lit lit = Lit(var, false); + + //NOTE this is **TIED TO** the forward subsumption during eliminate + // if this is NOT on, but the FRW subsumption is ON, then + // the E part of Arjun is working terribly!! + if (solver->conf.varelim_check_resolvent_subs && + !solver->varData[var].occ_simp_tried && + (n_occurs[lit.toInt()] + n_occurs[(~lit).toInt()] < 20)) + { + solver->varData[var].occ_simp_tried = 1; + uint32_t rem = 0; + occ_based_lit_rem(var, rem); + } + + if (solver->value(var) != l_Undef || !solver->okay()) return false; + if (!test_elim_and_fill_resolvents(var) || *limit_to_decrease < 0) return false; //didn't eliminate :( } + bvestats.triedToElimVars++; + + print_var_eliminate_stat(lit); + + //Remove clauses + create_dummy_elimed_clause(lit); + rem_cls_from_watch_due_to_varelim(lit); + rem_cls_from_watch_due_to_varelim(~lit); + + //Add resolvents + while(!resolvents.empty()) { + if (!add_varelim_resolvent(resolvents.back_lits(), + resolvents.back_stats(), resolvents.back_xor()) + ) { + goto end; + } + resolvents.pop(); + } + +end: + set_var_as_eliminated(var); + + return true; //eliminated! +} + +void OccSimplifier::add_pos_lits_to_dummy_and_seen( + const Watched& ps + , const Lit& posLit +) { + if (ps.isBin()) { + *limit_to_decrease -= 1; + assert(ps.lit2() != posLit); + + seen[ps.lit2().toInt()] = 1; + dummy.push_back(ps.lit2()); + } + + if (ps.isClause()) { + Clause& cl = *solver->cl_alloc.ptr(ps.get_offset()); + *limit_to_decrease -= (long)cl.size()/2; + for (const Lit lit : cl){ + if (lit != posLit) { + seen[lit.toInt()] = 1; + dummy.push_back(lit); + } + } + } +} + +bool OccSimplifier::add_neg_lits_to_dummy_and_seen( + const Watched& qs + , const Lit& posLit +) { + if (qs.isBin()) { + *limit_to_decrease -= 1; + assert(qs.lit2() != ~posLit); + + if (seen[(~qs.lit2()).toInt()]) { + return true; + } + if (!seen[qs.lit2().toInt()]) { + dummy.push_back(qs.lit2()); + seen[qs.lit2().toInt()] = 1; + } + } + + if (qs.isClause()) { + Clause& cl = *solver->cl_alloc.ptr(qs.get_offset()); + *limit_to_decrease -= (long)cl.size()/2; + for (const Lit lit: cl) { + if (lit == ~posLit) + continue; + + if (seen[(~lit).toInt()]) { + return true; + } + + if (!seen[lit.toInt()]) { + dummy.push_back(lit); + seen[lit.toInt()] = 1; + } + } + } + + return false; +} + +bool OccSimplifier::resolve_clauses( + const Watched& ps + , const Watched& qs + , const Lit& posLit +) { + //If clause has already been freed, skip + Clause *cl1 = NULL; + if (ps.isClause()) { + cl1 = solver->cl_alloc.ptr(ps.get_offset()); + if (cl1->freed()) { + return true; + } + } + + Clause *cl2 = NULL; + if (qs.isClause()) { + cl2 = solver->cl_alloc.ptr(qs.get_offset()); + if (cl2->freed()) { + return true; + } + } + + dummy.clear(); + add_pos_lits_to_dummy_and_seen(ps, posLit); + bool tautological = add_neg_lits_to_dummy_and_seen(qs, posLit); + + *limit_to_decrease -= (long)dummy.size()/2 + 1; + for (const Lit lit: dummy) { + seen[lit.toInt()] = 0; + } + + return tautological; +} + +uint32_t OccSimplifier::calc_data_for_heuristic(const Lit lit) +{ + uint32_t ret = 0; + watch_subarray_const ws_list = solver->watches[lit]; + + //BUT WATCHES ARE SMUDGED!! + //THIS IS WRONG!! + /*if (link_in_data_red.cl_linked < 100) { + ret = ws_list.size(); + return ret; + }*/ + + *limit_to_decrease -= (long)ws_list.size()*3 + 100; + for (const Watched ws: ws_list) { + //Skip redundant clauses + if (solver->redundant(ws)) + continue; + + switch(ws.getType()) { + case WatchType::watch_binary_t: + ret++; + break; + + case WatchType::watch_clause_t: { + const Clause* cl = solver->cl_alloc.ptr(ws.get_offset()); + if (!cl->getRemoved()) { + assert(!cl->freed() && "Inside occur, so cannot be freed"); + ret++; + } + break; + } + + default: + assert(false); + break; + } + } + return ret; +} + +uint32_t OccSimplifier::calc_occ_data(const Lit lit) +{ + uint32_t ret = 0; + watch_subarray_const ws_list = solver->watches[lit]; + for (const Watched ws: ws_list) { + //Skip redundant clauses + if (solver->redundant(ws)) + continue; + + switch(ws.getType()) { + case WatchType::watch_binary_t: + ret++; + break; + + case WatchType::watch_clause_t: { + const Clause* cl = solver->cl_alloc.ptr(ws.get_offset()); + if (!cl->getRemoved()) { + assert(!cl->freed() && "Inside occur, so cannot be freed"); + ret++; + } + break; + } + + default: + assert(false); + break; + } + } + return ret; +} + +bool OccSimplifier::check_empty_resolvent(Lit lit) +{ + //Take the smaller of the two + if (solver->watches[~lit].size() < solver->watches[lit].size()) + lit = ~lit; + + int num_bits_set = check_empty_resolvent_action( + lit + , ResolvCount::set + , 0 + ); + + int num_resolvents = numeric_limits::max(); + + //Can only count if the POS was small enough + //otherwise 'seen' cannot properly store the data + if (num_bits_set < 16) { + num_resolvents = check_empty_resolvent_action( + ~lit + , ResolvCount::count + , num_bits_set + ); + } + + //Clear the 'seen' array + check_empty_resolvent_action( + lit + , ResolvCount::unset + , 0 + ); + + //Okay, this would be great + return (num_resolvents == 0); +} + + +int OccSimplifier::check_empty_resolvent_action( + const Lit lit + , const ResolvCount action + , const int otherSize +) { + uint16_t at = 1; + int count = 0; + int numCls = 0; + + watch_subarray_const watch_list = solver->watches[lit]; + *limit_to_decrease -= (long)watch_list.size()*2; + for (const Watched& ws: watch_list) { + if (numCls >= 16 && + (action == ResolvCount::set || action == ResolvCount::unset)) + { + break; + } + + if (count > 0 && action == ResolvCount::count) break; + + //Handle binary + if (ws.isBin()){ + //Only count irred + if (!ws.red()) { + *limit_to_decrease -= 4; + switch(action) { + case ResolvCount::set: + seen[ws.lit2().toInt()] |= at; + break; + + case ResolvCount::unset: + seen[ws.lit2().toInt()] = 0; + break; + + case ResolvCount::count: + int num = __builtin_popcountll(seen[(~ws.lit2()).toInt()]); + assert(num <= otherSize); + count += otherSize - num; + break; + } + + //this "if" is only here to avoid undefined shift-up error by + //clang sanitizer + if (action == ResolvCount::set && numCls < 15) { + at = at << 1U; + } + numCls++; + } + continue; + } + + if (ws.isClause()) { + const Clause* cl = solver->cl_alloc.ptr(ws.get_offset()); + if (cl->getRemoved()) continue; + assert(!cl->freed() && "If in occur then it cannot be freed"); + + //Only irred is of relevance + if (!cl->red()) { + *limit_to_decrease -= (long)cl->size()*2; + uint32_t tmp = 0; + for(const Lit l: *cl) { + + //Ignore orig + if (l == lit) continue; + + switch (action) { + case ResolvCount::set: + seen[l.toInt()] |= at; + break; + + case ResolvCount::unset: + seen[l.toInt()] = 0; + break; + + case ResolvCount::count: + tmp |= seen[(~l).toInt()]; + break; + } + } + //this "if" is only here to avoid undefined shift-up error by + //clang sanitizer + if (action == ResolvCount::set && numCls < 15) { + at = at << 1U; + } + numCls++; + + //Count using tmp + if (action == ResolvCount::count) { + int num = __builtin_popcountll(tmp); + assert(num <= otherSize); + count += otherSize - num; + } + } + + continue; + } + + //Only these types are possible + assert(false); + } + + switch(action) { + case ResolvCount::count: + return count; + + case ResolvCount::set: + return numCls; + + case ResolvCount::unset: + return 0; + } + release_assert(false); +} + +uint64_t OccSimplifier::heuristicCalcVarElimScore(const uint32_t var) +{ + const Lit lit(var, false); + #ifdef CHECK_N_OCCUR + const uint32_t pos = calc_data_for_heuristic(lit); + if (pos != n_occurs[lit.toInt()]) { + cout << "for lit: " << lit << endl; + cout << "pos is: " << pos + << " n_occurs is:" << n_occurs[lit.toInt()] << endl; + assert(false); + } + + const uint32_t neg = calc_data_for_heuristic(~lit); + if (neg != n_occurs[(~lit).toInt()]) { + cout << "for lit: " << lit << endl; + cout << "neg is: " << neg + << " n_occurs is:" << n_occurs[(~lit).toInt()] << endl; + assert(false); + } + #endif + + return (uint64_t)n_occurs[lit.toInt()] * (uint64_t)n_occurs[(~lit).toInt()]; +} + +void OccSimplifier::order_vars_for_elim() +{ + velim_order.clear(); + varElimComplexity.clear(); + varElimComplexity.resize(solver->nVars(), 0); + elim_calc_need_update.clear(); + + //Go through all vars + for ( + size_t var = 0 + ; var < solver->nVars() && *limit_to_decrease > 0 + ; var++ + ) { + if (!can_eliminate_var(var)) + continue; + + *limit_to_decrease -= 50; + assert(!velim_order.inHeap(var)); + varElimComplexity[var] = heuristicCalcVarElimScore(var); + velim_order.insert(var); + } + assert(velim_order.heap_property()); + + //Print sorted listed list + #ifdef VERBOSE_DEBUG_VARELIM + /*cout << "-----------" << endl; + for(size_t i = 0; i < velim_order.size(); i++) { + cout + << "velim_order[" << i << "]: " + << " var: " << velim_order[i]+1 + << " val: " << varElimComplexity[velim_order[i]].first + << " , " << varElimComplexity[velim_order[i]].second + << endl; + }*/ + #endif +} + +void OccSimplifier::check_elimed_vars_are_unassigned() const +{ + for (size_t i = 0; i < solver->nVarsOuter(); i++) { + if (solver->varData[i].removed == Removed::elimed) { + assert(solver->value(i) == l_Undef); + } + } +} + +void OccSimplifier::check_elimed_vars_are_unassignedAndStats() const +{ + assert(solver->ok); + int64_t checkNumElimed = 0; + for (size_t i = 0; i < solver->nVarsOuter(); i++) { + if (solver->varData[i].removed == Removed::elimed) { + checkNumElimed++; + assert(solver->value(i) == l_Undef); + } + } + if (bvestats_global.numVarsElimed != checkNumElimed) { + std::cerr + << "ERROR: globalStats.numVarsElimed is "<< + bvestats_global.numVarsElimed + << " but checkNumElimed is: " << checkNumElimed + << endl; + + assert(false); + } +} + +size_t OccSimplifier::mem_used() const +{ + size_t b = 0; + b += dummy.capacity()*sizeof(char); + b += added_long_cl.capacity()*sizeof(ClOffset); + b += sub_str->mem_used(); + b += elimedClauses.capacity()*sizeof(ElimedClauses); + b += eClsLits.capacity()*sizeof(Lit); + b += blk_var_to_cls.size()*sizeof(uint32_t); + b += velim_order.mem_used(); + b += varElimComplexity.capacity()*sizeof(int)*2; + b += elim_calc_need_update.mem_used(); + b += clauses.capacity()*sizeof(ClOffset); + b += sampling_vars_occsimp.capacity(); + + return b; +} + +size_t OccSimplifier::mem_used_bva() const +{ + if (bva) + return bva->mem_used(); + else + return 0; +} + +void OccSimplifier::link_in_clause(Clause& cl) +{ + assert(!cl.stats.marked_clause); + assert(cl.size() > 2); + ClOffset offset = solver->cl_alloc.get_offset(&cl); + cl.recalc_abst_if_needed(); + if (!cl.red()) { + for(const Lit l: cl){ + n_occurs[l.toInt()]++; + added_cl_to_var.touch(l.var()); + } + } + assert(cl.stats.marked_clause == 0 && "marks must always be zero at linkin"); + + std::sort(cl.begin(), cl.end()); + for (const Lit lit: cl) { + watch_subarray ws = solver->watches[lit]; + ws.push(Watched(offset, cl.abst)); + } + cl.setOccurLinked(true); +} + +double OccSimplifier::Stats::total_time(OccSimplifier* occs) const +{ + return linkInTime + varElimTime + xorTime + triresolveTime + + finalCleanupTime + + occs->sub_str->get_stats().subsumeTime + + occs->sub_str->get_stats().strengthenTime + + occs->bvestats_global.timeUsed + + occs->bva->get_stats().time_used; +} + +void OccSimplifier::Stats::clear() +{ + Stats stats; + *this = stats; +} + +OccSimplifier::Stats& OccSimplifier::Stats::operator+=(const Stats& other) +{ + numCalls += other.numCalls; + + //Time + linkInTime += other.linkInTime; + varElimTime += other.varElimTime; + xorTime += other.xorTime; + triresolveTime += other.triresolveTime; + finalCleanupTime += other.finalCleanupTime; + zeroDepthAssings += other.zeroDepthAssings; + ternary_added_tri += other.ternary_added_tri; + ternary_added_bin += other.ternary_added_bin; + + return *this; +} + +BVEStats& BVEStats::operator+=(const BVEStats& other) +{ + numVarsElimed += other.numVarsElimed; + varElimTimeOut += other.varElimTimeOut; + clauses_elimed_long += other.clauses_elimed_long; + clauses_elimed_bin += other.clauses_elimed_bin; + clauses_elimed_sumsize += other.clauses_elimed_sumsize; + testedToElimVars += other.testedToElimVars; + triedToElimVars += other.triedToElimVars; + newClauses += other.newClauses; + subsumedByVE += other.subsumedByVE; + gatefind_timeouts += other.gatefind_timeouts; + + return *this; +} + +void OccSimplifier::Stats::print_extra_times() const +{ + + cout + << "c [occur] " << linkInTime+finalCleanupTime << " is overhead" + << endl; + + cout + << "c [occur] link-in T: " << linkInTime + << " cleanup T: " << finalCleanupTime + << endl; +} + +void OccSimplifier::Stats::print(const size_t nVars, OccSimplifier* occs) const +{ + cout << "c -------- OccSimplifier STATS ----------" << endl; + print_stats_line("c time" + , total_time(occs) + , stats_line_percent(varElimTime, total_time(occs)) + , "% var-elim" + ); + + print_stats_line("c called" + , numCalls + , float_div(total_time(occs), numCalls) + , "s per call" + ); + + print_stats_line("c 0-depth assigns" + , zeroDepthAssings + , stats_line_percent(zeroDepthAssings, nVars) + , "% vars" + ); + + cout << "c -------- OccSimplifier STATS END ----------" << endl; +} + +Clause* OccSimplifier::full_add_clause( + const vector& tmp_cl, + vector& finalLits, + ClauseStats* cl_stats, + bool red) +{ + Clause* newCl = solver->add_clause_int( + tmp_cl//Literals in new clause + , red //Is the new clause redundant? + , cl_stats + , false //Should clause be attached if long? + , &finalLits + ); + + if (solver->okay()) { + solver->ok = solver->propagate_occur(limit_to_decrease); + } + if (!solver->okay()) { + return NULL; + } + + if (!newCl) { + if (finalLits.size() == 2 && !red) { + n_occurs[finalLits[0].toInt()]++; + n_occurs[finalLits[1].toInt()]++; + added_irred_bin.push_back(std::make_pair(finalLits[0], finalLits[1])); + } + } else { + link_in_clause(*newCl); + ClOffset offset = solver->cl_alloc.get_offset(newCl); + clauses.push_back(offset); + } + + return newCl; +} + +bool OccSimplifier::remove_literal( + ClOffset offset, + const Lit toRemoveLit, + bool only_set_is_removed) +{ + Clause& cl = *solver->cl_alloc.ptr(offset); + #ifdef VERBOSE_DEBUG + cout << "-> Strenghtening clause :" << cl; + cout << " with lit: " << toRemoveLit << endl; + #endif + + *limit_to_decrease -= 5; + + (*solver->frat) << deldelay << cl << fin; + cl.strengthen(toRemoveLit); + added_cl_to_var.touch(toRemoveLit.var()); + cl.recalc_abst_if_needed(); + + INC_ID(cl); + (*solver->frat) << add << cl << fin << findelay; + if (!cl.red()) { + n_occurs[toRemoveLit.toInt()]--; + elim_calc_need_update.touch(toRemoveLit.var()); + removed_cl_with_var.touch(toRemoveLit.var()); + } + + removeWCl(solver->watches[toRemoveLit], offset); + if (cl.red()) + solver->litStats.redLits--; + else + solver->litStats.irredLits--; + + return clean_clause(offset, only_set_is_removed); +} + +void OccSimplifier::check_clauses_lits_ordered() const +{ + for (const auto & offset: clauses) { + Clause* cl = solver->cl_alloc.ptr(offset); + if (cl->freed() || cl->getRemoved()) continue; + for(uint32_t i = 1; i < cl->size(); i++) { + if ((*cl)[i-1] >= (*cl)[i]) { + cout << "ERRROR cl: " << *cl << endl; + assert(false); + } + } + } +} + +// Removes blocked clauses and **completely forgets them** +// So there is no way to reconstruct the solution +// Can be useful to simplify a problem +void OccSimplifier::blocked_clause_elim() +{ + for(const auto& off: clauses) { + Clause* cl = solver->cl_alloc.ptr(off); + if (cl->getRemoved() || cl->freed() || cl->red()) continue; + for(const auto& l: *cl) seen[l.toInt()] = true; + bool can_remove = false; + for(const auto& l: *cl) { + if (solver->var_inside_assumptions(l.var()) != l_Undef) continue; + bool all_blocking = true; + for(const auto& w: solver->watches[~l]) { + assert(!w.isBNN() && "TODO"); + if (w.isBin()) { + if (w.red()) continue; + if (seen[(~w.lit2()).toInt()]) continue; + all_blocking = false; break; + } + assert(w.isClause() && "Index not allowed"); + ClOffset off2 = w.get_offset(); + Clause* cl2 = solver->cl_alloc.ptr(off2); + if (cl2->getRemoved() || cl2->freed() || cl2->red()) continue; + bool found_blocking_lit = false; + for(const auto& l2: *cl2) { + if (l2 == ~l) continue; + if (seen[(~l2).toInt()]) {found_blocking_lit = true; break;} + } + if (!found_blocking_lit) {all_blocking = false; break;} + } + if (all_blocking) { can_remove = true; break; } + } + for(const auto& l: *cl) seen[l.toInt()] = 0; + if (!can_remove) continue; + unlink_clause(off); + } +} diff --git a/cryptominisat/cppsrc/src/occsimplifier.h b/cryptominisat/cppsrc/src/occsimplifier.h new file mode 100644 index 00000000..d417e1e9 --- /dev/null +++ b/cryptominisat/cppsrc/src/occsimplifier.h @@ -0,0 +1,712 @@ +/****************************************** +Copyright (C) 2009-2020 Authors of CryptoMiniSat, see AUTHORS file + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. +***********************************************/ + +#pragma once + +#include +#include +#include +#include +#include +#include +#include +#include +#ifdef ARJUN_SERIALIZE +#include +#endif + +#include "clause.h" +#include "solvertypes.h" +#include "heap.h" +#include "touchlist.h" +#include "varupdatehelper.h" +#include "watched.h" +#include "watcharray.h" +#include "simplefile.h" +struct PicoSAT; + +namespace CMSat { + +using std::vector; +using std::map; +using std::set; +using std::pair; + +class ClauseCleaner; +class SolutionExtender; +class Solver; +class SubsumeStrengthen; +class BVA; +class GateFinder; + +struct ElimedClauses { + ElimedClauses() + {} + + explicit ElimedClauses(size_t _start, size_t _end) : + start(_start) + , end(_end) + , toRemove(false) + {} + + void save_to_file(SimpleOutFile& f) const + { + f.put_uint32_t(toRemove); + f.put_uint64_t(start); + f.put_uint64_t(end); + } + + void load_from_file(SimpleInFile& f) + { + toRemove = f.get_uint32_t(); + start = f.get_uint64_t(); + end = f.get_uint64_t(); + } + + const Lit& at(const uint64_t at, const vector& eClsLits) const + { + return eClsLits[start+at]; + } + + Lit& at(const uint64_t at, vector& eClsLits) + { + return eClsLits[start+at]; + } + + uint64_t size() const { + return end-start; + } + + template + void serialize(Archive& ar, const unsigned int /*version*/) + { + ar & start; + ar & end; + ar & toRemove; + } + + uint64_t start; + uint64_t end; + bool toRemove = false; +}; + +struct BVEStats +{ + uint64_t numCalls = 0; + double timeUsed = 0.0; + + int64_t numVarsElimed = 0; + uint64_t varElimTimeOut = 0; + uint64_t clauses_elimed_long = 0; + uint64_t clauses_elimed_bin = 0; + uint64_t clauses_elimed_sumsize = 0; + uint64_t testedToElimVars = 0; + uint64_t triedToElimVars = 0; + uint64_t newClauses = 0; + uint64_t subsumedByVE = 0; + uint64_t gatefind_timeouts = 0; + + BVEStats& operator+=(const BVEStats& other); + + void print_short() const + { + //About elimination + cout + << "c [occ-bve]" + << " elimed: " << numVarsElimed + << " gatefind timeout: " << gatefind_timeouts + << endl; + + cout + << "c [occ-bve]" + << " cl-new: " << newClauses + << " tried: " << triedToElimVars + << " tested: " << testedToElimVars + << endl; + + cout + << "c [occ-bve]" + << " subs: " << subsumedByVE + << endl; + } + + void print() const + { + print_stats_line("c timeouted" + , stats_line_percent(varElimTimeOut, numCalls) + , "% called" + ); + print_stats_line("c v-elimed" + , numVarsElimed + , "% vars" + ); + + print_stats_line("c cl-new" + , newClauses + ); + + print_stats_line("c tried to elim" + , triedToElimVars + ); + + print_stats_line("c cl-elim-bin" + , clauses_elimed_bin); + + print_stats_line("c cl-elim-long" + , clauses_elimed_long); + + print_stats_line("c cl-elim-avg-s", + ((double)clauses_elimed_sumsize + /(double)(clauses_elimed_bin + clauses_elimed_long)) + ); + + print_stats_line("c v-elim-sub" + , subsumedByVE + ); + } + void clear() { + BVEStats tmp; + *this = tmp; + } +}; + +/** +@brief Handles subsumption, self-subsuming resolution, variable elimination, and related algorithms +*/ +class OccSimplifier +{ +public: + + //Construct-destruct + explicit OccSimplifier(Solver* solver); + ~OccSimplifier(); + + //Called from main + vector recover_or_gates(); + vector recover_ite_gates(); + + // definable vars + vector remove_definable_by_irreg_gate(const vector& vars); + void clean_sampl_and_get_empties(vector& empty_vars, vector& sampl_vars); + bool elim_var_by_str(uint32_t var, const vector>& cls); + uint32_t add_cls_to_picosat_definable(const Lit wsLit); + PicoSAT* picosat = NULL; + int lit_to_picolit(const Lit l); + uint64_t picolits_added = 0; + vector var_to_picovar; + vector picovars_used; + vector> equiv_subformula_cls; + bool check_equiv_subformula(Lit lit); + + bool simplify(const bool _startup, const std::string& schedule); + void new_var(const uint32_t orig_outer); + void new_vars(const size_t n); + void save_on_var_memory(); + bool uneliminate(const uint32_t var); + size_t mem_used() const; + size_t mem_used_bva() const; + uint32_t dump_elimed_clauses(std::ostream* outfile) const; + bool get_elimed_clause_at(uint32_t& at,uint32_t& at2, vector& out) const; + void subs_with_resolvent_clauses(); + void fill_tocheck_seen(const vec& ws, vector& tocheck); + void delete_component_unconnected_to_assumps(); //for arjun + void strengthen_dummy_with_bins(const bool avoid_redundant); + void blocked_clause_elim(); + + //UnElimination + void print_elimed_clauses_reverse() const; + void extend_model(SolutionExtender* extender); + uint32_t get_num_elimed_vars() const + { + return bvestats_global.numVarsElimed; + } + + struct Stats + { + void print(const size_t nVars, OccSimplifier* occs) const; + void print_extra_times() const; + Stats& operator+=(const Stats& other); + void clear(); + double total_time(OccSimplifier* occs) const; + + uint64_t numCalls = 0; + uint64_t ternary_added_tri = 0; + uint64_t ternary_added_bin = 0; + + //Time stats + double linkInTime = 0; + double varElimTime = 0; + double xorTime = 0; + double triresolveTime = 0; + double finalCleanupTime = 0; + + //General stat + uint64_t zeroDepthAssings = 0; + }; + + BVEStats bvestats; + BVEStats bvestats_global; + + const Stats& get_stats() const; + const SubsumeStrengthen* get_sub_str() const; + + //validity checking + void check_elimed_vars_are_unassigned() const; + void check_no_marked_clauses(); + bool getAnythingHasBeenElimed() const; + void sanityCheckElimedVars() const; + void printOccur(const Lit lit) const; + void check_clauses_lits_ordered() const; + + /// Used ONLY for XOR, changes occur setup + void sort_occurs_and_set_abst(); + vector added_long_cl; + TouchList added_cl_to_var; // to perform forward-subsumption of clauses added as part of BVE + // contains a list of literals that have been added as part of + // the clauses that have been added as resolvents + vector n_occurs; + TouchList removed_cl_with_var; + vector > added_irred_bin; + vector clauses; + void check_elimed_vars_are_unassignedAndStats() const; + void unlink_clause(ClOffset cc + , bool frat = true + , bool allow_empty_watch = false + , bool only_set_is_removed = false + ); + void free_clauses_to_free(); + + //Setup and teardown. Should be private, but testing needs it to be public + bool setup(); + void finishUp(size_t origTrailSize); + + //Ternary resolution. Should be private but testing needs it to be public + bool ternary_res(); + +#ifdef ARJUN_SERIALIZE + template + void serialize_elimed_cls (T& ar) const; + template + void unserialize_elimed_cls(T& ar); +#endif + +private: + friend class SubsumeStrengthen; + SubsumeStrengthen* sub_str; + friend class BVA; + BVA* bva; + void check_cls_sanity(); + + bool startup = false; + bool backward_sub_str(); + void backward_sub(); + bool execute_simplifier_strategy(const string& strategy); + bool remove_literal(ClOffset c, const Lit toRemoveLit, bool only_set_is_removed); + + //Ternary resolution + vector finalLits_ternary; + vector tmp_tern_res; + bool perform_ternary(Clause* cl, ClOffset offs, Sub1Ret& sub1_ret); + void check_ternary_cl(Clause* cl, ClOffset offs, watch_subarray ws); + struct Tri { + Lit lits[3]; + uint32_t size = 0; + Tri () : size(0) {} + Tri(const Tri & other) + { + memcpy(lits, other.lits, sizeof(Lit)*3); + size = other.size; + } + }; + vector cl_to_add_ternary; + + //debug + bool subsetReverse(const Clause& B) const; + + //Persistent data + Solver* solver; ///& seen; + vector& seen2; + vector& toClear; + vector sampling_vars_occsimp; + + //Temporaries + vector dummy; ///& toAdd) const; + void print_mem_usage_of_occur(uint64_t memUsage) const; + void print_linkin_data(const LinkInData link_in_data) const; + OccSimplifier::LinkInData link_in_clauses( + const vector& toAdd + , bool alsoOccur + , uint32_t max_size + , int64_t link_in_lit_limit + ); + void set_limits(); + + //Finish-up + void remove_by_frat_recently_elimed_clauses(size_t origElimedSize); + void add_back_to_solver(); + bool check_varelim_when_adding_back_cl(const Clause* cl) const; + void remove_all_longs_from_watches(); + bool complete_clean_clause(Clause& ps); + + //Clause update + bool clean_clause(ClOffset c, bool only_set_is_removed); + void link_in_clause(Clause& cl); + bool handleUpdatedClause(ClOffset c); + uint32_t sum_irred_cls_longs() const; + uint32_t sum_irred_cls_longs_lits() const; + Clause * full_add_clause( + const vector& tmp_cl, + vector& finalLits, + ClauseStats* cl_stats, + bool red + ); + + /////// + // Clearing clauses + vector cls_to_clean_tmp; + size_t last_trail_cleared; + bool clear_vars_from_cls_that_have_been_set(); + + ///////////////////// + //Variable elimination + uint32_t grow = 0; /// maximum grow rate for clauses + vector varElimComplexity; + ///Order variables according to their complexity of elimination + struct VarOrderLt { + const vector& varElimComplexity; + bool operator () (const uint64_t x, const uint64_t y) const + { + return varElimComplexity[x] < varElimComplexity[y]; + } + + explicit VarOrderLt( + const vector& _varElimComplexity + ) : + varElimComplexity(_varElimComplexity) + {} + }; + void order_vars_for_elim(); + Heap velim_order; + void rem_cls_from_watch_due_to_varelim( + const Lit lit, bool add_to_block = true); + vector tmp_rem_lits; + vec tmp_rem_cls_copy; + void add_clause_to_blck(const vector& lits, const uint64_t ID); + void set_var_as_eliminated(const uint32_t var); + bool can_eliminate_var(const uint32_t var) const; + bool mark_and_push_to_added_long_cl_cls_containing(const Lit lit); + bool simulate_frw_sub_str_with_added_cl_to_var(); + bool lit_rem_with_or_gates(); + bool cl_rem_with_or_gates(); + + + TouchList elim_calc_need_update; + vector cl_to_free_later; + bool maybe_eliminate(const uint32_t var); + bool forward_subsume_irred( + const Lit lit, + cl_abst_type abs, + const uint32_t size); + vector weaken_dummy; + bool check_taut_weaken_dummy(const uint32_t dontuse); + vector antec_poss_weakened; + vector antec_negs_weakened; + void weaken(const Lit lit, const vec& in, vector& out); + bool generate_resolvents( + vec& tmp_poss, + vec& tmp_negs, + Lit lit, + const uint32_t limit); + bool generate_resolvents_weakened( + vector& tmp_poss, + vector& tmp_negs, + vec& tmp_poss2, + vec& tmp_negs2, + Lit lit, + const uint32_t limit); + void get_antecedents( + const vec& gates, + const vec& full_set, + vec& output); + bool sub_str_with_added_long_and_bin(const bool verbose = true); + vector tmp_bin_cl; + vec gates_poss; + vec gates_negs; + vec antec_poss; + vec antec_negs; + vec poss; + vec negs; + void clean_from_satisfied(vec& in); + void clean_from_red_or_removed( + const vec& in, + vec& out); + void create_dummy_elimed_clause(const Lit lit); + vector tmp_subs; + bool test_elim_and_fill_resolvents(uint32_t var); + void get_gate(Lit elim_lit, watch_subarray_const poss, watch_subarray_const negs); + bool find_or_gate( + Lit lit, + watch_subarray_const a, + watch_subarray_const b, + vec& out_a, + vec& out_b + ); + void add_picosat_cls(const vec& ws, const Lit elim_lit, map& picosat_cl_to_cms_cl); + bool turned_off_irreg_gate = false; + bool resolve_gate; + bool find_irreg_gate( + Lit elim_lit, + watch_subarray_const a, + watch_subarray_const b, + vec& out_a, + vec& out_b); + bool find_equivalence_gate( + Lit lit + , watch_subarray_const a + , watch_subarray_const b + , vec& out_a + , vec& out_b); + bool find_xor_gate( + Lit lit + , watch_subarray_const a + , watch_subarray_const b + , vec& out_a + , vec& out_b); + bool find_ite_gate( + Lit elim_lit + , watch_subarray_const a + , watch_subarray_const b + , vec& out_a + , vec& out_b + , vec* out_a_all = NULL + ); + vector toclear_marked_cls; + set parities_found; + void print_var_eliminate_stat(Lit lit) const; + bool add_varelim_resolvent(vector& finalLits, const ClauseStats& stats, bool is_xor); + void update_varelim_complexity_heap(); + void print_var_elim_complexity_stats(const uint32_t var) const; + + //OccSimp + bool try_remove_lit_via_occurrence_simpl(const OccurClause& occ_cl); + bool occurrence_simp_based_resolv_skip(const Watched* it, const Lit lit); + bool occ_based_lit_rem(uint32_t var, uint32_t& removed); + bool all_occ_based_lit_rem(); + + struct ResolventData { + ResolventData() + {} + + ResolventData(const ClauseStats& cls, const bool _is_xor) : + stats(cls), + is_xor(_is_xor) + {} + + ClauseStats stats; + bool is_xor; + }; + + struct Resolvents { + uint32_t at = 0; + vector> resolvents_lits; + vector resolvents_stats; + void clear() { + at = 0; + } + void add_resolvent(const vector& res, const ClauseStats& stats, bool is_xor) { + if (resolvents_lits.size() < at+1) { + resolvents_lits.resize(at+1); + resolvents_stats.resize(at+1); + } + + resolvents_lits[at] = res; + resolvents_stats[at] = ResolventData(stats, is_xor); + at++; + } + vector& back_lits() { + assert(at > 0); + return resolvents_lits[at-1]; + } + const ClauseStats& back_stats() const { + assert(at > 0); + return resolvents_stats[at-1].stats; + } + bool back_xor() const { + assert(at > 0); + return resolvents_stats[at-1].is_xor; + } + void pop() { + at--; + } + bool empty() const { + return at == 0; + } + uint32_t size() const { + return at; + } + }; + Resolvents resolvents; + uint32_t calc_data_for_heuristic(const Lit lit); + uint64_t time_spent_on_calc_otf_update; + uint64_t num_otf_update_until_now; + + //for n_occur checking only + uint32_t calc_occ_data(const Lit lit); + void check_n_occur(); + + //For empty resolvents + enum class ResolvCount{count, set, unset}; + bool check_empty_resolvent(const Lit lit); + int check_empty_resolvent_action( + const Lit lit + , ResolvCount action + , int otherSize + ); + + uint64_t heuristicCalcVarElimScore(const uint32_t var); + bool resolve_clauses( + const Watched& ps + , const Watched& qs + , const Lit& noPosLit + ); + void add_pos_lits_to_dummy_and_seen( + const Watched& ps + , const Lit& posLit + ); + bool add_neg_lits_to_dummy_and_seen( + const Watched& qs + , const Lit& posLit + ); + bool eliminate_vars(); + void eliminate_empty_resolvent_vars(); + + ///////////////////// + //Helpers + friend class GateFinder; + GateFinder *gateFinder; + + ///////////////////// + //Elimed clause elimination + bool anythingHasBeenElimed; + vector eClsLits; + vector elimedClauses; /// blk_var_to_cls; + vector newly_elimed_cls_IDs; // temporary storage for newly elimed cls' IDs + bool elimedMapBuilt; + void buildElimedMap(); + void cleanElimedClauses(); + bool can_remove_elimed_clauses = false; + + ///Stats from this run + Stats runStats; + + ///Stats globally + Stats globalStats; +}; + +inline const OccSimplifier::Stats& OccSimplifier::get_stats() const +{ + return globalStats; +} + +inline bool OccSimplifier::getAnythingHasBeenElimed() const +{ + return anythingHasBeenElimed; +} + +inline bool OccSimplifier::subsetReverse(const Clause& B) const +{ + for (uint32_t i = 0; i != B.size(); i++) { + if (!seen[B[i].toInt()]) + return false; + } + return true; +} + +inline const SubsumeStrengthen* OccSimplifier::get_sub_str() const +{ + return sub_str; +} + +#ifdef ARJUN_SERIALIZE +template +void OccSimplifier::unserialize_elimed_cls(T& ar) +{ + ar >> eClsLits; + ar >> elimedClauses; +} + +template +void OccSimplifier::serialize_elimed_cls(T& ar) const +{ + ar << eClsLits; + ar << elimedClauses; +} +#endif + +} //end namespace diff --git a/cryptominisat/cppsrc/src/oracle/oracle.cpp b/cryptominisat/cppsrc/src/oracle/oracle.cpp new file mode 100644 index 00000000..0055501c --- /dev/null +++ b/cryptominisat/cppsrc/src/oracle/oracle.cpp @@ -0,0 +1,935 @@ +// SharpSAT-TD is a modification of SharpSAT (MIT License, 2019 Marc Thurley). +// +// SharpSAT-TD -- Copyright (c) 2021 Tuukka Korhonen +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, +// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR +// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE +// OR OTHER DEALINGS IN THE SOFTWARE. + +#include "oracle.h" +#include "constants.h" + +#include +#include +#include +#include "utils.h" +using std::cout; +using std::endl; +using std::max; +using std::min; +using std::pair; +using std::swap; + +namespace sspp { +namespace oracle { +namespace { +constexpr const double EPS = 1e-150; +} // namespace + +void Stats::Print() const { + cout <<"Decisions/Propagations "<& assumps) const { + // 1st variable's cache size is the same as all the rest + int cs = sol_cache[1].size(); + + // Try all cache lines + for (int i = 0; i < cs; i++) { + bool ok = true; + // all our assumptions must be in the solution + for (const Lit& l : assumps) { + if (IsPos(l)) { + if (sol_cache[VarOf(l)][i] == 0) { ok = false; break; } + } else { + if (sol_cache[VarOf(l)][i] == 1) { ok = false; break; } + } + } + if (ok) return true; + } + // Not in the cache + return false; +} + +void Oracle::ResizeClauseDb() { + std::sort(cla_info.begin(), cla_info.end(), [](const CInfo& a, const CInfo& b){ + if (a.glue == -1 || b.glue == -1) return a.glue < b.glue; + if (a.used != b.used) return a.used > b.used; + return a.total_used > b.total_used; + }); + { + vector new_reason(vars+2); + for (Var v = 1; v <= vars; v++) { new_reason[v] = vs[v].reason; } + size_t prev_orig_clauses_size = orig_clauses_size; + vector new_clauses(orig_clauses_size); + for (size_t i = 0; i < orig_clauses_size; i++) { new_clauses[i] = clauses[i]; } + vector new_cla_info; + // This sets new_clauses and fixes reasons + const size_t good_size = 10000; + num_lbd2_red_cls = 0; + num_used_red_cls = 0; + for (size_t i = 0; i < cla_info.size(); i++) { + if (i+1 < cla_info.size()) { + cmsat_prefetch(clauses.data() + cla_info[i+1].pt); + } + stats.mems++; + Lit impll = 0; + size_t cls = cla_info[i].pt; + if (vs[VarOf(clauses[cls+1])].reason == cls) { + swap(clauses[cls], clauses[cls+1]); + // Can only happen in binary clause + assert(clauses[cls+2] == 0); + } + if (vs[VarOf(clauses[cls])].reason == cls) { + impll = clauses[cls]; + assert(LitVal(impll) == 1); + for (size_t k = cls+1; clauses[k] != 0; k++) { + assert(LitVal(clauses[k]) == -1); + } + } + bool added = false; + if (cla_info[i].glue == -1) { + assert(cla_info[i].used <= -1); + added = true; + } + size_t len = 0; + bool frozen_sat = false; + while (clauses[cls+len]) { + if (!frozen_sat && LitVal(clauses[cls+len]) == 1) { + Var v = VarOf(clauses[cls+len]); + if (vs[v].level == 1) frozen_sat = true; + } + len++; + } + assert(len >= 2); + if (frozen_sat) assert(!impll); + if (cla_info[i].glue <= 2) num_lbd2_red_cls++; + else if (cla_info[i].used) num_used_red_cls++; + if (frozen_sat || (impll == 0 && !added && !cla_info[i].Keep() + && i > good_size+num_lbd2_red_cls)) { + stats.forgot_clauses++; + clauses[cls] = 0; + continue; + } + size_t new_pt = new_clauses.size(); + if (impll) new_reason[VarOf(impll)] = new_pt; + if (added) assert(new_clauses.size() == orig_clauses_size); + else new_cla_info.push_back({new_clauses.size(), cla_info[i].glue, cla_info[i].used-1, cla_info[i].total_used}); + for (size_t k = cls; clauses[k]; k++) new_clauses.push_back(clauses[k]); + new_clauses.push_back(0); + if (added) orig_clauses_size = new_clauses.size(); + clauses[cls] = new_pt; + } + for (Var v = 1; v <= vars; v++) vs[v].reason = new_reason[v]; + for (Lit l = 2; l <= vars*2+1; l++) { + size_t pos = 0; + for (size_t i = 0; i < watches[l].size(); i++) { + watches[l][pos++] = watches[l][i]; + if (watches[l][pos-1].cls >= prev_orig_clauses_size) { + if (clauses[watches[l][pos-1].cls] == 0) pos--; + else watches[l][pos-1].cls = clauses[watches[l][pos-1].cls]; + } + } + watches[l].resize(pos); + } + clauses = new_clauses; + cla_info = new_cla_info; +#ifdef SLOW_DEBUG + for (Lit l = 2; l <= vars*2+1; l++) { + for (const auto& Watch w : watches[l]) { + assert(clauses[w.cls] == l || clauses[w.cls+1] == l); + } + } +#endif + } + for (Var v = 1; v <= vars; v++) { + if (vs[v].reason) { + size_t cl = vs[v].reason; + assert(clauses[cl-1] == 0); + if (cl < orig_clauses_size) continue; + assert(VarOf(clauses[cl]) == v); + assert(LitVal(clauses[cl]) == 1); + for (size_t k = cl+1; clauses[k]; k++) { + assert(LitVal(clauses[k]) == -1); + } + } + } +} + +void Oracle::BumpClause(size_t cls) { + if (cls < orig_clauses_size) return; + assert(cla_info.size() > 0); + size_t i = 0; + for (size_t b = cla_info.size()/2; b >= 1; b /= 2) { + while (i + b < cla_info.size() && cla_info[i+b].pt <= cls) { + i += b; + } + } + assert(cla_info[i].pt == cls); + if (cla_info[i].glue == -1) { + // Special added clause + assert(cla_info[i].used == -1); + return; + } + lvl_it++; + int glue = 0; + for (;clauses[cls] != 0; cls++) { + if (lvl_seen[vs[VarOf(clauses[cls])].level] != lvl_it) { + lvl_seen[vs[VarOf(clauses[cls])].level] = lvl_it; + glue++; + } + } + cla_info[i].glue = glue; + cla_info[i].used = 1; + cla_info[i].total_used++; + return; +} + +void Oracle::InitLuby() { + luby.clear(); +} + +int Oracle::NextLuby() { + luby.push_back(1); + while (luby.size() >= 2 && luby[luby.size()-1] == luby[luby.size()-2]) { + luby.pop_back(); + luby.back() *= 2; + } + return luby.back(); +} + +Var Oracle::PopVarHeap() { + if (var_act_heap[1] <= 0) { + return 0; + } + size_t i = 1; + while (i < heap_N) { + if (var_act_heap[i*2] == var_act_heap[i]) { + i = i*2; + } else { + i = i*2+1; + } + } + assert(var_act_heap[i] == var_act_heap[1]); + assert(i > heap_N); + Var ret = i - heap_N; + var_act_heap[i] = -var_act_heap[i]; + for (i/=2;i;i/=2) { + var_act_heap[i] = max(var_act_heap[i*2], var_act_heap[i*2+1]); + } + return ret; +} + +void Oracle::ActivateActivity(Var v) { + if (var_act_heap[heap_N + v] > 0) return; + assert(var_act_heap[heap_N + v] < 0); + var_act_heap[heap_N + v] = -var_act_heap[heap_N + v]; + for (size_t i = (heap_N + v)/2; i >= 1; i/=2) { + var_act_heap[i] = max(var_act_heap[i*2], var_act_heap[i*2+1]); + } +} + +void Oracle::BumpVar(Var v) { + stats.mems++; + if (var_act_heap[heap_N + v] < 0) { + var_act_heap[heap_N + v] -= var_inc; + } else { + assert(var_act_heap[heap_N + v] > 0); + var_act_heap[heap_N + v] += var_inc; + for (size_t i = (heap_N + v)/2; i >= 1; i/=2) { + var_act_heap[i] = max(var_act_heap[i*2], var_act_heap[i*2+1]); + } + } + var_inc = var_inc * var_fact; + if (var_inc > 10000.0) { + stats.mems+=10; + var_inc /= 10000.0; + for (Var i = 1; i <= vars; i++) { + double& act = var_act_heap[heap_N + i]; + act /= 10000.0; + if (-EPS < act && act < EPS) { + assert(act != 0); + if (act < 0) { + act = -EPS; + } else { + act = EPS; + } + } + } + for (size_t i = heap_N-1; i >= 1; i--) { + var_act_heap[i] = max(var_act_heap[i*2], var_act_heap[i*2+1]); + } + } +} + +void Oracle::SetAssumpLit(Lit lit, bool freeze) { + assert(CurLevel() == 1); + Var v = VarOf(lit); + assert(vs[v].reason == 0); + assert(vs[v].level != 1); + for (Lit tl : {PosLit(v), NegLit(v)}) { + for (const Watch w : watches[tl]) { + stats.mems++; + assert(w.size > 2); + size_t pos = w.cls; + size_t opos = w.cls+1; + if (clauses[pos] != tl) { + pos++; + opos--; + } + assert(clauses[pos] == tl); + size_t f = 0; + for (size_t i = w.cls+2; clauses[i]; i++) { + if (LitVal(clauses[i]) == 0) { + f = i; + } + } + assert(f); + swap(clauses[f], clauses[pos]); + watches[clauses[pos]].push_back({w.cls, clauses[opos], w.size}); + } + watches[tl].clear(); + } + assert(watches[lit].empty()); + assert(watches[Neg(lit)].empty()); + assert(prop_q.empty()); + if (freeze) { Assign(lit, 0, 1); } + else { Assign(lit, 0, 2); } + assert(decided.back() == VarOf(lit)); + decided.pop_back(); + assert(prop_q.back() == Neg(lit)); + prop_q.pop_back(); +} + +void Oracle::Assign(Lit dec, size_t reason_clause, int level) { + if (level <= 1) reason_clause = 0; + Var v = VarOf(dec); + lit_val[dec] = 1; + lit_val[Neg(dec)] = -1; + vs[v].phase = IsPos(dec) ? 1 : 0; + vs[v].reason = reason_clause; + vs[v].level = level; + oclv("Assigning " << v << " to: " << IsPos(dec) << " at level: " << level << " reason: " << reason_clause); + decided.push_back(v); + prop_q.push_back(Neg(dec)); + cmsat_prefetch(watches[Neg(dec)].data()); +} + +void Oracle::UnDecide(int level) { + while (!decided.empty() && vs[decided.back()].level >= level) { + stats.mems++; + Var v = decided.back(); + decided.pop_back(); + lit_val[PosLit(v)] = 0; + lit_val[NegLit(v)] = 0; + vs[v].reason = 0; + vs[v].level = 0; + ActivateActivity(v); + oclv("UNAss " << v); + } + assert(prop_q.empty()); +} + +size_t Oracle::AddLearnedClause(const vector& clause) { + stats.learned_clauses++; + if (clause.size() == 2) stats.learned_bin_clauses++; + assert(clause.size() >= 2); + + // Compute LBD. Notice that the clause has been sorted already in terms of decision + // levels of its literals, before this function is called. + int glue = 2; + assert(!LitAssigned(clause[0])); + for (size_t i = 1; i < clause.size(); i++) { + assert(LitAssigned(clause[i]) && !LitSat(clause[i])); + if (i >= 2) { + assert(vs[VarOf(clause[i])].level <= vs[VarOf(clause[i-1])].level); + if (vs[VarOf(clause[i])].level < vs[VarOf(clause[i-1])].level) { + glue++; + } + } + } + + // Attach + size_t pt = clauses.size(); + watches[clause[0]].push_back({pt, clause[1], (int)clause.size()}); + watches[clause[1]].push_back({pt, clause[0], (int)clause.size()}); + for (Lit lit : clause) clauses.push_back(lit); + clauses.push_back(0); + cla_info.push_back({pt, glue, 1, 0}); + return pt; +} + +// Check if lit can be removed from the learned clause +bool Oracle::LitReduntant(Lit lit) { + // TODO: this can be optimized a lot + assert(redu_s.empty()); + redu_it++; + redu_s.push_back(lit); + int its = 0; + while (!redu_s.empty()) { + its++; + stats.mems++; + lit = redu_s.back(); + redu_s.pop_back(); + Var v = VarOf(lit); + assert(vs[v].reason); + size_t rc = vs[v].reason; + if (clauses[rc] != Neg(lit)) { + swap(clauses[rc], clauses[rc+1]); + } + assert(LitVal(lit) == -1); + assert(clauses[rc] == Neg(lit)); + for (size_t k = rc+1; clauses[k]; k++) { + if (!in_cc[clauses[k]] && vs[VarOf(clauses[k])].level > 1) { + if (vs[VarOf(clauses[k])].reason == 0) { + redu_s.clear(); + return false; + } else { + if (redu_seen[clauses[k]] != redu_it) { + redu_seen[clauses[k]] = redu_it; + redu_s.push_back(clauses[k]); + } + } + } + } + } + if (its >= 2) { + stats.nontriv_redu++; + } + return true; +} + +vector Oracle::LearnUip(size_t conflict_clause) { + assert(conflict_clause > 0); + BumpClause(conflict_clause); +#ifdef DEBUG_ORACLE_VERB + oclv2("Conflict clause NUM: " << conflict_clause << " cl:"); + for(size_t i = conflict_clause; clauses[i]; i++) { + oclv2(" v: " << VarOf(clauses[i]) << " val: " << LitVal(clauses[i])); + } + oclv2(endl); +#endif + + vector clause = {0}; + int level = vs[VarOf(clauses[conflict_clause])].level; + int open = 0; + oclv("---"); + for (size_t i = conflict_clause; clauses[i]; i++) { + assert(LitVal(clauses[i]) == -1); + oclv("clauses[i]: " << VarOf(clauses[i]) << " val: " << LitVal(clauses[i]) + << " vs[VarOf(clauses[i])].level: " << vs[VarOf(clauses[i])].level + << " level: " << level); + assert(vs[VarOf(clauses[i])].level <= level); + BumpVar(VarOf(clauses[i])); + if (vs[VarOf(clauses[i])].level == level) { + open++; + seen[VarOf(clauses[i])] = true; + } else if (vs[VarOf(clauses[i])].level > 1) { + clause.push_back(clauses[i]); + in_cc[clauses[i]] = true; + } + } + assert(open > 0); + for (size_t i = decided.size()-1; open; i--) { + Var v = decided[i]; + if (!seen[v]) continue; + assert(vs[v].level == level); + open--; + if (open) { + stats.mems++; + BumpClause(vs[v].reason); + for (size_t j = vs[v].reason; clauses[j]; j++) { + Var tv = VarOf(clauses[j]); + if (seen[tv]) continue; + BumpVar(tv); + if (vs[tv].level == level) { + open++; + seen[tv] = true; + } else if (!in_cc[clauses[j]] && vs[tv].level > 1) { + clause.push_back(clauses[j]); + in_cc[clauses[j]] = true; + } + } + } else { + clause[0] = Neg(MkLit(v, vs[v].phase)); + } + seen[v] = false; + } + for (size_t i = 1; i < clause.size(); i++) { + assert(VarOf(clause[i]) != VarOf(clause[i-1])); + } + + + // Conflict minimization + for (size_t i = 1; i < clause.size(); i++) { + if (vs[VarOf(clause[i])].reason) { + stats.mems++; + if (LitReduntant(clause[i])) { + assert(in_cc[clause[i]]); + in_cc[clause[i]] = false; + SwapDel(clause, i); + i--; + } + } + } + std::sort(clause.begin(), clause.end(), [&](Lit l1, Lit l2) { + int d1 = vs[VarOf(l1)].level; + int d2 = vs[VarOf(l2)].level; + if (d1 == d2) { + return l1 < l2; + } + return d1 > d2; + }); + for (size_t i = 1; i < clause.size(); i++) { + assert(in_cc[clause[i]]); + in_cc[clause[i]] = false; + } + return clause; +} + +// Returns id of conflict clause or 0 if no conflict +size_t Oracle::Propagate(int level) { + size_t conflict = 0; + for (size_t i = 0; i < prop_q.size(); i++) { + stats.mems++; + // ff short for falsified + const Lit ff = prop_q[i]; + assert(vs[VarOf(ff)].level == level); + vector& wt = watches[ff]; + vector::const_iterator j1 = wt.begin(); + vector::iterator j2 = wt.begin(); + while (j1 != wt.end()) { + // This code is inspired by cadical propagation code + const Watch w = *j2++ = *j1++; + int bv = LitVal(w.blit); + if (bv > 0) continue; // SAT by blit + if (w.size == 2) { + if (bv < 0) { + // CONFLICT + conflict = w.cls; + } else { + // UNIT + Assign(w.blit, w.cls, level); + } + continue; + } + if (conflict) break; + // Check if satisfied by the other watched literal + // fun xor swap trick + stats.mems++; + const Lit other = clauses[w.cls]^clauses[w.cls+1]^ff; + int ov = LitVal(other); + if (ov > 0) { // SAT by other watch - change blit + j2[-1].blit = other; + continue; + } + clauses[w.cls] = other; + clauses[w.cls+1] = ff; + // Try to find true or unassigned lit + size_t fo = 0; + for (size_t k = w.cls+2; clauses[k]; k++) { + if (LitVal(clauses[k]) != -1) { + fo = k; + break; + } + } + // Found true or unassigned lit + if (fo) { + clauses[w.cls+1] = clauses[fo]; + clauses[fo] = ff; + watches[clauses[w.cls+1]].push_back({w.cls, other, w.size}); + j2--; + continue; + } + // Now the clause is unit or unsat. + if (LitAssigned(clauses[w.cls])) { + // CONFLICT!! + conflict = w.cls; + break; + } else { + // UNIT + Assign(clauses[w.cls], w.cls, level); + } + } + if (j2 != wt.end()) { + while (j1 != wt.end()) { + *j2++ = *j1++; + } + wt.resize(j2 - wt.begin()); + } + if (conflict) break; + } + //stats.propagations += (int)prop_q.size(); + prop_q.clear(); + return conflict; +} + + +int Oracle::CDCLBT(size_t confl_clause, int min_level) { + stats.conflicts++; + auto clause = LearnUip(confl_clause); + assert(clause.size() >= 1); + if (clause.size() == 1 || vs[VarOf(clause[1])].level == 1) { + assert(min_level <= 2); + UnDecide(3); + Assign(clause[0], 0, 2); + learned_units.push_back(clause[0]); + stats.learned_units++; + return 2; + } else { + int ass_level = vs[VarOf(clause[1])].level; + assert(ass_level >= 2); + assert(ass_level < vs[VarOf(clause[0])].level); + oclv("ass_level: " << ass_level << " min_level: " << min_level); + if (ass_level >= min_level) { + oclv("if (ass_level >= min_level) "); + UnDecide(ass_level+1); + size_t cl_id = AddLearnedClause(clause); + Assign(clause[0], cl_id, ass_level); + return ass_level; + } else { + oclv("NOT if (ass_level >= min_level)"); + assert(prop_q.empty()); + UnDecide(min_level+1); + vector> decs; + for (int i = (int)decided.size()-1;; i--) { + assert(i>0); + Var v = decided[i]; + assert(vs[v].level <= min_level); + if (vs[v].level <= ass_level) { + break; + } + decs.push_back({MkLit(v, vs[v].phase), vs[v].level}); + } + UnDecide(ass_level+1); + size_t cl_id = AddLearnedClause(clause); + Assign(clause[0], cl_id, ass_level); + if (Propagate(ass_level)) return min_level-1; + int level = ass_level; + std::reverse(decs.begin(), decs.end()); + for (int i = 0; i < (int)decs.size(); i++) { + if (LitVal(decs[i].first) == -1) { + return min_level-1; + } + if (LitVal(decs[i].first) == 0) { + Decide(decs[i].first, decs[i].second); + if (Propagate(decs[i].second)) { + return min_level-1; + } + level = decs[i].second; + } + if (i) { + assert(decs[i].second >= decs[i-1].second); + } + } + return max(level, min_level); + } + } +} + +TriState Oracle::HardSolve(int64_t max_mems) { + InitLuby(); + int64_t confls = 0; + int64_t next_restart = 1; + int64_t mems_startup = stats.mems; + int cur_level = 2; + Var nv = 1; + while (true) { + size_t confl_clause = Propagate(cur_level); + if (stats.mems > mems_startup+max_mems) return TriState::unknown(); + if (confl_clause) { + confls++; + total_confls++; + if (cur_level <= 2) return false; + cur_level = CDCLBT(confl_clause); + assert(cur_level >= 2); + continue; + } + if (confls >= next_restart) { + int nl = NextLuby(); + next_restart = confls + nl*restart_factor; + UnDecide(3); + cur_level = 2; + stats.restarts++; + if (total_confls > last_db_clean + 10000) { + last_db_clean = total_confls; + oclv("c [oracle] Resizing cldb" + << " num_lbd2_red_cls: " << num_lbd2_red_cls + << " num_used_red_cls: " << num_used_red_cls + << " cla_info.size(): " << cla_info.size()); + ResizeClauseDb(); + oclv("c [oracle] after cldb resize" + << " num_lbd2_red_cls: " << num_lbd2_red_cls + << " num_used_red_cls: " << num_used_red_cls + << " cla_info.size(): " << cla_info.size()); + } + } + Var decv = 0; + if (confls == 0) { + while (nv <= vars && LitVal(PosLit(nv)) != 0) nv++; + if (nv <= vars) decv = nv; + } else { + while (true) { + decv = PopVarHeap(); + if (decv == 0 || LitVal(PosLit(decv)) == 0) break; + } + } + if (decv == 0) return true; + cur_level++; + Decide(MkLit(decv, vs[decv].phase), cur_level); + } +} + +void Oracle::AddOrigClause(vector clause, bool entailed) { + assert(CurLevel() == 1); + for (int i = 0; i < (int)clause.size(); i++) { + assert(VarOf(clause[i]) >= 1 && VarOf(clause[i]) <= vars); + if (LitVal(clause[i]) == 1) return; + if (LitVal(clause[i]) == -1) { + SwapDel(clause, i); + i--; + } + } + for (Lit lit : clause) assert(LitVal(lit) == 0); + if (!entailed) ClearSolCache(); + if (clause.size() == 0) { + unsat = true; + return; + } + if (clause.size() == 1) { + FreezeUnit(clause[0]); + return; + } + assert(clause.size() >= 2); + bool og = (clauses.size() == orig_clauses_size); + size_t pt = clauses.size(); + watches[clause[0]].push_back({clauses.size(), clause[1], (int)clause.size()}); + watches[clause[1]].push_back({clauses.size(), clause[0], (int)clause.size()}); + for (Lit lit : clause) clauses.push_back(lit); + clauses.push_back(0); + // If we have no learned clauses then this is original clause + // Otherwise this is "learned" clause with glue -1 and used -1 + if (og) { + orig_clauses_size = clauses.size(); + return; + } + cla_info.push_back({pt, -1, -1, 0}); +} + +Oracle::Oracle(int vars_, const vector>& clauses_, + const vector>& learned_clauses_) : Oracle(vars_, clauses_) { + for (const auto& clause : learned_clauses_) { + AddClauseIfNeededAndStr(clause, true); + } +} + +Oracle::Oracle(int vars_, const vector>& clauses_) : vars(vars_), rand_gen(1337) { + assert(vars >= 1); + vs.resize(vars+1); + seen.resize(vars+1); + lvl_seen.resize(vars+3); + sol_cache.resize(vars+1); + watches.resize(vars*2+2); + lit_val.resize(vars*2+2); + redu_seen.resize(vars*2+2); + in_cc.resize(vars*2+2); + // setting magic constants + restart_factor = 100; + + clauses.push_back(0); + orig_clauses_size = 1; + for (const vector& clause : clauses_) { + AddOrigClause(clause, false); + } + + // variable activity + var_fact = powl((long double)2, (long double)(1.0L/(long double)vars)); + assert(var_fact > 1.0); + heap_N = 1; + while (heap_N <= (size_t)vars) heap_N *= 2; + var_act_heap.resize(heap_N*2); + for (Var v = 1; v <= vars; v++) { + var_act_heap[heap_N + v] = var_inc * RandInt(95, 105, rand_gen); + } + for (int i = heap_N-1; i >= 1; i--) { + var_act_heap[i] = max(var_act_heap[i*2], var_act_heap[i*2+1]); + } +} + +TriState Oracle::Solve(const vector& assumps, bool usecache, int64_t max_mems) { + if (unsat) return false; + if (usecache && SatByCache(assumps)) {stats.cache_useful++; return true;} + oclv("SOLVE called "); + // TODO: solution caching + for (const auto& lit : assumps) { + if (LitVal(lit) == -1) { + prop_q.clear(); + UnDecide(2); + return false; + } else if (LitVal(lit) == 0) { + Decide(lit, 2); + } + } + size_t confl_clause = Propagate(2); + if (confl_clause) { UnDecide(2); return false; } + oclv("HARD SOLVING"); + TriState sol = HardSolve(max_mems); + UnDecide(2); + if (!unsat) { + while (!learned_units.empty()) { + Decide(learned_units.back(), 1); + learned_units.pop_back(); + } + if (Propagate(1)) { + unsat = true; + assert(sol.isFalse()); + } + } + if (sol.isTrue()) { + if (usecache) { AddSolToCache(); } + } else if (sol.isFalse()) { + // UNSAT + if (assumps.size() == 1) { + bool ok = FreezeUnit(Neg(assumps[0])); + if (!ok) { + assert(unsat); + } + } + } + return sol; +} + +bool Oracle::FreezeUnit(Lit unit) { + if (unsat) return false; + assert(CurLevel() == 1); + if (LitVal(unit) == -1) { + unsat = true; + return false; + } + if (LitVal(unit) == 1) { + return true; + } + Decide(unit, 1); + stats.learned_units++; + oclv("[oracle] learnt unit: " << VarOf(unit) << " val: " << LitVal(unit)); + size_t confl = Propagate(1); + if (confl) { + unsat = true; + return false; + } + return true; +} + +// Checks if the clause is SAT & then does strengthening on the clause +// before adding it to the CNF +bool Oracle::AddClauseIfNeededAndStr(vector clause, bool entailed) { + if (unsat) return false; + assert(CurLevel() == 1); + for (int i = 0; i < (int)clause.size(); i++) { + if (LitVal(clause[i]) == 1) { + return false; + } else if (LitVal(clause[i]) == -1) { + SwapDel(clause, i); + i--; + } + } + if (clause.size() <= 1) { + AddOrigClause(clause, entailed); + return true; + } + + // We are now going to do strengthening, lit-by-lit, recursively. + // For example, a V b V c. Enqueue (!a && !b) and propagate. If UNSAT, + // then we know (a V b) is also true. We just removed a literal. + for (int i = 0; i < (int)clause.size(); i++) { + Lit tp = clause[i]; + assert(LitVal(tp) == 0); + for (Lit o : clause) { + if (o != tp) { + Decide(Neg(o), 2); + } + } + size_t confl = Propagate(2); + if (confl || LitVal(tp) == -1) { + UnDecide(2); + SwapDel(clause, i); + return AddClauseIfNeededAndStr(clause, true); + } + + // No conflict. + if (LitVal(tp) == 1) { + // Propagation as intended + UnDecide(2); + } else if (LitVal(tp) == 0) { + // No propagation -- we need to add the clause + UnDecide(2); + AddOrigClause(clause, entailed); + return true; + } else { + assert(0); + } + } + return false; +} + +vector> Oracle::GetLearnedClauses() const { + assert(CurLevel() == 1); + vector> ret; + ret.push_back({}); + for (size_t i = orig_clauses_size; i < clauses.size(); i++) { + if (clauses[i] == 0) { + assert(ret.back().size() >= 2); + sort(ret.back().begin(), ret.back().end()); + ret.push_back({}); + } else { + ret.back().push_back(clauses[i]); + } + } + assert(ret.back().empty()); + ret.pop_back(); + + // Units + for (Var v = 1; v <= vars; v++) { + if (LitVal(PosLit(v)) == 1) { + ret.push_back({PosLit(v)}); + } else if (LitVal(PosLit(v)) == -1) { + ret.push_back({NegLit(v)}); + } + } + return ret; +} + +} // namespace oracle +} // namespace sspp diff --git a/cryptominisat/cppsrc/src/oracle/oracle.h b/cryptominisat/cppsrc/src/oracle/oracle.h new file mode 100644 index 00000000..77e3d7ec --- /dev/null +++ b/cryptominisat/cppsrc/src/oracle/oracle.h @@ -0,0 +1,227 @@ +// SharpSAT-TD is a modification of SharpSAT (MIT License, 2019 Marc Thurley). +// +// SharpSAT-TD -- Copyright (c) 2021 Tuukka Korhonen +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, +// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR +// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE +// OR OTHER DEALINGS IN THE SOFTWARE. + +#pragma once + +#include +#include "utils.h" +/* #define DEBUG_ORACLE_VERB */ + +#ifdef DEBUG_ORACLE_VERB +#define oclv(x) do {cout << x << endl;} while(0) +#define oclv2(x) do {cout << x;} while(0) +#else +#define oclv(x) do {} while(0) +#define oclv2(x) do {} while(0) +#endif + +namespace sspp { +namespace oracle { + +struct TriState { + TriState() {} + + TriState(bool _b) { + if (_b) val = 1; + else val = 0; + } + + static TriState unknown() { + TriState tmp; + tmp.val = 2; + return tmp; + } + + bool isTrue() const {return val == 1;} + bool isFalse() const {return val == 0;} + bool isUnknown() const {return val == 2;} + int val; +}; + +struct Stats { + int64_t mems = 0; + int64_t decisions = 0; + int64_t learned_clauses = 0; + int64_t learned_bin_clauses = 0; + int64_t learned_units = 0; + int64_t conflicts = 0; + int64_t nontriv_redu = 0; + int64_t forgot_clauses = 0; + int64_t restarts = 0; + int64_t cache_useful = 0; + int64_t cache_added = 0; + void Print() const; +}; + +struct Watch { + // should align to 8+4+4=16 bytes + size_t cls; + Lit blit; // blocked literal + int size; +}; + +struct VarC { + size_t reason = 0; + int level = 0; + char phase = 0; +}; + +struct CInfo { + size_t pt; + int glue; + int used; + uint32_t total_used; + bool Keep() const; +}; + +class Oracle { + public: + Oracle(int vars_, const vector>& clauses_); + Oracle(int vars_, const vector>& clauses_, const vector>& learned_clauses_); + + void SetAssumpLit(Lit lit, bool freeze); + void SetVerbosity(uint32_t _verb) { verb=_verb;} + TriState Solve(const vector& assumps, bool usecache=true, int64_t max_mems = 1000ULL*1000LL*1000LL); + bool FreezeUnit(Lit unit); + bool AddClauseIfNeededAndStr(vector clause, bool entailed); + void AddClause(const vector& clause, bool entailed); + void PrintStats() const; + vector> GetLearnedClauses() const; + + int CurLevel() const; + int LitVal(Lit lit) const; + const Stats& getStats() const {return stats;} + + private: + uint32_t verb = 0; + size_t total_confls = 0; + size_t last_db_clean = 0; + + void AddOrigClause(vector clause, bool entailed); + vector clauses; + vector> watches; + vector lit_val; + vector vs; + + bool unsat = false; + + const int vars; + size_t orig_clauses_size = 0; + Stats stats; + vector prop_q; + vector decided; + vector in_cc; + + std::mt19937 rand_gen; + + int64_t redu_it = 1; + vector seen; + vector redu_seen; + vector redu_s; + + int64_t lvl_it = 1; + vector lvl_seen; // for computing LBD + + vector learned_units; + + int restart_factor = 0; + vector luby; + void InitLuby(); + int NextLuby(); + + size_t num_lbd2_red_cls = 0; + size_t num_used_red_cls = 0; + void ResizeClauseDb(); + void BumpClause(size_t cls); + vector cla_info; + + double var_inc = 1; + double var_fact = 0; + size_t heap_N; + vector var_act_heap; + void BumpVar(Var v); + void ActivateActivity(Var v); + Var PopVarHeap(); + + bool LitSat(Lit lit) const; + bool LitAssigned(Lit lit) const; + void Assign(Lit dec, size_t reason_clause, int level); + void Decide(Lit dec, int level); + void UnDecide(int level); + + TriState HardSolve(int64_t max_mems = 1000LL*1000LL*1000LL); + // True if conflict + size_t Propagate(int level); + + size_t AddLearnedClause(const vector& clause); + bool LitReduntant(Lit lit); + void PopLit(vector& clause, int& confl_levels, int& impl_lits, int level); + vector LearnUip(size_t conflict_clause); + int CDCLBT(size_t confl_clause, int min_level=0); + + vector> sol_cache; // Caches found FULL solutions + void AddSolToCache(); + bool SatByCache(const vector& assumps) const; + void ClearSolCache(); +}; + + +inline int Oracle::LitVal(Lit lit) const { + return lit_val[lit]; +} + +inline bool Oracle::LitSat(Lit lit) const { + return LitVal(lit) > 0; +} + +inline bool Oracle::LitAssigned(Lit lit) const { + return LitVal(lit) != 0; +} + +// TOP level is 1. +inline int Oracle::CurLevel() const { + if (decided.empty()) { + return 1; + } + return vs[decided.back()].level; +} + +inline void Oracle::Decide(Lit dec, int level) { + assert(LitVal(dec) == 0); + stats.decisions++; + Assign(dec, 0, level); +} + +inline void Oracle::AddClause(const vector& clause, bool entailed) { + AddOrigClause(clause, entailed); +} + +inline void Oracle::PrintStats() const { + stats.Print(); +} + +inline bool CInfo::Keep() const { + return glue <= 2; +} + +} // namespace oracle +} // namespace sspp diff --git a/cryptominisat/cppsrc/src/oracle/utils.h b/cryptominisat/cppsrc/src/oracle/utils.h new file mode 100644 index 00000000..359d2847 --- /dev/null +++ b/cryptominisat/cppsrc/src/oracle/utils.h @@ -0,0 +1,91 @@ +// +// SharpSAT-TD -- Copyright (c) 2021 Tuukka Korhonen +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, +// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR +// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE +// OR OTHER DEALINGS IN THE SOFTWARE. + +#pragma once + +#include +#include +#include +#include +#include +#include +#include +#include + +namespace sspp { +typedef int Lit; +typedef int Var; + +using std::vector; +using std::string; + +inline Lit Neg(Lit x) { + return x^1; +} + +inline Var VarOf(Lit x) { + return x/2; +} + +inline Lit PosLit(Var x) { + return x*2; +} + +inline Lit NegLit(Var x) { + return x*2+1; +} + +inline Lit MkLit(Var var, bool phase) { + if (phase) { + return PosLit(var); + } else { + return NegLit(var); + } +} + +inline bool IsPos(Lit x) { + return !(x&1); +} + +inline bool IsNeg(Lit x) { + return x&1; +} + +inline vector Negate(vector vec) { + for (Lit& lit : vec) { + lit = Neg(lit); + } + return vec; +} + +template +inline T RandInt(T a, T b, std::mt19937& gen) { + return std::uniform_int_distribution(a,b)(gen); +} + +template +void SwapDel(vector& vec, size_t i) { + assert(i < vec.size()); + std::swap(vec[i], vec.back()); + vec.pop_back(); +} + +} // namespace sspp diff --git a/cryptominisat/cppsrc/src/packedmatrix.h b/cryptominisat/cppsrc/src/packedmatrix.h new file mode 100644 index 00000000..029a7c1a --- /dev/null +++ b/cryptominisat/cppsrc/src/packedmatrix.h @@ -0,0 +1,201 @@ +/****************************************** +Copyright (C) 2009-2020 Authors of CryptoMiniSat, see AUTHORS file +Copyright (c) 2012 Cheng-Shen Han +Copyright (c) 2012 Jie-Hong Roland Jiang + +For more information, see " When Boolean Satisfiability Meets Gaussian +Elimination in a Simplex Way." by Cheng-Shen Han and Jie-Hong Roland Jiang +in CAV (Computer Aided Verification), 2012: 410-426 + + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. +***********************************************/ + +#ifndef PACKEDMATRIX_H +#define PACKEDMATRIX_H + +#include +#include +#include "packedrow.h" + +//#define DEBUG_MATRIX + +namespace CMSat { + +class PackedMatrix +{ +public: + PackedMatrix() : + mp(NULL) + , numRows(0) + , numCols(0) + { + } + + ~PackedMatrix() + { + #ifdef _WIN32 + _aligned_free((void*)mp); + #else + free(mp); + #endif + } + + void resize(const uint32_t num_rows, uint32_t num_cols) + { + num_cols = num_cols / 64 + (bool)(num_cols % 64); + if (numRows*(numCols+1) < (int)num_rows*((int)num_cols+1)) { + size_t size = sizeof(int64_t) * num_rows*(num_cols+1); + #ifdef _WIN32 + _aligned_free((void*)mp); + mp = (int64_t*)_aligned_malloc(size, 16); + #else + free(mp); + int ret = posix_memalign((void**)&mp, 16, size); + release_assert(ret == 0); + #endif + } + + numRows = num_rows; + numCols = num_cols; + } + + void resizeNumRows(const uint32_t num_rows) + { + assert((int)num_rows <= numRows); + numRows = num_rows; + } + + PackedMatrix& operator=(const PackedMatrix& b) + { + if (numRows*(numCols+1) < b.numRows*(b.numCols+1)) { + size_t size = sizeof(int64_t) * b.numRows*(b.numCols+1); + #ifdef _WIN32 + _aligned_free((void*)mp); + mp = (int64_t*)_aligned_malloc(size, 16); + #else + free(mp); + int ret = posix_memalign((void**)&mp, 16, size); + release_assert(ret == 0); + #endif + } + numRows = b.numRows; + numCols = b.numCols; + memcpy(mp, b.mp, sizeof(int)*numRows*(numCols+1)); + + return *this; + } + + inline PackedRow operator[](const uint32_t i) + { + #ifdef DEBUG_MATRIX + assert(i <= numRows); + #endif + + return PackedRow(numCols, mp+i*(numCols+1)); + + } + + inline PackedRow operator[](const uint32_t i) const + { + #ifdef DEBUG_MATRIX + assert(i <= numRows); + #endif + + return PackedRow(numCols, mp+i*(numCols+1)); + } + + class iterator + { + public: + friend class PackedMatrix; + + PackedRow operator*() + { + return PackedRow(numCols, mp); + } + + iterator& operator++() + { + mp += (numCols+1); + return *this; + } + + iterator operator+(const uint32_t num) const + { + iterator ret(*this); + ret.mp += (numCols+1)*num; + return ret; + } + + uint32_t operator-(const iterator& b) const + { + return (mp - b.mp)/((numCols+1)); + } + + void operator+=(const uint32_t num) + { + mp += (numCols+1)*num; // add by f4 + } + + bool operator!=(const iterator& it) const + { + return mp != it.mp; + } + + bool operator==(const iterator& it) const + { + return mp == it.mp; + } + + private: + iterator(int64_t* _mp, const uint32_t _numCols) : + mp(_mp) + , numCols(_numCols) + {} + + int64_t *mp; + const uint32_t numCols; + }; + + inline iterator begin() + { + return iterator(mp, numCols); + } + + inline iterator end() + { + return iterator(mp+numRows*(numCols+1), numCols); + } + + inline uint32_t getSize() const + { + return numRows; + } + +private: + + int64_t *mp; + int numRows; + int numCols; +}; + +} + +#endif //PACKEDMATRIX_H diff --git a/cryptominisat/cppsrc/src/packedrow.cpp b/cryptominisat/cppsrc/src/packedrow.cpp new file mode 100644 index 00000000..cba85472 --- /dev/null +++ b/cryptominisat/cppsrc/src/packedrow.cpp @@ -0,0 +1,219 @@ +/****************************************** +Copyright (C) 2009-2020 Authors of CryptoMiniSat, see AUTHORS file +Copyright (c) 2012 Cheng-Shen Han +Copyright (c) 2012 Jie-Hong Roland Jiang + +For more information, see " When Boolean Satisfiability Meets Gaussian +Elimination in a Simplex Way." by Cheng-Shen Han and Jie-Hong Roland Jiang +in CAV (Computer Aided Verification), 2012: 410-426 + + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. +***********************************************/ + +#include "packedrow.h" + +// #define VERBOSE_DEBUG +// #define SLOW_DEBUG + +using namespace CMSat; + +#ifdef _MSC_VER +#include +#pragma intrinsic(_BitScanForward) +#pragma intrinsic(_BitScanForward64) +inline int scan_fwd_64b(int64_t value) +{ + unsigned long at; + unsigned char ret = _BitScanForward64(&at, value); + at++; + if (!ret) at = 0; + return at; +} +#else +inline int scan_fwd_64b(uint64_t value) +{ + return __builtin_ffsll(value); +} +#endif + +///returns popcnt +uint32_t PackedRow::find_watchVar( + vector& tmp_clause, + const vector& col_to_var, + vector &var_has_resp_row, + uint32_t& non_resp_var +) { + uint32_t popcnt = 0; + non_resp_var = numeric_limits::max(); + tmp_clause.clear(); + + for(int i = 0; i < size*64; i++) { + if (this->operator[](i)){ + popcnt++; + uint32_t var = col_to_var[i]; + tmp_clause.push_back(Lit(var, false)); + + if (!var_has_resp_row[var]) { + non_resp_var = var; + } else { + //What??? WARNING + //This var already has a responsible for it... + //How can it be 1??? + std::swap(tmp_clause[0], tmp_clause.back()); + } + } + } + assert(tmp_clause.size() == popcnt); + assert( popcnt == 0 || var_has_resp_row[ tmp_clause[0].var() ]) ; + return popcnt; +} + +void PackedRow::get_reason( + vector& tmp_clause, + [[maybe_unused]] const vector& assigns, + const vector& col_to_var, + PackedRow& cols_vals, + PackedRow& tmp_col2, + Lit prop +) { + tmp_col2.set_and(*this, cols_vals); + for (int i = 0; i < size; i++) if (mp[i]) { + int64_t tmp = mp[i]; + unsigned long at; + at = scan_fwd_64b(tmp); + int extra = 0; + while (at != 0) { + uint32_t col = extra + at-1 + i*64; + #ifdef SLOW_DEBUG + assert(this->operator[](col) == 1); + #endif + const uint32_t var = col_to_var[col]; + if (var == prop.var()) { + tmp_clause.push_back(prop); + std::swap(tmp_clause[0], tmp_clause.back()); + } else { + const bool val_bool = tmp_col2[col]; + tmp_clause.push_back(Lit(var, val_bool)); + } + + extra += at; + if (extra == 64) + break; + + tmp >>= at; + at = scan_fwd_64b(tmp); + } + } + + #ifdef SLOW_DEBUG + for(uint32_t i = 1; i < tmp_clause.size(); i++) { + assert(assigns[tmp_clause[i].var()] != l_Undef); + } + #endif +} + +gret PackedRow::propGause( + const vector& assigns, + const vector& col_to_var, + vector &var_has_resp_row, + uint32_t& new_resp_var, + PackedRow& tmp_col, + PackedRow& tmp_col2, + PackedRow& cols_vals, + PackedRow& cols_unset, + Lit& ret_lit_prop +) { + uint32_t pop = tmp_col.set_and_until_popcnt_atleast2(*this, cols_unset); + #ifdef VERBOSE_DEBUG + cout << "POP in GausE: " << pop << " row: " << endl; + cout << *this << endl; + cout << " cols_unset: " << endl; + cout << cols_unset << endl; + #endif + + //Find new watch + if (pop >= 2) { + for (int i = 0; i < size; i++) if (tmp_col.mp[i]) { + int64_t tmp = tmp_col.mp[i]; + unsigned long at; + at = scan_fwd_64b(tmp); + int extra = 0; + while (at != 0) { + uint32_t col = extra + at-1 + i*64; + #ifdef SLOW_DEBUG + assert(tmp_col[col] == 1); + #endif + const uint32_t var = col_to_var[col]; + + #ifdef SLOW_DEBUG + const lbool val = assigns[var]; + assert(val == l_Undef); + #endif + + // found new non-basic variable, let's watch it + if (!var_has_resp_row[var]) { + new_resp_var = var; + return gret::nothing_fnewwatch; + } + + extra += at; + if (extra == 64) + break; + + tmp >>= at; + at = scan_fwd_64b(tmp); + } + } + assert(false && "Should have found a new watch!"); + } + + //Calc value of row + tmp_col2.set_and(*this, cols_vals); + const uint32_t pop_t = tmp_col2.popcnt() + rhs(); + + //Lazy prop + if (pop == 1) { + for (int i = 0; i < size; i++) if (tmp_col.mp[i]) { + int at = scan_fwd_64b(tmp_col.mp[i]); + + // found prop + uint32_t col = at-1 + i*64; + #ifdef SLOW_DEBUG + assert(tmp_col[col] == 1); + #endif + const uint32_t var = col_to_var[col]; + assert(assigns[var] == l_Undef); + ret_lit_prop = Lit(var, !(pop_t % 2)); + return gret::prop; + } + assert(false && "Should have found the propagating literal!"); + } + + //Only SAT & UNSAT left. + assert(pop == 0); + + //Satisfied + if (pop_t % 2 == 0) { + return gret::nothing_satisfied; + } + + //Conflict + return gret::confl; +} diff --git a/cryptominisat/cppsrc/src/packedrow.h b/cryptominisat/cppsrc/src/packedrow.h new file mode 100644 index 00000000..a6f403b3 --- /dev/null +++ b/cryptominisat/cppsrc/src/packedrow.h @@ -0,0 +1,320 @@ +/****************************************** +Copyright (C) 2009-2020 Authors of CryptoMiniSat, see AUTHORS file +Copyright (c) 2012 Cheng-Shen Han +Copyright (c) 2012 Jie-Hong Roland Jiang + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. +***********************************************/ + +#pragma once + +//#define DEBUG_ROW + +#include +#include +#include +#include +#include +#include + +#include "solvertypes.h" +#include "Vec.h" + +namespace CMSat { + +using std::vector; + +class PackedMatrix; +class EGaussian; + +class PackedRow +{ +public: + PackedRow() = delete; + PackedRow& operator=(const PackedRow& b) + { + #ifdef DEBUG_ROW + assert(size > 0); + assert(b.size > 0); + assert(b.size == size); + #endif + + //start from -1, because that's wher RHS is + for (int i = -1; i < size; i++) { + *(mp + i) = *(b.mp + i); + } + + return *this; + } + + PackedRow& operator^=(const PackedRow& b) + { + #ifdef DEBUG_ROW + assert(size > 0); + assert(b.size > 0); + assert(b.size == size); + #endif + + //start from -1, because that's wher RHS is + for (int i = -1; i < size; i++) { + *(mp + i) ^= *(b.mp + i); + } + + return *this; + } + + void and_inv(const PackedRow& b) + { + #ifdef DEBUG_ROW + assert(size > 0); + assert(b.size > 0); + assert(b.size == size); + #endif + + for (int i = 0; i < size; i++) { + *(mp + i) &= ~(*(b.mp + i)); + } + } + + void set_and_inv(const PackedRow& a, const PackedRow& b) + { + #ifdef DEBUG_ROW + assert(size > 0); + assert(b.size > 0); + assert(b.size == size); + #endif + + for (int i = 0; i < size; i++) { + *(mp + i) = *(a.mp + i) & (~(*(b.mp + i))); + } + } + + void set_and(const PackedRow& a, const PackedRow& b) + { + #ifdef DEBUG_ROW + assert(size > 0); + assert(b.size > 0); + assert(b.size == size); + #endif + + for (int i = 0; i < size; i++) { + *(mp + i) = *(a.mp + i) & *(b.mp + i); + } + } + + uint32_t set_and_until_popcnt_atleast2(const PackedRow& a, const PackedRow& b) + { + #ifdef DEBUG_ROW + assert(size > 0); + assert(b.size > 0); + assert(b.size == size); + #endif + + uint32_t pop = 0; + for (int i = 0; i < size && pop < 2; i++) { + *(mp + i) = *(a.mp + i) & *(b.mp + i); + pop += __builtin_popcountll((uint64_t)*(mp + i)); + } + + return pop; + } + + void xor_in(const PackedRow& b) + { + #ifdef DEBUG_ROW + assert(size > 0); + assert(b.size > 0); + assert(b.size == size); + #endif + + rhs_internal ^= b.rhs_internal; + for (int i = 0; i < size; i++) { + *(mp + i) ^= *(b.mp + i); + } + } + + inline const int64_t& rhs() const + { + return rhs_internal; + } + + inline int64_t& rhs() + { + return rhs_internal; + } + + inline bool isZero() const + { + for (int i = 0; i < size; i++) { + if (mp[i]) return false; + } + return true; + } + + inline void setZero() + { + memset(mp, 0, sizeof(int64_t)*size); + } + + inline void setOne() + { + memset(mp, 0xff, sizeof(int64_t)*size); + } + + inline void clearBit(const uint32_t i) + { + mp[i/64] &= ~(1LL << (i%64)); + } + + inline void setBit(const uint32_t i) + { + //SetBit(mp+i/64, i%64); + mp[i/64] |= (1LL << (i%64)); + } + + inline void invert_rhs(const bool b = true) + { + rhs_internal ^= (int)b; + } + + void swapBoth(PackedRow b) + { + #ifdef DEBUG_ROW + assert(size > 0); + assert(b.size > 0); + assert(b.size == size); + #endif + + int64_t* __restrict mp1 = mp-1; + int64_t* __restrict mp2 = b.mp-1; + + uint32_t i = size+1; + while(i != 0) { + std::swap(*mp1, *mp2); + mp1++; + mp2++; + i--; + } + } + + inline bool operator[](const uint32_t i) const + { + #ifdef DEBUG_ROW + assert(size*64 > i); + #endif + + return (mp[i/64] >> (i%64)) & 1; + } + + template + void set( + const T& v, + const vector& var_to_col, + const uint32_t num_cols) + { + assert(size == ((int)num_cols/64) + ((bool)(num_cols % 64))); + + setZero(); + for (uint32_t i = 0; i != v.size(); i++) { + const uint32_t toset_var = var_to_col[v[i]]; + assert(toset_var != numeric_limits::max()); + + setBit(toset_var); + } + + rhs_internal = v.rhs; + } + + // using find nonbasic and basic value + uint32_t find_watchVar( + vector& tmp_clause, + const vector& col_to_var, + vector &var_has_resp_row, + uint32_t& non_resp_var); + + // using find nonbasic value after watch list is enter + gret propGause( + const vector& assigns, + const vector& col_to_var, + vector &var_has_resp_row, + uint32_t& new_resp_var, + PackedRow& tmp_col, + PackedRow& tmp_col2, + PackedRow& cols_vals, + PackedRow& cols_unset, + Lit& ret_lit_prop + ); + + void get_reason( + vector& tmp_clause, + const vector& assigns, + const vector& col_to_var, + PackedRow& cols_vals, + PackedRow& tmp_col2, + Lit prop + ); + + uint32_t popcnt() const; + uint32_t popcnt_at_least_2() const; + +private: + friend class PackedMatrix; + friend class EGaussian; + friend std::ostream& operator << (std::ostream& os, const PackedRow& m); + + PackedRow(const uint32_t _size, int64_t* const _mp) : + mp(_mp+1) + , rhs_internal(*_mp) + , size(_size) + {} + + //int __attribute__ ((aligned (16))) *const mp; + int64_t *__restrict const mp; + int64_t& rhs_internal; + const int size; +}; + +inline std::ostream& operator << (std::ostream& os, const PackedRow& m) +{ + for(int i = 0; i < m.size*64; i++) { + os << (int)m[i]; + } + os << " -- rhs: " << m.rhs(); + return os; +} + +inline uint32_t PackedRow::popcnt_at_least_2() const +{ + uint32_t ret = 0; + for (int i = 0; i < size && ret < 2; i++) { + ret += __builtin_popcountll((uint64_t)mp[i]); + } + return ret; +} + +inline uint32_t PackedRow::popcnt() const +{ + uint32_t ret = 0; + for (int i = 0; i < size; i++) { + ret += __builtin_popcountll((uint64_t)mp[i]); + } + return ret; +} + +} diff --git a/cryptominisat/cppsrc/src/picosat/LICENSE b/cryptominisat/cppsrc/src/picosat/LICENSE new file mode 100644 index 00000000..96739de2 --- /dev/null +++ b/cryptominisat/cppsrc/src/picosat/LICENSE @@ -0,0 +1,20 @@ +Copyright (c) 2006 - 2014, Armin Biere, Johannes Kepler University. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to +deal in the Software without restriction, including without limitation the +rights to use, copy, modify, merge, publish, distribute, sublicense, and/or +sell copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS +IN THE SOFTWARE. + diff --git a/cryptominisat/cppsrc/src/picosat/NEWS b/cryptominisat/cppsrc/src/picosat/NEWS new file mode 100644 index 00000000..7ad60b53 --- /dev/null +++ b/cryptominisat/cppsrc/src/picosat/NEWS @@ -0,0 +1,162 @@ +news for release 965 since 959 +------------------------------ + +* ADC code works again (spotted by Himanshu Jain) +* include into R projects (with Christoph Muessel) (--rcode) +* fixed 'undefined' + 'ptrdiff_' issues (thanks to Christoph Muessel) +* added 'picosat_set_interrupt' and '-a ' command line option +* fixed various issues pointed out by Stefan Hengelein: + - fixed incremental usage of 'picosat_adjust' + - added CPP fixes (STATS, NO_BINARY_CLAUSE versus TRACE mix-ups) + - removed redundant explicit set to zero on reset +* fixed various usage bugs with 'picomus' (thanks to Stefan Hengelein) +* removed '-fno-strict-aliasing' (thanks to Jerry James) + +news for release 959 since 953 +------------------------------ + +* fixed header comments + +* fixed minor compilation issues + +* fixed unitialized memory access problem for 'picosat_deref_partial' + and another issue with partial models + +* added 'picosat_add_arg' and 'picosat_add_lits' + +* '--plain' and 'picosat_set_plain' to disable failed literal probing + +* new '#define PICOSAT_REENTRANT_API' in 'picosat.h' + +* added manager so no more global variables + (allows multiple instances, requires manager object) + +news for release 951 since 941 +------------------------------ + +* cleaned up code (based on comments by Donald Knuth) + +* lreduce=O(conflicts^.5) + +* added 'picosat_visits' and 'picosat_decisions' + +* added '--partial' command line option + +* added 'picosat_deref_partial' and 'picosat_save_original_clauses' + +* added 'picomcs' as example for MSS computation + +news for release 941 since 936 +------------------------------ + +* added 'picogcnf' + +* added All-SAT mode ('--all' command line option) + +* statistics include time spent in failed literal preprocessing (probing) + +* 'picosat_failed_context' for 'push & pop' + (and tested failed assumptions for 'push & pop') + +* 'picosat_simplify' for forced garbage collection + +* undefined NFL, defined NADC (= failed literals on, ADC's off) + +* 'picosat_push' and 'picosat_pop' (beta version) + +* fixed some issues related to binary clause handling and + generating list of failed assumptions + +news for release 936 since 935 +------------------------------ + +* simple minimal unsatisfiable core (MUS) extractor 'picomus' + (example for using 'picosat_mus_assumptions' and 'picosat_coreclause') + +* added 'picosat_mus_assumptions' + +* added 'picosat_{set_}propagations' + +* new 'int' return value for 'picosat_enable_trace_generation' to + check for trace code being compiled + +news for release 935 since 926 +------------------------------ + +* added 'picosat_failed_assumptions' (plural) + +* new '-A ' command line option + +* fixed failed assumption issues + +* added 'picosat_remove_learned' + +* added 'picosat_reset_{phases,scores}' + +* added 'picosat_set_less_important_lit' + +* added 'picosat_res' + +news for release 926 since 846 +------------------------------ + +* random initial phase (API of 'picosat_set_default_phase' changed) + +* fixed accumulative failed assumption (multiple times) + +* fixed missing original clause in core generation with assumptions + +* fixed debugging code for memory allocation + +* shared library in addition to static library + +* removed potential UNKNOWN result without decision limit + +* added picosat_set_more_important_lit + +* added picosat_coreclause + +* propagation of binary clauses until completion + +* fixed API usage 'assume;sat;sat' + +* literals move to front (LMTF) during traversal of visited clauses + +* switched from inner/outer to Luby style restart scheduling + +* less agressive reduce schedule + +* replaced watched literals with head and tail pointers + +* add 'picosat_failed_assumption', which allows to avoid tracing and core + generation, if one is only interested in assumptions in the core + +* fixed a BUG in the generic iterator code of clauses + (should rarely happen unless you use a very sophisticated malloc lib) + +news for release 846 since 632 +------------------------------ + +* cleaned up assumption handling (actually removed buggy optimization) + +* incremental core generation + +* experimental 'all different constraint' handling as in our FMCAD'08 paper + +* new API calls: + + - picosat_add_ado_lit (add all different object literal) + - picosat_deref_top_level (deref top level assignment) + - picosat_changed (check whether extension was possible) + - picosat_measure_all_calls (per default do not measure adding time) + - picosat_set_prefix (set prefix for messages) + +* 64 bit port (and compilation options) + +* optional NVSIDS visualization code + +* resource controlled failed literal implementation + +* disconnect long clauses satisfied at lower decision level + +* controlling restarts diff --git a/cryptominisat/cppsrc/src/picosat/README b/cryptominisat/cppsrc/src/picosat/README new file mode 100644 index 00000000..05b84396 --- /dev/null +++ b/cryptominisat/cppsrc/src/picosat/README @@ -0,0 +1,5 @@ +These are the sources of the PicoSAT solver. +The preprocessor is not included. +To compile run './configure.sh && make'. +The API is document in 'picosat.h'. +See also 'NEWS' and 'LICENSE'. diff --git a/cryptominisat/cppsrc/src/picosat/main.c b/cryptominisat/cppsrc/src/picosat/main.c new file mode 100644 index 00000000..03fad79f --- /dev/null +++ b/cryptominisat/cppsrc/src/picosat/main.c @@ -0,0 +1,7 @@ +int picosat_main (int, char **); + +int +main (int argc, char **argv) +{ + return picosat_main (argc, argv); +} diff --git a/cryptominisat/cppsrc/src/picosat/pico_config.h b/cryptominisat/cppsrc/src/picosat/pico_config.h new file mode 100644 index 00000000..884a557a --- /dev/null +++ b/cryptominisat/cppsrc/src/picosat/pico_config.h @@ -0,0 +1,3 @@ +#define PICOSAT_CC "gcc" +#define PICOSAT_CFLAGS "-Wall -Wextra -DNDEBUG -O3" +#define PICOSAT_VERSION "965 3433fe9a1baf1f7872a641e6ee1b549ddd977d86" diff --git a/cryptominisat/cppsrc/src/picosat/picosat.c b/cryptominisat/cppsrc/src/picosat/picosat.c new file mode 100644 index 00000000..f0a9e331 --- /dev/null +++ b/cryptominisat/cppsrc/src/picosat/picosat.c @@ -0,0 +1,8504 @@ +/**************************************************************************** +Copyright (c) 2006 - 2015, Armin Biere, Johannes Kepler University. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to +deal in the Software without restriction, including without limitation the +rights to use, copy, modify, merge, publish, distribute, sublicense, and/or +sell copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS +IN THE SOFTWARE. +****************************************************************************/ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "picosat.h" + +/* By default code for 'all different constraints' is disabled, since 'NADC' + * is defined. + */ +#define NADC + +/* By default we enable failed literals, since 'NFL' is undefined. + * +#define NFL + */ + +/* By default we 'detach satisfied (large) clauses', e.g. NDSC undefined. + * +#define NDSC + */ + +/* Do not use luby restart schedule instead of inner/outer. + * +#define NLUBY + */ + +/* Enabling this define, will use gnuplot to visualize how the scores evolve. + * +#define VISCORES + */ +#ifdef VISCORES +// #define WRITEGIF /* ... to generate a video */ +#endif + +#ifdef VISCORES +#ifndef WRITEGIF +#include /* for 'usleep' */ +#endif +#endif + +#ifdef RCODE +#include +#endif + +#define MINRESTART 100 /* minimum restart interval */ +#define MAXRESTART 1000000 /* maximum restart interval */ +#define RDECIDE 1000 /* interval of random decisions */ +#define FRESTART 110 /* restart increase factor in percent */ +#define FREDUCE 110 /* reduce increase factor in percent */ +#define FREDADJ 121 /* reduce increase adjustment factor */ +#define MAXCILS 10 /* maximal number of unrecycled internals */ +#define FFLIPPED 10000 /* flipped reduce factor */ +#define FFLIPPEDPREC 10000000/* flipped reduce factor precision */ +#define INTERRUPTLIM 1024 /* check interrupt after that many decisions */ + +#ifndef TRACE +#define NO_BINARY_CLAUSES /* store binary clauses more compactly */ +#endif + +/* For debugging purposes you may want to define 'LOGGING', which actually + * can be enforced by using './configure.sh --log'. + */ +#ifdef LOGGING +#define LOG(code) do { code; } while (0) +#else +#define LOG(code) do { } while (0) +#endif +#define NOLOG(code) do { } while (0) /* log exception */ +#define ONLYLOG(code) do { code; } while (0) /* force logging */ + +#define FALSE ((Val)-1) +#define UNDEF ((Val)0) +#define TRUE ((Val)1) + +#define COMPACT_TRACECHECK_TRACE_FMT 0 +#define EXTENDED_TRACECHECK_TRACE_FMT 1 +#define RUP_TRACE_FMT 2 + +#define NEWN(p,n) do { (p) = new (ps, sizeof (*(p)) * (n)); } while (0) +#define CLRN(p,n) do { memset ((p), 0, sizeof (*(p)) * (n)); } while (0) +#define CLR(p) CLRN(p,1) +#define DELETEN(p,n) \ + do { delete (ps, p, sizeof (*(p)) * (n)); (p) = 0; } while (0) + +#define RESIZEN(p,old_num,new_num) \ + do { \ + size_t old_size = sizeof (*(p)) * (old_num); \ + size_t new_size = sizeof (*(p)) * (new_num); \ + (p) = resize (ps, (p), old_size, new_size) ; \ + } while (0) + +#define ENLARGE(start,head,end) \ + do { \ + unsigned old_num = (ptrdiff_t)((end) - (start)); \ + size_t new_num = old_num ? (2 * old_num) : 1; \ + unsigned count = (head) - (start); \ + assert ((start) <= (end)); \ + RESIZEN((start),old_num,new_num); \ + (head) = (start) + count; \ + (end) = (start) + new_num; \ + } while (0) + +#define NOTLIT(l) (ps->lits + (1 ^ ((l) - ps->lits))) + +#define LIT2IDX(l) ((ptrdiff_t)((l) - ps->lits) / 2) +#define LIT2IMPLS(l) (ps->impls + (ptrdiff_t)((l) - ps->lits)) +#define LIT2INT(l) ((int)(LIT2SGN(l) * LIT2IDX(l))) +#define LIT2SGN(l) (((ptrdiff_t)((l) - ps->lits) & 1) ? -1 : 1) +#define LIT2VAR(l) (ps->vars + LIT2IDX(l)) +#define LIT2HTPS(l) (ps->htps + (ptrdiff_t)((l) - ps->lits)) +#define LIT2JWH(l) (ps->jwh + ((l) - ps->lits)) + +#ifndef NDSC +#define LIT2DHTPS(l) (ps->dhtps + (ptrdiff_t)((l) - ps->lits)) +#endif + +#ifdef NO_BINARY_CLAUSES +typedef uintptr_t Wrd; +#define ISLITREASON(C) (1&(Wrd)C) +#define LIT2REASON(L) \ + (assert (L->val==TRUE), ((Cls*)(1 + (2*(L - ps->lits))))) +#define REASON2LIT(C) ((Lit*)(ps->lits + ((Wrd)C)/2)) +#endif + +#define ENDOFCLS(c) ((void*)((Lit**)(c)->lits + (c)->size)) + +#define SOC ((ps->oclauses == ps->ohead) ? ps->lclauses : ps->oclauses) +#define EOC (ps->lhead) +#define NXC(p) (((p) + 1 == ps->ohead) ? ps->lclauses : (p) + 1) + +#define OIDX2IDX(idx) (2 * ((idx) + 1)) +#define LIDX2IDX(idx) (2 * (idx) + 1) + +#define ISLIDX(idx) ((idx)&1) + +#define IDX2OIDX(idx) (assert(!ISLIDX(idx)), (idx)/2 - 1) +#define IDX2LIDX(idx) (assert(ISLIDX(idx)), (idx)/2) + +#define EXPORTIDX(idx) \ + ((ISLIDX(idx) ? (IDX2LIDX (idx) + (ps->ohead - ps->oclauses)) : IDX2OIDX(idx)) + 1) + +#define IDX2CLS(i) \ + (assert(i), (ISLIDX(i) ? ps->lclauses : ps->oclauses)[(i)/2 - !ISLIDX(i)]) + +#define IDX2ZHN(i) (assert(i), (ISLIDX(i) ? ps->zhains[(i)/2] : 0)) + +#define CLS2TRD(c) (((Trd*)(c)) - 1) +#define CLS2IDX(c) ((((Trd*)(c)) - 1)->idx) + +#define CLS2ACT(c) \ + ((Act*)((assert((c)->learned)),assert((c)->size>2),ENDOFCLS(c))) + +#define VAR2LIT(v) (ps->lits + 2 * ((v) - ps->vars)) +#define VAR2RNK(v) (ps->rnks + ((v) - ps->vars)) + +#define RNK2LIT(r) (ps->lits + 2 * ((r) - ps->rnks)) +#define RNK2VAR(r) (ps->vars + ((r) - ps->rnks)) + +#define BLK_FILL_BYTES 8 +#define SIZE_OF_BLK (sizeof (Blk) - BLK_FILL_BYTES) + +#define PTR2BLK(void_ptr) \ + ((void_ptr) ? (Blk*)(((char*)(void_ptr)) - SIZE_OF_BLK) : 0) + +#define AVERAGE(a,b) ((b) ? (((double)a) / (double)(b)) : 0.0) +#define PERCENT(a,b) (100.0 * AVERAGE(a,b)) + +#ifndef RCODE +#define ABORT(msg) \ + do { \ + fputs ("*** picosat: " msg "\n", stderr); \ + abort (); \ + } while (0) +#else +#define ABORT(msg) \ + do { \ + Rf_error (msg); \ + } while (0) +#endif + +#define ABORTIF(cond,msg) \ + do { \ + if (!(cond)) break; \ + ABORT (msg); \ + } while (0) + +#define ZEROFLT (0x00000000u) +#define EPSFLT (0x00000001u) +#define INFFLT (0xffffffffu) + +#define FLTCARRY (1u << 25) +#define FLTMSB (1u << 24) +#define FLTMAXMANTISSA (FLTMSB - 1) + +#define FLTMANTISSA(d) ((d) & FLTMAXMANTISSA) +#define FLTEXPONENT(d) ((int)((d) >> 24) - 128) + +#define FLTMINEXPONENT (-128) +#define FLTMAXEXPONENT (127) + +#define CMPSWAPFLT(a,b) \ + do { \ + Flt tmp; \ + if (((a) < (b))) \ + { \ + tmp = (a); \ + (a) = (b); \ + (b) = tmp; \ + } \ + } while (0) + +#define UNPACKFLT(u,m,e) \ + do { \ + (m) = FLTMANTISSA(u); \ + (e) = FLTEXPONENT(u); \ + (m) |= FLTMSB; \ + } while (0) + +#define INSERTION_SORT_LIMIT 10 + +#define SORTING_SWAP(T,p,q) \ +do { \ + T tmp = *(q); \ + *(q) = *(p); \ + *(p) = tmp; \ +} while (0) + +#define SORTING_CMP_SWAP(T,cmp,p,q) \ +do { \ + if ((cmp) (ps, *(p), *(q)) > 0) \ + SORTING_SWAP (T, p, q); \ +} while(0) + +#define QUICKSORT_PARTITION(T,cmp,a,l,r) \ +do { \ + T pivot; \ + int j; \ + i = (l) - 1; /* result in 'i' */ \ + j = (r); \ + pivot = (a)[j]; \ + for (;;) \ + { \ + while ((cmp) (ps, (a)[++i], pivot) < 0) \ + ; \ + while ((cmp) (ps, pivot, (a)[--j]) < 0) \ + if (j == (l)) \ + break; \ + if (i >= j) \ + break; \ + SORTING_SWAP (T, (a) + i, (a) + j); \ + } \ + SORTING_SWAP (T, (a) + i, (a) + (r)); \ +} while(0) + +#define QUICKSORT(T,cmp,a,n) \ +do { \ + int l = 0, r = (n) - 1, m, ll, rr, i; \ + assert (ps->ihead == ps->indices); \ + if (r - l <= INSERTION_SORT_LIMIT) \ + break; \ + for (;;) \ + { \ + m = (l + r) / 2; \ + SORTING_SWAP (T, (a) + m, (a) + r - 1); \ + SORTING_CMP_SWAP (T, cmp, (a) + l, (a) + r - 1); \ + SORTING_CMP_SWAP (T, cmp, (a) + l, (a) + r); \ + SORTING_CMP_SWAP (T, cmp, (a) + r - 1, (a) + r); \ + QUICKSORT_PARTITION (T, cmp, (a), l + 1, r - 1); \ + if (i - l < r - i) \ + { \ + ll = i + 1; \ + rr = r; \ + r = i - 1; \ + } \ + else \ + { \ + ll = l; \ + rr = i - 1; \ + l = i + 1; \ + } \ + if (r - l > INSERTION_SORT_LIMIT) \ + { \ + assert (rr - ll > INSERTION_SORT_LIMIT); \ + if (ps->ihead == ps->eoi) \ + ENLARGE (ps->indices, ps->ihead, ps->eoi); \ + *ps->ihead++ = ll; \ + if (ps->ihead == ps->eoi) \ + ENLARGE (ps->indices, ps->ihead, ps->eoi); \ + *ps->ihead++ = rr; \ + } \ + else if (rr - ll > INSERTION_SORT_LIMIT) \ + { \ + l = ll; \ + r = rr; \ + } \ + else if (ps->ihead > ps->indices) \ + { \ + r = *--ps->ihead; \ + l = *--ps->ihead; \ + } \ + else \ + break; \ + } \ +} while (0) + +#define INSERTION_SORT(T,cmp,a,n) \ +do { \ + T pivot; \ + int l = 0, r = (n) - 1, i, j; \ + for (i = r; i > l; i--) \ + SORTING_CMP_SWAP (T, cmp, (a) + i - 1, (a) + i); \ + for (i = l + 2; i <= r; i++) \ + { \ + j = i; \ + pivot = (a)[i]; \ + while ((cmp) (ps, pivot, (a)[j - 1]) < 0) \ + { \ + (a)[j] = (a)[j - 1]; \ + j--; \ + } \ + (a)[j] = pivot; \ + } \ +} while (0) + +#ifdef NDEBUG +#define CHECK_SORTED(cmp,a,n) do { } while(0) +#else +#define CHECK_SORTED(cmp,a,n) \ +do { \ + int i; \ + for (i = 0; i < (n) - 1; i++) \ + assert ((cmp) (ps, (a)[i], (a)[i + 1]) <= 0); \ +} while(0) +#endif + +#define SORT(T,cmp,a,n) \ +do { \ + T * aa = (a); \ + int nn = (n); \ + QUICKSORT (T, cmp, aa, nn); \ + INSERTION_SORT (T, cmp, aa, nn); \ + assert (ps->ihead == ps->indices); \ + CHECK_SORTED (cmp, aa, nn); \ +} while (0) + +#define WRDSZ (sizeof (long) * 8) + +#ifdef RCODE +#define fprintf(...) do { } while (0) +#define vfprintf(...) do { } while (0) +#define fputs(...) do { } while (0) +#define fputc(...) do { } while (0) +#endif + +typedef unsigned Flt; /* 32 bit deterministic soft float */ +typedef Flt Act; /* clause and variable activity */ +typedef struct Blk Blk; /* allocated memory block */ +typedef struct Cls Cls; /* clause */ +typedef struct Lit Lit; /* literal */ +typedef struct Rnk Rnk; /* variable to score mapping */ +typedef signed char Val; /* TRUE, UNDEF, FALSE */ +typedef struct Var Var; /* variable */ +#ifdef TRACE +typedef struct Trd Trd; /* trace data for clauses */ +typedef struct Zhn Zhn; /* compressed chain (=zain) data */ +typedef unsigned char Znt; /* compressed antecedent data */ +#endif + +#ifdef NO_BINARY_CLAUSES +typedef struct Ltk Ltk; + +struct Ltk +{ + Lit ** start; + unsigned count : WRDSZ == 32 ? 27 : 32; + unsigned ldsize : WRDSZ == 32 ? 5 : 32; +}; +#endif + +struct Lit +{ + Val val; +}; + +struct Var +{ + unsigned mark : 1; /*bit 1*/ + unsigned resolved : 1; /*bit 2*/ + unsigned phase : 1; /*bit 3*/ + unsigned assigned : 1; /*bit 4*/ + unsigned used : 1; /*bit 5*/ + unsigned failed : 1; /*bit 6*/ + unsigned internal : 1; /*bit 7*/ + unsigned usedefphase : 1; /*bit 8*/ + unsigned defphase : 1; /*bit 9*/ + unsigned msspos : 1; /*bit 10*/ + unsigned mssneg : 1; /*bit 11*/ + unsigned humuspos : 1; /*bit 12*/ + unsigned humusneg : 1; /*bit 13*/ + unsigned partial : 1; /*bit 14*/ +#ifdef TRACE + unsigned core : 1; /*bit 15*/ +#endif + unsigned level; + Cls *reason; +#ifndef NADC + Lit ** inado; + Lit ** ado; + Lit *** adotabpos; +#endif +}; + +struct Rnk +{ + Act score; + unsigned pos : 30; /* 0 iff not on heap */ + unsigned moreimportant : 1; + unsigned lessimportant : 1; +}; + +struct Cls +{ + unsigned size; + + unsigned collect:1; /* bit 1 */ + unsigned learned:1; /* bit 2 */ + unsigned locked:1; /* bit 3 */ + unsigned used:1; /* bit 4 */ +#ifndef NDEBUG + unsigned connected:1; /* bit 5 */ +#endif +#ifdef TRACE + unsigned collected:1; /* bit 6 */ + unsigned core:1; /* bit 7 */ +#endif + +#define LDMAXGLUE 25 /* 32 - 7 */ +#define MAXGLUE ((1<= FLTCARRY) + { + if (e >= FLTMAXEXPONENT) + return INFFLT; + + e++; + m >>= 1; + } + } + + m &= ~FLTMSB; + return packflt (m, e); +} + +static Flt +addflt (Flt a, Flt b) +{ + unsigned ma, mb, delta; + int ea, eb; + + CMPSWAPFLT (a, b); + if (!b) + return a; + + UNPACKFLT (a, ma, ea); + UNPACKFLT (b, mb, eb); + + assert (ea >= eb); + delta = ea - eb; + if (delta < 32) mb >>= delta; else mb = 0; + if (!mb) + return a; + + ma += mb; + if (ma & FLTCARRY) + { + if (ea == FLTMAXEXPONENT) + return INFFLT; + + ea++; + ma >>= 1; + } + + assert (ma < FLTCARRY); + ma &= FLTMAXMANTISSA; + + return packflt (ma, ea); +} + +static Flt +mulflt (Flt a, Flt b) +{ + unsigned ma, mb; + unsigned long long accu; + int ea, eb; + + CMPSWAPFLT (a, b); + if (!b) + return ZEROFLT; + + UNPACKFLT (a, ma, ea); + UNPACKFLT (b, mb, eb); + + ea += eb; + ea += 24; + if (ea > FLTMAXEXPONENT) + return INFFLT; + + if (ea < FLTMINEXPONENT) + return EPSFLT; + + accu = ma; + accu *= mb; + accu >>= 24; + + if (accu >= FLTCARRY) + { + if (ea == FLTMAXEXPONENT) + return INFFLT; + + ea++; + accu >>= 1; + + if (accu >= FLTCARRY) + return INFFLT; + } + + assert (accu < FLTCARRY); + assert (accu & FLTMSB); + + ma = accu; + ma &= ~FLTMSB; + + return packflt (ma, ea); +} + +static Flt +ascii2flt (const char *str) +{ + Flt ten = base2flt (10, 0); + Flt onetenth = base2flt (26843546, -28); + Flt res = ZEROFLT, tmp, base; + const char *p = str; + int ch; + + ch = *p++; + + if (ch != '.') + { + if (!isdigit (ch)) + return INFFLT; /* better abort ? */ + + res = base2flt (ch - '0', 0); + + while ((ch = *p++)) + { + if (ch == '.') + break; + + if (!isdigit (ch)) + return INFFLT; /* better abort? */ + + res = mulflt (res, ten); + tmp = base2flt (ch - '0', 0); + res = addflt (res, tmp); + } + } + + if (ch == '.') + { + ch = *p++; + if (!isdigit (ch)) + return INFFLT; /* better abort ? */ + + base = onetenth; + tmp = mulflt (base2flt (ch - '0', 0), base); + res = addflt (res, tmp); + + while ((ch = *p++)) + { + if (!isdigit (ch)) + return INFFLT; /* better abort? */ + + base = mulflt (base, onetenth); + tmp = mulflt (base2flt (ch - '0', 0), base); + res = addflt (res, tmp); + } + } + + return res; +} + +#if defined(VISCORES) + +static double +flt2double (Flt f) +{ + double res; + unsigned m; + int e, i; + + UNPACKFLT (f, m, e); + res = m; + + if (e < 0) + { + for (i = e; i < 0; i++) + res *= 0.5; + } + else + { + for (i = 0; i < e; i++) + res *= 2.0; + } + + return res; +} + +#endif + +static int +log2flt (Flt a) +{ + return FLTEXPONENT (a) + 24; +} + +static int +cmpflt (Flt a, Flt b) +{ + if (a < b) + return -1; + + if (a > b) + return 1; + + return 0; +} + +static void * +new (PS * ps, size_t size) +{ + size_t bytes; + Blk *b; + + if (!size) + return 0; + + bytes = size + SIZE_OF_BLK; + + if (ps->enew) + b = ps->enew (ps->emgr, bytes); + else + b = malloc (bytes); + + ABORTIF (!b, "out of memory in 'new'"); +#ifndef NDEBUG + b->header.size = size; +#endif + ps->current_bytes += size; + if (ps->current_bytes > ps->max_bytes) + ps->max_bytes = ps->current_bytes; + return b->data; +} + +static void +delete (PS * ps, void *void_ptr, size_t size) +{ + size_t bytes; + Blk *b; + + if (!void_ptr) + { + assert (!size); + return; + } + + assert (size); + b = PTR2BLK (void_ptr); + + assert (size <= ps->current_bytes); + ps->current_bytes -= size; + + assert (b->header.size == size); + + bytes = size + SIZE_OF_BLK; + if (ps->edelete) + ps->edelete (ps->emgr, b, bytes); + else + free (b); +} + +static void * +resize (PS * ps, void *void_ptr, size_t old_size, size_t new_size) +{ + size_t old_bytes, new_bytes; + Blk *b; + + b = PTR2BLK (void_ptr); + + assert (old_size <= ps->current_bytes); + ps->current_bytes -= old_size; + + if ((old_bytes = old_size)) + { + assert (old_size && b && b->header.size == old_size); + old_bytes += SIZE_OF_BLK; + } + else + assert (!b); + + if ((new_bytes = new_size)) + new_bytes += SIZE_OF_BLK; + + if (ps->eresize) + b = ps->eresize (ps->emgr, b, old_bytes, new_bytes); + else + b = realloc (b, new_bytes); + + if (!new_size) + { + assert (!b); + return 0; + } + + ABORTIF (!b, "out of memory in 'resize'"); +#ifndef NDEBUG + b->header.size = new_size; +#endif + + ps->current_bytes += new_size; + if (ps->current_bytes > ps->max_bytes) + ps->max_bytes = ps->current_bytes; + + return b->data; +} + +static unsigned +int2unsigned (int l) +{ + return (l < 0) ? 1 + 2 * -l : 2 * l; +} + +static Lit * +int2lit (PS * ps, int l) +{ + return ps->lits + int2unsigned (l); +} + +static Lit ** +end_of_lits (Cls * c) +{ + return (Lit**)c->lits + c->size; +} + +#if !defined(NDEBUG) || defined(LOGGING) + +static void +dumplits (PS * ps, Lit ** l, Lit ** end) +{ + int first; + Lit ** p; + + if (l == end) + { + /* empty clause */ + } + else if (l + 1 == end) + { + fprintf (ps->out, "%d ", LIT2INT (l[0])); + } + else + { + assert (l + 2 <= end); + first = (abs (LIT2INT (l[0])) > abs (LIT2INT (l[1]))); + fprintf (ps->out, "%d ", LIT2INT (l[first])); + fprintf (ps->out, "%d ", LIT2INT (l[!first])); + for (p = l + 2; p < end; p++) + fprintf (ps->out, "%d ", LIT2INT (*p)); + } + + fputc ('0', ps->out); +} + +static void +dumpcls (PS * ps, Cls * c) +{ + Lit **end; + + if (c) + { + end = end_of_lits (c); + dumplits (ps, c->lits, end); +#ifdef TRACE + if (ps->trace) + fprintf (ps->out, " clause(%u)", CLS2IDX (c)); +#endif + } + else + fputs ("DECISION", ps->out); +} + +static void +dumpclsnl (PS * ps, Cls * c) +{ + dumpcls (ps, c); + fputc ('\n', ps->out); +} + +void +dumpcnf (PS * ps) +{ + Cls **p, *c; + + for (p = SOC; p != EOC; p = NXC (p)) + { + c = *p; + + if (!c) + continue; + +#ifdef TRACE + if (c->collected) + continue; +#endif + + dumpclsnl (ps, *p); + } +} + +#endif + +static void +delete_prefix (PS * ps) +{ + if (!ps->prefix) + return; + + delete (ps, ps->prefix, strlen (ps->prefix) + 1); + ps->prefix = 0; +} + +static void +new_prefix (PS * ps, const char * str) +{ + delete_prefix (ps); + assert (str); + ps->prefix = new (ps, strlen (str) + 1); + strcpy (ps->prefix, str); +} + +static PS * +init (void * pmgr, + picosat_malloc pnew, picosat_realloc presize, picosat_free pdelete) +{ + PS * ps; + +#if 0 + int count = 3 - !pnew - !presize - !pdelete; + + ABORTIF (count && !pnew, "API usage: missing 'picosat_set_new'"); + ABORTIF (count && !presize, "API usage: missing 'picosat_set_resize'"); + ABORTIF (count && !pdelete, "API usage: missing 'picosat_set_delete'"); +#endif + + ps = pnew ? pnew (pmgr, sizeof *ps) : malloc (sizeof *ps); + ABORTIF (!ps, "failed to allocate memory for PicoSAT manager"); + memset (ps, 0, sizeof *ps); + + ps->emgr = pmgr; + ps->enew = pnew; + ps->eresize = presize; + ps->edelete = pdelete; + + ps->size_vars = 1; + ps->state = RESET; + ps->defaultphase = JWLPHASE; +#ifdef TRACE + ps->ocore = -1; +#endif + ps->lastrheader = -2; +#ifndef NADC + ps->adoconflictlimit = UINT_MAX; +#endif + ps->min_flipped = UINT_MAX; + + NEWN (ps->lits, 2 * ps->size_vars); + NEWN (ps->jwh, 2 * ps->size_vars); + NEWN (ps->htps, 2 * ps->size_vars); +#ifndef NDSC + NEWN (ps->dhtps, 2 * ps->size_vars); +#endif + NEWN (ps->impls, 2 * ps->size_vars); + NEWN (ps->vars, ps->size_vars); + NEWN (ps->rnks, ps->size_vars); + + /* because '0' pos denotes not on heap + */ + ENLARGE (ps->heap, ps->hhead, ps->eoh); + ps->hhead = ps->heap + 1; + + ps->vinc = base2flt (1, 0); /* initial var activity */ + ps->ifvinc = ascii2flt ("1.05"); /* var score rescore factor */ +#ifdef VISCORES + ps->fvinc = ascii2flt ("0.9523809"); /* 1/f = 1/1.05 */ + ps->nvinc = ascii2flt ("0.0476191"); /* 1 - 1/f = 1 - 1/1.05 */ +#endif + ps->lscore = base2flt (1, 90); /* var activity rescore limit */ + ps->ilvinc = base2flt (1, -90); /* inverse of 'lscore' */ + + ps->cinc = base2flt (1, 0); /* initial clause activity */ + ps->fcinc = ascii2flt ("1.001"); /* cls activity rescore factor */ + ps->lcinc = base2flt (1, 90); /* cls activity rescore limit */ + ps->ilcinc = base2flt (1, -90); /* inverse of 'ilcinc' */ + + ps->lreduceadjustcnt = ps->lreduceadjustinc = 100; + ps->lpropagations = ~0ull; + +#ifndef RCODE + ps->out = stdout; +#else + ps->out = 0; +#endif + new_prefix (ps, "c "); + ps->verbosity = 0; + ps->plain = 0; + +#ifdef NO_BINARY_CLAUSES + memset (&ps->impl, 0, sizeof (ps->impl)); + ps->impl.size = 2; + + memset (&ps->cimpl, 0, sizeof (ps->impl)); + ps->cimpl.size = 2; +#endif + +#ifdef VISCORES + ps->fviscores = popen ( + "/usr/bin/gnuplot -background black" + " -xrm 'gnuplot*textColor:white'" + " -xrm 'gnuplot*borderColor:white'" + " -xrm 'gnuplot*axisColor:white'" + , "w"); + fprintf (ps->fviscores, "unset key\n"); + // fprintf (ps->fviscores, "set log y\n"); + fflush (ps->fviscores); + system ("rm -rf /tmp/picosat-viscores"); + system ("mkdir /tmp/picosat-viscores"); + system ("mkdir /tmp/picosat-viscores/data"); +#ifdef WRITEGIF + system ("mkdir /tmp/picosat-viscores/gif"); + fprintf (ps->fviscores, + "set terminal gif giant animate opt size 1024,768 x000000 xffffff" + "\n"); + + fprintf (ps->fviscores, + "set output \"/tmp/picosat-viscores/gif/animated.gif\"\n"); +#endif +#endif + ps->defaultphase = JWLPHASE; + ps->state = READY; + ps->last_sat_call_result = 0; + + return ps; +} + +static size_t +bytes_clause (PS * ps, unsigned size, unsigned learned) +{ + size_t res; + + res = sizeof (Cls); + res += size * sizeof (Lit *); + res -= 2 * sizeof (Lit *); + + if (learned && size > 2) + res += sizeof (Act); /* add activity */ + +#ifdef TRACE + if (ps->trace) + res += sizeof (Trd); /* add trace data */ +#else + (void) ps; +#endif + + return res; +} + +static Cls * +new_clause (PS * ps, unsigned size, unsigned learned) +{ + size_t bytes; + void * tmp; +#ifdef TRACE + Trd *trd; +#endif + Cls *res; + + bytes = bytes_clause (ps, size, learned); + tmp = new (ps, bytes); + +#ifdef TRACE + if (ps->trace) + { + trd = tmp; + + if (learned) + trd->idx = LIDX2IDX (ps->lhead - ps->lclauses); + else + trd->idx = OIDX2IDX (ps->ohead - ps->oclauses); + + res = trd->cls; + } + else +#endif + res = tmp; + + res->size = size; + res->learned = learned; + + res->collect = 0; +#ifndef NDEBUG + res->connected = 0; +#endif + res->locked = 0; + res->used = 0; +#ifdef TRACE + res->core = 0; + res->collected = 0; +#endif + + if (learned && size > 2) + { + Act * p = CLS2ACT (res); + *p = ps->cinc; + } + + return res; +} + +static void +delete_clause (PS * ps, Cls * c) +{ + size_t bytes; +#ifdef TRACE + Trd *trd; +#endif + + bytes = bytes_clause (ps, c->size, c->learned); + +#ifdef TRACE + if (ps->trace) + { + trd = CLS2TRD (c); + delete (ps, trd, bytes); + } + else +#endif + delete (ps, c, bytes); +} + +static void +delete_clauses (PS * ps) +{ + Cls **p; + for (p = SOC; p != EOC; p = NXC (p)) + if (*p) + delete_clause (ps, *p); + + DELETEN (ps->oclauses, ps->eoo - ps->oclauses); + DELETEN (ps->lclauses, ps->EOL - ps->lclauses); + + ps->ohead = ps->eoo = ps->lhead = ps->EOL = 0; +} + +#ifdef TRACE + +static void +delete_zhain (PS * ps, Zhn * zhain) +{ + const Znt *p, *znt; + + assert (zhain); + + znt = zhain->znt; + for (p = znt; *p; p++) + ; + + delete (ps, zhain, sizeof (Zhn) + (p - znt) + 1); +} + +static void +delete_zhains (PS * ps) +{ + Zhn **p, *z; + for (p = ps->zhains; p < ps->zhead; p++) + if ((z = *p)) + delete_zhain (ps, z); + + DELETEN (ps->zhains, ps->eoz - ps->zhains); + ps->eoz = ps->zhead = 0; +} + +#endif + +#ifdef NO_BINARY_CLAUSES +static void +lrelease (PS * ps, Ltk * stk) +{ + if (stk->start) + DELETEN (stk->start, (1 << (stk->ldsize))); + memset (stk, 0, sizeof (*stk)); +} +#endif + +#ifndef NADC + +static unsigned +llength (Lit ** a) +{ + Lit ** p; + for (p = a; *p; p++) + ; + return p - a; +} + +static void +resetadoconflict (PS * ps) +{ + assert (ps->adoconflict); + delete_clause (ps, ps->adoconflict); + ps->adoconflict = 0; +} + +static void +reset_ados (PS * ps) +{ + Lit *** p; + + for (p = ps->ados; p < ps->hados; p++) + DELETEN (*p, llength (*p) + 1); + + DELETEN (ps->ados, ps->eados - ps->ados); + ps->hados = ps->eados = 0; + + DELETEN (ps->adotab, ps->szadotab); + ps->szadotab = ps->nadotab = 0; + + if (ps->adoconflict) + resetadoconflict (ps); + + ps->adoconflicts = 0; + ps->adoconflictlimit = UINT_MAX; + ps->adodisabled = 0; +} + +#endif + +static void +reset (PS * ps) +{ + ABORTIF (!ps || + ps->state == RESET, "API usage: reset without initialization"); + + delete_clauses (ps); +#ifdef TRACE + delete_zhains (ps); +#endif +#ifdef NO_BINARY_CLAUSES + { + unsigned i; + for (i = 2; i <= 2 * ps->max_var + 1; i++) + lrelease (ps, ps->impls + i); + } +#endif +#ifndef NADC + reset_ados (ps); +#endif +#ifndef NFL + DELETEN (ps->saved, ps->saved_size); +#endif + DELETEN (ps->htps, 2 * ps->size_vars); +#ifndef NDSC + DELETEN (ps->dhtps, 2 * ps->size_vars); +#endif + DELETEN (ps->impls, 2 * ps->size_vars); + DELETEN (ps->lits, 2 * ps->size_vars); + DELETEN (ps->jwh, 2 * ps->size_vars); + DELETEN (ps->vars, ps->size_vars); + DELETEN (ps->rnks, ps->size_vars); + DELETEN (ps->trail, ps->eot - ps->trail); + DELETEN (ps->heap, ps->eoh - ps->heap); + DELETEN (ps->als, ps->eoals - ps->als); + DELETEN (ps->CLS, ps->eocls - ps->CLS); + DELETEN (ps->rils, ps->eorils - ps->rils); + DELETEN (ps->cils, ps->eocils - ps->cils); + DELETEN (ps->fals, ps->eofals - ps->fals); + DELETEN (ps->mass, ps->szmass); + DELETEN (ps->mssass, ps->szmssass); + DELETEN (ps->mcsass, ps->szmcsass); + DELETEN (ps->humus, ps->szhumus); + DELETEN (ps->added, ps->eoa - ps->added); + DELETEN (ps->marked, ps->eom - ps->marked); + DELETEN (ps->dfs, ps->eod - ps->dfs); + DELETEN (ps->resolved, ps->eor - ps->resolved); + DELETEN (ps->levels, ps->eolevels - ps->levels); + DELETEN (ps->dused, ps->eodused - ps->dused); + DELETEN (ps->buffer, ps->eob - ps->buffer); + DELETEN (ps->indices, ps->eoi - ps->indices); + DELETEN (ps->soclauses, ps->eoso - ps->soclauses); + delete_prefix (ps); + delete (ps, ps->rline[0], ps->szrline); + delete (ps, ps->rline[1], ps->szrline); + assert (getenv ("LEAK") || !ps->current_bytes); /* found leak if failing */ +#ifdef VISCORES + pclose (ps->fviscores); +#endif + if (ps->edelete) + ps->edelete (ps->emgr, ps, sizeof *ps); + else + free (ps); +} + +inline static void +tpush (PS * ps, Lit * lit) +{ + assert (ps->lits < lit && lit <= ps->lits + 2* ps->max_var + 1); + if (ps->thead == ps->eot) + { + unsigned ttail2count = ps->ttail2 - ps->trail; + unsigned ttailcount = ps->ttail - ps->trail; +#ifndef NADC + unsigned ttailadocount = ps->ttailado - ps->trail; +#endif + ENLARGE (ps->trail, ps->thead, ps->eot); + ps->ttail = ps->trail + ttailcount; + ps->ttail2 = ps->trail + ttail2count; +#ifndef NADC + ps->ttailado = ps->trail + ttailadocount; +#endif + } + + *ps->thead++ = lit; +} + +static void +assign_reason (PS * ps, Var * v, Cls * reason) +{ +#if defined(NO_BINARY_CLAUSES) && !defined(NDEBUG) + assert (reason != &ps->impl); +#else + (void) ps; +#endif + v->reason = reason; +} + +static void +assign_phase (PS * ps, Lit * lit) +{ + unsigned new_phase, idx; + Var * v = LIT2VAR (lit); + +#ifndef NFL + /* In 'simplifying' mode we only need to keep 'min_flipped' up to date if + * we force assignments on the top level. The other assignments will be + * undone and thus we can keep the old saved value of the phase. + */ + if (!ps->LEVEL || !ps->simplifying) +#endif + { + new_phase = (LIT2SGN (lit) > 0); + + if (v->assigned) + { + ps->sdflips -= ps->sdflips/FFLIPPED; + + if (new_phase != v->phase) + { + assert (FFLIPPEDPREC >= FFLIPPED); + ps->sdflips += FFLIPPEDPREC / FFLIPPED; + ps->flips++; + + idx = LIT2IDX (lit); + if (idx < ps->min_flipped) + ps->min_flipped = idx; + + NOLOG (fprintf (ps->out, + "%sflipped %d\n", + ps->prefix, LIT2INT (lit))); + } + } + + v->phase = new_phase; + v->assigned = 1; + } + + lit->val = TRUE; + NOTLIT (lit)->val = FALSE; +} + +inline static void +assign (PS * ps, Lit * lit, Cls * reason) +{ + Var * v = LIT2VAR (lit); + assert (lit->val == UNDEF); +#ifdef STATS + ps->assignments++; +#endif + v->level = ps->LEVEL; + assign_phase (ps, lit); + assign_reason (ps, v, reason); + tpush (ps, lit); +} + +inline static int +cmp_added (PS * ps, Lit * k, Lit * l) +{ + Val a = k->val, b = l->val; + Var *u, *v; + int res; + + if (a == UNDEF && b != UNDEF) + return -1; + + if (a != UNDEF && b == UNDEF) + return 1; + + u = LIT2VAR (k); + v = LIT2VAR (l); + + if (a != UNDEF) + { + assert (b != UNDEF); + res = v->level - u->level; + if (res) + return res; /* larger level first */ + } + + res = cmpflt (VAR2RNK (u)->score, VAR2RNK (v)->score); + if (res) + return res; /* smaller activity first */ + + return u - v; /* smaller index first */ +} + +static void +sorttwolits (Lit ** v) +{ + Lit * a = v[0], * b = v[1]; + + assert (a != b); + + if (a < b) + return; + + v[0] = b; + v[1] = a; +} + +inline static void +sortlits (PS * ps, Lit ** v, unsigned size) +{ + if (size == 2) + sorttwolits (v); /* same order with and with out 'NO_BINARY_CLAUSES' */ + else + SORT (Lit *, cmp_added, v, size); +} + +#ifdef NO_BINARY_CLAUSES +static Cls * +setimpl (PS * ps, Lit * a, Lit * b) +{ + assert (!ps->implvalid); + assert (ps->impl.size == 2); + + ps->impl.lits[0] = a; + ps->impl.lits[1] = b; + + sorttwolits (ps->impl.lits); + ps->implvalid = 1; + + return &ps->impl; +} + +static void +resetimpl (PS * ps) +{ + ps->implvalid = 0; +} + +static Cls * +setcimpl (PS * ps, Lit * a, Lit * b) +{ + assert (!ps->cimplvalid); + assert (ps->cimpl.size == 2); + + ps->cimpl.lits[0] = a; + ps->cimpl.lits[1] = b; + + sorttwolits (ps->cimpl.lits); + ps->cimplvalid = 1; + + return &ps->cimpl; +} + +static void +resetcimpl (PS * ps) +{ + assert (ps->cimplvalid); + ps->cimplvalid = 0; +} + +#endif + +static int +cmp_ptr (PS * ps, void *l, void *k) +{ + (void) ps; + return ((char*)l) - (char*)k; /* arbitrarily already reverse */ +} + +static int +cmp_rnk (Rnk * r, Rnk * s) +{ + if (!r->moreimportant && s->moreimportant) + return -1; + + if (r->moreimportant && !s->moreimportant) + return 1; + + if (!r->lessimportant && s->lessimportant) + return 1; + + if (r->lessimportant && !s->lessimportant) + return -1; + + if (r->score < s->score) + return -1; + + if (r->score > s->score) + return 1; + + return -cmp_ptr (0, r, s); +} + +static void +hup (PS * ps, Rnk * v) +{ + int upos, vpos; + Rnk *u; + +#ifndef NFL + assert (!ps->simplifying); +#endif + + vpos = v->pos; + + assert (0 < vpos); + assert (vpos < ps->hhead - ps->heap); + assert (ps->heap[vpos] == v); + + while (vpos > 1) + { + upos = vpos / 2; + + u = ps->heap[upos]; + + if (cmp_rnk (u, v) > 0) + break; + + ps->heap[vpos] = u; + u->pos = vpos; + + vpos = upos; + } + + ps->heap[vpos] = v; + v->pos = vpos; +} + +static Cls *add_simplified_clause (PS *, int); + +inline static void +add_antecedent (PS * ps, Cls * c) +{ + assert (c); + +#ifdef NO_BINARY_CLAUSES + if (ISLITREASON (c)) + return; + + if (c == &ps->impl) + return; +#elif defined(STATS) && defined(TRACE) + ps->antecedents++; +#endif + if (ps->rhead == ps->eor) + ENLARGE (ps->resolved, ps->rhead, ps->eor); + + assert (ps->rhead < ps->eor); + *ps->rhead++ = c; +} + +#ifdef TRACE + +#ifdef NO_BINARY_CLAUSES +#error "can not combine TRACE and NO_BINARY_CLAUSES" +#endif + +#endif /* TRACE */ + +static void +add_lit (PS * ps, Lit * lit) +{ + assert (lit); + + if (ps->ahead == ps->eoa) + ENLARGE (ps->added, ps->ahead, ps->eoa); + + *ps->ahead++ = lit; +} + +static void +push_var_as_marked (PS * ps, Var * v) +{ + if (ps->mhead == ps->eom) + ENLARGE (ps->marked, ps->mhead, ps->eom); + + *ps->mhead++ = v; +} + +static void +mark_var (PS * ps, Var * v) +{ + assert (!v->mark); + v->mark = 1; + push_var_as_marked (ps, v); +} + +#ifdef NO_BINARY_CLAUSES + +static Cls * +impl2reason (PS * ps, Lit * lit) +{ + Lit * other; + Cls * res; + other = ps->impl.lits[0]; + if (lit == other) + other = ps->impl.lits[1]; + assert (other->val == FALSE); + res = LIT2REASON (NOTLIT (other)); + resetimpl (ps); + return res; +} + +#endif + +/* Whenever we have a top level derived unit we really should derive a unit + * clause otherwise the resolutions in 'add_simplified_clause' become + * incorrect. + */ +static Cls * +resolve_top_level_unit (PS * ps, Lit * lit, Cls * reason) +{ + unsigned count_resolved; + Lit **p, **eol, *other; + Var *u, *v; + + assert (ps->rhead == ps->resolved); + assert (ps->ahead == ps->added); + + add_lit (ps, lit); + add_antecedent (ps, reason); + count_resolved = 1; + v = LIT2VAR (lit); + + eol = end_of_lits (reason); + for (p = reason->lits; p < eol; p++) + { + other = *p; + u = LIT2VAR (other); + if (u == v) + continue; + + add_antecedent (ps, u->reason); + count_resolved++; + } + + /* Some of the literals could be assumptions. If at least one + * variable is not an assumption, we should resolve. + */ + if (count_resolved >= 2) + { +#ifdef NO_BINARY_CLAUSES + if (reason == &ps->impl) + resetimpl (ps); +#endif + reason = add_simplified_clause (ps, 1); +#ifdef NO_BINARY_CLAUSES + if (reason->size == 2) + { + assert (reason == &ps->impl); + reason = impl2reason (ps, lit); + } +#endif + assign_reason (ps, v, reason); + } + else + { + ps->ahead = ps->added; + ps->rhead = ps->resolved; + } + + return reason; +} + +static void +fixvar (PS * ps, Var * v) +{ + Rnk * r; + + assert (VAR2LIT (v) != UNDEF); + assert (!v->level); + + ps->fixed++; + + r = VAR2RNK (v); + r->score = INFFLT; + +#ifndef NFL + if (ps->simplifying) + return; +#endif + + if (!r->pos) + return; + + hup (ps, r); +} + +static void +use_var (PS * ps, Var * v) +{ + if (v->used) + return; + + v->used = 1; + ps->vused++; +} + +static void +assign_forced (PS * ps, Lit * lit, Cls * reason) +{ + Var *v; + + assert (reason); + assert (lit->val == UNDEF); + +#ifdef STATS + ps->FORCED++; +#endif + assign (ps, lit, reason); + +#ifdef NO_BINARY_CLAUSES + assert (reason != &ps->impl); + if (ISLITREASON (reason)) + { + reason = setimpl (ps, lit, NOTLIT (REASON2LIT (reason))); + assert (reason); + } +#endif + LOG ( fprintf (ps->out, + "%sassign %d at level %d by ", + ps->prefix, LIT2INT (lit), ps->LEVEL); + dumpclsnl (ps, reason)); + + v = LIT2VAR (lit); + if (!ps->LEVEL) + use_var (ps, v); + + if (!ps->LEVEL && reason->size > 1) + { + reason = resolve_top_level_unit (ps, lit, reason); + assert (reason); + } + +#ifdef NO_BINARY_CLAUSES + if (ISLITREASON (reason) || reason == &ps->impl) + { + /* DO NOTHING */ + } + else +#endif + { + assert (!reason->locked); + reason->locked = 1; + if (reason->learned && reason->size > 2) + ps->llocked++; + } + +#ifdef NO_BINARY_CLAUSES + if (reason == &ps->impl) + resetimpl (ps); +#endif + + if (!ps->LEVEL) + fixvar (ps, v); +} + +#ifdef NO_BINARY_CLAUSES + +static void +lpush (PS * ps, Lit * lit, Cls * c) +{ + int pos = (c->lits[0] == lit); + Ltk * s = LIT2IMPLS (lit); + unsigned oldsize, newsize; + + assert (c->size == 2); + + if (!s->start) + { + assert (!s->count); + assert (!s->ldsize); + NEWN (s->start, 1); + } + else + { + oldsize = (1 << (s->ldsize)); + assert (s->count <= oldsize); + if (s->count == oldsize) + { + newsize = 2 * oldsize; + RESIZEN (s->start, oldsize, newsize); + s->ldsize++; + } + } + + s->start[s->count++] = c->lits[pos]; +} + +#endif + +static void +connect_head_tail (PS * ps, Lit * lit, Cls * c) +{ + Cls ** s; + assert (c->size >= 1); + if (c->size == 2) + { +#ifdef NO_BINARY_CLAUSES + lpush (ps, lit, c); + return; +#else + s = LIT2IMPLS (lit); +#endif + } + else + s = LIT2HTPS (lit); + + if (c->lits[0] != lit) + { + assert (c->size >= 2); + assert (c->lits[1] == lit); + c->next[1] = *s; + } + else + c->next[0] = *s; + + *s = c; +} + +#ifdef TRACE +static void +zpush (PS * ps, Zhn * zhain) +{ + assert (ps->trace); + + if (ps->zhead == ps->eoz) + ENLARGE (ps->zhains, ps->zhead, ps->eoz); + + *ps->zhead++ = zhain; +} + +static int +cmp_resolved (PS * ps, Cls * c, Cls * d) +{ +#ifndef NDEBUG + assert (ps->trace); +#else + (void) ps; +#endif + return CLS2IDX (c) - CLS2IDX (d); +} + +static void +bpushc (PS * ps, unsigned char ch) +{ + if (ps->bhead == ps->eob) + ENLARGE (ps->buffer, ps->bhead, ps->eob); + + *ps->bhead++ = ch; +} + +static void +bpushu (PS * ps, unsigned u) +{ + while (u & ~0x7f) + { + bpushc (ps, u | 0x80); + u >>= 7; + } + + bpushc (ps, u); +} + +static void +bpushd (PS * ps, unsigned prev, unsigned this) +{ + unsigned delta; + assert (prev < this); + delta = this - prev; + bpushu (ps, delta); +} + +static void +add_zhain (PS * ps) +{ + unsigned prev, this, count, rcount; + Cls **p, *c; + Zhn *res; + + assert (ps->trace); + assert (ps->bhead == ps->buffer); + assert (ps->rhead > ps->resolved); + + rcount = ps->rhead - ps->resolved; + SORT (Cls *, cmp_resolved, ps->resolved, rcount); + + prev = 0; + for (p = ps->resolved; p < ps->rhead; p++) + { + c = *p; + this = CLS2TRD (c)->idx; + bpushd (ps, prev, this); + prev = this; + } + bpushc (ps, 0); + + count = ps->bhead - ps->buffer; + + res = new (ps, sizeof (Zhn) + count); + res->core = 0; + res->ref = 0; + memcpy (res->znt, ps->buffer, count); + + ps->bhead = ps->buffer; +#ifdef STATS + ps->znts += count - 1; +#endif + zpush (ps, res); +} + +#endif + +static void +add_resolved (PS * ps, int learned) +{ +#if defined(STATS) || defined(TRACE) + Cls **p, *c; + + for (p = ps->resolved; p < ps->rhead; p++) + { + c = *p; + if (c->used) + continue; + + c->used = 1; + + if (c->size <= 2) + continue; + +#ifdef STATS + if (c->learned) + ps->llused++; + else + ps->loused++; +#endif + } +#endif + +#ifdef TRACE + if (learned && ps->trace) + add_zhain (ps); +#else + (void) learned; +#endif + ps->rhead = ps->resolved; +} + +static void +incjwh (PS * ps, Cls * c) +{ + Lit **p, *lit, ** eol; + Flt * f, inc, sum; + unsigned size = 0; + Var * v; + Val val; + + eol = end_of_lits (c); + + for (p = c->lits; p < eol; p++) + { + lit = *p; + val = lit->val; + + if (val && ps->LEVEL > 0) + { + v = LIT2VAR (lit); + if (v->level > 0) + val = UNDEF; + } + + if (val == TRUE) + return; + + if (val != FALSE) + size++; + } + + inc = base2flt (1, -size); + + for (p = c->lits; p < eol; p++) + { + lit = *p; + f = LIT2JWH (lit); + sum = addflt (*f, inc); + *f = sum; + } +} + +static void +write_rup_header (PS * ps, FILE * file) +{ + char line[80]; + int i; + + sprintf (line, "%%RUPD32 %u %u", ps->rupvariables, ps->rupclauses); + + fputs (line, file); + for (i = 255 - strlen (line); i >= 0; i--) + fputc (' ', file); + + fputc ('\n', file); + fflush (file); +} + +static Cls * +add_simplified_clause (PS * ps, int learned) +{ + unsigned num_true, num_undef, num_false, size, count_resolved; + Lit **p, **q, *lit, ** end; + unsigned litlevel, glue; + Cls *res, * reason; + int reentered; + Val val; + Var *v; +#if !defined(NDEBUG) && defined(TRACE) + unsigned idx; +#endif + + reentered = 0; + +REENTER: + + size = ps->ahead - ps->added; + + add_resolved (ps, learned); + + if (learned) + { + ps->ladded++; + ps->llitsadded += size; + if (size > 2) + { + ps->lladded++; + ps->nlclauses++; + ps->llits += size; + } + } + else + { + ps->oadded++; + if (size > 2) + { + ps->loadded++; + ps->noclauses++; + ps->olits += size; + } + } + + ps->addedclauses++; + assert (ps->addedclauses == ps->ladded + ps->oadded); + +#ifdef NO_BINARY_CLAUSES + if (size == 2) + res = setimpl (ps, ps->added[0], ps->added[1]); + else +#endif + { + sortlits (ps, ps->added, size); + + if (learned) + { + if (ps->lhead == ps->EOL) + { + ENLARGE (ps->lclauses, ps->lhead, ps->EOL); + + /* A very difficult to find bug, which only occurs if the + * learned clauses stack is immediately allocated before the + * original clauses stack without padding. In this case, we + * have 'SOC == EOC', which terminates all loops using the + * idiom 'for (p = SOC; p != EOC; p = NXC(p))' immediately. + * Unfortunately this occurred in 'fix_clause_lits' after + * using a recent version of the memory allocator of 'Google' + * perftools in the context of one large benchmark for + * our SMT solver 'Boolector'. + */ + if (ps->EOL == ps->oclauses) + ENLARGE (ps->lclauses, ps->lhead, ps->EOL); + } + +#if !defined(NDEBUG) && defined(TRACE) + idx = LIDX2IDX (ps->lhead - ps->lclauses); +#endif + } + else + { + if (ps->ohead == ps->eoo) + { + ENLARGE (ps->oclauses, ps->ohead, ps->eoo); + if (ps->EOL == ps->oclauses) + ENLARGE (ps->oclauses, ps->ohead, ps->eoo); /* ditto */ + } + +#if !defined(NDEBUG) && defined(TRACE) + idx = OIDX2IDX (ps->ohead - ps->oclauses); +#endif + } + + assert (ps->EOL != ps->oclauses); /* ditto */ + + res = new_clause (ps, size, learned); + + glue = 0; + + if (learned) + { + assert (ps->dusedhead == ps->dused); + + for (p = ps->added; p < ps->ahead; p++) + { + lit = *p; + if (lit->val) + { + litlevel = LIT2VAR (lit)->level; + assert (litlevel <= ps->LEVEL); + while (ps->levels + litlevel >= ps->levelshead) + { + if (ps->levelshead >= ps->eolevels) + ENLARGE (ps->levels, ps->levelshead, ps->eolevels); + assert (ps->levelshead < ps->eolevels); + *ps->levelshead++ = 0; + } + if (!ps->levels[litlevel]) + { + if (ps->dusedhead >= ps->eodused) + ENLARGE (ps->dused, ps->dusedhead, ps->eodused); + assert (ps->dusedhead < ps->eodused); + *ps->dusedhead++ = litlevel; + ps->levels[litlevel] = 1; + glue++; + } + } + else + glue++; + } + + while (ps->dusedhead > ps->dused) + { + litlevel = *--ps->dusedhead; + assert (ps->levels + litlevel < ps->levelshead); + assert (ps->levels[litlevel]); + ps->levels[litlevel] = 0; + } + } + + assert (glue <= MAXGLUE); + res->glue = glue; + +#if !defined(NDEBUG) && defined(TRACE) + if (ps->trace) + assert (CLS2IDX (res) == idx); +#endif + if (learned) + *ps->lhead++ = res; + else + *ps->ohead++ = res; + +#if !defined(NDEBUG) && defined(TRACE) + if (ps->trace && learned) + assert (ps->zhead - ps->zhains == ps->lhead - ps->lclauses); +#endif + assert (ps->lhead != ps->oclauses); /* ditto */ + } + + if (learned && ps->rup) + { + if (!ps->rupstarted) + { + write_rup_header (ps, ps->rup); + ps->rupstarted = 1; + } + } + + num_true = num_undef = num_false = 0; + + q = res->lits; + for (p = ps->added; p < ps->ahead; p++) + { + lit = *p; + *q++ = lit; + + if (learned && ps->rup) + fprintf (ps->rup, "%d ", LIT2INT (lit)); + + val = lit->val; + + num_true += (val == TRUE); + num_undef += (val == UNDEF); + num_false += (val == FALSE); + } + assert (num_false + num_true + num_undef == size); + + if (learned && ps->rup) + fputs ("0\n", ps->rup); + + ps->ahead = ps->added; /* reset */ + + if (!reentered) // TODO merge + if (size > 0) + { + assert (size <= 2 || !reentered); // TODO remove + connect_head_tail (ps, res->lits[0], res); + if (size > 1) + connect_head_tail (ps, res->lits[1], res); + } + + if (size == 0) + { + if (!ps->mtcls) + ps->mtcls = res; + } + +#ifdef NO_BINARY_CLAUSES + if (size != 2) +#endif +#ifndef NDEBUG + res->connected = 1; +#endif + + LOG ( fprintf (ps->out, "%s%s ", ps->prefix, learned ? "learned" : "original"); + dumpclsnl (ps, res)); + + /* Shrink clause by resolving it against top level assignments. + */ + if (!ps->LEVEL && num_false > 0) + { + assert (ps->ahead == ps->added); + assert (ps->rhead == ps->resolved); + + count_resolved = 1; + add_antecedent (ps, res); + + end = end_of_lits (res); + for (p = res->lits; p < end; p++) + { + lit = *p; + v = LIT2VAR (lit); + use_var (ps, v); + + if (lit->val == FALSE) + { + add_antecedent (ps, v->reason); + count_resolved++; + } + else + add_lit (ps, lit); + } + + assert (count_resolved >= 2); + + learned = 1; +#ifdef NO_BINARY_CLAUSES + if (res == &ps->impl) + resetimpl (ps); +#endif + reentered = 1; + goto REENTER; /* and return simplified clause */ + } + + if (!num_true && num_undef == 1) /* unit clause */ + { + lit = 0; + for (p = res->lits; p < res->lits + size; p++) + { + if ((*p)->val == UNDEF) + lit = *p; + + v = LIT2VAR (*p); + use_var (ps, v); + } + assert (lit); + + reason = res; +#ifdef NO_BINARY_CLAUSES + if (size == 2) + { + Lit * other = res->lits[0]; + if (other == lit) + other = res->lits[1]; + + assert (other->val == FALSE); + reason = LIT2REASON (NOTLIT (other)); + } +#endif + assign_forced (ps, lit, reason); + num_true++; + } + + if (num_false == size && !ps->conflict) + { +#ifdef NO_BINARY_CLAUSES + if (res == &ps->impl) + ps->conflict = setcimpl (ps, res->lits[0], res->lits[1]); + else +#endif + ps->conflict = res; + } + + if (!learned && !num_true && num_undef) + incjwh (ps, res); + +#ifdef NO_BINARY_CLAUSES + if (res == &ps->impl) + resetimpl (ps); +#endif + return res; +} + +static int +trivial_clause (PS * ps) +{ + Lit **p, **q, *prev; + Var *v; + + SORT (Lit *, cmp_ptr, ps->added, ps->ahead - ps->added); + + prev = 0; + q = ps->added; + for (p = q; p < ps->ahead; p++) + { + Lit *this = *p; + + v = LIT2VAR (this); + + if (prev == this) /* skip repeated literals */ + continue; + + /* Top level satisfied ? + */ + if (this->val == TRUE && !v->level) + return 1; + + if (prev == NOTLIT (this))/* found pair of dual literals */ + return 1; + + *q++ = prev = this; + } + + ps->ahead = q; /* shrink */ + + return 0; +} + +static void +simplify_and_add_original_clause (PS * ps) +{ +#ifdef NO_BINARY_CLAUSES + Cls * c; +#endif + if (trivial_clause (ps)) + { + ps->ahead = ps->added; + + if (ps->ohead == ps->eoo) + ENLARGE (ps->oclauses, ps->ohead, ps->eoo); + + *ps->ohead++ = 0; + + ps->addedclauses++; + ps->oadded++; + } + else + { + if (ps->CLS != ps->clshead) + add_lit (ps, NOTLIT (ps->clshead[-1])); + +#ifdef NO_BINARY_CLAUSES + c = +#endif + add_simplified_clause (ps, 0); +#ifdef NO_BINARY_CLAUSES + if (c == &ps->impl) assert (!ps->implvalid); +#endif + } +} + +#ifndef NADC + +static void +add_ado (PS * ps) +{ + unsigned len = ps->ahead - ps->added; + Lit ** ado, ** p, ** q, *lit; + Var * v, * u; + +#ifdef TRACE + assert (!ps->trace); +#endif + + ABORTIF (ps->ados < ps->hados && llength (ps->ados[0]) != len, + "internal: non matching all different constraint object lengths"); + + if (ps->hados == ps->eados) + ENLARGE (ps->ados, ps->hados, ps->eados); + + NEWN (ado, len + 1); + *ps->hados++ = ado; + + p = ps->added; + q = ado; + u = 0; + while (p < ps->ahead) + { + lit = *p++; + v = LIT2VAR (lit); + ABORTIF (v->inado, + "internal: variable in multiple all different objects"); + v->inado = ado; + if (!u && !lit->val) + u = v; + *q++ = lit; + } + + assert (q == ado + len); + *q++ = 0; + + /* TODO simply do a conflict test as in propado */ + + ABORTIF (!u, + "internal: " + "adding fully instantiated all different object not implemented yet"); + + assert (u); + assert (u->inado == ado); + assert (!u->ado); + u->ado = ado; + + ps->ahead = ps->added; +} + +#endif + +static void +hdown (PS * ps, Rnk * r) +{ + unsigned end, rpos, cpos, opos; + Rnk *child, *other; + + assert (r->pos > 0); + assert (ps->heap[r->pos] == r); + + end = ps->hhead - ps->heap; + rpos = r->pos; + + for (;;) + { + cpos = 2 * rpos; + if (cpos >= end) + break; + + opos = cpos + 1; + child = ps->heap[cpos]; + + if (cmp_rnk (r, child) < 0) + { + if (opos < end) + { + other = ps->heap[opos]; + + if (cmp_rnk (child, other) < 0) + { + child = other; + cpos = opos; + } + } + } + else if (opos < end) + { + child = ps->heap[opos]; + + if (cmp_rnk (r, child) >= 0) + break; + + cpos = opos; + } + else + break; + + ps->heap[rpos] = child; + child->pos = rpos; + rpos = cpos; + } + + r->pos = rpos; + ps->heap[rpos] = r; +} + +static Rnk * +htop (PS * ps) +{ + assert (ps->hhead > ps->heap + 1); + return ps->heap[1]; +} + +static Rnk * +hpop (PS * ps) +{ + Rnk *res, *last; + unsigned end; + + assert (ps->hhead > ps->heap + 1); + + res = ps->heap[1]; + res->pos = 0; + + end = --ps->hhead - ps->heap; + if (end == 1) + return res; + + last = ps->heap[end]; + + ps->heap[last->pos = 1] = last; + hdown (ps, last); + + return res; +} + +inline static void +hpush (PS * ps, Rnk * r) +{ + assert (!r->pos); + + if (ps->hhead == ps->eoh) + ENLARGE (ps->heap, ps->hhead, ps->eoh); + + r->pos = ps->hhead++ - ps->heap; + ps->heap[r->pos] = r; + hup (ps, r); +} + +static void +fix_trail_lits (PS * ps, long delta) +{ + Lit **p; + for (p = ps->trail; p < ps->thead; p++) + *p += delta; +} + +#ifdef NO_BINARY_CLAUSES +static void +fix_impl_lits (PS * ps, long delta) +{ + Ltk * s; + Lit ** p; + + for (s = ps->impls + 2; s <= ps->impls + 2 * ps->max_var + 1; s++) + for (p = s->start; p < s->start + s->count; p++) + *p += delta; +} +#endif + +static void +fix_clause_lits (PS * ps, long delta) +{ + Cls **p, *clause; + Lit **q, *lit, **eol; + + for (p = SOC; p != EOC; p = NXC (p)) + { + clause = *p; + if (!clause) + continue; + + q = clause->lits; + eol = end_of_lits (clause); + while (q < eol) + { + assert (q - clause->lits <= (int) clause->size); + lit = *q; + lit += delta; + *q++ = lit; + } + } +} + +static void +fix_added_lits (PS * ps, long delta) +{ + Lit **p; + for (p = ps->added; p < ps->ahead; p++) + *p += delta; +} + +static void +fix_assumed_lits (PS * ps, long delta) +{ + Lit **p; + for (p = ps->als; p < ps->alshead; p++) + *p += delta; +} + +static void +fix_cls_lits (PS * ps, long delta) +{ + Lit **p; + for (p = ps->CLS; p < ps->clshead; p++) + *p += delta; +} + +static void +fix_heap_rnks (PS * ps, long delta) +{ + Rnk **p; + + for (p = ps->heap + 1; p < ps->hhead; p++) + *p += delta; +} + +#ifndef NADC + +static void +fix_ado (long delta, Lit ** ado) +{ + Lit ** p; + for (p = ado; *p; p++) + *p += delta; +} + +static void +fix_ados (PS * ps, long delta) +{ + Lit *** p; + + for (p = ps->ados; p < ps->hados; p++) + fix_ado (delta, *p); +} + +#endif + +static void +enlarge (PS * ps, unsigned new_size_vars) +{ + long rnks_delta, lits_delta; + Lit *old_lits = ps->lits; + Rnk *old_rnks = ps->rnks; + + RESIZEN (ps->lits, 2 * ps->size_vars, 2 * new_size_vars); + RESIZEN (ps->jwh, 2 * ps->size_vars, 2 * new_size_vars); + RESIZEN (ps->htps, 2 * ps->size_vars, 2 * new_size_vars); +#ifndef NDSC + RESIZEN (ps->dhtps, 2 * ps->size_vars, 2 * new_size_vars); +#endif + RESIZEN (ps->impls, 2 * ps->size_vars, 2 * new_size_vars); + RESIZEN (ps->vars, ps->size_vars, new_size_vars); + RESIZEN (ps->rnks, ps->size_vars, new_size_vars); + + if ((lits_delta = ps->lits - old_lits)) + { + fix_trail_lits (ps, lits_delta); + fix_clause_lits (ps, lits_delta); + fix_added_lits (ps, lits_delta); + fix_assumed_lits (ps, lits_delta); + fix_cls_lits (ps, lits_delta); +#ifdef NO_BINARY_CLAUSES + fix_impl_lits (ps, lits_delta); +#endif +#ifndef NADC + fix_ados (ps, lits_delta); +#endif + } + + if ((rnks_delta = ps->rnks - old_rnks)) + { + fix_heap_rnks (ps, rnks_delta); + } + + assert (ps->mhead == ps->marked); + + ps->size_vars = new_size_vars; +} + +static void +unassign (PS * ps, Lit * lit) +{ + Cls *reason; + Var *v; + Rnk *r; + + assert (lit->val == TRUE); + + LOG ( fprintf (ps->out, "%sunassign %d\n", ps->prefix, LIT2INT (lit))); + + v = LIT2VAR (lit); + reason = v->reason; + +#ifdef NO_BINARY_CLAUSES + assert (reason != &ps->impl); + if (ISLITREASON (reason)) + { + /* DO NOTHING */ + } + else +#endif + if (reason) + { + assert (reason->locked); + reason->locked = 0; + if (reason->learned && reason->size > 2) + { + assert (ps->llocked > 0); + ps->llocked--; + } + } + + lit->val = UNDEF; + NOTLIT (lit)->val = UNDEF; + + r = VAR2RNK (v); + if (!r->pos) + hpush (ps, r); + +#ifndef NDSC + { + Cls * p, * next, ** q; + + q = LIT2DHTPS (lit); + p = *q; + *q = 0; + + while (p) + { + Lit * other = p->lits[0]; + + if (other == lit) + { + other = p->lits[1]; + q = p->next + 1; + } + else + { + assert (p->lits[1] == lit); + q = p->next; + } + + next = *q; + *q = *LIT2HTPS (other); + *LIT2HTPS (other) = p; + p = next; + } + } +#endif + +#ifndef NADC + if (v->adotabpos) + { + assert (ps->nadotab); + assert (*v->adotabpos == v->ado); + + *v->adotabpos = 0; + v->adotabpos = 0; + + ps->nadotab--; + } +#endif +} + +static Cls * +var2reason (PS * ps, Var * var) +{ + Cls * res = var->reason; +#ifdef NO_BINARY_CLAUSES + Lit * this, * other; + if (ISLITREASON (res)) + { + this = VAR2LIT (var); + if (this->val == FALSE) + this = NOTLIT (this); + + other = REASON2LIT (res); + assert (other->val == TRUE); + assert (this->val == TRUE); + res = setimpl (ps, NOTLIT (other), this); + } +#else + (void) ps; +#endif + return res; +} + +static void +mark_clause_to_be_collected (Cls * c) +{ + assert (!c->collect); + c->collect = 1; +} + +static void +undo (PS * ps, unsigned new_level) +{ + Lit *lit; + Var *v; + + while (ps->thead > ps->trail) + { + lit = *--ps->thead; + v = LIT2VAR (lit); + if (v->level == new_level) + { + ps->thead++; /* fix pre decrement */ + break; + } + + unassign (ps, lit); + } + + ps->LEVEL = new_level; + ps->ttail = ps->thead; + ps->ttail2 = ps->thead; +#ifndef NADC + ps->ttailado = ps->thead; +#endif + +#ifdef NO_BINARY_CLAUSES + if (ps->conflict == &ps->cimpl) + resetcimpl (ps); +#endif +#ifndef NADC + if (ps->conflict && ps->conflict == ps->adoconflict) + resetadoconflict (ps); +#endif + ps->conflict = ps->mtcls; + if (ps->LEVEL < ps->adecidelevel) + { + assert (ps->als < ps->alshead); + ps->adecidelevel = 0; + ps->alstail = ps->als; + } + LOG ( fprintf (ps->out, "%sback to level %u\n", ps->prefix, ps->LEVEL)); +} + +#ifndef NDEBUG + +static int +clause_satisfied (Cls * c) +{ + Lit **p, **eol, *lit; + + eol = end_of_lits (c); + for (p = c->lits; p < eol; p++) + { + lit = *p; + if (lit->val == TRUE) + return 1; + } + + return 0; +} + +static void +original_clauses_satisfied (PS * ps) +{ + Cls **p, *c; + + for (p = ps->oclauses; p < ps->ohead; p++) + { + c = *p; + + if (!c) + continue; + + if (c->learned) + continue; + + assert (clause_satisfied (c)); + } +} + +static void +assumptions_satisfied (PS * ps) +{ + Lit *lit, ** p; + + for (p = ps->als; p < ps->alshead; p++) + { + lit = *p; + assert (lit->val == TRUE); + } +} + +#endif + +static void +sflush (PS * ps) +{ + double now = picosat_time_stamp (); + double delta = now - ps->entered; + delta = (delta < 0) ? 0 : delta; + ps->seconds += delta; + ps->entered = now; +} + +static double +mb (PS * ps) +{ + return ps->current_bytes / (double) (1 << 20); +} + +static double +avglevel (PS * ps) +{ + return ps->decisions ? ps->levelsum / ps->decisions : 0.0; +} + +static void +rheader (PS * ps) +{ + assert (ps->lastrheader <= ps->reports); + + if (ps->lastrheader == ps->reports) + return; + + ps->lastrheader = ps->reports; + + fprintf (ps->out, "%s\n", ps->prefix); + fprintf (ps->out, "%s %s\n", ps->prefix, ps->rline[0]); + fprintf (ps->out, "%s %s\n", ps->prefix, ps->rline[1]); + fprintf (ps->out, "%s\n", ps->prefix); +} + +static unsigned +dynamic_flips_per_assignment_per_mille (PS * ps) +{ + assert (FFLIPPEDPREC >= 1000); + return ps->sdflips / (FFLIPPEDPREC / 1000); +} + +#ifdef NLUBY + +static int +high_agility (PS * ps) +{ + return dynamic_flips_per_assignment_per_mille (ps) >= 200; +} + +static int +very_high_agility (PS * ps) +{ + return dynamic_flips_per_assignment_per_mille (ps) >= 250; +} + +#else + +static int +medium_agility (PS * ps) +{ + return dynamic_flips_per_assignment_per_mille (ps) >= 230; +} + +#endif + +static void +relemdata (PS * ps) +{ + char *p; + int x; + + if (ps->reports < 0) + { + /* strip trailing white space + */ + for (x = 0; x <= 1; x++) + { + p = ps->rline[x] + strlen (ps->rline[x]); + while (p-- > ps->rline[x]) + { + if (*p != ' ') + break; + + *p = 0; + } + } + + rheader (ps); + } + else + fputc ('\n', ps->out); + + ps->RCOUNT = 0; +} + +static void +relemhead (PS * ps, const char * name, int fp, double val) +{ + int x, y, len, size; + const char *fmt; + unsigned tmp, e; + + if (ps->reports < 0) + { + x = ps->RCOUNT & 1; + y = (ps->RCOUNT / 2) * 12 + x * 6; + + if (ps->RCOUNT == 1) + sprintf (ps->rline[1], "%6s", ""); + + len = strlen (name); + while (ps->szrline <= len + y + 1) + { + size = ps->szrline ? 2 * ps->szrline : 128; + ps->rline[0] = resize (ps, ps->rline[0], ps->szrline, size); + ps->rline[1] = resize (ps, ps->rline[1], ps->szrline, size); + ps->szrline = size; + } + + fmt = (len <= 6) ? "%6s%10s" : "%-10s%4s"; + sprintf (ps->rline[x] + y, fmt, name, ""); + } + else if (val < 0) + { + assert (fp); + + if (val > -100 && (tmp = val * 10.0 - 0.5) > -1000.0) + { + fprintf (ps->out, "-%4.1f ", -tmp / 10.0); + } + else + { + tmp = -val / 10.0 + 0.5; + e = 1; + while (tmp >= 100) + { + tmp /= 10; + e++; + } + + fprintf (ps->out, "-%2ue%u ", tmp, e); + } + } + else + { + if (fp && val < 1000 && (tmp = val * 10.0 + 0.5) < 10000) + { + fprintf (ps->out, "%5.1f ", tmp / 10.0); + } + else if (!fp && (tmp = val) < 100000) + { + fprintf (ps->out, "%5u ", tmp); + } + else + { + tmp = val / 10.0 + 0.5; + e = 1; + + while (tmp >= 1000) + { + tmp /= 10; + e++; + } + + fprintf (ps->out, "%3ue%u ", tmp, e); + } + } + + ps->RCOUNT++; +} + +inline static void +relem (PS * ps, const char *name, int fp, double val) +{ + if (name) + relemhead (ps, name, fp, val); + else + relemdata (ps); +} + +static unsigned +reduce_limit_on_lclauses (PS * ps) +{ + unsigned res = ps->lreduce; + res += ps->llocked; + return res; +} + +static void +report (PS * ps, int replevel, char type) +{ + int rounds; + +#ifdef RCODE + (void) type; +#endif + + if (ps->verbosity < replevel) + return; + + sflush (ps); + + if (!ps->reports) + ps->reports = -1; + + for (rounds = (ps->reports < 0) ? 2 : 1; rounds; rounds--) + { + if (ps->reports >= 0) + fprintf (ps->out, "%s%c ", ps->prefix, type); + + relem (ps, "seconds", 1, ps->seconds); + relem (ps, "level", 1, avglevel (ps)); + assert (ps->fixed <= ps->max_var); + relem (ps, "variables", 0, ps->max_var - ps->fixed); + relem (ps, "used", 1, PERCENT (ps->vused, ps->max_var)); + relem (ps, "original", 0, ps->noclauses); + relem (ps, "conflicts", 0, ps->conflicts); + // relem (ps, "decisions", 0, ps->decisions); + // relem (ps, "conf/dec", 1, PERCENT(ps->conflicts,ps->decisions)); + // relem (ps, "limit", 0, reduce_limit_on_lclauses (ps)); + relem (ps, "learned", 0, ps->nlclauses); + // relem (ps, "limit", 1, PERCENT (ps->nlclauses, reduce_limit_on_lclauses (ps))); + relem (ps, "limit", 0, ps->lreduce); +#ifdef STATS + relem (ps, "learning", 1, PERCENT (ps->llused, ps->lladded)); +#endif + relem (ps, "agility", 1, dynamic_flips_per_assignment_per_mille (ps) / 10.0); + // relem (ps, "original", 0, ps->noclauses); + relem (ps, "MB", 1, mb (ps)); + // relem (ps, "lladded", 0, ps->lladded); + // relem (ps, "llused", 0, ps->llused); + + relem (ps, 0, 0, 0); + + ps->reports++; + } + + /* Adapt this to the number of rows in your terminal. + */ + #define ROWS 25 + + if (ps->reports % (ROWS - 3) == (ROWS - 4)) + rheader (ps); + + fflush (ps->out); +} + +static int +bcp_queue_is_empty (PS * ps) +{ + if (ps->ttail != ps->thead) + return 0; + + if (ps->ttail2 != ps->thead) + return 0; + +#ifndef NADC + if (ps->ttailado != ps->thead) + return 0; +#endif + + return 1; +} + +static int +satisfied (PS * ps) +{ + assert (!ps->mtcls); + assert (!ps->failed_assumption); + if (ps->alstail < ps->alshead) + return 0; + assert (!ps->conflict); + assert (bcp_queue_is_empty (ps)); + return ps->thead == ps->trail + ps->max_var; /* all assigned */ +} + +static void +vrescore (PS * ps) +{ + Rnk *p, *eor = ps->rnks + ps->max_var; + for (p = ps->rnks + 1; p <= eor; p++) + if (p->score != INFFLT) + p->score = mulflt (p->score, ps->ilvinc); + ps->vinc = mulflt (ps->vinc, ps->ilvinc);; +#ifdef VISCORES + ps->nvinc = mulflt (ps->nvinc, ps->lscore);; +#endif +} + +static void +inc_score (PS * ps, Var * v) +{ + Flt score; + Rnk *r; + +#ifndef NFL + if (ps->simplifying) + return; +#endif + + if (!v->level) + return; + + if (v->internal) + return; + + r = VAR2RNK (v); + score = r->score; + + assert (score != INFFLT); + + score = addflt (score, ps->vinc); + assert (score < INFFLT); + r->score = score; + if (r->pos > 0) + hup (ps, r); + + if (score > ps->lscore) + vrescore (ps); +} + +static void +inc_activity (PS * ps, Cls * c) +{ + Act *p; + + if (!c->learned) + return; + + if (c->size <= 2) + return; + + p = CLS2ACT (c); + *p = addflt (*p, ps->cinc); +} + +static unsigned +hashlevel (unsigned l) +{ + return 1u << (l & 31); +} + +static void +push (PS * ps, Var * v) +{ + if (ps->dhead == ps->eod) + ENLARGE (ps->dfs, ps->dhead, ps->eod); + + *ps->dhead++ = v; +} + +static Var * +pop (PS * ps) +{ + assert (ps->dfs < ps->dhead); + return *--ps->dhead; +} + +static void +analyze (PS * ps) +{ + unsigned open, minlevel, siglevels, l, old, i, orig; + Lit *this, *other, **p, **q, **eol; + Var *v, *u, **m, *start, *uip; + Cls *c; + + assert (ps->conflict); + + assert (ps->ahead == ps->added); + assert (ps->mhead == ps->marked); + assert (ps->rhead == ps->resolved); + + /* First, search for First UIP variable and mark all resolved variables. + * At the same time determine the minimum decision level involved. + * Increase activities of resolved variables. + */ + q = ps->thead; + open = 0; + minlevel = ps->LEVEL; + siglevels = 0; + uip = 0; + + c = ps->conflict; + + for (;;) + { + add_antecedent (ps, c); + inc_activity (ps, c); + eol = end_of_lits (c); + for (p = c->lits; p < eol; p++) + { + other = *p; + + if (other->val == TRUE) + continue; + + assert (other->val == FALSE); + + u = LIT2VAR (other); + if (u->mark) + continue; + + u->mark = 1; + inc_score (ps, u); + use_var (ps, u); + + if (u->level == ps->LEVEL) + { + open++; + } + else + { + push_var_as_marked (ps, u); + + if (u->level) + { + /* The statistics counter 'nonminimizedllits' sums up the + * number of literals that would be added if only the + * 'first UIP' scheme for learned clauses would be used + * and no clause minimization. + */ + ps->nonminimizedllits++; + + if (u->level < minlevel) + minlevel = u->level; + + siglevels |= hashlevel (u->level); + } + else + { + assert (!u->level); + assert (u->reason); + } + } + } + + do + { + if (q == ps->trail) + { + uip = 0; + goto DONE_FIRST_UIP; + } + + this = *--q; + uip = LIT2VAR (this); + } + while (!uip->mark); + + uip->mark = 0; + + c = var2reason (ps, uip); +#ifdef NO_BINARY_CLAUSES + if (c == &ps->impl) + resetimpl (ps); +#endif + open--; + if ((!open && ps->LEVEL) || !c) + break; + + assert (c); + } + +DONE_FIRST_UIP: + + if (uip) + { + assert (ps->LEVEL); + this = VAR2LIT (uip); + this += (this->val == TRUE); + ps->nonminimizedllits++; + ps->minimizedllits++; + add_lit (ps, this); +#ifdef STATS + if (uip->reason) + ps->uips++; +#endif + } + else + assert (!ps->LEVEL); + + /* Second, try to mark more intermediate variables, with the goal to + * minimize the conflict clause. This is a DFS from already marked + * variables backward through the implication graph. It tries to reach + * other marked variables. If the search reaches an unmarked decision + * variable or a variable assigned below the minimum level of variables in + * the first uip learned clause or a level on which no variable has been + * marked, then the variable from which the DFS is started is not + * redundant. Otherwise the start variable is redundant and will + * eventually be removed from the learned clause in step 4. We initially + * implemented BFS, but then profiling revelead that this step is a bottle + * neck for certain incremental applications. After switching to DFS this + * hot spot went away. + */ + orig = ps->mhead - ps->marked; + for (i = 0; i < orig; i++) + { + start = ps->marked[i]; + + assert (start->mark); + assert (start != uip); + assert (start->level < ps->LEVEL); + + if (!start->reason) + continue; + + old = ps->mhead - ps->marked; + assert (ps->dhead == ps->dfs); + push (ps, start); + + while (ps->dhead > ps->dfs) + { + u = pop (ps); + assert (u->mark); + + c = var2reason (ps, u); +#ifdef NO_BINARY_CLAUSES + if (c == &ps->impl) + resetimpl (ps); +#endif + if (!c || + ((l = u->level) && + (l < minlevel || ((hashlevel (l) & ~siglevels))))) + { + while (ps->mhead > ps->marked + old) /* reset all marked */ + (*--ps->mhead)->mark = 0; + + ps->dhead = ps->dfs; /* and DFS stack */ + break; + } + + eol = end_of_lits (c); + for (p = c->lits; p < eol; p++) + { + v = LIT2VAR (*p); + if (v->mark) + continue; + + mark_var (ps, v); + push (ps, v); + } + } + } + + for (m = ps->marked; m < ps->mhead; m++) + { + v = *m; + + assert (v->mark); + assert (!v->resolved); + + use_var (ps, v); + + c = var2reason (ps, v); + if (!c) + continue; + +#ifdef NO_BINARY_CLAUSES + if (c == &ps->impl) + resetimpl (ps); +#endif + eol = end_of_lits (c); + for (p = c->lits; p < eol; p++) + { + other = *p; + + u = LIT2VAR (other); + if (!u->level) + continue; + + if (!u->mark) /* 'MARKTEST' */ + break; + } + + if (p != eol) + continue; + + add_antecedent (ps, c); + v->resolved = 1; + } + + for (m = ps->marked; m < ps->mhead; m++) + { + v = *m; + + assert (v->mark); + v->mark = 0; + + if (v->resolved) + { + v->resolved = 0; + continue; + } + + this = VAR2LIT (v); + if (this->val == TRUE) + this++; /* actually NOTLIT */ + + add_lit (ps, this); + ps->minimizedllits++; + } + + assert (ps->ahead <= ps->eoa); + assert (ps->rhead <= ps->eor); + + ps->mhead = ps->marked; +} + +static void +fanalyze (PS * ps) +{ + Lit ** eol, ** p, * lit; + Cls * c, * reason; + Var * v, * u; + int next; + +#ifndef RCODE + double start = picosat_time_stamp (); +#endif + + assert (ps->failed_assumption); + assert (ps->failed_assumption->val == FALSE); + + v = LIT2VAR (ps->failed_assumption); + reason = var2reason (ps, v); + if (!reason) return; +#ifdef NO_BINARY_CLAUSES + if (reason == &ps->impl) + resetimpl (ps); +#endif + + eol = end_of_lits (reason); + for (p = reason->lits; p != eol; p++) + { + lit = *p; + u = LIT2VAR (lit); + if (u == v) continue; + if (u->reason) break; + } + if (p == eol) return; + + assert (ps->ahead == ps->added); + assert (ps->mhead == ps->marked); + assert (ps->rhead == ps->resolved); + + next = 0; + mark_var (ps, v); + add_lit (ps, NOTLIT (ps->failed_assumption)); + + do + { + v = ps->marked[next++]; + use_var (ps, v); + if (v->reason) + { + reason = var2reason (ps, v); +#ifdef NO_BINARY_CLAUSES + if (reason == &ps->impl) + resetimpl (ps); +#endif + add_antecedent (ps, reason); + eol = end_of_lits (reason); + for (p = reason->lits; p != eol; p++) + { + lit = *p; + u = LIT2VAR (lit); + if (u == v) continue; + if (u->mark) continue; + mark_var (ps, u); + } + } + else + { + lit = VAR2LIT (v); + if (lit->val == TRUE) lit = NOTLIT (lit); + add_lit (ps, lit); + } + } + while (ps->marked + next < ps->mhead); + + c = add_simplified_clause (ps, 1); + v = LIT2VAR (ps->failed_assumption); + reason = v->reason; +#ifdef NO_BINARY_CLAUSES + if (!ISLITREASON (reason)) +#endif + { + assert (reason->locked); + reason->locked = 0; + if (reason->learned && reason->size > 2) + { + assert (ps->llocked > 0); + ps->llocked--; + } + } + +#ifdef NO_BINARY_CLAUSES + if (c == &ps->impl) + { + c = impl2reason (ps, NOTLIT (ps->failed_assumption)); + } + else +#endif + { + assert (c->learned); + assert (!c->locked); + c->locked = 1; + if (c->size > 2) + { + ps->llocked++; + assert (ps->llocked > 0); + } + } + + v->reason = c; + + while (ps->mhead > ps->marked) + (*--ps->mhead)->mark = 0; + + if (ps->verbosity) + fprintf (ps->out, "%sfanalyze took %.1f seconds\n", + ps->prefix, picosat_time_stamp () - start); +} + +/* Propagate assignment of 'this' to 'FALSE' by visiting all binary clauses in + * which 'this' occurs. + */ +inline static void +prop2 (PS * ps, Lit * this) +{ +#ifdef NO_BINARY_CLAUSES + Lit ** l, ** start; + Ltk * lstk; +#else + Cls * c, ** p; + Cls * next; +#endif + Lit * other; + Val tmp; + + assert (this->val == FALSE); + +#ifdef NO_BINARY_CLAUSES + lstk = LIT2IMPLS (this); + start = lstk->start; + l = start + lstk->count; + while (l != start) + { + /* The counter 'visits' is the number of clauses that are + * visited during propagations of assignments. + */ + ps->visits++; +#ifdef STATS + ps->bvisits++; +#endif + other = *--l; + tmp = other->val; + + if (tmp == TRUE) + { +#ifdef STATS + ps->othertrue++; + ps->othertrue2++; + if (LIT2VAR (other)->level < ps->LEVEL) + ps->othertrue2u++; +#endif + continue; + } + + if (tmp != FALSE) + { + assign_forced (ps, other, LIT2REASON (NOTLIT(this))); + continue; + } + + if (ps->conflict == &ps->cimpl) + resetcimpl (ps); + ps->conflict = setcimpl (ps, this, other); + } +#else + /* Traverse all binary clauses with 'this'. Head/Tail pointers for binary + * clauses do not have to be modified here. + */ + p = LIT2IMPLS (this); + for (c = *p; c; c = next) + { + ps->visits++; +#ifdef STATS + ps->bvisits++; +#endif + assert (!c->collect); +#ifdef TRACE + assert (!c->collected); +#endif + assert (c->size == 2); + + other = c->lits[0]; + if (other == this) + { + next = c->next[0]; + other = c->lits[1]; + } + else + next = c->next[1]; + + tmp = other->val; + + if (tmp == TRUE) + { +#ifdef STATS + ps->othertrue++; + ps->othertrue2++; + if (LIT2VAR (other)->level < ps->LEVEL) + ps->othertrue2u++; +#endif + continue; + } + + if (tmp == FALSE) + ps->conflict = c; + else + assign_forced (ps, other, c); /* unit clause */ + } +#endif /* !defined(NO_BINARY_CLAUSES) */ +} + +#ifndef NDSC +static int +should_disconnect_head_tail (PS * ps, Lit * lit) +{ + unsigned litlevel; + Var * v; + + assert (lit->val == TRUE); + + v = LIT2VAR (lit); + litlevel = v->level; + + if (!litlevel) + return 1; + +#ifndef NFL + if (ps->simplifying) + return 0; +#endif + + return litlevel < ps->LEVEL; +} +#endif + +inline static void +propl (PS * ps, Lit * this) +{ + Lit **l, *other, *prev, *new_lit, **eol; + Cls *next, **htp_ptr, **new_htp_ptr; + Cls *c; +#ifdef STATS + unsigned size; +#endif + + htp_ptr = LIT2HTPS (this); + assert (this->val == FALSE); + + /* Traverse all non binary clauses with 'this'. Head/Tail pointers are + * updated as well. + */ + for (c = *htp_ptr; c; c = next) + { + ps->visits++; +#ifdef STATS + size = c->size; + assert (size >= 3); + ps->traversals++; /* other is dereferenced at least */ + + if (size == 3) + ps->tvisits++; + else if (size >= 4) + { + ps->lvisits++; + ps->ltraversals++; + } +#endif +#ifdef TRACE + assert (!c->collected); +#endif + assert (c->size > 0); + + other = c->lits[0]; + if (other != this) + { + assert (c->size != 1); + c->lits[0] = this; + c->lits[1] = other; + next = c->next[1]; + c->next[1] = c->next[0]; + c->next[0] = next; + } + else if (c->size == 1) /* With assumptions we need to + * traverse unit clauses as well. + */ + { + assert (!ps->conflict); + ps->conflict = c; + break; + } + else + { + assert (other == this && c->size > 1); + other = c->lits[1]; + next = c->next[0]; + } + assert (other == c->lits[1]); + assert (this == c->lits[0]); + assert (next == c->next[0]); + assert (!c->collect); + + if (other->val == TRUE) + { +#ifdef STATS + ps->othertrue++; + ps->othertruel++; +#endif +#ifndef NDSC + if (should_disconnect_head_tail (ps, other)) + { + new_htp_ptr = LIT2DHTPS (other); + c->next[0] = *new_htp_ptr; + *new_htp_ptr = c; +#ifdef STATS + ps->othertruelu++; +#endif + *htp_ptr = next; + continue; + } +#endif + htp_ptr = c->next; + continue; + } + + l = c->lits + 1; + eol = (Lit**) c->lits + c->size; + prev = this; + + while (++l != eol) + { +#ifdef STATS + if (size >= 3) + { + ps->traversals++; + if (size > 3) + ps->ltraversals++; + } +#endif + new_lit = *l; + *l = prev; + prev = new_lit; + if (new_lit->val != FALSE) break; + } + + if (l == eol) + { + while (l > c->lits + 2) + { + new_lit = *--l; + *l = prev; + prev = new_lit; + } + assert (c->lits[0] == this); + + assert (other == c->lits[1]); + if (other->val == FALSE) /* found conflict */ + { + assert (!ps->conflict); + ps->conflict = c; + return; + } + + assign_forced (ps, other, c); /* unit clause */ + htp_ptr = c->next; + } + else + { + assert (new_lit->val == TRUE || new_lit->val == UNDEF); + c->lits[0] = new_lit; + // *l = this; + new_htp_ptr = LIT2HTPS (new_lit); + c->next[0] = *new_htp_ptr; + *new_htp_ptr = c; + *htp_ptr = next; + } + } +} + +#ifndef NADC + +static unsigned primes[] = { 996293, 330643, 753947, 500873 }; + +#define PRIMES ((sizeof primes)/sizeof *primes) + +static unsigned +hash_ado (PS * ps, Lit ** ado, unsigned salt) +{ + unsigned i, res, tmp; + Lit ** p, * lit; + + assert (salt < PRIMES); + + i = salt; + res = 0; + + for (p = ado; (lit = *p); p++) + { + assert (lit->val); + + tmp = res >> 31; + res <<= 1; + + if (lit->val > 0) + res |= 1; + + assert (i < PRIMES); + res *= primes[i++]; + if (i == PRIMES) + i = 0; + + res += tmp; + } + + return res & (ps->szadotab - 1); +} + +static unsigned +cmp_ado (Lit ** a, Lit ** b) +{ + Lit ** p, ** q, * l, * k; + int res; + + for (p = a, q = b; (l = *p); p++, q++) + { + k = *q; + assert (k); + if ((res = (l->val - k->val))) + return res; + } + + assert (!*q); + + return 0; +} + +static Lit *** +find_ado (PS * ps, Lit ** ado) +{ + Lit *** res, ** other; + unsigned pos, delta; + + pos = hash_ado (ps, ado, 0); + assert (pos < ps->szadotab); + res = ps->adotab + pos; + + other = *res; + if (!other || !cmp_ado (other, ado)) + return res; + + delta = hash_ado (ps, ado, 1); + if (!(delta & 1)) + delta++; + + assert (delta & 1); + assert (delta < ps->szadotab); + + for (;;) + { + pos += delta; + if (pos >= ps->szadotab) + pos -= ps->szadotab; + + assert (pos < ps->szadotab); + res = ps->adotab + pos; + other = *res; + if (!other || !cmp_ado (other, ado)) + return res; + } +} + +static void +enlarge_adotab (PS * ps) +{ + /* TODO make this generic */ + + ABORTIF (ps->szadotab, + "internal: all different objects table needs larger initial size"); + assert (!ps->nadotab); + ps->szadotab = 10000; + NEWN (ps->adotab, ps->szadotab); + CLRN (ps->adotab, ps->szadotab); +} + +static int +propado (PS * ps, Var * v) +{ + Lit ** p, ** q, *** adotabpos, **ado, * lit; + Var * u; + + if (ps->LEVEL && ps->adodisabled) + return 1; + + assert (!ps->conflict); + assert (!ps->adoconflict); + assert (VAR2LIT (v)->val != UNDEF); + assert (!v->adotabpos); + + if (!v->ado) + return 1; + + assert (v->inado); + + for (p = v->ado; (lit = *p); p++) + if (lit->val == UNDEF) + { + u = LIT2VAR (lit); + assert (!u->ado); + u->ado = v->ado; + v->ado = 0; + + return 1; + } + + if (4 * ps->nadotab >= 3 * ps->szadotab) /* at least 75% filled */ + enlarge_adotab (ps); + + adotabpos = find_ado (ps, v->ado); + ado = *adotabpos; + + if (!ado) + { + ps->nadotab++; + v->adotabpos = adotabpos; + *adotabpos = v->ado; + return 1; + } + + assert (ado != v->ado); + + ps->adoconflict = new_clause (ps, 2 * llength (ado), 1); + q = ps->adoconflict->lits; + + for (p = ado; (lit = *p); p++) + *q++ = lit->val == FALSE ? lit : NOTLIT (lit); + + for (p = v->ado; (lit = *p); p++) + *q++ = lit->val == FALSE ? lit : NOTLIT (lit); + + assert (q == ENDOFCLS (ps->adoconflict)); + ps->conflict = ps->adoconflict; + ps->adoconflicts++; + return 0; +} + +#endif + +static void +bcp (PS * ps) +{ + int props = 0; + assert (!ps->conflict); + + if (ps->mtcls) + return; + + for (;;) + { + if (ps->ttail2 < ps->thead) /* prioritize implications */ + { + props++; + prop2 (ps, NOTLIT (*ps->ttail2++)); + } + else if (ps->ttail < ps->thead) /* unit clauses or clauses with length > 2 */ + { + if (ps->conflict) break; + propl (ps, NOTLIT (*ps->ttail++)); + if (ps->conflict) break; + } +#ifndef NADC + else if (ps->ttailado < ps->thead) + { + if (ps->conflict) break; + propado (ps, LIT2VAR (*ps->ttailado++)); + if (ps->conflict) break; + } +#endif + else + break; /* all assignments propagated, so break */ + } + + ps->propagations += props; +} + +static unsigned +drive (PS * ps) +{ + unsigned res, vlevel; + Lit **p; + Var *v; + + res = 0; + for (p = ps->added; p < ps->ahead; p++) + { + v = LIT2VAR (*p); + vlevel = v->level; + assert (vlevel <= ps->LEVEL); + if (vlevel < ps->LEVEL && vlevel > res) + res = vlevel; + } + + return res; +} + +#ifdef VISCORES + +static void +viscores (PS * ps) +{ + Rnk *p, *eor = ps->rnks + ps->max_var; + char name[100], cmd[200]; + FILE * data; + Flt s; + int i; + + for (p = ps->rnks + 1; p <= ps->eor; p++) + { + s = p->score; + if (s == INFFLT) + continue; + s = mulflt (s, ps->nvinc); + assert (flt2double (s) <= 1.0); + } + + sprintf (name, "/tmp/picosat-viscores/data/%08u", ps->conflicts); + sprintf (cmd, "sort -n|nl>%s", name); + + data = popen (cmd, "w"); + for (p = ps->rnks + 1; p <= ps->eor; p++) + { + s = p->score; + if (s == INFFLT) + continue; + s = mulflt (s, ps->nvinc); + fprintf (data, "%lf %d\n", 100.0 * flt2double (s), (int)(p - ps->rnks)); + } + fflush (data); + pclose (data); + + for (i = 0; i < 8; i++) + { + sprintf (cmd, "awk '$3%%8==%d' %s>%s.%d", i, name, name, i); + system (cmd); + } + + fprintf (ps->fviscores, "set title \"%u\"\n", ps->conflicts); + fprintf (ps->fviscores, "plot [0:%u] 0, 100 * (1 - 1/1.1), 100", ps->max_var); + + for (i = 0; i < 8; i++) + fprintf (ps->fviscores, + ", \"%s.%d\" using 1:2:3 with labels tc lt %d", + name, i, i + 1); + + fputc ('\n', ps->fviscores); + fflush (ps->fviscores); +#ifndef WRITEGIF + usleep (50000); /* refresh rate of 20 Hz */ +#endif +} + +#endif + +static void +crescore (PS * ps) +{ + Cls **p, *c; + Act *a; + Flt factor; + int l = log2flt (ps->cinc); + assert (l > 0); + factor = base2flt (1, -l); + + for (p = ps->lclauses; p != ps->lhead; p++) + { + c = *p; + + if (!c) + continue; + +#ifdef TRACE + if (c->collected) + continue; +#endif + assert (c->learned); + + if (c->size <= 2) + continue; + + a = CLS2ACT (c); + *a = mulflt (*a, factor); + } + + ps->cinc = mulflt (ps->cinc, factor); +} + +static void +inc_vinc (PS * ps) +{ +#ifdef VISCORES + ps->nvinc = mulflt (ps->nvinc, ps->fvinc); +#endif + ps->vinc = mulflt (ps->vinc, ps->ifvinc); +} + +inline static void +inc_max_var (PS * ps) +{ + Lit *lit; + Rnk *r; + Var *v; + + assert (ps->max_var < ps->size_vars); + + if (ps->max_var + 1 == ps->size_vars) + enlarge (ps, ps->size_vars + 2*(ps->size_vars + 3) / 4); /* +25% */ + + ps->max_var++; /* new index of variable */ + assert (ps->max_var); /* no unsigned overflow */ + + assert (ps->max_var < ps->size_vars); + + lit = ps->lits + 2 * ps->max_var; + lit[0].val = lit[1].val = UNDEF; + + memset (ps->htps + 2 * ps->max_var, 0, 2 * sizeof *ps->htps); +#ifndef NDSC + memset (ps->dhtps + 2 * ps->max_var, 0, 2 * sizeof *ps->dhtps); +#endif + memset (ps->impls + 2 * ps->max_var, 0, 2 * sizeof *ps->impls); + memset (ps->jwh + 2 * ps->max_var, 0, 2 * sizeof *ps->jwh); + + v = ps->vars + ps->max_var; /* initialize variable components */ + CLR (v); + + r = ps->rnks + ps->max_var; /* initialize rank */ + CLR (r); + + hpush (ps, r); +} + +static void +force (PS * ps, Cls * c) +{ + Lit ** p, ** eol, * lit, * forced; + Cls * reason; + + forced = 0; + reason = c; + + eol = end_of_lits (c); + for (p = c->lits; p < eol; p++) + { + lit = *p; + if (lit->val == UNDEF) + { + assert (!forced); + forced = lit; +#ifdef NO_BINARY_CLAUSES + if (c == &ps->impl) + reason = LIT2REASON (NOTLIT (p[p == c->lits ? 1 : -1])); +#endif + } + else + assert (lit->val == FALSE); + } + +#ifdef NO_BINARY_CLAUSES + if (c == &ps->impl) + resetimpl (ps); +#endif + if (!forced) + return; + + assign_forced (ps, forced, reason); +} + +static void +inc_lreduce (PS * ps) +{ +#ifdef STATS + ps->inclreduces++; +#endif + ps->lreduce *= FREDUCE; + ps->lreduce /= 100; + report (ps, 1, '+'); +} + +static void +backtrack (PS * ps) +{ + unsigned new_level; + Cls * c; + + ps->conflicts++; + LOG ( fprintf (ps->out, "%sconflict ", ps->prefix); dumpclsnl (ps, ps->conflict)); + + analyze (ps); + new_level = drive (ps); + // TODO: why not? assert (new_level != 1 || (ps->ahead - ps->added) == 2); + c = add_simplified_clause (ps, 1); + undo (ps, new_level); + force (ps, c); + + if ( +#ifndef NFL + !ps->simplifying && +#endif + !--ps->lreduceadjustcnt) + { + /* With FREDUCE==110 and FREDADJ=121 we stir 'lreduce' to be + * proportional to 'sqrt(conflicts)'. In earlier version we actually + * used 'FREDADJ=150', which results in 'lreduce' to approximate + * 'conflicts^(log(1.1)/log(1.5))' which is close to the fourth root + * of 'conflicts', since log(1.1)/log(1.5)=0.235 (as observed by + * Donald Knuth). The square root is the same we get by a Glucose + * style increase, which simply adds a constant at every reduction. + * This would be way simpler to implement but for now we keep the more + * complicated code using the adjust increments and counters. + */ + ps->lreduceadjustinc *= FREDADJ; ps->lreduceadjustinc /= 100; ps->lreduceadjustcnt + = ps->lreduceadjustinc; + inc_lreduce (ps); + } + + if (ps->verbosity >= 4 && !(ps->conflicts % 1000)) + report (ps, 4, 'C'); +} + +static void +inc_cinc (PS * ps) +{ + ps->cinc = mulflt (ps->cinc, ps->fcinc); + if (ps->lcinc < ps->cinc) + crescore (ps); +} + +static void +incincs (PS * ps) +{ + inc_vinc (ps); + inc_cinc (ps); +#ifdef VISCORES + viscores (ps); +#endif +} + +static void +disconnect_clause (PS * ps, Cls * c) +{ + assert (c->connected); + + if (c->size > 2) + { + if (c->learned) + { + assert (ps->nlclauses > 0); + ps->nlclauses--; + + assert (ps->llits >= c->size); + ps->llits -= c->size; + } + else + { + assert (ps->noclauses > 0); + ps->noclauses--; + + assert (ps->olits >= c->size); + ps->olits -= c->size; + } + } + +#ifndef NDEBUG + c->connected = 0; +#endif +} + +static int +clause_is_toplevel_satisfied (PS * ps, Cls * c) +{ + Lit *lit, **p, **eol = end_of_lits (c); + Var *v; + + for (p = c->lits; p < eol; p++) + { + lit = *p; + if (lit->val == TRUE) + { + v = LIT2VAR (lit); + if (!v->level) + return 1; + } + } + + return 0; +} + +static int +collect_clause (PS * ps, Cls * c) +{ + assert (c->collect); + c->collect = 0; + +#ifdef TRACE + assert (!c->collected); + c->collected = 1; +#endif + disconnect_clause (ps, c); + +#ifdef TRACE + if (ps->trace && (!c->learned || c->used)) + return 0; +#endif + delete_clause (ps, c); + + return 1; +} + +static size_t +collect_clauses (PS * ps) +{ + Cls *c, **p, **q, * next; + Lit * lit, * eol; + size_t res; + int i; + + res = ps->current_bytes; + + eol = ps->lits + 2 * ps->max_var + 1; + for (lit = ps->lits + 2; lit <= eol; lit++) + { + for (i = 0; i <= 1; i++) + { + if (i) + { +#ifdef NO_BINARY_CLAUSES + Ltk * lstk = LIT2IMPLS (lit); + Lit ** r, ** s; + r = lstk->start; + if (lit->val != TRUE || LIT2VAR (lit)->level) + for (s = r; s < lstk->start + lstk->count; s++) + { + Lit * other = *s; + Var *v = LIT2VAR (other); + if (v->level || + other->val != TRUE) + *r++ = other; + } + lstk->count = r - lstk->start; + continue; +#else + p = LIT2IMPLS (lit); +#endif + } + else + p = LIT2HTPS (lit); + + for (c = *p; c; c = next) + { + q = c->next; + if (c->lits[0] != lit) + q++; + + next = *q; + if (c->collect) + *p = next; + else + p = q; + } + } + } + +#ifndef NDSC + for (lit = ps->lits + 2; lit <= eol; lit++) + { + p = LIT2DHTPS (lit); + while ((c = *p)) + { + Lit * other = c->lits[0]; + if (other == lit) + { + q = c->next + 1; + } + else + { + assert (c->lits[1] == lit); + q = c->next; + } + + if (c->collect) + *p = *q; + else + p = q; + } + } +#endif + + for (p = SOC; p != EOC; p = NXC (p)) + { + c = *p; + + if (!c) + continue; + + if (!c->collect) + continue; + + if (collect_clause (ps, c)) + *p = 0; + } + +#ifdef TRACE + if (!ps->trace) +#endif + { + q = ps->oclauses; + for (p = q; p < ps->ohead; p++) + if ((c = *p)) + *q++ = c; + ps->ohead = q; + + q = ps->lclauses; + for (p = q; p < ps->lhead; p++) + if ((c = *p)) + *q++ = c; + ps->lhead = q; + } + + assert (ps->current_bytes <= res); + res -= ps->current_bytes; + ps->recycled += res; + + LOG ( fprintf (ps->out, "%scollected %ld bytes\n", ps->prefix, (long)res)); + + return res; +} + +static int +need_to_reduce (PS * ps) +{ + return ps->nlclauses >= reduce_limit_on_lclauses (ps); +} + +#ifdef NLUBY + +static void +inc_drestart (PS * ps) +{ + ps->drestart *= FRESTART; + ps->drestart /= 100; + + if (ps->drestart >= MAXRESTART) + ps->drestart = MAXRESTART; +} + +static void +inc_ddrestart (PS * ps) +{ + ps->ddrestart *= FRESTART; + ps->ddrestart /= 100; + + if (ps->ddrestart >= MAXRESTART) + ps->ddrestart = MAXRESTART; +} + +#else + +static unsigned +luby (unsigned i) +{ + unsigned k; + for (k = 1; k < 32; k++) + if (i == (1u << k) - 1) + return 1u << (k - 1); + + for (k = 1;; k++) + if ((1u << (k - 1)) <= i && i < (1u << k) - 1) + return luby (i - (1u << (k-1)) + 1); +} + +#endif + +#ifndef NLUBY +static void +inc_lrestart (PS * ps, int skip) +{ + unsigned delta; + + delta = 100 * luby (++ps->lubycnt); + ps->lrestart = ps->conflicts + delta; + + if (ps->waslubymaxdelta) + report (ps, 1, skip ? 'N' : 'R'); + else + report (ps, 2, skip ? 'n' : 'r'); + + if (delta > ps->lubymaxdelta) + { + ps->lubymaxdelta = delta; + ps->waslubymaxdelta = 1; + } + else + ps->waslubymaxdelta = 0; +} +#endif + +static void +init_restart (PS * ps) +{ +#ifdef NLUBY + /* TODO: why is it better in incremental usage to have smaller initial + * outer restart interval? + */ + ps->ddrestart = ps->calls > 1 ? MINRESTART : 1000; + ps->drestart = MINRESTART; + ps->lrestart = ps->conflicts + ps->drestart; +#else + ps->lubycnt = 0; + ps->lubymaxdelta = 0; + ps->waslubymaxdelta = 0; + inc_lrestart (ps, 0); +#endif +} + +static void +restart (PS * ps) +{ + int skip; +#ifdef NLUBY + char kind; + int outer; + + inc_drestart (ps); + outer = (ps->drestart >= ps->ddrestart); + + if (outer) + skip = very_high_agility (ps); + else + skip = high_agility (ps); +#else + skip = medium_agility (ps); +#endif + +#ifdef STATS + if (skip) + ps->skippedrestarts++; +#endif + + assert (ps->conflicts >= ps->lrestart); + + if (!skip) + { + ps->restarts++; + assert (ps->LEVEL > 1); + LOG ( fprintf (ps->out, "%srestart %u\n", ps->prefix, ps->restarts)); + undo (ps, 0); + } + +#ifdef NLUBY + if (outer) + { + kind = skip ? 'N' : 'R'; + inc_ddrestart (ps); + ps->drestart = MINRESTART; + } + else if (skip) + { + kind = 'n'; + } + else + { + kind = 'r'; + } + + assert (ps->drestart <= MAXRESTART); + ps->lrestart = ps->conflicts + ps->drestart; + assert (ps->lrestart > ps->conflicts); + + report (outer ? 1 : 2, kind); +#else + inc_lrestart (ps, skip); +#endif +} + +inline static void +assign_decision (PS * ps, Lit * lit) +{ + assert (!ps->conflict); + + ps->LEVEL++; + + LOG ( fprintf (ps->out, "%snew level %u\n", ps->prefix, ps->LEVEL)); + LOG ( fprintf (ps->out, + "%sassign %d at level %d <= DECISION\n", + ps->prefix, LIT2INT (lit), ps->LEVEL)); + + assign (ps, lit, 0); +} + +#ifndef NFL + +static int +lit_has_binary_clauses (PS * ps, Lit * lit) +{ +#ifdef NO_BINARY_CLAUSES + Ltk* lstk = LIT2IMPLS (lit); + return lstk->count != 0; +#else + return *LIT2IMPLS (lit) != 0; +#endif +} + +static void +flbcp (PS * ps) +{ +#ifdef STATS + unsigned long long propagaions_before_bcp = ps->propagations; +#endif + bcp (ps); +#ifdef STATS + ps->flprops += ps->propagations - propagaions_before_bcp; +#endif +} + +inline static int +cmp_inverse_rnk (PS * ps, Rnk * a, Rnk * b) +{ + (void) ps; + return -cmp_rnk (a, b); +} + +inline static Flt +rnk2jwh (PS * ps, Rnk * r) +{ + Flt res, sum, pjwh, njwh; + Lit * plit, * nlit; + + plit = RNK2LIT (r); + nlit = plit + 1; + + pjwh = *LIT2JWH (plit); + njwh = *LIT2JWH (nlit); + + res = mulflt (pjwh, njwh); + + sum = addflt (pjwh, njwh); + sum = mulflt (sum, base2flt (1, -10)); + res = addflt (res, sum); + + return res; +} + +static int +cmp_inverse_jwh_rnk (PS * ps, Rnk * r, Rnk * s) +{ + Flt a = rnk2jwh (ps, r); + Flt b = rnk2jwh (ps, s); + int res = cmpflt (a, b); + + if (res) + return -res; + + return cmp_inverse_rnk (ps, r, s); +} + +static void +faillits (PS * ps) +{ + unsigned i, j, old_trail_count, common, saved_count; + unsigned new_saved_size, oldladded = ps->ladded; + unsigned long long limit, delta; + Lit * lit, * other, * pivot; + Rnk * r, ** p, ** q; + int new_trail_count; + double started; + + if (ps->plain) + return; + + if (ps->heap + 1 >= ps->hhead) + return; + + if (ps->propagations < ps->fllimit) + return; + + sflush (ps); + started = ps->seconds; + + ps->flcalls++; +#ifdef STATSA + ps->flrounds++; +#endif + delta = ps->propagations/10; + if (delta >= 100*1000*1000) delta = 100*1000*1000; + else if (delta <= 100*1000) delta = 100*1000; + + limit = ps->propagations + delta; + ps->fllimit = ps->propagations; + + assert (!ps->LEVEL); + assert (ps->simplifying); + + if (ps->flcalls <= 1) + SORT (Rnk *, cmp_inverse_jwh_rnk, ps->heap + 1, ps->hhead - (ps->heap + 1)); + else + SORT (Rnk *, cmp_inverse_rnk, ps->heap + 1, ps->hhead - (ps->heap + 1)); + + i = 1; /* NOTE: heap starts at position '1' */ + + while (ps->propagations < limit) + { + if (ps->heap + i == ps->hhead) + { + if (ps->ladded == oldladded) + break; + + i = 1; +#ifdef STATS + ps->flrounds++; +#endif + oldladded = ps->ladded; + } + + assert (ps->heap + i < ps->hhead); + + r = ps->heap[i++]; + lit = RNK2LIT (r); + + if (lit->val) + continue; + + if (!lit_has_binary_clauses (ps, NOTLIT (lit))) + { +#ifdef STATS + ps->flskipped++; +#endif + continue; + } + +#ifdef STATS + ps->fltried++; +#endif + LOG ( fprintf (ps->out, "%strying %d as failed literal\n", + ps->prefix, LIT2INT (lit))); + + assign_decision (ps, lit); + old_trail_count = ps->thead - ps->trail; + flbcp (ps); + + if (ps->conflict) + { +EXPLICITLY_FAILED_LITERAL: + LOG ( fprintf (ps->out, "%sfound explicitly failed literal %d\n", + ps->prefix, LIT2INT (lit))); + + ps->failedlits++; + ps->efailedlits++; + + backtrack (ps); + flbcp (ps); + + if (!ps->conflict) + continue; + +CONTRADICTION: + assert (!ps->LEVEL); + backtrack (ps); + assert (ps->mtcls); + + goto RETURN; + } + + if (ps->propagations >= limit) + { + undo (ps, 0); + break; + } + + lit = NOTLIT (lit); + + if (!lit_has_binary_clauses (ps, NOTLIT (lit))) + { +#ifdef STATS + ps->flskipped++; +#endif + undo (ps, 0); + continue; + } + +#ifdef STATS + ps->fltried++; +#endif + LOG ( fprintf (ps->out, "%strying %d as failed literals\n", + ps->prefix, LIT2INT (lit))); + + new_trail_count = ps->thead - ps->trail; + saved_count = new_trail_count - old_trail_count; + + if (saved_count > ps->saved_size) + { + new_saved_size = ps->saved_size ? 2 * ps->saved_size : 1; + while (saved_count > new_saved_size) + new_saved_size *= 2; + + RESIZEN (ps->saved, ps->saved_size, new_saved_size); + ps->saved_size = new_saved_size; + } + + for (j = 0; j < saved_count; j++) + ps->saved[j] = ps->trail[old_trail_count + j]; + + undo (ps, 0); + + assign_decision (ps, lit); + flbcp (ps); + + if (ps->conflict) + goto EXPLICITLY_FAILED_LITERAL; + + pivot = (ps->thead - ps->trail <= new_trail_count) ? lit : NOTLIT (lit); + + common = 0; + for (j = 0; j < saved_count; j++) + if ((other = ps->saved[j])->val == TRUE) + ps->saved[common++] = other; + + undo (ps, 0); + + LOG (if (common) + fprintf (ps->out, + "%sfound %d literals implied by %d and %d\n", + ps->prefix, common, + LIT2INT (NOTLIT (lit)), LIT2INT (lit))); + +#if 1 // set to zero to disable 'lifting' + for (j = 0; + j < common + /* TODO: For some Velev benchmarks, extracting the common implicit + * failed literals took quite some time. This needs to be fixed by + * a dedicated analyzer. Up to then we bound the number of + * propagations in this loop as well. + */ + && ps->propagations < limit + delta + ; j++) + { + other = ps->saved[j]; + + if (other->val == TRUE) + continue; + + assert (!other->val); + + LOG ( fprintf (ps->out, + "%sforcing %d as forced implicitly failed literal\n", + ps->prefix, LIT2INT (other))); + + assert (pivot != NOTLIT (other)); + assert (pivot != other); + + assign_decision (ps, NOTLIT (other)); + flbcp (ps); + + assert (ps->LEVEL == 1); + + if (ps->conflict) + { + backtrack (ps); + assert (!ps->LEVEL); + } + else + { + assign_decision (ps, pivot); + flbcp (ps); + + backtrack (ps); + + if (ps->LEVEL) + { + assert (ps->LEVEL == 1); + + flbcp (ps); + + if (ps->conflict) + { + backtrack (ps); + assert (!ps->LEVEL); + } + else + { + assign_decision (ps, NOTLIT (pivot)); + flbcp (ps); + backtrack (ps); + + if (ps->LEVEL) + { + assert (ps->LEVEL == 1); + flbcp (ps); + + if (!ps->conflict) + { +#ifdef STATS + ps->floopsed++; +#endif + undo (ps, 0); + continue; + } + + backtrack (ps); + } + + assert (!ps->LEVEL); + } + + assert (!ps->LEVEL); + } + } + assert (!ps->LEVEL); + flbcp (ps); + + ps->failedlits++; + ps->ifailedlits++; + + if (ps->conflict) + goto CONTRADICTION; + } +#endif + } + + ps->fllimit += 9 * (ps->propagations - ps->fllimit); /* 10% for failed literals */ + +RETURN: + + /* First flush top level assigned literals. Those are prohibited from + * being pushed up the heap during 'faillits' since 'simplifying' is set. + */ + assert (ps->heap < ps->hhead); + for (p = q = ps->heap + 1; p < ps->hhead; p++) + { + r = *p; + lit = RNK2LIT (r); + if (lit->val) + r->pos = 0; + else + *q++ = r; + } + + /* Then resort with respect to EVSIDS score and fix positions. + */ + SORT (Rnk *, cmp_inverse_rnk, ps->heap + 1, ps->hhead - (ps->heap + 1)); + for (p = ps->heap + 1; p < ps->hhead; p++) + (*p)->pos = p - ps->heap; + + sflush (ps); + ps->flseconds += ps->seconds - started; +} + +#endif + +static void +simplify (PS * ps, int forced) +{ + Lit * lit, * notlit, ** t; + unsigned collect, delta; +#ifdef STATS + size_t bytes_collected; +#endif + int * q, ilit; + Cls **p, *c; + Var * v; + +#ifndef NDEDBUG + (void) forced; +#endif + + assert (!ps->mtcls); + assert (!satisfied (ps)); + assert (forced || ps->lsimplify <= ps->propagations); + assert (forced || ps->fsimplify <= ps->fixed); + + if (ps->LEVEL) + undo (ps, 0); +#ifndef NFL + ps->simplifying = 1; + faillits (ps); + ps->simplifying = 0; + + if (ps->mtcls) + return; +#endif + + if (ps->cils != ps->cilshead) + { + assert (ps->ttail == ps->thead); + assert (ps->ttail2 == ps->thead); + ps->ttail = ps->trail; + for (t = ps->trail; t < ps->thead; t++) + { + lit = *t; + v = LIT2VAR (lit); + if (v->internal) + { + assert (LIT2INT (lit) < 0); + assert (lit->val == TRUE); + unassign (ps, lit); + } + else + *ps->ttail++ = lit; + } + ps->ttail2 = ps->thead = ps->ttail; + + for (q = ps->cils; q != ps->cilshead; q++) + { + ilit = *q; + assert (0 < ilit && ilit <= (int) ps->max_var); + v = ps->vars + ilit; + assert (v->internal); + v->level = 0; + v->reason = 0; + lit = int2lit (ps, -ilit); + assert (lit->val == UNDEF); + lit->val = TRUE; + notlit = NOTLIT (lit); + assert (notlit->val == UNDEF); + notlit->val = FALSE; + } + } + + collect = 0; + for (p = SOC; p != EOC; p = NXC (p)) + { + c = *p; + if (!c) + continue; + +#ifdef TRACE + if (c->collected) + continue; +#endif + + if (c->locked) + continue; + + assert (!c->collect); + if (clause_is_toplevel_satisfied (ps, c)) + { + mark_clause_to_be_collected (c); + collect++; + } + } + + LOG ( fprintf (ps->out, "%scollecting %d clauses\n", ps->prefix, collect)); +#ifdef STATS + bytes_collected = +#endif + collect_clauses (ps); +#ifdef STATS + ps->srecycled += bytes_collected; +#endif + + if (ps->cils != ps->cilshead) + { + for (q = ps->cils; q != ps->cilshead; q++) + { + ilit = *q; + assert (0 < ilit && ilit <= (int) ps->max_var); + assert (ps->vars[ilit].internal); + if (ps->rilshead == ps->eorils) + ENLARGE (ps->rils, ps->rilshead, ps->eorils); + *ps->rilshead++ = ilit; + lit = int2lit (ps, -ilit); + assert (lit->val == TRUE); + lit->val = UNDEF; + notlit = NOTLIT (lit); + assert (notlit->val == FALSE); + notlit->val = UNDEF; + } + ps->cilshead = ps->cils; + } + + delta = 10 * (ps->olits + ps->llits) + 100000; + if (delta > 2000000) + delta = 2000000; + ps->lsimplify = ps->propagations + delta; + ps->fsimplify = ps->fixed; + ps->simps++; + + report (ps, 1, 's'); +} + +static void +iteration (PS * ps) +{ + assert (!ps->LEVEL); + assert (bcp_queue_is_empty (ps)); + assert (ps->isimplify < ps->fixed); + + ps->iterations++; + report (ps, 2, 'i'); +#ifdef NLUBY + ps->drestart = MINRESTART; + ps->lrestart = ps->conflicts + ps->drestart; +#else + init_restart (ps); +#endif + ps->isimplify = ps->fixed; +} + +static int +cmp_glue_activity_size (PS * ps, Cls * c, Cls * d) +{ + Act a, b, * p, * q; + + (void) ps; + + assert (c->learned); + assert (d->learned); + + if (c->glue < d->glue) // smaller glue preferred + return 1; + + if (c->glue > d->glue) + return -1; + + p = CLS2ACT (c); + q = CLS2ACT (d); + a = *p; + b = *q; + + if (a < b) // then higher activity + return -1; + + if (b < a) + return 1; + + if (c->size < d->size) // then smaller size + return 1; + + if (c->size > d->size) + return -1; + + return 0; +} + +static void +reduce (PS * ps, unsigned percentage) +{ + unsigned redcount, lcollect, collect, target; +#ifdef STATS + size_t bytes_collected; +#endif + Cls **p, *c; + + assert (ps->rhead == ps->resolved); + + ps->lastreduceconflicts = ps->conflicts; + + assert (percentage <= 100); + LOG ( fprintf (ps->out, + "%sreducing %u%% learned clauses\n", + ps->prefix, percentage)); + + while (ps->nlclauses - ps->llocked > (unsigned)(ps->eor - ps->resolved)) + ENLARGE (ps->resolved, ps->rhead, ps->eor); + + collect = 0; + lcollect = 0; + + for (p = ((ps->fsimplify < ps->fixed) ? SOC : ps->lclauses); p != EOC; p = NXC (p)) + { + c = *p; + if (!c) + continue; + +#ifdef TRACE + if (c->collected) + continue; +#endif + + if (c->locked) + continue; + + assert (!c->collect); + if (ps->fsimplify < ps->fixed && clause_is_toplevel_satisfied (ps, c)) + { + mark_clause_to_be_collected (c); + collect++; + + if (c->learned && c->size > 2) + lcollect++; + + continue; + } + + if (!c->learned) + continue; + + if (c->size <= 2) + continue; + + assert (ps->rhead < ps->eor); + *ps->rhead++ = c; + } + assert (ps->rhead <= ps->eor); + + ps->fsimplify = ps->fixed; + + redcount = ps->rhead - ps->resolved; + SORT (Cls *, cmp_glue_activity_size, ps->resolved, redcount); + + assert (ps->nlclauses >= lcollect); + target = ps->nlclauses - lcollect + 1; + + target = (percentage * target + 99) / 100; + + if (target >= redcount) + target = redcount; + + ps->rhead = ps->resolved + target; + while (ps->rhead > ps->resolved) + { + c = *--ps->rhead; + mark_clause_to_be_collected (c); + + collect++; + if (c->learned && c->size > 2) /* just for consistency */ + lcollect++; + } + + if (collect) + { + ps->reductions++; +#ifdef STATS + bytes_collected = +#endif + collect_clauses (ps); +#ifdef STATS + ps->rrecycled += bytes_collected; +#endif + report (ps, 2, '-'); + } + + if (!lcollect) + inc_lreduce (ps); /* avoid dead lock */ + + assert (ps->rhead == ps->resolved); +} + +static void +init_reduce (PS * ps) +{ + // lreduce = loadded / 2; + ps->lreduce = 1000; + + if (ps->lreduce < 100) + ps->lreduce = 100; + + if (ps->verbosity) + fprintf (ps->out, + "%s\n%sinitial reduction limit %u clauses\n%s\n", + ps->prefix, ps->prefix, ps->lreduce, ps->prefix); +} + +static unsigned +rng (PS * ps) +{ + unsigned res = ps->srng; + ps->srng *= 1664525u; + ps->srng += 1013904223u; + NOLOG ( fprintf (ps->out, "%srng () = %u\n", ps->prefix, res)); + return res; +} + +static unsigned +rrng (PS * ps, unsigned low, unsigned high) +{ + unsigned long long tmp; + unsigned res, elements; + assert (low <= high); + elements = high - low + 1; + tmp = rng (ps); + tmp *= elements; + tmp >>= 32; + tmp += low; + res = tmp; + NOLOG ( fprintf (ps->out, "%srrng (ps, %u, %u) = %u\n", ps->prefix, low, high, res)); + assert (low <= res); + assert (res <= high); + return res; +} + +static Lit * +decide_phase (PS * ps, Lit * lit) +{ + Lit * not_lit = NOTLIT (lit); + Var *v = LIT2VAR (lit); + + assert (LIT2SGN (lit) > 0); + if (v->usedefphase) + { + if (v->defphase) + { + /* assign to TRUE */ + } + else + { + /* assign to FALSE */ + lit = not_lit; + } + } + else if (!v->assigned) + { +#ifdef STATS + ps->staticphasedecisions++; +#endif + if (ps->defaultphase == POSPHASE) + { + /* assign to TRUE */ + } + else if (ps->defaultphase == NEGPHASE) + { + /* assign to FALSE */ + lit = not_lit; + } + else if (ps->defaultphase == RNDPHASE) + { + /* randomly assign default phase */ + if (rrng (ps, 1, 2) != 2) + lit = not_lit; + } + else if (*LIT2JWH(lit) <= *LIT2JWH (not_lit)) + { + /* assign to FALSE (Jeroslow-Wang says there are more short + * clauses with negative occurence of this variable, so satisfy + * those, to minimize BCP) + */ + lit = not_lit; + } + else + { + /* assign to TRUE (... but strictly more positive occurrences) */ + } + } + else + { + /* repeat last phase: phase saving heuristic */ + + if (v->phase) + { + /* assign to TRUE (last phase was TRUE as well) */ + } + else + { + /* assign to FALSE (last phase was FALSE as well) */ + lit = not_lit; + } + } + + return lit; +} + +static unsigned +gcd (unsigned a, unsigned b) +{ + unsigned tmp; + + assert (a); + assert (b); + + if (a < b) + { + tmp = a; + a = b; + b = tmp; + } + + while (b) + { + assert (a >= b); + tmp = b; + b = a % b; + a = tmp; + } + + return a; +} + +static Lit * +rdecide (PS * ps) +{ + unsigned idx, delta, spread; + Lit * res; + + spread = RDECIDE; + if (rrng (ps, 1, spread) != 2) + return 0; + + assert (1 <= ps->max_var); + idx = rrng (ps, 1, ps->max_var); + res = int2lit (ps, idx); + + if (res->val != UNDEF) + { + delta = rrng (ps, 1, ps->max_var); + while (gcd (delta, ps->max_var) != 1) + delta--; + + assert (1 <= delta); + assert (delta <= ps->max_var); + + do { + idx += delta; + if (idx > ps->max_var) + idx -= ps->max_var; + res = int2lit (ps, idx); + } while (res->val != UNDEF); + } + +#ifdef STATS + ps->rdecisions++; +#endif + res = decide_phase (ps, res); + LOG ( fprintf (ps->out, "%srdecide %d\n", ps->prefix, LIT2INT (res))); + + return res; +} + +static Lit * +sdecide (PS * ps) +{ + Lit *res; + Rnk *r; + + for (;;) + { + r = htop (ps); + res = RNK2LIT (r); + if (res->val == UNDEF) break; + (void) hpop (ps); + NOLOG ( fprintf (ps->out, + "%shpop %u %u %u\n", + ps->prefix, r - ps->rnks, + FLTMANTISSA(r->score), + FLTEXPONENT(r->score))); + } + +#ifdef STATS + ps->sdecisions++; +#endif + res = decide_phase (ps, res); + + LOG ( fprintf (ps->out, "%ssdecide %d\n", ps->prefix, LIT2INT (res))); + + return res; +} + +static Lit * +adecide (PS * ps) +{ + Lit *lit; + Var * v; + + assert (ps->als < ps->alshead); + assert (!ps->failed_assumption); + + while (ps->alstail < ps->alshead) + { + lit = *ps->alstail++; + + if (lit->val == FALSE) + { + ps->failed_assumption = lit; + v = LIT2VAR (lit); + + use_var (ps, v); + + LOG ( fprintf (ps->out, "%sfirst failed assumption %d\n", + ps->prefix, LIT2INT (ps->failed_assumption))); + fanalyze (ps); + return 0; + } + + if (lit->val == TRUE) + { + v = LIT2VAR (lit); + if (v->level > ps->adecidelevel) + ps->adecidelevel = v->level; + continue; + } + +#ifdef STATS + ps->assumptions++; +#endif + LOG ( fprintf (ps->out, "%sadecide %d\n", ps->prefix, LIT2INT (lit))); + ps->adecidelevel = ps->LEVEL + 1; + + return lit; + } + + return 0; +} + +static void +decide (PS * ps) +{ + Lit * lit; + + assert (!satisfied (ps)); + assert (!ps->conflict); + + if (ps->alstail < ps->alshead && (lit = adecide (ps))) + ; + else if (ps->failed_assumption) + return; + else if (satisfied (ps)) + return; + else if (!(lit = rdecide (ps))) + lit = sdecide (ps); + + assert (lit); + assign_decision (ps, lit); + + ps->levelsum += ps->LEVEL; + ps->decisions++; +} + +static int +sat (PS * ps, int l) +{ + int count = 0, backtracked; + + if (!ps->conflict) + bcp (ps); + + if (ps->conflict) + backtrack (ps); + + if (ps->mtcls) + return PICOSAT_UNSATISFIABLE; + + if (satisfied (ps)) + goto SATISFIED; + + if (ps->lsimplify <= ps->propagations) + simplify (ps, 0); + + if (ps->mtcls) + return PICOSAT_UNSATISFIABLE; + + if (satisfied (ps)) + goto SATISFIED; + + init_restart (ps); + + if (!ps->lreduce) + init_reduce (ps); + + ps->isimplify = ps->fixed; + backtracked = 0; + + for (;;) + { + if (!ps->conflict) + bcp (ps); + + if (ps->conflict) + { + incincs (ps); + backtrack (ps); + + if (ps->mtcls) + return PICOSAT_UNSATISFIABLE; + backtracked = 1; + continue; + } + + if (satisfied (ps)) + { +SATISFIED: +#ifndef NDEBUG + original_clauses_satisfied (ps); + assumptions_satisfied (ps); +#endif + return PICOSAT_SATISFIABLE; + } + + if (backtracked) + { + backtracked = 0; + if (!ps->LEVEL && ps->isimplify < ps->fixed) + iteration (ps); + } + + if (l >= 0 && count >= l) /* decision limit reached ? */ + return PICOSAT_UNKNOWN; + + if (ps->interrupt.function && /* external interrupt */ + count > 0 && !(count % INTERRUPTLIM) && + ps->interrupt.function (ps->interrupt.state)) + return PICOSAT_UNKNOWN; + + if (ps->propagations >= ps->lpropagations)/* propagation limit reached ? */ + return PICOSAT_UNKNOWN; + +#ifndef NADC + if (!ps->adodisabled && ps->adoconflicts >= ps->adoconflictlimit) + { + assert (bcp_queue_is_empty (ps)); + return PICOSAT_UNKNOWN; + } +#endif + + if (ps->fsimplify < ps->fixed && ps->lsimplify <= ps->propagations) + { + simplify (ps, 0); + if (!bcp_queue_is_empty (ps)) + continue; +#ifndef NFL + if (ps->mtcls) + return PICOSAT_UNSATISFIABLE; + + if (satisfied (ps)) + return PICOSAT_SATISFIABLE; + + assert (!ps->LEVEL); +#endif + } + + if (need_to_reduce (ps)) + reduce (ps, 50); + + if (ps->conflicts >= ps->lrestart && ps->LEVEL > 2) + restart (ps); + + decide (ps); + if (ps->failed_assumption) + return PICOSAT_UNSATISFIABLE; + count++; + } +} + +static void +rebias (PS * ps) +{ + Cls ** p, * c; + Var * v; + + for (v = ps->vars + 1; v <= ps->vars + ps->max_var; v++) + v->assigned = 0; + + memset (ps->jwh, 0, 2 * (ps->max_var + 1) * sizeof *ps->jwh); + + for (p = ps->oclauses; p < ps->ohead; p++) + { + c = *p; + + if (!c) + continue; + + if (c->learned) + continue; + + incjwh (ps, c); + } +} + +#ifdef TRACE + +static unsigned +core (PS * ps) +{ + unsigned idx, prev, this, delta, i, lcore, vcore; + unsigned *stack, *shead, *eos; + Lit **q, **eol, *lit; + Cls *c, *reason; + Znt *p, byte; + Zhn *zhain; + Var *v; + + assert (ps->trace); + + assert (ps->mtcls || ps->failed_assumption); + if (ps->ocore >= 0) + return ps->ocore; + + lcore = ps->ocore = vcore = 0; + + stack = shead = eos = 0; + ENLARGE (stack, shead, eos); + + if (ps->mtcls) + { + idx = CLS2IDX (ps->mtcls); + *shead++ = idx; + } + else + { + assert (ps->failed_assumption); + v = LIT2VAR (ps->failed_assumption); + reason = v->reason; + assert (reason); + idx = CLS2IDX (reason); + *shead++ = idx; + } + + while (shead > stack) + { + idx = *--shead; + zhain = IDX2ZHN (idx); + + if (zhain) + { + if (zhain->core) + continue; + + zhain->core = 1; + lcore++; + + c = IDX2CLS (idx); + if (c) + { + assert (!c->core); + c->core = 1; + } + + i = 0; + delta = 0; + prev = 0; + for (p = zhain->znt; (byte = *p); p++, i += 7) + { + delta |= (byte & 0x7f) << i; + if (byte & 0x80) + continue; + + this = prev + delta; + assert (prev < this); /* no overflow */ + + if (shead == eos) + ENLARGE (stack, shead, eos); + *shead++ = this; + + prev = this; + delta = 0; + i = -7; + } + } + else + { + c = IDX2CLS (idx); + + assert (c); + assert (!c->learned); + + if (c->core) + continue; + + c->core = 1; + ps->ocore++; + + eol = end_of_lits (c); + for (q = c->lits; q < eol; q++) + { + lit = *q; + v = LIT2VAR (lit); + if (v->core) + continue; + + v->core = 1; + vcore++; + + if (!ps->failed_assumption) continue; + if (lit != ps->failed_assumption) continue; + + reason = v->reason; + if (!reason) continue; + if (reason->core) continue; + + idx = CLS2IDX (reason); + if (shead == eos) + ENLARGE (stack, shead, eos); + *shead++ = idx; + } + } + } + + DELETEN (stack, eos - stack); + + if (ps->verbosity) + fprintf (ps->out, + "%s%u core variables out of %u (%.1f%%)\n" + "%s%u core original clauses out of %u (%.1f%%)\n" + "%s%u core learned clauses out of %u (%.1f%%)\n", + ps->prefix, vcore, ps->max_var, PERCENT (vcore, ps->max_var), + ps->prefix, ps->ocore, ps->oadded, PERCENT (ps->ocore, ps->oadded), + ps->prefix, lcore, ps->ladded, PERCENT (lcore, ps->ladded)); + + return ps->ocore; +} + +static void +trace_lits (PS * ps, Cls * c, FILE * file) +{ + Lit **p, **eol = end_of_lits (c); + + assert (c); + assert (c->core); + + for (p = c->lits; p < eol; p++) + fprintf (file, "%d ", LIT2INT (*p)); + + fputc ('0', file); +} + +static void +write_idx (PS * ps, unsigned idx, FILE * file) +{ + fprintf (file, "%ld", EXPORTIDX (idx)); +} + +static void +trace_clause (PS * ps, unsigned idx, Cls * c, FILE * file, int fmt) +{ + assert (c); + assert (c->core); + assert (fmt == RUP_TRACE_FMT || !c->learned); + assert (CLS2IDX (c) == idx); + + if (fmt != RUP_TRACE_FMT) + { + write_idx (ps, idx, file); + fputc (' ', file); + } + + trace_lits (ps, c, file); + + if (fmt != RUP_TRACE_FMT) + fputs (" 0", file); + + fputc ('\n', file); +} + +static void +trace_zhain (PS * ps, unsigned idx, Zhn * zhain, FILE * file, int fmt) +{ + unsigned prev, this, delta, i; + Znt *p, byte; + Cls * c; + + assert (zhain); + assert (zhain->core); + + write_idx (ps, idx, file); + fputc (' ', file); + + if (fmt == EXTENDED_TRACECHECK_TRACE_FMT) + { + c = IDX2CLS (idx); + assert (c); + trace_lits (ps, c, file); + } + else + { + assert (fmt == COMPACT_TRACECHECK_TRACE_FMT); + putc ('*', file); + } + + i = 0; + delta = 0; + prev = 0; + + for (p = zhain->znt; (byte = *p); p++, i += 7) + { + delta |= (byte & 0x7f) << i; + if (byte & 0x80) + continue; + + this = prev + delta; + + putc (' ', file); + write_idx (ps, this, file); + + prev = this; + delta = 0; + i = -7; + } + + fputs (" 0\n", file); +} + +static void +write_core (PS * ps, FILE * file) +{ + Lit **q, **eol; + Cls **p, *c; + + fprintf (file, "p cnf %u %u\n", ps->max_var, core (ps)); + + for (p = SOC; p != EOC; p = NXC (p)) + { + c = *p; + + if (!c || c->learned || !c->core) + continue; + + eol = end_of_lits (c); + for (q = c->lits; q < eol; q++) + fprintf (file, "%d ", LIT2INT (*q)); + + fputs ("0\n", file); + } +} + +#endif + +static void +write_trace (PS * ps, FILE * file, int fmt) +{ +#ifdef TRACE + Cls *c, ** p; + Zhn *zhain; + unsigned i; + + core (ps); + + if (fmt == RUP_TRACE_FMT) + { + ps->rupvariables = picosat_variables (ps), + ps->rupclauses = picosat_added_original_clauses (ps); + write_rup_header (ps, file); + } + + for (p = SOC; p != EOC; p = NXC (p)) + { + c = *p; + + if (ps->oclauses <= p && p < ps->eoo) + { + i = OIDX2IDX (p - ps->oclauses); + assert (!c || CLS2IDX (c) == i); + } + else + { + assert (ps->lclauses <= p && p < ps->EOL); + i = LIDX2IDX (p - ps->lclauses); + } + + zhain = IDX2ZHN (i); + + if (zhain) + { + if (zhain->core) + { + if (fmt == RUP_TRACE_FMT) + trace_clause (ps,i, c, file, fmt); + else + trace_zhain (ps, i, zhain, file, fmt); + } + } + else if (c) + { + if (fmt != RUP_TRACE_FMT && c) + { + if (c->core) + trace_clause (ps, i, c, file, fmt); + } + } + } +#else + (void) file; + (void) fmt; + (void) ps; +#endif +} + +static void +write_core_wrapper (PS * ps, FILE * file, int fmt) +{ + (void) fmt; +#ifdef TRACE + write_core (ps, file); +#else + (void) ps; + (void) file; +#endif +} + +static Lit * +import_lit (PS * ps, int lit, int nointernal) +{ + Lit * res; + Var * v; + + ABORTIF (lit == INT_MIN, "API usage: INT_MIN literal"); + ABORTIF (abs (lit) > (int) ps->max_var && ps->CLS != ps->clshead, + "API usage: new variable index after 'picosat_push'"); + + if (abs (lit) <= (int) ps->max_var) + { + res = int2lit (ps, lit); + v = LIT2VAR (res); + if (nointernal && v->internal) + ABORT ("API usage: trying to import invalid literal"); + else if (!nointernal && !v->internal) + ABORT ("API usage: trying to import invalid context"); + } + else + { + while (abs (lit) > (int) ps->max_var) + inc_max_var (ps); + res = int2lit (ps, lit); + } + + return res; +} + +#ifdef TRACE +static void +reset_core (PS * ps) +{ + Cls ** p, * c; + Zhn ** q, * z; + unsigned i; + + for (i = 1; i <= ps->max_var; i++) + ps->vars[i].core = 0; + + for (p = SOC; p != EOC; p = NXC (p)) + if ((c = *p)) + c->core = 0; + + for (q = ps->zhains; q != ps->zhead; q++) + if ((z = *q)) + z->core = 0; + + ps->ocore = -1; +} +#endif + +static void +reset_assumptions (PS * ps) +{ + Lit ** p; + + ps->failed_assumption = 0; + + if (ps->extracted_all_failed_assumptions) + { + for (p = ps->als; p < ps->alshead; p++) + LIT2VAR (*p)->failed = 0; + + ps->extracted_all_failed_assumptions = 0; + } + + ps->alstail = ps->alshead = ps->als; + ps->adecidelevel = 0; +} + +static void +check_ready (PS * ps) +{ + ABORTIF (!ps || ps->state == RESET, "API usage: uninitialized"); +} + +static void +check_sat_state (PS * ps) +{ + ABORTIF (ps->state != SAT, "API usage: expected to be in SAT state"); +} + +static void +check_unsat_state (PS * ps) +{ + ABORTIF (ps->state != UNSAT, "API usage: expected to be in UNSAT state"); +} + +static void +check_sat_or_unsat_or_unknown_state (PS * ps) +{ + ABORTIF (ps->state != SAT && ps->state != UNSAT && ps->state != UNKNOWN, + "API usage: expected to be in SAT, UNSAT, or UNKNOWN state"); +} + +static void +reset_partial (PS * ps) +{ + unsigned idx; + if (!ps->partial) + return; + for (idx = 1; idx <= ps->max_var; idx++) + ps->vars[idx].partial = 0; + ps->partial = 0; +} + +static void +reset_incremental_usage (PS * ps) +{ + unsigned num_non_false; + Lit * lit, ** q; + + check_sat_or_unsat_or_unknown_state (ps); + + LOG ( fprintf (ps->out, "%sRESET incremental usage\n", ps->prefix)); + + if (ps->LEVEL) + undo (ps, 0); + + reset_assumptions (ps); + + if (ps->conflict) + { + num_non_false = 0; + for (q = ps->conflict->lits; q < end_of_lits (ps->conflict); q++) + { + lit = *q; + if (lit->val != FALSE) + num_non_false++; + } + + // assert (num_non_false >= 2); // TODO: why this assertion? +#ifdef NO_BINARY_CLAUSES + if (ps->conflict == &ps->cimpl) + resetcimpl (ps); +#endif +#ifndef NADC + if (ps->conflict == ps->adoconflict) + resetadoconflict (ps); +#endif + ps->conflict = 0; + } + +#ifdef TRACE + reset_core (ps); +#endif + + reset_partial (ps); + + ps->saved_flips = ps->flips; + ps->min_flipped = UINT_MAX; + ps->saved_max_var = ps->max_var; + + ps->state = READY; +} + +static void +enter (PS * ps) +{ + if (ps->nentered++) + return; + + check_ready (ps); + ps->entered = picosat_time_stamp (); +} + +static void +leave (PS * ps) +{ + assert (ps->nentered); + if (--ps->nentered) + return; + + sflush (ps); +} + +static void +check_trace_support_and_execute (PS * ps, + FILE * file, + void (*f)(PS*,FILE*,int), int fmt) +{ + check_ready (ps); + check_unsat_state (ps); +#ifdef TRACE + ABORTIF (!ps->trace, "API usage: tracing disabled"); + enter (ps); + f (ps, file, fmt); + leave (ps); +#else + (void) file; + (void) fmt; + (void) f; + ABORT ("compiled without trace support"); +#endif +} + +static void +extract_all_failed_assumptions (PS * ps) +{ + Lit ** p, ** eol; + Var * v, * u; + int pos; + Cls * c; + + assert (!ps->extracted_all_failed_assumptions); + + assert (ps->failed_assumption); + assert (ps->mhead == ps->marked); + + if (ps->marked == ps->eom) + ENLARGE (ps->marked, ps->mhead, ps->eom); + + v = LIT2VAR (ps->failed_assumption); + mark_var (ps, v); + pos = 0; + + while (pos < ps->mhead - ps->marked) + { + v = ps->marked[pos++]; + assert (v->mark); + c = var2reason (ps, v); + if (!c) + continue; + eol = end_of_lits (c); + for (p = c->lits; p < eol; p++) + { + u = LIT2VAR (*p); + if (!u->mark) + mark_var (ps, u); + } +#ifdef NO_BINARY_CLAUSES + if (c == &ps->impl) + resetimpl (ps); +#endif + } + + for (p = ps->als; p < ps->alshead; p++) + { + u = LIT2VAR (*p); + if (!u->mark) continue; + u->failed = 1; + LOG ( fprintf (ps->out, + "%sfailed assumption %d\n", + ps->prefix, LIT2INT (*p))); + } + + while (ps->mhead > ps->marked) + (*--ps->mhead)->mark = 0; + + ps->extracted_all_failed_assumptions = 1; +} + +const char * +picosat_copyright (void) +{ + return "Copyright (c) 2006 - 2014 Armin Biere JKU Linz"; +} + +PicoSAT * +picosat_init (void) +{ + return init (0, 0, 0, 0); +} + +PicoSAT * +picosat_minit (void * pmgr, + picosat_malloc pnew, + picosat_realloc presize, + picosat_free pfree) +{ + ABORTIF (!pnew, "API usage: zero 'picosat_malloc' argument"); + ABORTIF (!presize, "API usage: zero 'picosat_realloc' argument"); + ABORTIF (!pfree, "API usage: zero 'picosat_free' argument"); + return init (pmgr, pnew, presize, pfree); +} + + +void +picosat_adjust (PS * ps, int new_max_var) +{ + unsigned new_size_vars; + + ABORTIF (abs (new_max_var) > (int) ps->max_var && ps->CLS != ps->clshead, + "API usage: adjusting variable index after 'picosat_push'"); + enter (ps); + + new_max_var = abs (new_max_var); + new_size_vars = new_max_var + 1; + + if (ps->size_vars < new_size_vars) + enlarge (ps, new_size_vars); + + while (ps->max_var < (unsigned) new_max_var) + inc_max_var (ps); + + leave (ps); +} + +int +picosat_inc_max_var (PS * ps) +{ + if (ps->measurealltimeinlib) + enter (ps); + else + check_ready (ps); + + inc_max_var (ps); + + if (ps->measurealltimeinlib) + leave (ps); + + return ps->max_var; +} + +int +picosat_context (PS * ps) +{ + return ps->clshead == ps->CLS ? 0 : LIT2INT (ps->clshead[-1]); +} + +int +picosat_push (PS * ps) +{ + int res; + Lit *lit; + Var * v; + + if (ps->measurealltimeinlib) + enter (ps); + else + check_ready (ps); + + if (ps->state != READY) + reset_incremental_usage (ps); + + if (ps->rils != ps->rilshead) + { + res = *--ps->rilshead; + assert (ps->vars[res].internal); + } + else + { + inc_max_var (ps); + res = ps->max_var; + v = ps->vars + res; + assert (!v->internal); + v->internal = 1; + ps->internals++; + LOG ( fprintf (ps->out, "%snew internal variable index %d\n", ps->prefix, res)); + } + + lit = int2lit (ps, res); + + if (ps->clshead == ps->eocls) + ENLARGE (ps->CLS, ps->clshead, ps->eocls); + *ps->clshead++ = lit; + + ps->contexts++; + + LOG ( fprintf (ps->out, "%snew context %d at depth %ld after push\n", + ps->prefix, res, (long)(ps->clshead - ps->CLS))); + + if (ps->measurealltimeinlib) + leave (ps); + + return res; +} + +int +picosat_pop (PS * ps) +{ + Lit * lit; + int res; + ABORTIF (ps->CLS == ps->clshead, "API usage: too many 'picosat_pop'"); + ABORTIF (ps->added != ps->ahead, "API usage: incomplete clause"); + + if (ps->measurealltimeinlib) + enter (ps); + else + check_ready (ps); + + if (ps->state != READY) + reset_incremental_usage (ps); + + assert (ps->CLS < ps->clshead); + lit = *--ps->clshead; + LOG ( fprintf (ps->out, "%sclosing context %d at depth %ld after pop\n", + ps->prefix, LIT2INT (lit), (long)(ps->clshead - ps->CLS) + 1)); + + if (ps->cilshead == ps->eocils) + ENLARGE (ps->cils, ps->cilshead, ps->eocils); + *ps->cilshead++ = LIT2INT (lit); + + if (ps->cilshead - ps->cils > MAXCILS) { + LOG ( fprintf (ps->out, + "%srecycling %ld interals with forced simplification\n", + ps->prefix, (long)(ps->cilshead - ps->cils))); + simplify (ps, 1); + } + + res = picosat_context (ps); + if (res) + LOG ( fprintf (ps->out, "%snew context %d at depth %ld after pop\n", + ps->prefix, res, (long)(ps->clshead - ps->CLS))); + else + LOG ( fprintf (ps->out, "%souter most context reached after pop\n", ps->prefix)); + + if (ps->measurealltimeinlib) + leave (ps); + + return res; +} + +void +picosat_set_verbosity (PS * ps, int new_verbosity_level) +{ + check_ready (ps); + ps->verbosity = new_verbosity_level; +} + +void +picosat_set_plain (PS * ps, int new_plain_value) +{ + check_ready (ps); + ps->plain = new_plain_value; +} + +int +picosat_enable_trace_generation (PS * ps) +{ + int res = 0; + check_ready (ps); +#ifdef TRACE + ABORTIF (ps->addedclauses, + "API usage: trace generation enabled after adding clauses"); + res = ps->trace = 1; +#endif + return res; +} + +void +picosat_set_incremental_rup_file (PS * ps, FILE * rup_file, int m, int n) +{ + check_ready (ps); + assert (!ps->rupstarted); + ps->rup = rup_file; + ps->rupvariables = m; + ps->rupclauses = n; +} + +void +picosat_set_output (PS * ps, FILE * output_file) +{ + check_ready (ps); + ps->out = output_file; +} + +void +picosat_measure_all_calls (PS * ps) +{ + check_ready (ps); + ps->measurealltimeinlib = 1; +} + +void +picosat_set_prefix (PS * ps, const char * str) +{ + check_ready (ps); + new_prefix (ps, str); +} + +void +picosat_set_seed (PS * ps, unsigned s) +{ + check_ready (ps); + ps->srng = s; +} + +void +picosat_reset (PS * ps) +{ + check_ready (ps); + reset (ps); +} + +int +picosat_add (PS * ps, int int_lit) +{ + int res = ps->oadded; + Lit *lit; + + if (ps->measurealltimeinlib) + enter (ps); + else + check_ready (ps); + + ABORTIF (ps->rup && ps->rupstarted && ps->oadded >= (unsigned)ps->rupclauses, + "API usage: adding too many clauses after RUP header written"); +#ifndef NADC + ABORTIF (ps->addingtoado, + "API usage: 'picosat_add' and 'picosat_add_ado_lit' mixed"); +#endif + if (ps->state != READY) + reset_incremental_usage (ps); + + if (ps->saveorig) + { + if (ps->sohead == ps->eoso) + ENLARGE (ps->soclauses, ps->sohead, ps->eoso); + + *ps->sohead++ = int_lit; + } + + if (int_lit) + { + lit = import_lit (ps, int_lit, 1); + add_lit (ps, lit); + } + else + simplify_and_add_original_clause (ps); + + if (ps->measurealltimeinlib) + leave (ps); + + return res; +} + +int +picosat_add_arg (PS * ps, ...) +{ + int lit; + va_list ap; + va_start (ap, ps); + while ((lit = va_arg (ap, int))) + (void) picosat_add (ps, lit); + va_end (ap); + return picosat_add (ps, 0); +} + +int +picosat_add_lits (PS * ps, int * lits) +{ + const int * p; + int lit; + for (p = lits; (lit = *p); p++) + (void) picosat_add (ps, lit); + return picosat_add (ps, 0); +} + +void +picosat_add_ado_lit (PS * ps, int external_lit) +{ +#ifndef NADC + Lit * internal_lit; + + if (ps->measurealltimeinlib) + enter (ps); + else + check_ready (ps); + + if (ps->state != READY) + reset_incremental_usage (ps); + + ABORTIF (!ps->addingtoado && ps->ahead > ps->added, + "API usage: 'picosat_add' and 'picosat_add_ado_lit' mixed"); + + if (external_lit) + { + ps->addingtoado = 1; + internal_lit = import_lit (ps, external_lit, 1); + add_lit (ps, internal_lit); + } + else + { + ps->addingtoado = 0; + add_ado (ps); + } + if (ps->measurealltimeinlib) + leave (ps); +#else + (void) ps; + (void) external_lit; + ABORT ("compiled without all different constraint support"); +#endif +} + +static void +assume (PS * ps, Lit * lit) +{ + if (ps->alshead == ps->eoals) + { + assert (ps->alstail == ps->als); + ENLARGE (ps->als, ps->alshead, ps->eoals); + ps->alstail = ps->als; + } + + *ps->alshead++ = lit; + LOG ( fprintf (ps->out, "%sassumption %d\n", ps->prefix, LIT2INT (lit))); +} + +static void +assume_contexts (PS * ps) +{ + Lit ** p; + if (ps->als != ps->alshead) + return; + for (p = ps->CLS; p != ps->clshead; p++) + assume (ps, *p); +} + +#ifndef RCODE +static const char * enumstr (int i) { + int last = i % 10; + if (last == 1) return "st"; + if (last == 2) return "nd"; + if (last == 3) return "rd"; + return "th"; +} +#endif + +static int +tderef (PS * ps, int int_lit) +{ + Lit * lit; + Var * v; + + assert (abs (int_lit) <= (int) ps->max_var); + + lit = int2lit (ps, int_lit); + + v = LIT2VAR (lit); + if (v->level > 0) + return 0; + + if (lit->val == TRUE) + return 1; + + if (lit->val == FALSE) + return -1; + + return 0; +} + +static int +pderef (PS * ps, int int_lit) +{ + Lit * lit; + Var * v; + + assert (abs (int_lit) <= (int) ps->max_var); + + v = ps->vars + abs (int_lit); + if (!v->partial) + return 0; + + lit = int2lit (ps, int_lit); + + if (lit->val == TRUE) + return 1; + + if (lit->val == FALSE) + return -1; + + return 0; +} + +static void +minautarky (PS * ps) +{ + unsigned * occs, maxoccs, tmpoccs, npartial; + int * p, * c, lit, best, val; +#ifdef LOGGING + int tl; +#endif + + assert (!ps->partial); + + npartial = 0; + + NEWN (occs, 2*ps->max_var + 1); + CLRN (occs, 2*ps->max_var + 1); + occs += ps->max_var; + for (p = ps->soclauses; p < ps->sohead; p++) + occs[*p]++; + assert (occs[0] == ps->oadded); + + for (c = ps->soclauses; c < ps->sohead; c = p + 1) + { +#ifdef LOGGING + tl = 0; +#endif + best = 0; + maxoccs = 0; + for (p = c; (lit = *p); p++) + { + val = tderef (ps, lit); + if (val < 0) + continue; + if (val > 0) + { +#ifdef LOGGING + tl = 1; +#endif + best = lit; + maxoccs = occs[lit]; + } + + val = pderef (ps, lit); + if (val > 0) + break; + if (val < 0) + continue; + val = int2lit (ps, lit)->val; + assert (val); + if (val < 0) + continue; + tmpoccs = occs[lit]; + if (best && tmpoccs <= maxoccs) + continue; + best = lit; + maxoccs = tmpoccs; + } + if (!lit) + { + assert (best); + LOG ( fprintf (ps->out, "%sautark %d with %d occs%s\n", + ps->prefix, best, maxoccs, tl ? " (top)" : "")); + ps->vars[abs (best)].partial = 1; + npartial++; + } + for (p = c; (lit = *p); p++) + { + assert (occs[lit] > 0); + occs[lit]--; + } + } + occs -= ps->max_var; + DELETEN (occs, 2*ps->max_var + 1); + ps->partial = 1; + + if (ps->verbosity) + fprintf (ps->out, + "%sautarky of size %u out of %u satisfying all clauses (%.1f%%)\n", + ps->prefix, npartial, ps->max_var, PERCENT (npartial, ps->max_var)); +} + +void +picosat_assume (PS * ps, int int_lit) +{ + Lit *lit; + + if (ps->measurealltimeinlib) + enter (ps); + else + check_ready (ps); + + if (ps->state != READY) + reset_incremental_usage (ps); + + assume_contexts (ps); + lit = import_lit (ps, int_lit, 1); + assume (ps, lit); + + if (ps->measurealltimeinlib) + leave (ps); +} + +int +picosat_sat (PS * ps, int l) +{ + int res; + char ch; + + enter (ps); + + ps->calls++; + LOG ( fprintf (ps->out, "%sSTART call %u\n", ps->prefix, ps->calls)); + + if (ps->added < ps->ahead) + { +#ifndef NADC + if (ps->addingtoado) + ABORT ("API usage: incomplete all different constraint"); + else +#endif + ABORT ("API usage: incomplete clause"); + } + + if (ps->state != READY) + reset_incremental_usage (ps); + + assume_contexts (ps); + + res = sat (ps, l); + + assert (ps->state == READY); + + switch (res) + { + case PICOSAT_UNSATISFIABLE: + ch = '0'; + ps->state = UNSAT; + break; + case PICOSAT_SATISFIABLE: + ch = '1'; + ps->state = SAT; + break; + default: + ch = '?'; + ps->state = UNKNOWN; + break; + } + + if (ps->verbosity) + { + report (ps, 1, ch); + rheader (ps); + } + + leave (ps); + LOG ( fprintf (ps->out, "%sEND call %u result %d\n", ps->prefix, ps->calls, res)); + + ps->last_sat_call_result = res; + + return res; +} + +int +picosat_res (PS * ps) +{ + return ps->last_sat_call_result; +} + +int +picosat_deref (PS * ps, int int_lit) +{ + Lit *lit; + + check_ready (ps); + check_sat_state (ps); + ABORTIF (!int_lit, "API usage: can not deref zero literal"); + ABORTIF (ps->mtcls, "API usage: deref after empty clause generated"); + +#ifdef STATS + ps->derefs++; +#endif + + if (abs (int_lit) > (int) ps->max_var) + return 0; + + lit = int2lit (ps, int_lit); + + if (lit->val == TRUE) + return 1; + + if (lit->val == FALSE) + return -1; + + return 0; +} + +int +picosat_deref_toplevel (PS * ps, int int_lit) +{ + check_ready (ps); + ABORTIF (!int_lit, "API usage: can not deref zero literal"); + +#ifdef STATS + ps->derefs++; +#endif + if (abs (int_lit) > (int) ps->max_var) + return 0; + + return tderef (ps, int_lit); +} + +int +picosat_inconsistent (PS * ps) +{ + check_ready (ps); + return ps->mtcls != 0; +} + +int +picosat_corelit (PS * ps, int int_lit) +{ + check_ready (ps); + check_unsat_state (ps); + ABORTIF (!int_lit, "API usage: zero literal can not be in core"); + + assert (ps->mtcls || ps->failed_assumption); + +#ifdef TRACE + { + int res = 0; + ABORTIF (!ps->trace, "tracing disabled"); + if (ps->measurealltimeinlib) + enter (ps); + core (ps); + if (abs (int_lit) <= (int) ps->max_var) + res = ps->vars[abs (int_lit)].core; + assert (!res || ps->failed_assumption || ps->vars[abs (int_lit)].used); + if (ps->measurealltimeinlib) + leave (ps); + return res; + } +#else + ABORT ("compiled without trace support"); + return 0; +#endif +} + +int +picosat_coreclause (PS * ps, int ocls) +{ + check_ready (ps); + check_unsat_state (ps); + + ABORTIF (ocls < 0, "API usage: negative original clause index"); + ABORTIF (ocls >= (int)ps->oadded, "API usage: original clause index exceeded"); + + assert (ps->mtcls || ps->failed_assumption); + +#ifdef TRACE + { + Cls ** clsptr, * c; + int res = 0; + + ABORTIF (!ps->trace, "tracing disabled"); + if (ps->measurealltimeinlib) + enter (ps); + core (ps); + clsptr = ps->oclauses + ocls; + assert (clsptr < ps->ohead); + c = *clsptr; + if (c) + res = c->core; + if (ps->measurealltimeinlib) + leave (ps); + + return res; + } +#else + ABORT ("compiled without trace support"); + return 0; +#endif +} + +int +picosat_failed_assumption (PS * ps, int int_lit) +{ + Lit * lit; + Var * v; + ABORTIF (!int_lit, "API usage: zero literal as assumption"); + check_ready (ps); + check_unsat_state (ps); + if (ps->mtcls) + return 0; + assert (ps->failed_assumption); + if (abs (int_lit) > (int) ps->max_var) + return 0; + if (!ps->extracted_all_failed_assumptions) + extract_all_failed_assumptions (ps); + lit = import_lit (ps, int_lit, 1); + v = LIT2VAR (lit); + return v->failed; +} + +int +picosat_failed_context (PS * ps, int int_lit) +{ + Lit * lit; + Var * v; + ABORTIF (!int_lit, "API usage: zero literal as context"); + ABORTIF (abs (int_lit) > (int) ps->max_var, "API usage: invalid context"); + check_ready (ps); + check_unsat_state (ps); + assert (ps->failed_assumption); + if (!ps->extracted_all_failed_assumptions) + extract_all_failed_assumptions (ps); + lit = import_lit (ps, int_lit, 0); + v = LIT2VAR (lit); + return v->failed; +} + +const int * +picosat_failed_assumptions (PS * ps) +{ + Lit ** p, * lit; + Var * v; + int ilit; + + ps->falshead = ps->fals; + check_ready (ps); + check_unsat_state (ps); + if (!ps->mtcls) + { + assert (ps->failed_assumption); + if (!ps->extracted_all_failed_assumptions) + extract_all_failed_assumptions (ps); + + for (p = ps->als; p < ps->alshead; p++) + { + lit = *p; + v = LIT2VAR (*p); + if (!v->failed) + continue; + ilit = LIT2INT (lit); + if (ps->falshead == ps->eofals) + ENLARGE (ps->fals, ps->falshead, ps->eofals); + *ps->falshead++ = ilit; + } + } + if (ps->falshead == ps->eofals) + ENLARGE (ps->fals, ps->falshead, ps->eofals); + *ps->falshead++ = 0; + return ps->fals; +} + +const int * +picosat_mus_assumptions (PS * ps, void * s, void (*cb)(void*,const int*), int fix) +{ + int i, j, ilit, len, nwork, * work, res; + signed char * redundant; + Lit ** p, * lit; + int failed; + Var * v; +#ifndef NDEBUG + int oldlen; +#endif +#ifndef RCODE + int norig = ps->alshead - ps->als; +#endif + + check_ready (ps); + check_unsat_state (ps); + len = 0; + if (!ps->mtcls) + { + assert (ps->failed_assumption); + if (!ps->extracted_all_failed_assumptions) + extract_all_failed_assumptions (ps); + + for (p = ps->als; p < ps->alshead; p++) + if (LIT2VAR (*p)->failed) + len++; + } + + if (ps->mass) + DELETEN (ps->mass, ps->szmass); + ps->szmass = len + 1; + NEWN (ps->mass, ps->szmass); + + i = 0; + for (p = ps->als; p < ps->alshead; p++) + { + lit = *p; + v = LIT2VAR (lit); + if (!v->failed) + continue; + ilit = LIT2INT (lit); + assert (i < len); + ps->mass[i++] = ilit; + } + assert (i == len); + ps->mass[i] = 0; + if (ps->verbosity) + fprintf (ps->out, + "%sinitial set of failed assumptions of size %d out of %d (%.0f%%)\n", + ps->prefix, len, norig, PERCENT (len, norig)); + if (cb) + cb (s, ps->mass); + + nwork = len; + NEWN (work, nwork); + for (i = 0; i < len; i++) + work[i] = ps->mass[i]; + + NEWN (redundant, nwork); + CLRN (redundant, nwork); + + for (i = 0; i < nwork; i++) + { + if (redundant[i]) + continue; + + if (ps->verbosity > 1) + fprintf (ps->out, + "%strying to drop %d%s assumption %d\n", + ps->prefix, i, enumstr (i), work[i]); + for (j = 0; j < nwork; j++) + { + if (i == j) continue; + if (j < i && fix) continue; + if (redundant[j]) continue; + picosat_assume (ps, work[j]); + } + + res = picosat_sat (ps, -1); + if (res == 10) + { + if (ps->verbosity > 1) + fprintf (ps->out, + "%sfailed to drop %d%s assumption %d\n", + ps->prefix, i, enumstr (i), work[i]); + + if (fix) + { + picosat_add (ps, work[i]); + picosat_add (ps, 0); + } + } + else + { + assert (res == 20); + if (ps->verbosity > 1) + fprintf (ps->out, + "%ssuceeded to drop %d%s assumption %d\n", + ps->prefix, i, enumstr (i), work[i]); + redundant[i] = 1; + for (j = 0; j < nwork; j++) + { + failed = picosat_failed_assumption (ps, work[j]); + if (j <= i) + { + assert ((j < i && fix) || redundant[j] == !failed); + continue; + } + + if (!failed) + { + redundant[j] = -1; + if (ps->verbosity > 1) + fprintf (ps->out, + "%salso suceeded to drop %d%s assumption %d\n", + ps->prefix, j, enumstr (j), work[j]); + } + } + +#ifndef NDEBUG + oldlen = len; +#endif + len = 0; + for (j = 0; j < nwork; j++) + if (!redundant[j]) + ps->mass[len++] = work[j]; + ps->mass[len] = 0; + assert (len < oldlen); + + if (fix) + { + picosat_add (ps, -work[i]); + picosat_add (ps, 0); + } + +#ifndef NDEBUG + for (j = 0; j <= i; j++) + assert (redundant[j] >= 0); +#endif + for (j = i + 1; j < nwork; j++) + { + if (redundant[j] >= 0) + continue; + + if (fix) + { + picosat_add (ps, -work[j]); + picosat_add (ps, 0); + } + + redundant[j] = 1; + } + + if (ps->verbosity) + fprintf (ps->out, + "%sreduced set of failed assumptions of size %d out of %d (%.0f%%)\n", + ps->prefix, len, norig, PERCENT (len, norig)); + if (cb) + cb (s, ps->mass); + } + } + + DELETEN (work, nwork); + DELETEN (redundant, nwork); + + if (ps->verbosity) + { + fprintf (ps->out, "%sreinitializing unsat state\n", ps->prefix); + fflush (ps->out); + } + + for (i = 0; i < len; i++) + picosat_assume (ps, ps->mass[i]); + +#ifndef NDEBUG + res = +#endif + picosat_sat (ps, -1); + assert (res == 20); + + if (!ps->mtcls) + { + assert (!ps->extracted_all_failed_assumptions); + extract_all_failed_assumptions (ps); + } + + return ps->mass; +} + +static const int * +mss (PS * ps, int * a, int size) +{ + int i, j, k, res; + + assert (!ps->mtcls); + + if (ps->szmssass) + DELETEN (ps->mssass, ps->szmssass); + + ps->szmssass = 0; + ps->mssass = 0; + + ps->szmssass = size + 1; + NEWN (ps->mssass, ps->szmssass); + + LOG ( fprintf (ps->out, "%ssearch MSS over %d assumptions\n", ps->prefix, size)); + + k = 0; + for (i = k; i < size; i++) + { + for (j = 0; j < k; j++) + picosat_assume (ps, ps->mssass[j]); + + LOG ( fprintf (ps->out, + "%strying to add assumption %d to MSS : %d\n", + ps->prefix, i, a[i])); + + picosat_assume (ps, a[i]); + + res = picosat_sat (ps, -1); + if (res == 10) + { + LOG ( fprintf (ps->out, + "%sadding assumption %d to MSS : %d\n", ps->prefix, i, a[i])); + + ps->mssass[k++] = a[i]; + + for (j = i + 1; j < size; j++) + { + if (picosat_deref (ps, a[j]) <= 0) + continue; + + LOG ( fprintf (ps->out, + "%salso adding assumption %d to MSS : %d\n", + ps->prefix, j, a[j])); + + ps->mssass[k++] = a[j]; + + if (++i != j) + { + int tmp = a[i]; + a[i] = a[j]; + a[j] = tmp; + } + } + } + else + { + assert (res == 20); + + LOG ( fprintf (ps->out, + "%signoring assumption %d in MSS : %d\n", ps->prefix, i, a[i])); + } + } + ps->mssass[k] = 0; + LOG ( fprintf (ps->out, "%sfound MSS of size %d\n", ps->prefix, k)); + + return ps->mssass; +} + +static void +reassume (PS * ps, const int * a, int size) +{ + int i; + LOG ( fprintf (ps->out, "%sreassuming all assumptions\n", ps->prefix)); + for (i = 0; i < size; i++) + picosat_assume (ps, a[i]); +} + +const int * +picosat_maximal_satisfiable_subset_of_assumptions (PS * ps) +{ + const int * res; + int i, *a, size; + + ABORTIF (ps->mtcls, + "API usage: CNF inconsistent (use 'picosat_inconsistent')"); + + enter (ps); + + size = ps->alshead - ps->als; + NEWN (a, size); + + for (i = 0; i < size; i++) + a[i] = LIT2INT (ps->als[i]); + + res = mss (ps, a, size); + reassume (ps, a, size); + + DELETEN (a, size); + + leave (ps); + + return res; +} + +static void +check_mss_flags_clean (PS * ps) +{ +#ifndef NDEBUG + unsigned i; + for (i = 1; i <= ps->max_var; i++) + { + assert (!ps->vars[i].msspos); + assert (!ps->vars[i].mssneg); + } +#else + (void) ps; +#endif +} + +static void +push_mcsass (PS * ps, int lit) +{ + if (ps->nmcsass == ps->szmcsass) + { + ps->szmcsass = ps->szmcsass ? 2*ps->szmcsass : 1; + RESIZEN (ps->mcsass, ps->nmcsass, ps->szmcsass); + } + + ps->mcsass[ps->nmcsass++] = lit; +} + +static const int * +next_mss (PS * ps, int mcs) +{ + int i, *a, size, mssize, mcsize, lit, inmss; + const int * res, * p; + Var * v; + + if (ps->mtcls) return 0; + + check_mss_flags_clean (ps); + + if (mcs && ps->mcsass) + { + DELETEN (ps->mcsass, ps->szmcsass); + ps->nmcsass = ps->szmcsass = 0; + ps->mcsass = 0; + } + + size = ps->alshead - ps->als; + NEWN (a, size); + + for (i = 0; i < size; i++) + a[i] = LIT2INT (ps->als[i]); + + (void) picosat_sat (ps, -1); + + //TODO short cut for 'picosat_res () == 10'? + + if (ps->mtcls) + { + assert (picosat_res (ps) == 20); + res = 0; + goto DONE; + } + + res = mss (ps, a, size); + + if (ps->mtcls) + { + res = 0; + goto DONE; + } + + for (p = res; (lit = *p); p++) + { + v = ps->vars + abs (lit); + if (lit < 0) + { + assert (!v->msspos); + v->mssneg = 1; + } + else + { + assert (!v->mssneg); + v->msspos = 1; + } + } + + mssize = p - res; + mcsize = INT_MIN; + + for (i = 0; i < size; i++) + { + lit = a[i]; + v = ps->vars + abs (lit); + if (lit > 0 && v->msspos) + inmss = 1; + else if (lit < 0 && v->mssneg) + inmss = 1; + else + inmss = 0; + + if (mssize < mcsize) + { + if (inmss) + picosat_add (ps, -lit); + } + else + { + if (!inmss) + picosat_add (ps, lit); + } + + if (!inmss && mcs) + push_mcsass (ps, lit); + } + picosat_add (ps, 0); + if (mcs) + push_mcsass (ps, 0); + + for (i = 0; i < size; i++) + { + lit = a[i]; + v = ps->vars + abs (lit); + v->msspos = 0; + v->mssneg = 0; + } + +DONE: + + reassume (ps, a, size); + DELETEN (a, size); + + return res; +} + +const int * +picosat_next_maximal_satisfiable_subset_of_assumptions (PS * ps) +{ + const int * res; + enter (ps); + res = next_mss (ps, 0); + leave (ps); + return res; +} + +const int * +picosat_next_minimal_correcting_subset_of_assumptions (PS * ps) +{ + const int * res, * tmp; + enter (ps); + tmp = next_mss (ps, 1); + res = tmp ? ps->mcsass : 0; + leave (ps); + return res; +} + +const int * +picosat_humus (PS * ps, + void (*callback)(void*state,int nmcs,int nhumus), + void * state) +{ + int lit, nmcs, j, nhumus; + const int * mcs, * p; + unsigned i; + Var * v; + enter (ps); +#ifndef NDEBUG + for (i = 1; i <= ps->max_var; i++) + { + v = ps->vars + i; + assert (!v->humuspos); + assert (!v->humusneg); + } +#endif + nhumus = nmcs = 0; + while ((mcs = picosat_next_minimal_correcting_subset_of_assumptions (ps))) + { + for (p = mcs; (lit = *p); p++) + { + v = ps->vars + abs (lit); + if (lit < 0) + { + if (!v->humusneg) + { + v->humusneg = 1; + nhumus++; + } + } + else + { + if (!v->humuspos) + { + v->humuspos = 1; + nhumus++; + } + } + } + nmcs++; + LOG ( fprintf (ps->out, + "%smcs %d of size %d humus %d\n", + ps->prefix, nmcs, (int)(p - mcs), nhumus)); + if (callback) + callback (state, nmcs, nhumus); + } + assert (!ps->szhumus); + ps->szhumus = 1; + for (i = 1; i <= ps->max_var; i++) + { + v = ps->vars + i; + if (v->humuspos) + ps->szhumus++; + if (v->humusneg) + ps->szhumus++; + } + assert (nhumus + 1 == ps->szhumus); + NEWN (ps->humus, ps->szhumus); + j = 0; + for (i = 1; i <= ps->max_var; i++) + { + v = ps->vars + i; + if (v->humuspos) + { + assert (j < nhumus); + ps->humus[j++] = (int) i; + } + if (v->humusneg) + { + assert (j < nhumus); + assert (i < INT_MAX); + ps->humus[j++] = - (int) i; + } + } + assert (j == nhumus); + assert (j < ps->szhumus); + ps->humus[j] = 0; + leave (ps); + return ps->humus; +} + +int +picosat_usedlit (PS * ps, int int_lit) +{ + int res; + check_ready (ps); + check_sat_or_unsat_or_unknown_state (ps); + ABORTIF (!int_lit, "API usage: zero literal can not be used"); + int_lit = abs (int_lit); + res = (int_lit <= (int) ps->max_var) ? ps->vars[int_lit].used : 0; + return res; +} + +void +picosat_write_clausal_core (PS * ps, FILE * file) +{ + check_trace_support_and_execute (ps, file, write_core_wrapper, 0); +} + +void +picosat_write_compact_trace (PS * ps, FILE * file) +{ + check_trace_support_and_execute (ps, file, write_trace, + COMPACT_TRACECHECK_TRACE_FMT); +} + +void +picosat_write_extended_trace (PS * ps, FILE * file) +{ + check_trace_support_and_execute (ps, file, write_trace, + EXTENDED_TRACECHECK_TRACE_FMT); +} + +void +picosat_write_rup_trace (PS * ps, FILE * file) +{ + check_trace_support_and_execute (ps, file, write_trace, RUP_TRACE_FMT); +} + +size_t +picosat_max_bytes_allocated (PS * ps) +{ + check_ready (ps); + return ps->max_bytes; +} + +void +picosat_set_propagation_limit (PS * ps, unsigned long long l) +{ + ps->lpropagations = l; +} + +unsigned long long +picosat_propagations (PS * ps) +{ + return ps->propagations; +} + +unsigned long long +picosat_visits (PS * ps) +{ + return ps->visits; +} + +unsigned long long +picosat_decisions (PS * ps) +{ + return ps->decisions; +} + +int +picosat_variables (PS * ps) +{ + check_ready (ps); + return (int) ps->max_var; +} + +int +picosat_added_original_clauses (PS * ps) +{ + check_ready (ps); + return (int) ps->oadded; +} + +void +picosat_stats (PS * ps) +{ +#ifndef RCODE + unsigned redlits; +#endif +#ifdef STATS + check_ready (ps); + assert (ps->sdecisions + ps->rdecisions + ps->assumptions == ps->decisions); +#endif + if (ps->calls > 1) + fprintf (ps->out, "%s%u calls\n", ps->prefix, ps->calls); + if (ps->contexts) + { + fprintf (ps->out, "%s%u contexts", ps->prefix, ps->contexts); +#ifdef STATS + fprintf (ps->out, " %u internal variables", ps->internals); +#endif + fprintf (ps->out, "\n"); + } + fprintf (ps->out, "%s%u iterations\n", ps->prefix, ps->iterations); + fprintf (ps->out, "%s%u restarts", ps->prefix, ps->restarts); +#ifdef STATS + fprintf (ps->out, " (%u skipped)", ps->skippedrestarts); +#endif + fputc ('\n', ps->out); +#ifndef NFL + fprintf (ps->out, "%s%u failed literals", ps->prefix, ps->failedlits); +#ifdef STATS + fprintf (ps->out, + ", %u calls, %u rounds, %llu propagations", + ps->flcalls, ps->flrounds, ps->flprops); +#endif + fputc ('\n', ps->out); +#ifdef STATS + fprintf (ps->out, + "%sfl: %u = %.1f%% implicit, %llu oopsed, %llu tried, %llu skipped\n", + ps->prefix, + ps->ifailedlits, PERCENT (ps->ifailedlits, ps->failedlits), + ps->floopsed, ps->fltried, ps->flskipped); +#endif +#endif + fprintf (ps->out, "%s%u conflicts", ps->prefix, ps->conflicts); +#ifdef STATS + fprintf (ps->out, " (%u uips = %.1f%%)\n", ps->uips, PERCENT(ps->uips,ps->conflicts)); +#else + fputc ('\n', ps->out); +#endif +#ifndef NADC + fprintf (ps->out, "%s%u adc conflicts\n", ps->prefix, ps->adoconflicts); +#endif +#ifdef STATS + fprintf (ps->out, "%s%llu dereferenced literals\n", ps->prefix, ps->derefs); +#endif + fprintf (ps->out, "%s%u decisions", ps->prefix, ps->decisions); +#ifdef STATS + fprintf (ps->out, " (%u random = %.2f%%", + ps->rdecisions, PERCENT (ps->rdecisions, ps->decisions)); + fprintf (ps->out, ", %u assumptions", ps->assumptions); + fputc (')', ps->out); +#endif + fputc ('\n', ps->out); +#ifdef STATS + fprintf (ps->out, + "%s%u static phase decisions (%.1f%% of all variables)\n", + ps->prefix, + ps->staticphasedecisions, PERCENT (ps->staticphasedecisions, ps->max_var)); +#endif + fprintf (ps->out, "%s%u fixed variables\n", ps->prefix, ps->fixed); + assert (ps->nonminimizedllits >= ps->minimizedllits); +#ifndef RCODE + redlits = ps->nonminimizedllits - ps->minimizedllits; +#endif + fprintf (ps->out, "%s%u learned literals\n", ps->prefix, ps->llitsadded); + fprintf (ps->out, "%s%.1f%% deleted literals\n", + ps->prefix, PERCENT (redlits, ps->nonminimizedllits)); + +#ifdef STATS +#ifdef TRACE + fprintf (ps->out, + "%s%llu antecedents (%.1f antecedents per clause", + ps->prefix, ps->antecedents, AVERAGE (ps->antecedents, ps->conflicts)); + if (ps->trace) + fprintf (ps->out, ", %.1f bytes/antecedent)", AVERAGE (ps->znts, ps->antecedents)); + fputs (")\n", ps->out); +#endif + + fprintf (ps->out, "%s%llu propagations (%.1f propagations per decision)\n", + ps->prefix, ps->propagations, AVERAGE (ps->propagations, ps->decisions)); + fprintf (ps->out, "%s%llu visits (%.1f per propagation)\n", + ps->prefix, ps->visits, AVERAGE (ps->visits, ps->propagations)); + fprintf (ps->out, + "%s%llu binary clauses visited (%.1f%% %.1f per propagation)\n", + ps->prefix, ps->bvisits, + PERCENT (ps->bvisits, ps->visits), + AVERAGE (ps->bvisits, ps->propagations)); + fprintf (ps->out, + "%s%llu ternary clauses visited (%.1f%% %.1f per propagation)\n", + ps->prefix, ps->tvisits, + PERCENT (ps->tvisits, ps->visits), + AVERAGE (ps->tvisits, ps->propagations)); + fprintf (ps->out, + "%s%llu large clauses visited (%.1f%% %.1f per propagation)\n", + ps->prefix, ps->lvisits, + PERCENT (ps->lvisits, ps->visits), + AVERAGE (ps->lvisits, ps->propagations)); + fprintf (ps->out, "%s%llu other true (%.1f%% of visited clauses)\n", + ps->prefix, ps->othertrue, PERCENT (ps->othertrue, ps->visits)); + fprintf (ps->out, + "%s%llu other true in binary clauses (%.1f%%)" + ", %llu upper (%.1f%%)\n", + ps->prefix, ps->othertrue2, PERCENT (ps->othertrue2, ps->othertrue), + ps->othertrue2u, PERCENT (ps->othertrue2u, ps->othertrue2)); + fprintf (ps->out, + "%s%llu other true in large clauses (%.1f%%)" + ", %llu upper (%.1f%%)\n", + ps->prefix, ps->othertruel, PERCENT (ps->othertruel, ps->othertrue), + ps->othertruelu, PERCENT (ps->othertruelu, ps->othertruel)); + fprintf (ps->out, "%s%llu ternary and large traversals (%.1f per visit)\n", + ps->prefix, ps->traversals, AVERAGE (ps->traversals, ps->visits)); + fprintf (ps->out, "%s%llu large traversals (%.1f per large visit)\n", + ps->prefix, ps->ltraversals, AVERAGE (ps->ltraversals, ps->lvisits)); + fprintf (ps->out, "%s%llu assignments\n", ps->prefix, ps->assignments); +#else + fprintf (ps->out, "%s%llu propagations\n", ps->prefix, picosat_propagations (ps)); + fprintf (ps->out, "%s%llu visits\n", ps->prefix, picosat_visits (ps)); +#endif + fprintf (ps->out, "%s%.1f%% variables used\n", ps->prefix, PERCENT (ps->vused, ps->max_var)); + + sflush (ps); + fprintf (ps->out, "%s%.1f seconds in library\n", ps->prefix, ps->seconds); + fprintf (ps->out, "%s%.1f megaprops/second\n", + ps->prefix, AVERAGE (ps->propagations / 1e6f, ps->seconds)); + fprintf (ps->out, "%s%.1f megavisits/second\n", + ps->prefix, AVERAGE (ps->visits / 1e6f, ps->seconds)); + fprintf (ps->out, "%sprobing %.1f seconds %.0f%%\n", + ps->prefix, ps->flseconds, PERCENT (ps->flseconds, ps->seconds)); +#ifdef STATS + fprintf (ps->out, + "%srecycled %.1f MB in %u reductions\n", + ps->prefix, ps->rrecycled / (double) (1 << 20), ps->reductions); + fprintf (ps->out, + "%srecycled %.1f MB in %u simplifications\n", + ps->prefix, ps->srecycled / (double) (1 << 20), ps->simps); +#else + fprintf (ps->out, "%s%u simplifications\n", ps->prefix, ps->simps); + fprintf (ps->out, "%s%u reductions\n", ps->prefix, ps->reductions); + fprintf (ps->out, "%s%.1f MB recycled\n", ps->prefix, ps->recycled / (double) (1 << 20)); +#endif + fprintf (ps->out, "%s%.1f MB maximally allocated\n", + ps->prefix, picosat_max_bytes_allocated (ps) / (double) (1 << 20)); +} + +#if defined (_MSC_VER) || defined (__MINGW32__) || defined(_WIN32) || defined(EMSCRIPTEN) +#else +#include +#include +#include +#endif + +double +picosat_time_stamp (void) +{ + double res = -1; + res = 0; +#if defined (_MSC_VER) || defined (__MINGW32__) || defined(_WIN32) || defined(EMSCRIPTEN) +#else + struct rusage u; + if (!getrusage (RUSAGE_SELF, &u)) + { + res += u.ru_utime.tv_sec + 1e-6 * u.ru_utime.tv_usec; + res += u.ru_stime.tv_sec + 1e-6 * u.ru_stime.tv_usec; + } +#endif + return res; +} + +double +picosat_seconds (PS * ps) +{ + check_ready (ps); + return ps->seconds; +} + +void +picosat_print (PS * ps, FILE * file) +{ +#ifdef NO_BINARY_CLAUSES + Lit * lit, *other, * last; + Ltk * stack; +#endif + Lit **q, **eol; + Cls **p, *c; + unsigned n; + + if (ps->measurealltimeinlib) + enter (ps); + else + check_ready (ps); + + n = 0; + n += ps->alshead - ps->als; + + for (p = SOC; p != EOC; p = NXC (p)) + { + c = *p; + + if (!c) + continue; + +#ifdef TRACE + if (c->collected) + continue; +#endif + n++; + } + +#ifdef NO_BINARY_CLAUSES + last = int2lit (ps, -ps->max_var); + for (lit = int2lit (ps, 1); lit <= last; lit++) + { + stack = LIT2IMPLS (lit); + eol = stack->start + stack->count; + for (q = stack->start; q < eol; q++) + if (*q >= lit) + n++; + } +#endif + + fprintf (file, "p cnf %d %u\n", ps->max_var, n); + + for (p = SOC; p != EOC; p = NXC (p)) + { + c = *p; + if (!c) + continue; + +#ifdef TRACE + if (c->collected) + continue; +#endif + + eol = end_of_lits (c); + for (q = c->lits; q < eol; q++) + fprintf (file, "%d ", LIT2INT (*q)); + + fputs ("0\n", file); + } + +#ifdef NO_BINARY_CLAUSES + last = int2lit (ps, -ps->max_var); + for (lit = int2lit (ps, 1); lit <= last; lit++) + { + stack = LIT2IMPLS (lit); + eol = stack->start + stack->count; + for (q = stack->start; q < eol; q++) + if ((other = *q) >= lit) + fprintf (file, "%d %d 0\n", LIT2INT (lit), LIT2INT (other)); + } +#endif + + { + Lit **r; + for (r = ps->als; r < ps->alshead; r++) + fprintf (file, "%d 0\n", LIT2INT (*r)); + } + + fflush (file); + + if (ps->measurealltimeinlib) + leave (ps); +} + +void +picosat_enter (PS * ps) +{ + enter (ps); +} + +void +picosat_leave (PS * ps) +{ + leave (ps); +} + +void +picosat_message (PS * ps, int vlevel, const char * fmt, ...) +{ + va_list ap; + + if (vlevel > ps->verbosity) + return; + + fputs (ps->prefix, ps->out); + va_start (ap, fmt); + vfprintf (ps->out, fmt, ap); + va_end (ap); + fputc ('\n', ps->out); +} + +int +picosat_changed (PS * ps) +{ + int res; + + check_ready (ps); + check_sat_state (ps); + + res = (ps->min_flipped <= ps->saved_max_var); + assert (!res || ps->saved_flips != ps->flips); + + return res; +} + +void +picosat_reset_phases (PS * ps) +{ + rebias (ps); +} + +void +picosat_reset_scores (PS * ps) +{ + Rnk * r; + ps->hhead = ps->heap + 1; + for (r = ps->rnks + 1; r <= ps->rnks + ps->max_var; r++) + { + CLR (r); + hpush (ps, r); + } +} + +void +picosat_remove_learned (PS * ps, unsigned percentage) +{ + enter (ps); + reset_incremental_usage (ps); + reduce (ps, percentage); + leave (ps); +} + +void +picosat_set_global_default_phase (PS * ps, int phase) +{ + check_ready (ps); + ABORTIF (phase < 0, "API usage: 'picosat_set_global_default_phase' " + "with negative argument"); + ABORTIF (phase > 3, "API usage: 'picosat_set_global_default_phase' " + "with argument > 3"); + ps->defaultphase = phase; +} + +void +picosat_set_default_phase_lit (PS * ps, int int_lit, int phase) +{ + unsigned newphase; + Lit * lit; + Var * v; + + check_ready (ps); + + lit = import_lit (ps, int_lit, 1); + v = LIT2VAR (lit); + + if (phase) + { + newphase = (int_lit < 0) == (phase < 0); + v->defphase = v->phase = newphase; + v->usedefphase = v->assigned = 1; + } + else + { + v->usedefphase = v->assigned = 0; + } +} + +void +picosat_set_more_important_lit (PS * ps, int int_lit) +{ + Lit * lit; + Var * v; + Rnk * r; + + check_ready (ps); + + lit = import_lit (ps, int_lit, 1); + v = LIT2VAR (lit); + r = VAR2RNK (v); + + ABORTIF (r->lessimportant, "can not mark variable more and less important"); + + if (r->moreimportant) + return; + + r->moreimportant = 1; + + if (r->pos) + hup (ps, r); +} + +void +picosat_set_less_important_lit (PS * ps, int int_lit) +{ + Lit * lit; + Var * v; + Rnk * r; + + check_ready (ps); + + lit = import_lit (ps, int_lit, 1); + v = LIT2VAR (lit); + r = VAR2RNK (v); + + ABORTIF (r->moreimportant, "can not mark variable more and less important"); + + if (r->lessimportant) + return; + + r->lessimportant = 1; + + if (r->pos) + hdown (ps, r); +} + +#ifndef NADC + +unsigned +picosat_ado_conflicts (PS * ps) +{ + check_ready (ps); + return ps->adoconflicts; +} + +void +picosat_disable_ado (PS * ps) +{ + check_ready (ps); + assert (!ps->adodisabled); + ps->adodisabled = 1; +} + +void +picosat_enable_ado (PS * ps) +{ + check_ready (ps); + assert (ps->adodisabled); + ps->adodisabled = 0; +} + +void +picosat_set_ado_conflict_limit (PS * ps, unsigned newadoconflictlimit) +{ + check_ready (ps); + ps->adoconflictlimit = newadoconflictlimit; +} + +#endif + +void +picosat_simplify (PS * ps) +{ + enter (ps); + reset_incremental_usage (ps); + simplify (ps, 1); + leave (ps); +} + +int +picosat_haveados (void) +{ +#ifndef NADC + return 1; +#else + return 0; +#endif +} + +void +picosat_save_original_clauses (PS * ps) +{ + if (ps->saveorig) return; + ABORTIF (ps->oadded, "API usage: 'picosat_save_original_clauses' too late"); + ps->saveorig = 1; +} + +void picosat_set_interrupt (PicoSAT * ps, + void * external_state, + int (*interrupted)(void * external_state)) +{ + ps->interrupt.state = external_state; + ps->interrupt.function = interrupted; +} + +int +picosat_deref_partial (PS * ps, int int_lit) +{ + check_ready (ps); + check_sat_state (ps); + ABORTIF (!int_lit, "API usage: can not partial deref zero literal"); + ABORTIF (ps->mtcls, "API usage: deref partial after empty clause generated"); + ABORTIF (!ps->saveorig, "API usage: 'picosat_save_original_clauses' missing"); + +#ifdef STATS + ps->derefs++; +#endif + + if (!ps->partial) + minautarky (ps); + + return pderef (ps, int_lit); +} diff --git a/cryptominisat/cppsrc/src/picosat/picosat.h b/cryptominisat/cppsrc/src/picosat/picosat.h new file mode 100644 index 00000000..31abdeb3 --- /dev/null +++ b/cryptominisat/cppsrc/src/picosat/picosat.h @@ -0,0 +1,661 @@ +/**************************************************************************** +Copyright (c) 2006 - 2015, Armin Biere, Johannes Kepler University. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to +deal in the Software without restriction, including without limitation the +rights to use, copy, modify, merge, publish, distribute, sublicense, and/or +sell copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS +IN THE SOFTWARE. +****************************************************************************/ + +#ifndef picosat_h_INCLUDED +#define picosat_h_INCLUDED + +#undef TRACE +#define TRACE ON + +/*------------------------------------------------------------------------*/ + +#include +#include +#include + +/*------------------------------------------------------------------------*/ +/* The following macros allows for users to distiguish between different + * versions of the API. The first 'PICOSAT_REENTRANT_API' is defined for + * the new reentrant API which allows to generate multiple instances of + * PicoSAT in one process. The second 'PICOSAT_API_VERSION' defines the + * (smallest) version of PicoSAT to which this API conforms. + */ +#define PICOSAT_REENTRANT_API +#define PICOSAT_API_VERSION 953 /* API version */ + +/*------------------------------------------------------------------------*/ +/* These are the return values for 'picosat_sat' as for instance + * standardized by the output format of the SAT competition. + */ +#define PICOSAT_UNKNOWN 0 +#define PICOSAT_SATISFIABLE 10 +#define PICOSAT_UNSATISFIABLE 20 + +/*------------------------------------------------------------------------*/ + +typedef struct PicoSAT PicoSAT; + +/*------------------------------------------------------------------------*/ + +const char *picosat_version (void); +const char *picosat_config (void); +const char *picosat_copyright (void); + +/*------------------------------------------------------------------------*/ +/* You can make PicoSAT use an external memory manager instead of the one + * provided by LIBC. But then you need to call these three function before + * 'picosat_init'. The memory manager functions here all have an additional + * first argument which is a pointer to the memory manager, but otherwise + * are supposed to work as their LIBC counter parts 'malloc', 'realloc' and + * 'free'. As exception the 'resize' and 'delete' function have as third + * argument the number of bytes of the block given as second argument. + */ + +typedef void * (*picosat_malloc)(void *, size_t); +typedef void * (*picosat_realloc)(void*, void *, size_t, size_t); +typedef void (*picosat_free)(void*, void*, size_t); + +/*------------------------------------------------------------------------*/ + +PicoSAT * picosat_init (void); /* constructor */ + +PicoSAT * picosat_minit (void * state, + picosat_malloc, + picosat_realloc, + picosat_free); + +void picosat_reset (PicoSAT *); /* destructor */ + +/*------------------------------------------------------------------------*/ +/* The following five functions are essentially parameters to 'init', and + * thus should be called right after 'picosat_init' before doing anything + * else. You should not call any of them after adding a literal. + */ + +/* Set output file, default is 'stdout'. + */ +void picosat_set_output (PicoSAT *, FILE *); + +/* Measure all time spent in all calls in the solver. By default only the + * time spent in 'picosat_sat' is measured. Enabling this function might + * for instance triple the time needed to add large CNFs, since every call + * to 'picosat_add' will trigger a call to 'getrusage'. + */ +void picosat_measure_all_calls (PicoSAT *); + +/* Set the prefix used for printing verbose messages and statistics. + * Default is "c ". + */ +void picosat_set_prefix (PicoSAT *, const char *); + +/* Set verbosity level. A verbosity level of 1 and above prints more and + * more detailed progress reports on the output file, set by + * 'picosat_set_output'. Verbose messages are prefixed with the string set + * by 'picosat_set_prefix'. + */ +void picosat_set_verbosity (PicoSAT *, int new_verbosity_level); + +/* Disable/Enable all pre-processing, currently only failed literal probing. + * + * new_plain_value != 0 only 'plain' solving, so no preprocessing + * new_plain_value == 0 allow preprocessing + */ +void picosat_set_plain (PicoSAT *, int new_plain_value); + +/* Set default initial phase: + * + * 0 = false + * 1 = true + * 2 = Jeroslow-Wang (default) + * 3 = random initial phase + * + * After a variable has been assigned the first time, it will always + * be assigned the previous value if it is picked as decision variable. + * The initial assignment can be chosen with this function. + */ +void picosat_set_global_default_phase (PicoSAT *, int); + +/* Set next/initial phase of a particular variable if picked as decision + * variable. Second argument 'phase' has the following meaning: + * + * negative = next value if picked as decision variable is false + * + * positive = next value if picked as decision variable is true + * + * 0 = use global default phase as next value and + * assume 'lit' was never assigned + * + * Again if 'lit' is assigned afterwards through a forced assignment, + * then this forced assignment is the next phase if this variable is + * used as decision variable. + */ +void picosat_set_default_phase_lit (PicoSAT *, int lit, int phase); + +/* You can reset all phases by the following function. + */ +void picosat_reset_phases (PicoSAT *); + +/* Scores can be erased as well. Note, however, that even after erasing + * scores and phases, learned clauses are kept. In addition head tail + * pointers for literals are not moved either. So expect a difference + * between calling the solver in incremental mode or with a fresh copy of + * the CNF. + */ +void picosat_reset_scores (PicoSAT *); + +/* Reset assignment if in SAT state and then remove the given percentage of + * less active (large) learned clauses. If you specify 100% all large + * learned clauses are removed. + */ +void picosat_remove_learned (PicoSAT *, unsigned percentage); + +/* Set some variables to be more important than others. These variables are + * always used as decisions before other variables are used. Dually there + * is a set of variables that is used last. The default is + * to mark all variables as being indifferent only. + */ +void picosat_set_more_important_lit (PicoSAT *, int lit); +void picosat_set_less_important_lit (PicoSAT *, int lit); + +/* Allows to print to internal 'out' file from client. + */ +void picosat_message (PicoSAT *, int verbosity_level, const char * fmt, ...); + +/* Set a seed for the random number generator. The random number generator + * is currently just used for generating random decisions. In our + * experiments having random decisions did not really help on industrial + * examples, but was rather helpful to randomize the solver in order to + * do proper benchmarking of different internal parameter sets. + */ +void picosat_set_seed (PicoSAT *, unsigned random_number_generator_seed); + +/* If you ever want to extract cores or proof traces with the current + * instance of PicoSAT initialized with 'picosat_init', then make sure to + * call 'picosat_enable_trace_generation' right after 'picosat_init'. This + * is not necessary if you only use 'picosat_set_incremental_rup_file'. + * + * NOTE, trace generation code is not necessarily included, e.g. if you + * configure PicoSAT with full optimzation as './configure.sh -O' or with + + * you do not get any results by trying to generate traces. + * + * The return value is non-zero if code for generating traces is included + * and it is zero if traces can not be generated. + */ +int picosat_enable_trace_generation (PicoSAT *); + +/* You can dump proof traces in RUP format incrementally even without + * keeping the proof trace in memory. The advantage is a reduction of + * memory usage, but the dumped clauses do not necessarily belong to the + * clausal core. Beside the file the additional parameters denotes the + * maximal number of variables and the number of original clauses. + */ +void picosat_set_incremental_rup_file (PicoSAT *, FILE * file, int m, int n); + +/* Save original clauses for 'picosat_deref_partial'. See comments to that + * function further down. + */ +void picosat_save_original_clauses (PicoSAT *); + +/* Add a call back which is checked regularly to notify the SAT solver + * to terminate earlier. This is useful for setting external time limits + * or terminate early in say a portfolio style parallel SAT solver. + */ +void picosat_set_interrupt (PicoSAT *, + void * external_state, + int (*interrupted)(void * external_state)); + +/*------------------------------------------------------------------------*/ +/* This function returns the next available unused variable index and + * allocates a variable for it even though this variable does not occur as + * assumption, nor in a clause or any other constraints. In future calls to + * 'picosat_sat', 'picosat_deref' and particularly for 'picosat_changed', + * this variable is treated as if it had been used. + */ +int picosat_inc_max_var (PicoSAT *); + +/*------------------------------------------------------------------------*/ +/* Push and pop semantics for PicoSAT. 'picosat_push' opens up a new + * context. All clauses added in this context are attached to it and + * discarded when the context is closed with 'picosat_pop'. It is also + * possible to nest contexts. + * + * The current implementation uses a new internal variable for each context. + * However, the indices for these internal variables are shared with + * ordinary external variables. This means that after any call to + * 'picosat_push', new variable indices should be obtained with + * 'picosat_inc_max_var' and not just by incrementing the largest variable + * index used so far. + * + * The return value is the index of the literal that assumes this context. + * This literal can only be used for 'picosat_failed_context' otherwise + * it will lead to an API usage error. + */ +int picosat_push (PicoSAT *); + +/* This is as 'picosat_failed_assumption', but only for internal variables + * generated by 'picosat_push'. + */ +int picosat_failed_context (PicoSAT *, int lit); + +/* Returns the literal that assumes the current context or zero if the + * outer context has been reached. + */ +int picosat_context (PicoSAT *); + +/* Closes the current context and recycles the literal generated for + * assuming this context. The return value is the literal for the new + * outer context or zero if the outer most context has been reached. + */ +int picosat_pop (PicoSAT *); + +/* Force immmediate removal of all satisfied clauses and clauses that are + * added or generated in closed contexts. This function is called + * internally if enough units are learned or after a certain number of + * contexts have been closed. This number is fixed at compile time + * and defined as MAXCILS in 'picosat.c'. + * + * Note that learned clauses which only involve outer contexts are kept. + */ +void picosat_simplify (PicoSAT *); + +/*------------------------------------------------------------------------*/ +/* If you know a good estimate on how many variables you are going to use + * then calling this function before adding literals will result in less + * resizing of the variable table. But this is just a minor optimization. + * Beside exactly allocating enough variables it has the same effect as + * calling 'picosat_inc_max_var'. + */ +void picosat_adjust (PicoSAT *, int max_idx); + +/*------------------------------------------------------------------------*/ +/* Statistics. + */ +int picosat_variables (PicoSAT *); /* p cnf n */ +int picosat_added_original_clauses (PicoSAT *); /* p cnf m */ +size_t picosat_max_bytes_allocated (PicoSAT *); +double picosat_time_stamp (void); /* ... in process */ +void picosat_stats (PicoSAT *); /* > output file */ +unsigned long long picosat_propagations (PicoSAT *); /* #propagations */ +unsigned long long picosat_decisions (PicoSAT *); /* #decisions */ +unsigned long long picosat_visits (PicoSAT *); /* #visits */ + +/* The time spent in calls to the library or in 'picosat_sat' respectively. + * The former is returned if, right after initialization + * 'picosat_measure_all_calls' is called. + */ +double picosat_seconds (PicoSAT *); + +/*------------------------------------------------------------------------*/ +/* Add a literal of the next clause. A zero terminates the clause. The + * solver is incremental. Adding a new literal will reset the previous + * assignment. The return value is the original clause index to which + * this literal respectively the trailing zero belong starting at 0. + */ +int picosat_add (PicoSAT *, int lit); + +/* As the previous function, but allows to add a full clause at once with an + * at compiled time known size. The list of argument literals has to be + * terminated with a zero literal. Literals beyond the first zero literal + * are discarded. + */ +int picosat_add_arg (PicoSAT *, ...); + +/* As the previous function but with an at compile time unknown size. + */ +int picosat_add_lits (PicoSAT *, int * lits); + +/* Print the CNF to the given file in DIMACS format. + */ +void picosat_print (PicoSAT *, FILE *); + +/* You can add arbitrary many assumptions before the next 'picosat_sat' + * call. This is similar to the using assumptions in MiniSAT, except that + * for PicoSAT you do not have to collect all your assumptions in a vector + * yourself. In PicoSAT you can add one after the other, to be used in the + * next call to 'picosat_sat'. + * + * These assumptions can be interpreted as adding unit clauses with those + * assumptions as literals. However these assumption clauses are only valid + * for exactly the next call to 'picosat_sat', and will be removed + * afterwards, e.g. in following future calls to 'picosat_sat' after the + * next 'picosat_sat' call, unless they are assumed again trough + * 'picosat_assume'. + * + * More precisely, assumptions actually remain valid even after the next + * call to 'picosat_sat' has returned. Valid means they remain 'assumed' + * internally until a call to 'picosat_add', 'picosat_assume', or a second + * 'picosat_sat', following the first 'picosat_sat'. The reason for keeping + * them valid is to allow 'picosat_failed_assumption' to return correct + * values. + * + * Example: + * + * picosat_assume (1); // assume unit clause '1 0' + * picosat_assume (-2); // additionally assume clause '-2 0' + * res = picosat_sat (1000); // assumes 1 and -2 to hold + * // 1000 decisions max. + * + * if (res == PICOSAT_UNSATISFIABLE) + * { + * if (picosat_failed_assumption (1)) + * // unit clause '1 0' was necessary to derive UNSAT + * + * if (picosat_failed_assumption (-2)) + * // unit clause '-2 0' was necessary to derive UNSAT + * + * // at least one but also both could be necessary + * + * picosat_assume (17); // previous assumptions are removed + * // now assume unit clause '17 0' for + * // the next call to 'picosat_sat' + * + * // adding a new clause, actually the first literal of + * // a clause would also make the assumptions used in the previous + * // call to 'picosat_sat' invalid. + * + * // The first two assumptions above are not assumed anymore. Only + * // the assumptions, since the last call to 'picosat_sat' returned + * // are assumed, e.g. the unit clause '17 0'. + * + * res = picosat_sat (-1); + * } + * else if (res == PICOSAT_SATISFIABLE) + * { + * // now the assignment is valid and we can call 'picosat_deref' + * + * assert (picosat_deref (1) == 1)); + * assert (picosat_deref (-2) == 1)); + * + * val = picosat_deref (15); + * + * // previous two assumptions are still valid + * + * // would become invalid if 'picosat_add' or 'picosat_assume' is + * // called here, but we immediately call 'picosat_sat'. Now when + * // entering 'picosat_sat' the solver knows that the previous call + * // returned SAT and it can safely reset the previous assumptions + * + * res = picosat_sat (-1); + * } + * else + * { + * assert (res == PICOSAT_UNKNOWN); + * + * // assumptions valid, but assignment invalid + * // except for top level assigned literals which + * // necessarily need to have this value if the formula is SAT + * + * // as above the solver nows that the previous call returned UNKWOWN + * // and will before doing anything else reset assumptions + * + * picosat_sat (-1); + * } + */ +void picosat_assume (PicoSAT *, int lit); + +/*------------------------------------------------------------------------*/ +/* This is an experimental feature for handling 'all different constraints' + * (ADC). Currently only one global ADC can be handled. The bit-width of + * all the bit-vectors entered in this ADC (stored in 'all different + * objects' or ADOs) has to be identical. + * + * TODO: also handle top level assigned literals here. + */ +void picosat_add_ado_lit (PicoSAT *, int); + +/*------------------------------------------------------------------------*/ +/* Call the main SAT routine. A negative decision limit sets no limit on + * the number of decisions. The return values are as above, e.g. + * 'PICOSAT_UNSATISFIABLE', 'PICOSAT_SATISFIABLE', or 'PICOSAT_UNKNOWN'. + */ +int picosat_sat (PicoSAT *, int decision_limit); + +/* As alternative to a decision limit you can use the number of propagations + * as limit. This is more linearly related to execution time. This has to + * be called after 'picosat_init' and before 'picosat_sat'. + */ +void picosat_set_propagation_limit (PicoSAT *, unsigned long long limit); + +/* Return last result of calling 'picosat_sat' or '0' if not called. + */ +int picosat_res (PicoSAT *); + +/* After 'picosat_sat' was called and returned 'PICOSAT_SATISFIABLE', then + * the satisfying assignment can be obtained by 'dereferencing' literals. + * The value of the literal is return as '1' for 'true', '-1' for 'false' + * and '0' for an unknown value. + */ +int picosat_deref (PicoSAT *, int lit); + +/* Same as before but just returns true resp. false if the literals is + * forced to this assignment at the top level. This function does not + * require that 'picosat_sat' was called and also does not internally reset + * incremental usage. + */ +int picosat_deref_toplevel (PicoSAT *, int lit); + +/* After 'picosat_sat' was called and returned 'PICOSAT_SATISFIABLE' a + * partial satisfying assignment can be obtained as well. It satisfies all + * original clauses. The value of the literal is return as '1' for 'true', + * '-1' for 'false' and '0' for an unknown value. In order to make this + * work all original clauses have to be saved internally, which has to be + * enabled by 'picosat_save_original_clauses' right after initialization. + */ +int picosat_deref_partial (PicoSAT *, int lit); + +/* Returns non zero if the CNF is unsatisfiable because an empty clause was + * added or derived. + */ +int picosat_inconsistent (PicoSAT *); + +/* Returns non zero if the literal is a failed assumption, which is defined + * as an assumption used to derive unsatisfiability. This is as accurate as + * generating core literals, but still of course is an overapproximation of + * the set of assumptions really necessary. The technique does not need + * clausal core generation nor tracing to be enabled and thus can be much + * more effective. The function can only be called as long the current + * assumptions are valid. See 'picosat_assume' for more details. + */ +int picosat_failed_assumption (PicoSAT *, int lit); + +/* Returns a zero terminated list of failed assumption in the last call to + * 'picosat_sat'. The pointer is valid until the next call to + * 'picosat_sat' or 'picosat_failed_assumptions'. It only makes sense if the + * last call to 'picosat_sat' returned 'PICOSAT_UNSATISFIABLE'. + */ +const int * picosat_failed_assumptions (PicoSAT *); + +/* Returns a zero terminated minimized list of failed assumption for the last + * call to 'picosat_sat'. The pointer is valid until the next call to this + * function or 'picosat_sat' or 'picosat_mus_assumptions'. It only makes sense + * if the last call to 'picosat_sat' returned 'PICOSAT_UNSATISFIABLE'. + * + * The call back function is called for all successful simplification + * attempts. The first argument of the call back function is the state + * given as first argument to 'picosat_mus_assumptions'. The second + * argument to the call back function is the new reduced list of failed + * assumptions. + * + * This function will call 'picosat_assume' and 'picosat_sat' internally but + * before returning reestablish a proper UNSAT state, e.g. + * 'picosat_failed_assumption' will work afterwards as expected. + * + * The last argument if non zero fixes assumptions. In particular, if an + * assumption can not be removed it is permanently assigned true, otherwise + * if it turns out to be redundant it is permanently assumed to be false. + */ +const int * picosat_mus_assumptions (PicoSAT *, void *, + void(*)(void*,const int*),int); + +/* Compute one maximal subset of satisfiable assumptions. You need to set + * the assumptions, call 'picosat_sat' and check for 'picosat_inconsistent', + * before calling this function. The result is a zero terminated array of + * assumptions that consistently can be asserted at the same time. Before + * returing the library 'reassumes' all assumptions. + * + * It could be beneficial to set the default phase of assumptions + * to true (positive). This can speed up the computation. + */ +const int * picosat_maximal_satisfiable_subset_of_assumptions (PicoSAT *); + +/* This function assumes that you have set up all assumptions with + * 'picosat_assume'. Then it calls 'picosat_sat' internally unless the + * formula is already inconsistent without assumptions, i.e. it contains + * the empty clause. After that it extracts a maximal satisfiable subset of + * assumptions. + * + * The result is a zero terminated maximal subset of consistent assumptions + * or a zero pointer if the formula contains the empty clause and thus no + * more maximal consistent subsets of assumptions can be extracted. In the + * first case, before returning, a blocking clause is added, that rules out + * the result for the next call. + * + * NOTE: adding the blocking clause changes the CNF. + * + * So the following idiom + * + * const int * mss; + * picosat_assume (a1); + * picosat_assume (a2); + * picosat_assume (a3); + * picosat_assume (a4); + * while ((mss = picosat_next_maximal_satisfiable_subset_of_assumptions ())) + * process_mss (mss); + * + * can be used to iterate over all maximal consistent subsets of + * the set of assumptions {a1,a2,a3,a4}. + * + * It could be beneficial to set the default phase of assumptions + * to true (positive). This might speed up the computation. + */ +const int * +picosat_next_maximal_satisfiable_subset_of_assumptions (PicoSAT *); + +/* Similarly we can iterate over all minimal correcting assumption sets. + * See the CAMUS literature [M. Liffiton, K. Sakallah JAR 2008]. + * + * The result contains each assumed literal only once, even if it + * was assumed multiple times (in contrast to the maximal consistent + * subset functions above). + * + * It could be beneficial to set the default phase of assumptions + * to true (positive). This might speed up the computation. + */ +const int * +picosat_next_minimal_correcting_subset_of_assumptions (PicoSAT *); + +/* Compute the union of all minmal correcting sets, which is called + * the 'high level union of all minimal unsatisfiable subset sets' + * or 'HUMUS' in our papers. + * + * It uses 'picosat_next_minimal_correcting_subset_of_assumptions' and + * the same notes and advices apply. In particular, this implies that + * after calling the function once, the current CNF becomes inconsistent, + * and PicoSAT has to be reset. So even this function internally uses + * PicoSAT incrementally, it can not be used incrementally itself at this + * point. + * + * The 'callback' can be used for progress logging and is called after + * each extracted minimal correcting set if non zero. The 'nhumus' + * parameter of 'callback' denotes the number of assumptions found to be + * part of the HUMUS sofar. + */ +const int * +picosat_humus (PicoSAT *, + void (*callback)(void * state, int nmcs, int nhumus), + void * state); + +/*------------------------------------------------------------------------*/ +/* Assume that a previous call to 'picosat_sat' in incremental usage, + * returned 'SATISFIABLE'. Then a couple of clauses and optionally new + * variables were added (a new variable is a variable that has an index + * larger then the maximum variable added so far). The next call to + * 'picosat_sat' also returns 'SATISFIABLE'. If this function + * 'picosat_changed' returns '0', then the assignment to the old variables + * is guaranteed to not have changed. Otherwise it might have changed. + * + * The return value to this function is only valid until new clauses are + * added through 'picosat_add', an assumption is made through + * 'picosat_assume', or again 'picosat_sat' is called. This is the same + * assumption as for 'picosat_deref'. + * + * TODO currently this function might also return a non zero value even if + * the old assignment did not change, because it only checks whether the + * assignment of at least one old variable was flipped at least once during + * the search. In principle it should be possible to be exact in the other + * direction as well by using a counter of variables that have an odd number + * of flips. But this is not implemented yet. + */ +int picosat_changed (PicoSAT *); + +/*------------------------------------------------------------------------*/ +/* The following six functions internally extract the variable and clausal + * core and thus require trace generation to be enabled with + * 'picosat_enable_trace_generation' right after calling 'picosat_init'. + * + * TODO: using these functions in incremental mode with failed assumptions + * has only been tested for 'picosat_corelit' thoroughly. The others + * probably only work in non-incremental mode or without using + * 'picosat_assume'. + */ + +/* This function determines whether the i'th added original clause is in the + * core. The 'i' is the return value of 'picosat_add', which starts at zero + * and is incremented by one after a original clause is added (that is after + * 'picosat_add (0)'). For the index 'i' the following has to hold: + * + * 0 <= i < picosat_added_original_clauses () + */ +int picosat_coreclause (PicoSAT *, int i); + +/* This function gives access to the variable core, which is made up of the + * variables that were resolved in deriving the empty clause. + */ +int picosat_corelit (PicoSAT *, int lit); + +/* Write the clauses that were used in deriving the empty clause to a file + * in DIMACS format. + */ +void picosat_write_clausal_core (PicoSAT *, FILE * core_file); + +/* Write a proof trace in TraceCheck format to a file. + */ +void picosat_write_compact_trace (PicoSAT *, FILE * trace_file); +void picosat_write_extended_trace (PicoSAT *, FILE * trace_file); + +/* Write a RUP trace to a file. This trace file contains only the learned + * core clauses while this is not necessarily the case for the RUP file + * obtained with 'picosat_set_incremental_rup_file'. + */ +void picosat_write_rup_trace (PicoSAT *, FILE * trace_file); + +/*------------------------------------------------------------------------*/ +/* Keeping the proof trace around is not necessary if an over-approximation + * of the core is enough. A literal is 'used' if it was involved in a + * resolution to derive a learned clause. The core literals are necessarily + * a subset of the 'used' literals. + */ + +int picosat_usedlit (PicoSAT *, int lit); +/*------------------------------------------------------------------------*/ +#endif diff --git a/cryptominisat/cppsrc/src/picosat/version.c b/cryptominisat/cppsrc/src/picosat/version.c new file mode 100644 index 00000000..c2b6d420 --- /dev/null +++ b/cryptominisat/cppsrc/src/picosat/version.c @@ -0,0 +1,14 @@ +#include "pico_config.h" + +const char * +picosat_version (void) +{ + return PICOSAT_VERSION; +} + +const char * +picosat_config (void) +{ + return PICOSAT_CC " " PICOSAT_CFLAGS; +} + diff --git a/cryptominisat/cppsrc/src/pre.js b/cryptominisat/cppsrc/src/pre.js new file mode 100644 index 00000000..123c6bc9 --- /dev/null +++ b/cryptominisat/cppsrc/src/pre.js @@ -0,0 +1,17 @@ +Module['print'] = function(text) { + var bottom = at_bottom(); + $('#output').append(text+"\n") + if (bottom) { + scroll(); + } +}; +Module['printErr'] = function(text) { + $('#output').append("--error-- " + text+"\n") + scroll(); +}; +Module['onRuntimeInitialized'] = function () { + $().ready(function () { + $('#runbutton').removeAttr("disabled") + $('#result').text('Ready'); + }) +} diff --git a/cryptominisat/cppsrc/src/predict_func_type.h b/cryptominisat/cppsrc/src/predict_func_type.h new file mode 100644 index 00000000..2e7b3518 --- /dev/null +++ b/cryptominisat/cppsrc/src/predict_func_type.h @@ -0,0 +1,39 @@ +/****************************************** +Copyright (C) 2009-2020 Authors of CryptoMiniSat, see AUTHORS file + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. +***********************************************/ +#ifndef PREDICT_FUN_TYPE_H +#define PREDICT_FUN_TYPE_H + +#include "clause.h" + +namespace CMSat { + +typedef float (*keep_func_type)( +const CMSat::Clause* +, const uint64_t +, const uint32_t +, const double +, const uint32_t +); + +} + +#endif //PREDICT_FUN_TYPE_H diff --git a/cryptominisat/cppsrc/src/propby.h b/cryptominisat/cppsrc/src/propby.h new file mode 100644 index 00000000..34b586b5 --- /dev/null +++ b/cryptominisat/cppsrc/src/propby.h @@ -0,0 +1,346 @@ +/****************************************** +Copyright (C) 2009-2020 Authors of CryptoMiniSat, see AUTHORS file + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. +***********************************************/ + +#pragma once + +#include "constants.h" +#include "solvertypes.h" +#include "clause.h" +#include "cloffset.h" + +#ifdef ARJUN_SERIALIZE +#include +#endif + +//#define DEBUG_PROPAGATEFROM + +namespace CMSat { + +enum PropByType { + null_clause_t = 0, clause_t = 1, binary_t = 2, + xor_t = 3, bnn_t = 4 +}; + +class PropBy +{ + enum bitFieldSizes { + bitsize_red_step = 1, + bitsize_data1 = 31, + bitsize_type = 3, + bitsize_data2 = 29 + }; + + private: + uint32_t red_step:bitsize_red_step; + uint32_t data1:bitsize_data1; + uint32_t type:bitsize_type; + //0: clause, NULL + //1: clause, non-null + //2: binary + //3: xor + //4: bnn + uint32_t data2:bitsize_data2; + int32_t ID; + + public: + PropBy() : + red_step(0) + , data1(0) + , type(null_clause_t) + , data2(0) + {} + + template + void save(Archive& ar, const unsigned int /*version*/) const { + const uint32_t my_red_step = red_step; + const uint32_t my_data1 = data1; + const uint32_t my_type = type; + const uint32_t my_data2 = data2; + ar << my_red_step; + ar << my_data1; + ar << my_type; + ar << my_data2; + ar << ID; + } + + template + void load(Archive& ar, const unsigned int /*version*/) { + uint32_t tmp; + ar >> tmp; red_step = tmp; + ar >> tmp; data1 = tmp; + ar >> tmp; type = tmp; + ar >> tmp; data2 = tmp; + ar >> ID; + } +#ifdef ARJUN_SERIALIZE + BOOST_SERIALIZATION_SPLIT_MEMBER() +#endif + +#ifndef LARGE_OFFSETS + //Normal clause prop + explicit PropBy(const ClOffset offset) : + red_step(0) + , data1(offset) + , type(clause_t) + , data2(0) + { + //No roll-over + /*#ifdef DEBUG_PROPAGATEFROM + assert(offset == get_offset()); + #endif*/ + } +#else + //Normal clause prop + explicit PropBy(const ClOffset offset) : + red_step(0) + , type(clause_t) + { + //No roll-over + data1 = offset & ((((ClOffset)1) << bitsize_data1) - 1); + data2 = offset >> bitsize_data1; + /*#ifdef DEBUG_PROPAGATEFROM + assert(offset == get_offset()); + #endif*/ + } +#endif + + //XOR + PropBy(const uint32_t matrix_num, const uint32_t row_num): + data1(matrix_num) + , type(xor_t) + , data2(row_num) + { + } + + //BNN prop + PropBy(uint32_t bnn_idx, void*): + data1(0xfffffff) + , type(bnn_t) + , data2(bnn_idx) + { + } + + //Binary prop + PropBy(const Lit lit, const bool redStep, int32_t _ID) : + red_step(redStep) + , data1(lit.toInt()) + , type(binary_t) + , data2(0) + , ID(_ID) + { + } + + //For hyper-bin, etc. + PropBy( + const Lit lit + , bool redStep //Step that lead here from ancestor is redundant + , bool hyperBin //It's a hyper-binary clause + , bool hyperBinNotAdded //It's a hyper-binary clause, but was never added because all the rest was zero-level + , int32_t _ID + ) : + red_step(redStep) + , data1(lit.toInt()) + , type(binary_t) + , data2(0) + , ID(_ID) + { + //HACK: if we are doing seamless hyper-bin and transitive reduction + //then if we are at toplevel, .getAncestor() + //must work, and return lit_Undef, but at the same time, .isNULL() + //must also work, for conflict generation. So this is a hack to + //achieve that. What an awful hack. + if (lit == ~lit_Undef) + type = null_clause_t; + + data2 = ((uint32_t)hyperBin) << 1 + | ((uint32_t)hyperBinNotAdded) << 2; + } + + void set_bnn_reason(uint32_t idx) + { + assert(isBNN()); + data1 = idx; + } + + bool bnn_reason_set() const + { + assert(isBNN()); + return data1 != 0xfffffff; + } + + uint32_t get_bnn_reason() const + { + assert(bnn_reason_set()); + return data1; + } + + uint32_t isBNN() const + { + return type == bnn_t; + } + + uint32_t getBNNidx() const + { + assert(isBNN()); + return data2; + } + + bool isRedStep() const + { + return red_step; + } + + int32_t getID() const + { + return ID; + } + + bool getHyperbin() const + { + return data2 & 2U; + } + + void setHyperbin(bool toSet) + { + data2 &= ~2U; + data2 |= (uint32_t)toSet << 1; + } + + bool getHyperbinNotAdded() const + { + return data2 & 4U; + } + + void setHyperbinNotAdded(bool toSet) + { + data2 &= ~4U; + data2 |= (uint32_t)toSet << 2; + } + + Lit getAncestor() const + { + #ifdef DEBUG_PROPAGATEFROM + assert(type == null_clause_t || type == binary_t); + #endif + return ~Lit::toLit(data1); + } + + bool isClause() const + { + return type == clause_t; + } + + PropByType getType() const + { + return (PropByType)type; + } + + Lit lit2() const + { + #ifdef DEBUG_PROPAGATEFROM + assert(type == binary_t); + #endif + return Lit::toLit(data1); + } + + uint32_t get_matrix_num() const + { + #ifdef DEBUG_PROPAGATEFROM + assert(type == xor_t); + #endif + return data1; + } + + uint32_t get_row_num() const + { + #ifdef DEBUG_PROPAGATEFROM + assert(type == xor_t); + #endif + return data2; + } + + ClOffset get_offset() const + { + #ifdef DEBUG_PROPAGATEFROM + assert(isClause()); + #endif +#ifndef LARGE_OFFSETS + return data1; +#else + ClOffset offset = data2; + offset <<= bitsize_data1; + offset |= data1; + return offset; +#endif + } + + bool isNULL() const + { + return type == null_clause_t; + } + + bool operator==(const PropBy other) const + { + return (type == other.type + && red_step == other.red_step + && data1 == other.data1 + && data2 == other.data2 + ); + } + + bool operator!=(const PropBy other) const + { + return !(*this == other); + } +}; + +inline std::ostream& operator<<(std::ostream& os, const PropBy& pb) +{ + switch (pb.getType()) { + case binary_t: + os << " binary, other lit= " << pb.lit2(); + break; + + case clause_t: + os << " clause, num= " << pb.get_offset(); + break; + + case null_clause_t: + os << " NULL"; + break; + + case bnn_t: + os << " BNN reason, bnn idx: " << pb.get_bnn_reason(); + break; + + case xor_t: + os << " xor reason, matrix= " << pb.get_matrix_num() << " row: " << pb.get_row_num(); + break; + + default: + assert(false); + break; + } + return os; +} + +} //end namespace diff --git a/cryptominisat/cppsrc/src/propby_backup.h b/cryptominisat/cppsrc/src/propby_backup.h new file mode 100644 index 00000000..047f2fde --- /dev/null +++ b/cryptominisat/cppsrc/src/propby_backup.h @@ -0,0 +1,232 @@ +/****************************************** +Copyright (C) 2009-2020 Authors of CryptoMiniSat, see AUTHORS file + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. +***********************************************/ + +#ifndef PROPBY_H +#define PROPBY_H + +#include "constants.h" +#include "solvertypes.h" +#include "clause.h" + +//#define DEBUG_PROPAGATEFROM + +#include "cloffset.h" + +namespace CMSat { + +enum PropByType {null_clause_t = 0, clause_t = 1, binary_t = 2, tertiary_t = 3}; + +class PropBy +{ + private: + uint32_t data1; + uint32_t data2; + + //0: clause, NULL + //1: clause, non-null + //2: binary + //3: tertiary + char type; + + char red_step; + + public: + PropBy() : + red_step(0) + , data1(0) + , type(null_clause_t) + , data2(0) + {} + + //Normal clause prop + explicit PropBy(const ClOffset offset) : + red_step(0) + , data1(offset) + , type(clause_t) + , data2(0) + { + //No roll-over + /*#ifdef DEBUG_PROPAGATEFROM + assert(offset == get_offset()); + #endif*/ + } + + //Binary prop + PropBy(const Lit lit, const bool redStep) : + red_step(redStep) + , data1(lit.toInt()) + , type(binary_t) + , data2(0) + { + } + + //For hyper-bin, etc. + PropBy( + const Lit lit + , bool redStep //Step that lead here from ancestor is redundant + , bool hyperBin //It's a hyper-binary clause + , bool hyperBinNotAdded //It's a hyper-binary clause, but was never added because all the rest was zero-level + ) : + red_step(redStep) + , data1(lit.toInt()) + , type(binary_t) + , data2(0) + { + //HACK: if we are doing seamless hyper-bin and transitive reduction + //then if we are at toplevel, .getAncestor() + //must work, and return lit_Undef, but at the same time, .isNULL() + //must also work, for conflict generation. So this is a hack to + //achieve that. What an awful hack. + if (lit == ~lit_Undef) + type = null_clause_t; + + data2 = ((uint32_t)hyperBin) << 1 + | ((uint32_t)hyperBinNotAdded) << 2; + } + + //Tertiary prop + PropBy(const Lit lit1, const Lit lit2, const bool redStep) : + red_step(redStep) + , data1(lit1.toInt()) + , type(tertiary_t) + , data2(lit2.toInt()) + { + } + + bool isRedStep() const + { + return red_step; + } + + bool getHyperbin() const + { + return data2 & 2U; + } + + void setHyperbin(bool toSet) + { + data2 &= ~2U; + data2 |= (uint32_t)toSet << 1; + } + + bool getHyperbinNotAdded() const + { + return data2 & 4U; + } + + void setHyperbinNotAdded(bool toSet) + { + data2 &= ~4U; + data2 |= (uint32_t)toSet << 2; + } + + Lit getAncestor() const + { + #ifdef DEBUG_PROPAGATEFROM + assert(type == null_clause_t || type == binary_t); + #endif + return ~Lit::toLit(data1); + } + + bool isClause() const + { + return type == clause_t; + } + + PropByType getType() const + { + return (PropByType)type; + } + + Lit lit2() const + { + #ifdef DEBUG_PROPAGATEFROM + assert(type == tertiary_t || type == binary_t); + #endif + return Lit::toLit(data1); + } + + Lit lit3() const + { + #ifdef DEBUG_PROPAGATEFROM + assert(type == tertiary_t); + #endif + return Lit::toLit(data2); + } + + ClOffset get_offset() const + { + #ifdef DEBUG_PROPAGATEFROM + assert(isClause()); + #endif + return data1; + } + + bool isNULL() const + { + return type == null_clause_t; + } + + bool operator==(const PropBy other) const + { + return (type == other.type + && red_step == other.red_step + && data1 == other.data1 + && data2 == other.data2 + ); + } + + bool operator!=(const PropBy other) const + { + return !(*this == other); + } +}; + +inline std::ostream& operator<<(std::ostream& os, const PropBy& pb) +{ + switch (pb.getType()) { + case binary_t : + os << " binary, other lit= " << pb.lit2(); + break; + + case tertiary_t : + os << " tri, other 2 lits= " << pb.lit2() << " , "<< pb.lit3(); + break; + + case clause_t : + os << " clause, num= " << pb.get_offset(); + break; + + case null_clause_t : + os << " NULL"; + break; + + default: + assert(false); + break; + } + return os; +} + +} //end namespace + +#endif //PROPBY_H diff --git a/cryptominisat/cppsrc/src/propbyforgraph.h b/cryptominisat/cppsrc/src/propbyforgraph.h new file mode 100644 index 00000000..92f844d4 --- /dev/null +++ b/cryptominisat/cppsrc/src/propbyforgraph.h @@ -0,0 +1,151 @@ +/****************************************** +Copyright (C) 2009-2020 Authors of CryptoMiniSat, see AUTHORS file + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. +***********************************************/ + +#include "solvertypes.h" +#include "clause.h" +#include "propby.h" +#include "clauseallocator.h" + +#ifndef __PROPBYFORGRAPH_H__ +#define __PROPBYFORGRAPH_H__ + +namespace CMSat { + +class PropByForGraph +{ + private: + uint16_t type; + uint32_t isize; + Clause* clause; + Lit lits[3]; + + public: + PropByForGraph(PropBy orig + , Lit otherLit + , const ClauseAllocator& alloc + ) : + type(10) + , isize(0) + , clause(NULL) + { + if (orig.getType() == binary_t) { + lits[0] = otherLit; + lits[1] = orig.lit2(); + type = 1; + isize = 2; + } + if (orig.isClause()) { + if (orig.isNULL()) { + type = 0; + isize = 0; + clause = NULL; + return; + } + clause = alloc.ptr(orig.get_offset()); + isize = clause->size(); + type = 0; + } + } + + PropByForGraph() : + type(0) + , clause(NULL) + {} + + PropByForGraph(const PropByForGraph& other) : + type(other.type) + , isize(other.isize) + , clause(other.clause) + { + memcpy(lits, other.lits, sizeof(Lit)*3); + } + + PropByForGraph& operator=(const PropByForGraph& other) + { + type = other.type, + isize = other.isize; + clause = other.clause; + //delete xorLits; + memcpy(lits, other.lits, sizeof(Lit)*3); + return *this; + } + + uint32_t size() const + { + return isize; + } + + bool isNULL() const + { + return type == 0 && clause == NULL; + } + + bool isClause() const + { + return type == 0; + } + + bool isBin() const + { + return type == 1; + } + + const Clause* getClause() const + { + return clause; + } + + Clause* getClause() + { + return clause; + } + + Lit operator[](const uint32_t i) const + { + switch (type) { + case 0: + assert(clause != NULL); + return (*clause)[i]; + + default : + return lits[i]; + } + } +}; + +inline std::ostream& operator<<( + std::ostream& os + , const PropByForGraph& propByFull +) { + + if (propByFull.isBin()) { + os << propByFull[0] << " " << propByFull[1]; + } else if (propByFull.isClause()) { + if (propByFull.isNULL()) os << "null clause"; + else os << *propByFull.getClause(); + } + return os; +} + +} //end namespace + +#endif //__PROPBYFORGRAPH_H__ diff --git a/cryptominisat/cppsrc/src/propengine.cpp b/cryptominisat/cppsrc/src/propengine.cpp new file mode 100644 index 00000000..6a2a33b6 --- /dev/null +++ b/cryptominisat/cppsrc/src/propengine.cpp @@ -0,0 +1,1033 @@ +/****************************************** +Copyright (C) 2009-2020 Authors of CryptoMiniSat, see AUTHORS file + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. +***********************************************/ + +#include "propengine.h" +#include +#include +#include +#include +#include +#include +#include + +#include "solver.h" +#include "clauseallocator.h" +#include "clause.h" +#include "time_mem.h" +#include "varupdatehelper.h" +#include "watchalgos.h" +#include "sqlstats.h" +#include "gaussian.h" + +using namespace CMSat; +using std::cout; +using std::endl; + +//#define DEBUG_ENQUEUE_LEVEL0 +//#define VERBOSE_DEBUG_POLARITIES +//#define DEBUG_DYNAMIC_RESTART + +/** +@brief Sets a sane default config and allocates handler classes +*/ +PropEngine::PropEngine( + const SolverConf* _conf + , Solver* _solver + , std::atomic* _must_interrupt_inter +) : + CNF(_conf, _must_interrupt_inter) + , order_heap_vsids(VarOrderLt(var_act_vsids)) + , qhead(0) + , solver(_solver) +{ +} + +PropEngine::~PropEngine() +{ +} + +void PropEngine::new_var( + const bool bva, + uint32_t orig_outer, + const bool insert_varorder) +{ + CNF::new_var(bva, orig_outer, insert_varorder); + + var_act_vsids.insert(var_act_vsids.end(), 1, 0); + vmtf_btab.insert(vmtf_btab.end(), 1, 0); + vmtf_links.insert(vmtf_links.end(), 1, Link()); +} + +void PropEngine::new_vars(size_t n) +{ + CNF::new_vars(n); + + var_act_vsids.insert(var_act_vsids.end(), n, 0); + vmtf_btab.insert(vmtf_btab.end(), n, 0); + vmtf_links.insert(vmtf_links.end(), n, Link()); +} + +void PropEngine::save_on_var_memory() +{ + CNF::save_on_var_memory(); + + var_act_vsids.resize(nVars()); + var_act_vsids.shrink_to_fit(); +} + +/** + @ *brief Attach normal a clause to the watchlists + + Handles 2, 3 and >3 clause sizes differently and specially + */ + +void PropEngine::attachClause( + const Clause& c + , const bool checkAttach +) { + const ClOffset offset = cl_alloc.get_offset(&c); + + assert(c.size() > 2); + if (checkAttach) { + assert(value(c[0]) == l_Undef); + assert(value(c[1]) == l_Undef || value(c[1]) == l_False); + } + + #ifdef DEBUG_ATTACH + for (uint32_t i = 0; i < c.size(); i++) { + assert(varData[c[i].var()].removed == Removed::none); + } + #endif //DEBUG_ATTACH + + const Lit blocked_lit = c[2]; + watches[c[0]].push(Watched(offset, blocked_lit)); + watches[c[1]].push(Watched(offset, blocked_lit)); +} + +/** +@brief Detaches a (potentially) modified clause + +The first two literals might have chaned through modification, so they are +passed along as arguments -- they are needed to find the correct place where +the clause is +*/ +void PropEngine::detach_modified_clause( + const Lit lit1 + , const Lit lit2 + , const Clause* address +) { + ClOffset offset = cl_alloc.get_offset(address); + removeWCl(watches[lit1], offset); + removeWCl(watches[lit2], offset); +} + +PropBy PropEngine::gauss_jordan_elim(const Lit p, const uint32_t currLevel) +{ + VERBOSE_PRINT("PropEngine::gauss_jordan_elim called, declev: " + << decisionLevel() << " lit to prop: " << p); + + if (gmatrices.empty()) return PropBy(); + for(uint32_t i = 0; i < gqueuedata.size(); i++) { + if (gqueuedata[i].disabled || !gmatrices[i]->is_initialized()) continue; + gqueuedata[i].reset(); + gmatrices[i]->update_cols_vals_set(); + } + + bool confl_in_gauss = false; + assert(gwatches.size() > p.var()); + vec& ws = gwatches[p.var()]; + GaussWatched* i = ws.begin(); + GaussWatched* j = i; + const GaussWatched* end = ws.end(); + + for (; i != end; i++) { + if (gqueuedata[i->matrix_num].disabled || !gmatrices[i->matrix_num]->is_initialized()) + continue; //remove watch and continue + + gqueuedata[i->matrix_num].new_resp_var = numeric_limits::max(); + gqueuedata[i->matrix_num].new_resp_row = numeric_limits::max(); + gqueuedata[i->matrix_num].do_eliminate = false; + gqueuedata[i->matrix_num].currLevel = currLevel; + + if (gmatrices[i->matrix_num]->find_truths( + i, j, p.var(), i->row_n, gqueuedata[i->matrix_num]) + ) { + continue; + } else { + confl_in_gauss = true; + i++; + break; + } + } + + for (; i != end; i++) *j++ = *i; + ws.shrink(i-j); + + for (size_t g = 0; g < gqueuedata.size(); g++) { + if (gqueuedata[g].disabled || !gmatrices[g]->is_initialized()) + continue; + + if (gqueuedata[g].do_eliminate) { + gmatrices[g]->eliminate_col(p.var(), gqueuedata[g]); + confl_in_gauss |= (gqueuedata[g].ret == gauss_res::confl); + } + } + + for (GaussQData& gqd: gqueuedata) { + if (gqd.disabled) continue; + + //There was a conflict but this is not that matrix. + //Just skip. + if (confl_in_gauss && gqd.ret != gauss_res::confl) continue; + + switch (gqd.ret) { + case gauss_res::confl :{ + gqd.num_conflicts++; + qhead = trail.size(); + return gqd.confl; + } + + case gauss_res::prop: + gqd.num_props++; + break; + + case gauss_res::none: + //nothing + break; + + default: + assert(false); + return PropBy(); + } + } + return PropBy(); +} + +lbool PropEngine::bnn_prop( + const uint32_t bnn_idx, uint32_t level, Lit /*l*/, BNNPropType prop_t) +{ + BNN* bnn = bnns[bnn_idx]; + switch(prop_t) { + case bnn_neg_t: + bnn->ts++; + bnn->undefs--; + break; + case bnn_pos_t: + bnn->undefs--; + break; + case bnn_out_t: + break; + } + #ifdef SLOW_DEBUG + assert (bnn->ts >= 0); + assert (bnn->undefs >= 0); + assert (bnn->ts <= (int32_t)bnn->size()); + assert (bnn->undefs <= (int32_t)bnn->size()); + #endif + + const int32_t ts = bnn->ts; + const int32_t undefs = bnn->undefs; + + if (ts+undefs < bnn->cutoff) { + // we are under the cutoff no matter what undef+unknowns is + if (bnn->set) { +// cout << "returning l_False from bnn_prop" << "declev: " << decisionLevel() << endl; + return l_False; + } + + if (value(bnn->out) == l_False) + return l_True; + if (value(bnn->out) == l_True) + return l_False; + + assert(value(bnn->out) == l_Undef); + enqueue(~bnn->out, level, PropBy(bnn_idx, nullptr)); +// cout << "BNN prop set BNN out " << ~bnn->out << " due to being under for sure" << endl; + return l_True; + } + + if (ts >= bnn->cutoff) { + // we are over the cutoff + if (bnn->set) { + return l_True; + } + + // we are at the cutoff no matter what undefs is + if (value(bnn->out) == l_True) + return l_True; + if (value(bnn->out) == l_False) + return l_False; + + assert(value(bnn->out) == l_Undef); + enqueue(bnn->out, level, PropBy(bnn_idx, nullptr)); + // cout << "BNN prop set BNN out " << bnn->out << " due to being over for sure" << endl; } + return l_True; + } + + if ( + ((!bnn->set && value(bnn->out) == l_True) || bnn->set) && + bnn->cutoff - ts == undefs) + { + //it's TRUE and UNDEF is exactly what's missing + + for(const auto& p: *bnn) { + if (value(p) == l_Undef) { + enqueue(p, level, PropBy(bnn_idx, nullptr)); + } + } + return l_True; + } + + if ( + ((!bnn->set && value(bnn->out) == l_False) && + bnn->cutoff == ts + 1)) + { + //it's FALSE and UNDEF must ALL be set to 0 + + for(const auto& p: *bnn) { + if (value(p) == l_Undef) { + enqueue(~p, level, PropBy(bnn_idx, nullptr)); + } + } + return l_True; + } + + return l_Undef; +} + +vector* PropEngine::get_bnn_reason(BNN* bnn, Lit lit) +{ +// cout << "Getting BNN reason, lit: " << lit << " bnn: " << *bnn << endl; +// cout << "values: "; +// for(const auto& l: bnn->in) { +// cout << l << " val: " << value(l) << " , "; +// } +// if (!bnn->set) { +// cout << " -- out : " << value(bnn->out); +// } +// cout << endl; + + if (lit == lit_Undef) { + get_bnn_confl_reason(bnn, &bnn_confl_reason); + return &bnn_confl_reason; + } + + auto& reason = varData[lit.var()].reason; +// cout +// << " reason lev: " << varData[lit.var()].level +// << " sublev: " << varData[lit.var()].sublevel +// << " reason type: " << varData[lit.var()].reason.getType() +// << endl; + assert(reason.isBNN()); + if (reason.bnn_reason_set()) { + return &bnn_reasons[reason.get_bnn_reason()]; + } + + vector* ret; + + //Get an empty slot + uint32_t empty_slot; + if (bnn_reasons_empty_slots.empty()) { + bnn_reasons.push_back(vector()); + empty_slot = bnn_reasons.size()-1; + } else { + empty_slot = bnn_reasons_empty_slots.back(); + bnn_reasons_empty_slots.pop_back(); + } + ret = &bnn_reasons[empty_slot]; + reason.set_bnn_reason(empty_slot); + + get_bnn_prop_reason(bnn, lit, ret); +// cout << "get_bnn_reason (" << lit << ") returning: "; +// for(const auto& l: *ret) { +// cout << l << " val(" << value(l) << ") "; +// } +// cout << "0" << endl; + + return ret; +} + +void PropEngine::get_bnn_confl_reason(BNN* bnn, vector* ret) +{ + assert(bnn->set || value(bnn->out) != l_Undef); + + //It's set to TRUE, but it's actually LESS than cutoff + if (bnn->set|| + (!bnn->set && value(bnn->out) == l_True)) + { + ret->clear(); + if (!bnn->set) + ret->push_back(~bnn->out); + + int32_t need = bnn->size()-bnn->cutoff+1; + for(const auto& l: *bnn) { + if (value(l) == l_False) { + ret->push_back(l); + need--; + } + if (need == 0) break; + } + } + + //it's set to FALSE but it's actually MORE than cutoff. + if ((!bnn->set && value(bnn->out) == l_False)) + { + ret->clear(); + if (!bnn->set) + ret->push_back(bnn->out); + + int32_t need = bnn->cutoff; + for(const auto& l: *bnn) { + if (value(l) == l_True) { + ret->push_back(~l); + need--; + } + if (need == 0) break; + } + } + + uint32_t maxsublevel = 0; + uint32_t at = 0; + for(uint32_t i = 0; i < ret->size(); i ++) { + Lit l = (*ret)[i]; + if (varData[l.var()].sublevel >= maxsublevel) { + maxsublevel = varData[l.var()].sublevel; + at = i; + } + } + std::swap((*ret)[0], (*ret)[at]); +} + +void PropEngine::get_bnn_prop_reason( + BNN* bnn, Lit lit, vector* ret) +{ + assert(bnn->set|| value(bnn->out) != l_Undef); + assert(value(lit) == l_True); //it's being propagated + + if (lit.var() == bnn->out.var()) { + // bnn->out got set + + //It's set to TRUE + if (value(bnn->out) == l_True) { + ret->clear(); + ret->push_back(lit); //this is what's propagated, must be 1st + + //Caused it to meet cutoff + int32_t need = bnn->cutoff; + for(const auto& l: *bnn) { + if (varData[l.var()].sublevel <= varData[lit.var()].sublevel + && value(l) == l_True) + { + need--; + ret->push_back(~l); + } + if (need == 0) break; + } + } + + //it's set to FALSE + if (value(bnn->out) == l_False) { + ret->clear(); + ret->push_back(lit); //this is what's propagated, must be 1st + + //Caused it to meet cutoff + int32_t need = bnn->size()-bnn->cutoff+1; + for(const auto& l: *bnn) { + if (varData[l.var()].sublevel <= varData[lit.var()].sublevel + && value(l) == l_False) + { + need--; + ret->push_back(l); + } + if (need == 0) break; + } + } + return; + } else { + // bnn->in got set + + ret->clear(); + ret->push_back(lit); //this is what's propagated, must be 1st + if (!bnn->set) { + ret->push_back(bnn->out ^ (value(bnn->out) == l_True)); + } + for(const auto& l: *bnn) { + if (varData[l.var()].sublevel < varData[lit.var()].sublevel) { + if (bnn->set || + (!bnn->set && value(bnn->out) == l_True)) + { + if (value(l) == l_False) { + ret->push_back(l); + } + } + if (!bnn->set && value(bnn->out) == l_False) + { + if (value(l) == l_True) { + ret->push_back(~l); + } + } + } + } + return; + } + assert(false); +} + +/** +@brief Propagates a binary clause + +Need to be somewhat tricky if the clause indicates that current assignment +is incorrect (i.e. both literals evaluate to FALSE). If conflict if found, +sets failBinLit +*/ +template +inline bool PropEngine::prop_bin_cl( + const Watched* i + , const Lit p + , PropBy& confl + , uint32_t currLevel +) { + const lbool val = value(i->lit2()); + if (val == l_Undef) { + enqueue(i->lit2(), currLevel, PropBy(~p, i->red(), i->get_ID())); + } else if (val == l_False) { + confl = PropBy(~p, i->red(), i->get_ID()); + failBinLit = i->lit2(); + qhead = trail.size(); + return false; + } + + return true; +} + +template +bool PropEngine::prop_long_cl_any_order( + Watched* i + , Watched*& j + , const Lit p + , PropBy& confl + , uint32_t currLevel +) { + //Blocked literal is satisfied, so clause is satisfied + if (value(i->getBlockedLit()) == l_True) { + *j++ = *i; + return true; + } + if (inprocess) { + propStats.bogoProps += 4; + } + const ClOffset offset = i->get_offset(); + Clause& c = *cl_alloc.ptr(offset); + + #ifdef SLOW_DEBUG + assert(!c.getRemoved()); + assert(!c.freed()); + if (!use_disable) { + assert(!c.disabled); + } + #endif + + if (!red_also && c.red()) { + *j++ = *i; + return true; + } + + if (use_disable && c.disabled) { + *j++ = *i; + return true; + } + + if (prop_normal_helper(c, offset, j, p) == PROP_NOTHING) { + return true; + } + + // Did not find watch -- clause is unit under assignment: + *j++ = *i; + if (value(c[0]) == l_False) { + handle_normal_prop_fail(c, offset, confl); + return false; + } else { + if (!inprocess) { + #if defined(NORMAL_CL_USE_STATS) + c.stats.props_made++; + #endif + #if defined(STATS_NEEDED) || defined(FINAL_PREDICTOR) + c.stats.props_made++; + c.stats.last_touched_any = sumConflicts; + #endif + } + + if (currLevel == decisionLevel()) { + enqueue(c[0], currLevel, PropBy(offset)); + } else { + uint32_t nMaxLevel = currLevel; + uint32_t nMaxInd = 1; + // pass over all the literals in the clause and find the one with the biggest level + for (uint32_t nInd = 2; nInd < c.size(); ++nInd) { + uint32_t nLevel = varData[c[nInd].var()].level; + if (nLevel > nMaxLevel) { + nMaxLevel = nLevel; + nMaxInd = nInd; + } + } + + if (nMaxInd != 1) { + std::swap(c[1], c[nMaxInd]); + j--; // undo last watch + watches[c[1]].push(*i); + } + + enqueue(c[0], nMaxLevel, PropBy(offset)); + } + } + + return true; +} + +void CMSat::PropEngine::reverse_one_bnn(uint32_t idx, BNNPropType t) { + BNN* const bnn= bnns[idx]; + SLOW_DEBUG_DO(assert(bnn != NULL)); + switch(t) { + case bnn_neg_t: + bnn->ts--; + bnn->undefs++; + break; + case bnn_pos_t: + bnn->undefs++; + break; + case bnn_out_t: + break; + } + VERBOSE_PRINT("reverse bnn idx: " << idx + << " bnn->undefs: " << bnn->undefs + << " bnn->ts: " << bnn->ts + << " bnn->sz: " << bnn->size() + << " BNN: " << *bnn); + + SLOW_DEBUG_DO(assert(bnn->ts >= 0)); + SLOW_DEBUG_DO(assert(bnn->undefs >= 0)); + SLOW_DEBUG_DO(assert(bnn->ts <= (int32_t)bnn->size())); + SLOW_DEBUG_DO(assert(bnn->undefs <= (int32_t)bnn->size())); +} + +void CMSat::PropEngine::reverse_prop(const CMSat::Lit l) +{ + if (!varData[l.var()].propagated) return; + watch_subarray ws = watches[~l]; + for (const auto& i: ws) { + if (i.isBNN()) { + reverse_one_bnn(i.get_bnn(), i.get_bnn_prop_t()); + } + } + varData[l.var()].propagated = false; +} + +template +PropBy PropEngine::propagate_any_order() +{ + PropBy confl; + VERBOSE_PRINT("propagate_any_order started"); + + while (qhead < trail.size() && confl.isNULL()) { + const Lit p = trail[qhead].lit; // 'p' is enqueued fact to propagate. + varData[p.var()].propagated = true; + watch_subarray ws = watches[~p]; + uint32_t currLevel = trail[qhead].lev; + + Watched* i = ws.begin(); + Watched* j = i; + Watched* end = ws.end(); + if (inprocess) { + propStats.bogoProps += ws.size()/4 + 1; + } + propStats.propagations++; + simpDB_props--; + for (; i != end; i++) { + // propagate binary clause + if (likely(i->isBin())) { + *j++ = *i; + if (!red_also && i->red()) { + continue; + } + if (distill_use && i->bin_cl_marked()) { + continue; + } + prop_bin_cl(i, p, confl, currLevel); + continue; + } + + // propagate BNN constraint + if (i->isBNN()) { + *j++ = *i; + const lbool val = bnn_prop( + i->get_bnn(), currLevel, p, i->get_bnn_prop_t()); + if (val == l_False) confl = PropBy(i->get_bnn(), nullptr); + continue; + } + + //propagate normal clause + assert(i->isClause()); + prop_long_cl_any_order(i, j, p, confl, currLevel); + continue; + } + while (i != end) { + *j++ = *i++; + } + ws.shrink_(end-j); + VERBOSE_PRINT("prop went through watchlist of " << p); + + //distillation would need to generate TBDD proofs to simplify clauses with GJ + if (confl.isNULL() && !distill_use) { + confl = gauss_jordan_elim(p, currLevel); + } + + qhead++; + } + + #ifdef SLOW_DEBUG + if (confl.isNULL() && !distill_use) { + for (size_t g = 0; g < gqueuedata.size(); g++) { + if (gqueuedata[g].disabled) continue; + gmatrices[g]->check_invariants(); + } + } + #endif + +// For BNN debugging +// if (confl.isNULL()) { +// for(uint32_t idx = 0; idx < bnns.size(); idx++) { +// auto& bnn = bnns[idx]; +// if (!bnn) continue; +// int32_t undefs = 0; +// int32_t ts = 0; +// for(const auto& l: *bnn) { +// if (value(l) == l_True) { +// ts++; +// } +// if (value(l) == l_Undef) { +// undefs++; +// } +// } +// cout << "u: " << undefs << " my u: " << bnn->undefs << " -- "; +// cout << "t: " << ts << " my t: " << bnn->ts << " idx: " << idx +// << " sz :" << bnn->size() << endl; +// assert(undefs == bnn->undefs); +// assert(ts == bnn->ts); +// } +// cout << "ALL BNNS CHECKED========" << endl; +// } + + + VERBOSE_PRINT("Propagation (propagate_any_order) ended."); + + return confl; +} +template PropBy PropEngine::propagate_any_order(); +template PropBy PropEngine::propagate_any_order(); +template PropBy PropEngine::propagate_any_order(); +template PropBy PropEngine::propagate_any_order(); + + +void PropEngine::printWatchList(const Lit lit) const +{ + watch_subarray_const ws = watches[lit]; + for (const Watched *it2 = ws.begin(), *end2 = ws.end() + ; it2 != end2 + ; it2++ + ) { + if (it2->isBin()) { + cout << "bin: " << lit << " , " << it2->lit2() << " red : " << (it2->red()) << endl; + } else if (it2->isClause()) { + cout << "cla:" << it2->get_offset() << endl; + } else { + assert(false); + } + } +} + +void PropEngine::updateVars( + [[maybe_unused]] const vector& outerToInter, + [[maybe_unused]] const vector& interToOuter +) { + //Trail is NOT correct, only its length is correct + for(Trail& t: trail) { + t.lit = lit_Undef; + } +} + +void PropEngine::print_trail() +{ + for(size_t i = trail_lim[0]; i < trail.size(); i++) { + assert(varData[trail[i].lit.var()].level == trail[i].lev); + cout + << "trail " << i << ":" << trail[i].lit + << " lev: " << trail[i].lev + << " reason: " << varData[trail[i].lit.var()].reason + << endl; + } +} + +template +bool PropEngine::propagate_occur(int64_t* limit_to_decrease) +{ + assert(ok); + bool ret = true; + + while (qhead < trail.size()) { + const Lit p = trail[qhead].lit; + qhead++; + watch_subarray ws = watches[~p]; + + //Go through each occur + *limit_to_decrease -= 1; + for (const Watched* it = ws.begin(), *end = ws.end() + ; it != end + ; ++it + ) { + if (it->isClause()) { + *limit_to_decrease -= 1; + if (!prop_long_cl_occur(it->get_offset())) ret = false; + } + if (it->isBin()) { + if (!prop_bin_cl_occur(*it)) ret = false; + } + assert(!it->isBNN()); + } + } + assert(gmatrices.empty()); + + if (decisionLevel() == 0 && !ret) { + *frat << add << ++clauseID << fin; + assert(unsat_cl_ID == 0); + unsat_cl_ID = clauseID; + } + + return ret; +} + +template bool PropEngine::propagate_occur(int64_t*); +template bool PropEngine::propagate_occur(int64_t*); + +template +inline bool PropEngine::prop_bin_cl_occur( + const Watched& ws) +{ + const lbool val = value(ws.lit2()); + if (val == l_False) return false; + if (val == l_Undef) enqueue(ws.lit2()); + return true; +} + +template +inline bool PropEngine::prop_long_cl_occur( + const ClOffset offset) +{ + const Clause& cl = *cl_alloc.ptr(offset); + assert(!cl.freed() && "Cannot be already freed in occur"); + if (cl.getRemoved()) + return true; + + Lit lastUndef = lit_Undef; + uint32_t numUndef = 0; + bool satcl = false; + for (const Lit lit: cl) { + const lbool val = value(lit); + if (val == l_True) { + satcl = true; + break; + } + if (val == l_Undef) { + numUndef++; + if (numUndef > 1) break; + lastUndef = lit; + } + } + if (satcl) + return true; + + //Problem is UNSAT + if (numUndef == 0) { + return false; + } + + if (numUndef > 1) + return true; + + enqueue(lastUndef); + + return true; +} + +#ifdef STATS_NEEDED_BRANCH +void PropEngine::sql_dump_vardata_picktime(uint32_t v, PropBy from) +{ + if (!solver->sqlStats) + return; + + bool dump = false; + double rnd_num = solver->mtrand.randDblExc(); + if (rnd_num <= conf.dump_individual_cldata_ratio*0.1) { + dump = true; + } + varData[v].dump = dump; + if (!dump) + return; + + solver->dump_restart_sql(rst_dat_type::var); + + uint64_t outer_var = map_inter_to_outer(v); + + varData[v].sumDecisions_at_picktime = sumDecisions; + varData[v].sumConflicts_at_picktime = sumConflicts; + varData[v].sumAntecedents_at_picktime = sumAntecedents; + varData[v].sumAntecedentsLits_at_picktime = sumAntecedentsLits; + varData[v].sumConflictClauseLits_at_picktime = sumConflictClauseLits; + varData[v].sumPropagations_at_picktime = sumPropagations; + varData[v].sumDecisionBasedCl_at_picktime = sumDecisionBasedCl; + varData[v].sumClLBD_at_picktime = sumClLBD; + varData[v].sumClSize_at_picktime = sumClSize; + double rel_activity_at_picktime = + std::log2(var_act_vsids[v]+10e-300)/std::log2(max_vsids_act+10e-300); + + varData[v].last_time_set_was_dec = (from == PropBy()); + + //inside data + varData[v].inside_conflict_clause_glue_at_picktime = varData[v].inside_conflict_clause_glue; + varData[v].inside_conflict_clause_at_picktime = varData[v].inside_conflict_clause; + varData[v].inside_conflict_clause_antecedents_at_picktime = varData[v].inside_conflict_clause_antecedents; + + solver->sqlStats->var_data_picktime( + solver + , outer_var + , varData[v] + , rel_activity_at_picktime + ); +} +#endif + +///// VMTF //// + +void PropEngine::vmtf_check_unassigned() +{ + uint32_t at = vmtf_queue.unassigned; + uint32_t unassigned = 0; + while (at != numeric_limits::max()) { + at = vmtf_links[at].next; + if (at != numeric_limits::max()) { + if (value(at) == l_Undef && varData[at].removed == Removed::none) { + cout << "vmtf OOOPS, var " << at+1 << " would have been unassigned. btab[var]: " << vmtf_btab[at] << endl; + unassigned++; + } + } + } + if (unassigned) { + cout << "unassigned total: " << unassigned << endl; + assert(unassigned == 0); + } +} + +uint32_t PropEngine::vmtf_pick_var() +{ + uint64_t searched = 0; + uint32_t res = vmtf_queue.unassigned; + VERBOSE_PRINT("vmtf start unassigned: " << res); + + SLOW_DEBUG_DO(vmtf_check_unassigned()); + while (res != numeric_limits::max() + && value(res) != l_Undef + ) { + res = vmtf_links[res].prev; + searched++; + } + + if (res == numeric_limits::max()) { + vmtf_check_unassigned(); + return var_Undef; + } + if (searched) vmtf_update_queue_unassigned(res); + VERBOSE_PRINT("vmtf next queue decision variable " << res << " btab value: " << vmtf_btab[res]); + return res; +} + +// Update queue to point to last potentially still unassigned variable. +// All variables after 'queue.unassigned' in bump order are assumed to be +// assigned. Then update the 'queue.vmtf_bumped' field and log it. +void PropEngine::vmtf_update_queue_unassigned (const uint32_t var) { + assert(var != numeric_limits::max()); + assert(var < nVars()); + VERBOSE_PRINT("vmtf_queue.unassigned set to: " << var+1 + << " vmtf_queue.vmtf_bumped set to: " << vmtf_btab[var]); + vmtf_queue.unassigned = var; + vmtf_queue.vmtf_bumped = vmtf_btab[var]; +} + +void PropEngine::vmtf_init_enqueue (const uint32_t var) { + assert(var < nVars()); + assert(var < vmtf_links.size()); + Link & l = vmtf_links[var]; + + //Put at the end of the queue + l.next = numeric_limits::max(); + if (vmtf_queue.last != numeric_limits::max()) { + // Not empty queue + assert(vmtf_links[vmtf_queue.last].next == numeric_limits::max()); + vmtf_links[vmtf_queue.last].next = var; + } else { + // Empty queue + assert(vmtf_queue.first == numeric_limits::max()); + vmtf_queue.first = var; + } + l.prev = vmtf_queue.last; + vmtf_queue.last = var; + + vmtf_btab[var] = ++stats_bumped; // set timestamp of enqueue + vmtf_update_queue_unassigned(vmtf_queue.last); +} + +void PropEngine::vmtf_dequeue (const uint32_t var) { + Link & l = vmtf_links[var]; + if (vmtf_queue.unassigned == var) { + vmtf_queue.unassigned = l.prev; + if (vmtf_queue.unassigned != numeric_limits::max()) { + vmtf_update_queue_unassigned(vmtf_queue.unassigned); + } + } + //vmtf_queue.dequeue (vmtf_links, var); +} + +// Move vmtf_bumped variables to the front of the (VMTF) decision queue. The +// 'vmtf_bumped' time stamp is updated accordingly. It is used to determine +// whether the 'queue.assigned' pointer has to be moved in 'unassign'. + +void PropEngine::vmtf_bump_queue (const uint32_t var) { + if (vmtf_links[var].next == numeric_limits::max()) { + return; + } + //Remove from wherever it is, put to the end + vmtf_queue.dequeue (vmtf_links, var); + vmtf_queue.enqueue (vmtf_links, var); + + assert (stats_bumped != numeric_limits::max()); + vmtf_btab[var] = ++stats_bumped; + VERBOSE_PRINT("vmtf moved to last element in queue the variable " << var+1 << " and vmtf_bumped to " << vmtf_btab[var]); + if (value(var) == l_Undef) vmtf_update_queue_unassigned(var); +} diff --git a/cryptominisat/cppsrc/src/propengine.h b/cryptominisat/cppsrc/src/propengine.h new file mode 100644 index 00000000..46b25aa4 --- /dev/null +++ b/cryptominisat/cppsrc/src/propengine.h @@ -0,0 +1,745 @@ +/****************************************** +Copyright (C) 2009-2020 Authors of CryptoMiniSat, see AUTHORS file + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. +***********************************************/ + +#pragma once + +// #define VERBOSE_DEBUG +#include +#include +#include +#include +#include + +#include "constants.h" +#include "propby.h" +#include "vmtf.h" + +#include "avgcalc.h" +#include "propby.h" +#include "heap.h" +#include "alg.h" +#include "clause.h" +#include "boundedqueue.h" +#include "cnf.h" +#include "watchalgos.h" +#include "gqueuedata.h" +#include + +using std::mt19937_64; + +namespace CMSat { + +class Solver; +class SQLStats; +class DataSync; + +//#define VERBOSE_DEBUG_FULLPROP +//#define VERBOSE_DEBUG + +#ifdef VERBOSE_DEBUG +#define VERBOSE_DEBUG_FULLPROP +#define ENQUEUE_DEBUG +#define DEBUG_ENQUEUE_LEVEL0 +#endif + +class Solver; +class ClauseAllocator; +class Gaussian; +class EGaussian; + +enum PropResult { + PROP_FAIL = 0 + , PROP_NOTHING = 1 + , PROP_SOMETHING = 2 + , PROP_TODO = 3 +}; + +struct Trail { + + Trail () { + } + + Trail (Lit _lit, uint32_t _lev) : + lit(_lit) + , lev(_lev) + {} + + Lit lit; + uint32_t lev; +}; + + +struct RandHeap +{ + vector in_heap; + vector vars; + + bool inHeap(uint32_t x) const { + if (in_heap.size() <= x) { + return false; + } + return in_heap[x]; + } + + void clear() { + in_heap.clear(); + vars.clear(); + } + + void insert(uint32_t x) { + assert(!inHeap(x)); + if (in_heap.size() <= x) { + uint32_t n = x - in_heap.size() + 1; + in_heap.insert(in_heap.end(), n, false); + } + in_heap[x] = true; + vars.push_back(x); + } + + size_t size() const { + return vars.size(); + } + + void print_heap() const { + for(const auto& x: vars) { + cout << x << ", "; + } + cout << endl; + } + + uint32_t mem_used() const { + uint32_t ret = 0; + ret += in_heap.capacity() * sizeof(unsigned char); + //ret += vars.capacity() * sizeof(uint32_t); + return ret; + } + + void build(const vector& vs) { + in_heap.clear(); + uint32_t max = 0; + for(const auto x: vs) { + max = std::max(x, max); + } + in_heap.resize(max+1, false); + vars.clear(); + std::copy( + vs.begin(), + vs.end(), + std::inserter(vars, vars.end())); + for(const auto& x: vars) { + in_heap[x] = true; + } + } + + bool heap_property() const + { + for(const auto& x: vars) { + if (!in_heap[x]) { + return false; + } + } + + return true; + } + + uint32_t get_random_element(mt19937_64& mtrand) + { + if (vars.empty()) { + return var_Undef; + } + + uint32_t which = rnd_uint(mtrand, vars.size()-1); + uint32_t picked = vars[which]; + std::swap(vars[which], vars[vars.size()-1]); + vars.pop_back(); + assert(inHeap(picked)); + in_heap[picked] = false; + + return picked; + } +}; + + +/** +@brief The propagating and conflict generation class + +Handles watchlists, conflict analysis, propagation, variable settings, etc. +*/ +class PropEngine: public CNF +{ +public: + + // Constructor/Destructor: + // + PropEngine( + const SolverConf* _conf + , Solver* solver + , std::atomic* _must_interrupt_inter + ); + virtual ~PropEngine(); + + // Read state: + // + uint32_t nAssigns () const; /// + bool propagate_occur(int64_t* limit_to_decrease); + void reverse_prop(const Lit l); + void reverse_one_bnn(uint32_t idx, BNNPropType t); + PropStats propStats; + template + void enqueue(const Lit p, const uint32_t level, + const PropBy from = PropBy(), const bool do_unit_frat = true); + template void enqueue(const Lit p); + void enqueue_light(const Lit p); + void new_decision_level(); + + ///////////////////// + // Branching + ///////////////////// + vector var_act_vsids; + double var_decay = 0.95; + struct VarOrderLt { ///Order variables according to their activities + const vector& activities; + bool operator () (const uint32_t x, const uint32_t y) const + { + return activities[x] > activities[y]; + } + + explicit VarOrderLt(const vector& _activities) : + activities(_activities) + {} + }; + ///activity-ordered heap of decision variables. + Heap order_heap_vsids; ///NOT VALID WHILE SIMPLIFYING + RandHeap order_heap_rand; + Queue vmtf_queue; + uint64_t stats_bumped = 0; + vector vmtf_btab; ///< Indexed by variable number. enqueue time stamps for queue + void vmtf_update_queue_unassigned (const uint32_t var); + void vmtf_init_enqueue (const uint32_t var); + void vmtf_dequeue (const uint32_t var); + void vmtf_bump_queue (const uint32_t var); + void vmtf_check_unassigned(); + uint32_t vmtf_pick_var(); + vector vmtf_links; ///< Indexed by variable number. table of vmtf_links for decision queue. + double max_vsids_act = 0.0; + + //Clause activities + double max_cl_act = 0.0; + vector chain; ///< For resolution chains + + enum class gauss_ret {g_cont, g_nothing, g_false}; + vector gmatrices; + vector gqueuedata; + +protected: + friend class DataSync; + int64_t simpDB_props = 0; + void new_var( + const bool bva, + const uint32_t orig_outer, + const bool insert_varorder = true) override; + void new_vars(const size_t n) override; + void save_on_var_memory(); + template uint32_t calc_glue(const T& ps); + + // Solver state: + // + vector trail; ///< Assignment stack; stores all assignments made in the order they were made. + vector trail_lim; ///< Separator indices for different decision levels in 'trail'. + uint32_t qhead; ///< Head of queue (as index into the trail) + Lit failBinLit; ///< Used to store which watches[lit] we were looking through when conflict occured + + friend class EGaussian; + + ///////////////// + // Operations on clauses: + ///////////////// + vector* get_bnn_reason(BNN* bnn, Lit lit); + void get_bnn_confl_reason(BNN* bnn, vector* ret); + void get_bnn_prop_reason(BNN* bnn, Lit lit, vector* ret); + lbool bnn_prop( + const uint32_t bnn_idx, uint32_t level, + Lit l, BNNPropType prop_t); + void attachClause( + const Clause& c + , const bool checkAttach = true + ); + + void detach_bin_clause( + Lit lit1 + , Lit lit2 + , bool red + , const uint64_t ID + , bool allow_empty_watch = false + , bool allow_change_order = false + ) { + if (!allow_change_order) { + if (!(allow_empty_watch && watches[lit1].empty())) { + removeWBin(watches, lit1, lit2, red, ID); + } + if (!(allow_empty_watch && watches[lit2].empty())) { + removeWBin(watches, lit2, lit1, red, ID); + } + } else { + if (!(allow_empty_watch && watches[lit1].empty())) { + removeWBin_change_order(watches, lit1, lit2, red, ID); + } + if (!(allow_empty_watch && watches[lit2].empty())) { + removeWBin_change_order(watches, lit2, lit1, red, ID); + } + } + } + void attach_bin_clause( + const Lit lit1 + , const Lit lit2 + , const bool red + , const uint64_t ID + , [[maybe_unused]] const bool checkUnassignedFirst = true + ); + void detach_modified_clause( + const Lit lit1 + , const Lit lit2 + , const Clause* address + ); + + // Debug & etc: + void print_all_clauses(); + void printWatchList(const Lit lit) const; + void print_trail(); + + //Var selection, activity, etc. + void updateVars( + const vector& outerToInter + , const vector& interToOuter + ); + + size_t mem_used() const + { + size_t mem = 0; + mem += CNF::mem_used(); + mem += trail.capacity()*sizeof(Lit); + mem += trail_lim.capacity()*sizeof(uint32_t); + mem += toClear.capacity()*sizeof(Lit); + return mem; + } + +protected: + template + PropBy propagate_any_order(); + template PropBy propagate_light(); + template + PropResult prop_normal_helper( + Clause& c + , ClOffset offset + , Watched*& j + , const Lit p + ); + template + PropResult handle_normal_prop_fail(Clause& c, ClOffset offset, PropBy& confl); + +private: + Solver* solver; + + template + bool prop_bin_cl_occur(const Watched& ws); + template + bool prop_long_cl_occur(const ClOffset offset); + template + bool prop_bin_cl( + const Watched* i + , const Lit p + , PropBy& confl + , uint32_t currLevel + ); + template + bool prop_long_cl_any_order( + Watched* i + , Watched*& j + , const Lit p + , PropBy& confl + , uint32_t currLevel + ); + void sql_dump_vardata_picktime(uint32_t v, PropBy from); + + PropBy gauss_jordan_elim(const Lit p, const uint32_t currLevel); +}; + +inline void PropEngine::new_decision_level() +{ + trail_lim.push_back(trail.size()); + #ifdef VERBOSE_DEBUG + cout << "New decision level: " << trail_lim.size() << endl; + #endif +} + +inline uint32_t PropEngine::decisionLevel() const +{ + return trail_lim.size(); +} + +inline uint32_t PropEngine::nAssigns() const +{ + return trail.size(); +} + +inline size_t PropEngine::getTrailSize() const +{ + if (decisionLevel() == 0) { + return trail.size(); + } else { + return trail_lim[0]; + } +} + +template inline +uint32_t PropEngine::calc_glue(const T& ps) +{ + MYFLAG++; + uint32_t nblevels = 0; + for (Lit lit: ps) { + int l = varData[lit.var()].level; + if (l != 0 && permDiff[l] != MYFLAG) { + permDiff[l] = MYFLAG; + nblevels++; + if (nblevels >= 1000) { + return nblevels; + } + } + } + return nblevels; +} + +template +inline PropResult PropEngine::prop_normal_helper( + Clause& c + , ClOffset offset + , Watched*& j + , const Lit p +) { + // Make sure the false literal is data[1]: + if (c[0] == ~p) { + std::swap(c[0], c[1]); + } + + assert(c[1] == ~p); + + // If 0th watch is true, then clause is already satisfied. + if (value(c[0]) == l_True) { + *j = Watched(offset, c[0]); + j++; + return PROP_NOTHING; + } + + // Look for new watch: + for (Lit *k = c.begin() + 2, *end2 = c.end() + ; k != end2 + ; k++ + ) { + //Literal is either unset or satisfied, attach to other watchlist + if (value(*k) != l_False) { + c[1] = *k; + *k = ~p; + watches[c[1]].push(Watched(offset, c[0])); + return PROP_NOTHING; + } + } + + return PROP_TODO; +} + + +template +inline PropResult PropEngine::handle_normal_prop_fail( + Clause& + #ifdef STATS_NEEDED + c + #endif + , ClOffset offset + , PropBy& confl +) { + confl = PropBy(offset); + #ifdef VERBOSE_DEBUG_FULLPROP + Clause& c = *cl_alloc.ptr(offset); + cout << "Conflict from cl: " << c << endl; + #endif + + //Update stats + #ifdef STATS_NEEDED + if (!inprocess && c.red()) { + red_stats_extra[c.stats.extra_pos].conflicts_made++; + } + #endif + + qhead = trail.size(); + return PROP_FAIL; +} + +template +void PropEngine::enqueue(const Lit p) +{ + enqueue(p, decisionLevel(), PropBy()); +} + +template +void PropEngine::enqueue(const Lit p, const uint32_t level, const PropBy from, bool do_unit_frat) +{ + #ifdef VERBOSE_DEBUG + if (level == 0) { + cout << "enqueue var " << p.var()+1 + << " to val " << !p.sign() + << " level: " << level + << " decisonLevel(): " << decisionLevel() + << " sublevel: " << trail.size() + << " by: " << from << endl; + cout << "trail at level 0: "; + for(auto const& x: trail) { + cout << "(lit: " << x.lit << " lev: " << x.lev << ")"; + } + cout << endl; + } + #endif //DEBUG_ENQUEUE_LEVEL0 + + #ifdef ENQUEUE_DEBUG + assert(trail.size() <= nVarsOuter()); + #endif + + const uint32_t v = p.var(); + assert(value(v) == l_Undef); + SLOW_DEBUG_DO(assert(varData[v].removed == Removed::none)); + if (level == 0 && frat->enabled()) + { if (do_unit_frat) { + const uint32_t ID = ++clauseID; + chain.clear(); + if (from.getType() == PropByType::binary_t) { + chain.push_back(from.getID()); + chain.push_back(unit_cl_IDs[from.lit2().var()]); + } else if (from.getType() == PropByType::clause_t) { + Clause* cl = cl_alloc.ptr(from.get_offset()); + chain.push_back(cl->stats.ID); + for(auto const& l: *cl) if (l != p) chain.push_back(unit_cl_IDs[l.var()]); + } else { + // These are too difficult and not worth it + } + + *frat << add << ID << p; + if (!chain.empty()) { + *frat << DratFlag::chain; + for(auto const& id: chain) *frat << id; + } + *frat << fin; + + VERBOSE_PRINT("unit " << p << " ID: " << ID); + assert(unit_cl_IDs[v] == 0); + unit_cl_IDs[v] = ID; + } else { + assert(unit_cl_IDs[v] != 0); + } + } + + if (!watches[~p].empty()) watches.prefetch((~p).toInt()); + + #if defined(STATS_NEEDED_BRANCH) || defined(FINAL_PREDICTOR_BRANCH) + if (!inprocess) { + varData[v].set++; + if (from == PropBy()) { + #ifdef STATS_NEEDED_BRANCH + sql_dump_vardata_picktime(v, from); + varData[v].num_decided++; + varData[v].last_decided_on = sumConflicts; + if (!p.sign()) varData[v].num_decided_pos++; + #endif + } else { + sumPropagations++; + #ifdef STATS_NEEDED_BRANCH + bool flipped = (varData[v].polarity != !p.sign()); + if (flipped) { + varData[v].last_flipped = sumConflicts; + } + varData[v].num_propagated++; + varData[v].last_propagated = sumConflicts; + if (!p.sign()) varData[v].num_propagated_pos++; + #endif + } + } + #endif + + const bool sign = p.sign(); + assigns[v] = boolToLBool(!sign); + varData[v].reason = from; + varData[v].level = level; + varData[v].sublevel = trail.size(); + if (!inprocess) { + #ifdef STATS_NEEDED + if (sign) { + propStats.varSetNeg++; + } else { + propStats.varSetPos++; + } + #endif + } + trail.push_back(Trail(p, level)); + + if (inprocess) { + propStats.bogoProps += 1; + } +} + +template +PropBy PropEngine::propagate_light() +{ + PropBy confl; + VERBOSE_PRINT("propagate_light started"); + + while (qhead < trail.size() && confl.isNULL()) { + const Lit p = trail[qhead].lit; + watch_subarray ws = watches[~p]; + + Watched* i = ws.begin(); + Watched* j = i; + Watched* end = ws.end(); + propStats.bogoProps += ws.size()/4 + 1; + for (; i != end; i++) { + if (bin_only && !confl.isNULL()) break; + + // propagate binary clause + if (i->isBin()) { + if (!bin_only) *j++ = *i; + + const lbool val = value(i->lit2()); + if (val == l_Undef) { + enqueue_light(i->lit2()); + } else if (val == l_False) { + confl = PropBy(~p, i->red(), i->get_ID()); + } + continue; + } + + if (!bin_only && i->isClause()) { + if (value(i->getBlockedLit()) == l_True) { + *j++ = *i; + continue; + } + propStats.bogoProps += 4; + const ClOffset offset = i->get_offset(); + Clause& c = *cl_alloc.ptr(offset); + + if (c[0] == ~p) std::swap(c[0], c[1]); + assert(c[1] == ~p); + + // If 0th watch is true, then clause is already satisfied. + if (value(c[0]) == l_True) { + *j = Watched(offset, c[0]); + j++; + continue; + } + + // Look for new watch: + bool cont = false; + for (Lit *k = c.begin() + 2, *end2 = c.end() + ; k != end2 + ; k++ + ) { + //Literal is either unset or satisfied, attach to other watchlist + if (value(*k) != l_False) { + c[1] = *k; + *k = ~p; + watches[c[1]].push(Watched(offset, c[0])); + cont = true; + break; + } + } + if (cont) continue; + + // Did not find watch -- clause is unit under assignment: + *j++ = *i; + if (value(c[0]) == l_False) confl = PropBy(offset); + else enqueue_light(c[0]); + continue; + } + + if (!bin_only) { + *j++=*i; + } + } + + if (!bin_only) { + while (i != end) { + *j++ = *i++; + } + ws.shrink_(end-j); + } + + VERBOSE_PRINT("propagate_light went through watchlist of " << p); + qhead++; + } + VERBOSE_PRINT("propagate_light ended."); + return confl; +} + +inline void PropEngine::enqueue_light(const Lit p) +{ + const uint32_t v = p.var(); + assert(value(v) == l_Undef); + SLOW_DEBUG_DO(assert(varData[v].removed == Removed::none)); + if (!watches[~p].empty()) watches.prefetch((~p).toInt()); + + const bool sign = p.sign(); + assigns[v] = boolToLBool(!sign); + trail.push_back(Trail(p, 1)); + propStats.bogoProps += 1; +} + +inline void PropEngine::attach_bin_clause( + const Lit lit1 + , const Lit lit2 + , const bool red + , const uint64_t ID + , [[maybe_unused]] const bool checkUnassignedFirst +) { + #ifdef DEBUG_ATTACH + assert(lit1.var() != lit2.var()); + if (checkUnassignedFirst) { + assert(value(lit1.var()) == l_Undef); + assert(value(lit2) == l_Undef || value(lit2) == l_False); + } + + assert(varData[lit1.var()].removed == Removed::none); + assert(varData[lit2.var()].removed == Removed::none); + #endif //DEBUG_ATTACH + + watches[lit1].push(Watched(lit2, red, ID)); + watches[lit2].push(Watched(lit1, red, ID)); +} + +} //end namespace diff --git a/cryptominisat/cppsrc/src/reducedb.cpp b/cryptominisat/cppsrc/src/reducedb.cpp new file mode 100644 index 00000000..cf57aba0 --- /dev/null +++ b/cryptominisat/cppsrc/src/reducedb.cpp @@ -0,0 +1,1385 @@ +/****************************************** +Copyright (C) 2009-2020 Authors of CryptoMiniSat, see AUTHORS file + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. +***********************************************/ + +#include "reducedb.h" +#include "solver.h" +#include "solverconf.h" +#include "sqlstats.h" +#ifdef FINAL_PREDICTOR +#include "cl_predictors_xgb.h" +#include "cl_predictors_lgbm.h" +#include "cl_predictors_py.h" +#endif + +// #define VERBOSE_DEBUG + + +#include +#include + +using namespace CMSat; + +inline double safe_div(double a, double b) { + if (b == 0) { + assert(a == 0); + return 0; + } + return a/b; +} + +struct SortValAndPos { + inline bool operator () (const val_and_pos& a, const val_and_pos& b) const + { + return a.val > b.val; + } +}; + +struct SortRedClsGlue +{ + explicit SortRedClsGlue(ClauseAllocator& _cl_alloc) : + cl_alloc(_cl_alloc) + {} + ClauseAllocator& cl_alloc; + + inline bool operator () (const ClOffset xOff, const ClOffset yOff) const + { + const Clause* x = cl_alloc.ptr(xOff); + const Clause* y = cl_alloc.ptr(yOff); + return x->stats.glue < y->stats.glue; + } +}; + +struct SortRedClsSize +{ + explicit SortRedClsSize(ClauseAllocator& _cl_alloc) : + cl_alloc(_cl_alloc) + {} + ClauseAllocator& cl_alloc; + + inline bool operator () (const ClOffset xOff, const ClOffset yOff) const + { + const Clause* x = cl_alloc.ptr(xOff); + const Clause* y = cl_alloc.ptr(yOff); + return x->size() < y->size(); + } +}; + +struct SortRedClsAct +{ + explicit SortRedClsAct(ClauseAllocator& _cl_alloc) : + cl_alloc(_cl_alloc) + {} + ClauseAllocator& cl_alloc; + + inline bool operator () (const ClOffset xOff, const ClOffset yOff) const + { + const Clause* x = cl_alloc.ptr(xOff); + const Clause* y = cl_alloc.ptr(yOff); + return x->stats.activity > y->stats.activity; + } +}; + +#if defined(STATS_NEEDED) || defined(FINAL_PREDICTOR) +struct SortRedClsUIP1 +{ + explicit SortRedClsUIP1(ClauseAllocator& _cl_alloc) : + cl_alloc(_cl_alloc) + {} + ClauseAllocator& cl_alloc; + + inline bool operator () (const ClOffset xOff, const ClOffset yOff) const + { + const Clause* x = cl_alloc.ptr(xOff); + const Clause* y = cl_alloc.ptr(yOff); + return x->stats.uip1_used > y->stats.uip1_used; + } +}; + +struct SortRedClsProps +{ + explicit SortRedClsProps(ClauseAllocator& _cl_alloc) : + cl_alloc(_cl_alloc) + {} + ClauseAllocator& cl_alloc; + + inline bool operator () (const ClOffset xOff, const ClOffset yOff) const + { + const Clause* x = cl_alloc.ptr(xOff); + const Clause* y = cl_alloc.ptr(yOff); + return x->stats.props_made > y->stats.props_made; + } +}; + +#endif + +#ifdef FINAL_PREDICTOR +struct SortRedClsPredShort +{ + explicit SortRedClsPredShort( + const ClauseAllocator& _cl_alloc, + const vector& _extdata): + cl_alloc(_cl_alloc), + extdata(_extdata) + {} + const ClauseAllocator& cl_alloc; + const vector& extdata; + + inline bool operator () (const ClOffset xOff, const ClOffset yOff) const + { + uint32_t x_num = cl_alloc.ptr(xOff)->stats.extra_pos; + uint32_t y_num = cl_alloc.ptr(yOff)->stats.extra_pos; + return extdata[x_num].pred_short_use > extdata[y_num].pred_short_use; + } +}; + +struct SortRedClsPredLong +{ + explicit SortRedClsPredLong( + const ClauseAllocator& _cl_alloc, + const vector& _extdata): + cl_alloc(_cl_alloc), + extdata(_extdata) + {} + const ClauseAllocator& cl_alloc; + const vector& extdata; + + inline bool operator () (const ClOffset xOff, const ClOffset yOff) const + { + uint32_t x_num = cl_alloc.ptr(xOff)->stats.extra_pos; + uint32_t y_num = cl_alloc.ptr(yOff)->stats.extra_pos; + return extdata[x_num].pred_long_use > extdata[y_num].pred_long_use; + } +}; + +struct SortRedClsPredForever +{ + explicit SortRedClsPredForever( + const ClauseAllocator& _cl_alloc, + const vector& _extdata): + cl_alloc(_cl_alloc), + extdata(_extdata) + {} + const ClauseAllocator& cl_alloc; + const vector& extdata; + + inline bool operator () (const ClOffset xOff, const ClOffset yOff) const + { + uint32_t x_num = cl_alloc.ptr(xOff)->stats.extra_pos; + uint32_t y_num = cl_alloc.ptr(yOff)->stats.extra_pos; + return extdata[x_num].pred_forever_use > extdata[y_num].pred_forever_use; + } +}; +#endif + + +ReduceDB::ReduceDB(Solver* _solver) : + solver(_solver) +{ + cl_stats.resize(3); +} + +ReduceDB::~ReduceDB() +{ + #ifdef FINAL_PREDICTOR + //delete predictors; + #endif +} + +void ReduceDB::sort_red_cls(ClauseClean clean_type) +{ + #ifdef VERBOSE_DEBUG + cout << "Before sort" << endl; + uint64_t i = 0; + for(const auto& x: solver->longRedCls[2]) { + const ClOffset offset = x; + Clause* cl = solver->cl_alloc.ptr(offset); + cout << i << " offset: " << offset << " cl->stats.last_touched_any: " << cl->stats.last_touched_any + << " act:" << std::setprecision(9) << cl->stats.activity + << " which_red_array:" << cl->stats.which_red_array << endl + << " -- cl:" << *cl << " tern:" << cl->stats.is_ternary_resolvent + << endl; + } + #endif + + switch (clean_type) { + case ClauseClean::glue : { + std::sort(solver->longRedCls[2].begin(), solver->longRedCls[2].end(), SortRedClsGlue(solver->cl_alloc)); + break; + } + + case ClauseClean::activity : { + std::sort(solver->longRedCls[2].begin(), solver->longRedCls[2].end(), SortRedClsAct(solver->cl_alloc)); + break; + } + + default: { + assert(false && "Unknown cleaning type"); + } + } +} + +#if defined(NORMAL_CL_USE_STATS) +void ReduceDB::gather_normal_cl_use_stats() +{ + for(uint32_t i = 0; i < 3; i++) { + ClauseStats cl_stat; + for(const auto& offset: solver->longRedCls[i]) { + Clause* cl = solver->cl_alloc.ptr(offset); + + assert(cl->stats.introduced_at_conflict <= solver->sumConflicts); + const uint64_t age = solver->sumConflicts - cl->stats.introduced_at_conflict; + cl_stat.add_in(*cl, age); + cl->stats.reset_rdb_stats(); + } + cl_stat.print(i); + cl_stats[i] += cl_stat; + } +} + +#endif + +//TODO maybe we chould count binary learnt clauses as well into the +//kept no. of clauses as other solvers do +void ReduceDB::handle_lev2() +{ + solver->dump_memory_stats_to_sql(); + size_t orig_size = solver->longRedCls[2].size(); + + const double myTime = cpuTime(); + assert(solver->watches.get_smudged_list().empty()); + + //lev2 -- clean + int64_t num_to_reduce = solver->longRedCls[2].size(); + for(unsigned keep_type = 0 + ; keep_type < sizeof(solver->conf.ratio_keep_clauses)/sizeof(double) + ; keep_type++ + ) { + const uint64_t keep_num = (double)num_to_reduce*solver->conf.ratio_keep_clauses[keep_type]; + if (keep_num == 0) { + continue; + } + sort_red_cls(static_cast(keep_type)); + mark_top_N_clauses_lev2(keep_num); + } + assert(delayed_clause_free.empty()); + cl_marked = 0; + cl_ttl = 0; + cl_locked_solver = 0; + remove_cl_from_lev2(); + + solver->clean_occur_from_removed_clauses_only_smudged(); + for(ClOffset offset: delayed_clause_free) { + solver->free_cl(offset); + } + delayed_clause_free.clear(); + + #ifdef SLOW_DEBUG + solver->check_no_removed_or_freed_cl_in_watch(); + #endif + + if (solver->conf.verbosity >= 2) { + cout << "c [DBclean lev2]" + << " confl: " << solver->sumConflicts + << " orig size: " << orig_size + << " marked: " << cl_marked + << " ttl:" << cl_ttl + << " locked_solver:" << cl_locked_solver + << solver->conf.print_times(cpuTime()-myTime) + << endl; + } + + if (solver->sqlStats) { + solver->sqlStats->time_passed_min( + solver + , "dbclean-lev2" + , cpuTime()-myTime + ); + } + total_time += cpuTime()-myTime; + + last_reducedb_num_conflicts = solver->sumConflicts; +} + +#if defined(STATS_NEEDED) || defined(FINAL_PREDICTOR) +const CMSat::ClauseStats& +ReduceDB::get_median_stat(const vector& all_learnt) const +{ + return solver->cl_alloc.ptr(all_learnt[all_learnt.size()/2])->stats; +} + +const CMSat::ClauseStats& +ReduceDB::get_median_stat_dat(const vector& all_learnt, const vector& dat) const +{ + return solver->cl_alloc.ptr(all_learnt[dat[dat.size()/2].pos])->stats; +} + +void ReduceDB::prepare_features(vector& all_learnt) +{ + //Prop and also save total_* data for stats + std::sort(all_learnt.begin(), all_learnt.end(), SortRedClsProps(solver->cl_alloc)); + //total_glue = 0; + total_props = 0; + total_uip1_used = 0; + total_sum_uip1_used = 0; + total_sum_props_used = 0; + total_time_in_solver = 0; + for(size_t i = 0; i < all_learnt.size(); i++) { + ClOffset offs = all_learnt[i]; + Clause* cl = solver->cl_alloc.ptr(offs); + ClauseStatsExtra& stats_extra = solver->red_stats_extra[cl->stats.extra_pos]; + stats_extra.prop_ranking = i+1; + assert(cl->stats.glue > 0); + stats_extra.update_rdb_stats(cl->stats); + + //total_glue += cl->stats.glue; CANNOT CALCULATE! ternaries have no glues + total_props += cl->stats.props_made; + total_uip1_used += cl->stats.uip1_used; + total_sum_uip1_used += stats_extra.sum_uip1_used; + total_sum_props_used += stats_extra.sum_props_made; + assert(solver->sumConflicts >= stats_extra.introduced_at_conflict); + total_time_in_solver += solver->sumConflicts - stats_extra.introduced_at_conflict; + } + if (all_learnt.empty()) { + median_data.median_props = 0; + } else { + median_data.median_props = get_median_stat(all_learnt).props_made; + } + + //UIP1 + std::sort(all_learnt.begin(), all_learnt.end(), SortRedClsUIP1(solver->cl_alloc)); + for(size_t i = 0; i < all_learnt.size(); i++) { + ClOffset offs = all_learnt[i]; + Clause* cl = solver->cl_alloc.ptr(offs); + ClauseStatsExtra& stats_extra = solver->red_stats_extra[cl->stats.extra_pos]; + stats_extra.uip1_ranking = i+1; + } + if (all_learnt.empty()) { + median_data.median_uip1_used = 0; + } else { + median_data.median_uip1_used = get_median_stat(all_learnt).uip1_used; + } + + // Sum UIP1 use/time + vector dat(all_learnt.size()); + for(uint32_t i = 0; i < all_learnt.size(); i++) { + ClOffset offs = all_learnt[i]; + Clause* cl = solver->cl_alloc.ptr(offs); + ClauseStatsExtra& stats_extra = solver->red_stats_extra[cl->stats.extra_pos]; + dat[i].pos = i; + dat[i].val = stats_extra.calc_sum_uip1_per_time(solver->sumConflicts); + } + std::sort(dat.begin(), dat.end(), SortValAndPos()); + for(size_t i = 0; i < dat.size(); i++) { + ClOffset offs = all_learnt[dat[i].pos]; + Clause* cl = solver->cl_alloc.ptr(offs); + ClauseStatsExtra& stats_extra = solver->red_stats_extra[cl->stats.extra_pos]; + stats_extra.sum_uip1_per_time_ranking = i+1; + } + if (all_learnt.empty()) { + median_data.median_sum_uip1_per_time = 0; + } else { + uint32_t extra_at = get_median_stat_dat(all_learnt, dat).extra_pos; + const ClauseStatsExtra& stats_extra = solver->red_stats_extra[extra_at]; + median_data.median_sum_uip1_per_time = stats_extra.calc_sum_uip1_per_time(solver->sumConflicts); + } + + // Sum props/time + for(uint32_t i = 0; i < all_learnt.size(); i++) { + ClOffset offs = all_learnt[i]; + Clause* cl = solver->cl_alloc.ptr(offs); + ClauseStatsExtra& stats_extra = solver->red_stats_extra[cl->stats.extra_pos]; + dat[i].pos = i; + dat[i].val = stats_extra.calc_sum_props_per_time(solver->sumConflicts); + } + std::sort(dat.begin(), dat.end(), SortValAndPos()); + for(size_t i = 0; i < all_learnt.size(); i++) { + ClOffset offs = all_learnt[dat[i].pos]; + Clause* cl = solver->cl_alloc.ptr(offs); + ClauseStatsExtra& stats_extra = solver->red_stats_extra[cl->stats.extra_pos]; + stats_extra.sum_props_per_time_ranking = i+1; + } + if (all_learnt.empty()) { + median_data.median_sum_props_per_time = 0; + } else { + uint32_t extra_at = get_median_stat_dat(all_learnt, dat).extra_pos; + const ClauseStatsExtra& stats_extra = solver->red_stats_extra[extra_at]; + median_data.median_sum_props_per_time = stats_extra.calc_sum_props_per_time(solver->sumConflicts); + } + + //We'll also compact solver->red_stats_extra + uint32_t new_extra_pos = 0; + vector new_red_stats_extra(all_learnt.size()); + for(uint32_t i = 0; i < all_learnt.size(); i++) { + ClOffset offs = all_learnt[i]; + Clause* cl = solver->cl_alloc.ptr(offs); + dat[i].pos = i; + dat[i].val = cl->stats.activity; + } + std::sort(dat.begin(), dat.end(), SortValAndPos()); + for(size_t i = 0; i < all_learnt.size(); i++) { + ClOffset offs = all_learnt[dat[i].pos]; + Clause* cl = solver->cl_alloc.ptr(offs); + ClauseStatsExtra& stats_extra = solver->red_stats_extra[cl->stats.extra_pos]; + stats_extra.act_ranking = i+1; + + new_red_stats_extra[new_extra_pos] = stats_extra; + cl->stats.extra_pos = new_extra_pos; + new_extra_pos++; + } + if (all_learnt.empty()) { + median_data.median_act = 0; + } else { + median_data.median_act = get_median_stat_dat(all_learnt, dat).activity; + } + std::swap(solver->red_stats_extra, new_red_stats_extra); +} +#endif + +#ifdef STATS_NEEDED +void ReduceDB::dump_sql_cl_data( + const uint32_t cur_rst_type +) { + assert(solver->sqlStats); + + reduceDB_called++; + double myTime = cpuTime(); + uint32_t non_locked_lev0 = 0; + + //Set up features + vector all_learnt; + uint32_t num_locked_for_data_gen = 0; + for(uint32_t lev = 0; lev < solver->longRedCls.size(); lev++) { + auto& cc = solver->longRedCls[lev]; + for(const auto& offs: cc) { + Clause* cl = solver->cl_alloc.ptr(offs); + assert(!cl->getRemoved()); + assert(cl->red()); + assert(!cl->freed()); + if (cl->stats.locked_for_data_gen) { + assert(cl->stats.which_red_array == 0); + } else if (cl->stats.which_red_array == 0) { + non_locked_lev0++; + } + all_learnt.push_back(offs); + num_locked_for_data_gen += cl->stats.locked_for_data_gen; + } + } + if (all_learnt.empty()) { + return; + } + prepare_features(all_learnt); + + AverageCommonDataRDB avgdata; +// avgdata.avg_glue = (double)total_glue/(double)all_learnt.size(); + avgdata.avg_props = (double)total_props/(double)all_learnt.size(); + avgdata.avg_uip1_used = (double)total_uip1_used/(double)all_learnt.size(); + if (total_time_in_solver > 0) { + avgdata.avg_sum_uip1_per_time = (double)total_sum_uip1_used/(double)(all_learnt.size()*total_time_in_solver); + avgdata.avg_sum_props_per_time = (double)total_sum_props_used/(double)(all_learnt.size()*total_time_in_solver); + } + + + //Dump common features + solver->sqlStats->begin_transaction(); + solver->sqlStats->reduceDB_common( + solver, + reduceDB_called, + all_learnt.size(), + cur_rst_type, + median_data, + avgdata + ); + + //Dump clause features + uint64_t added_to_db = 0; + for(size_t i = 0; i < all_learnt.size(); i++) { + ClOffset offs = all_learnt[i]; + Clause* cl = solver->cl_alloc.ptr(offs); + if (!cl->stats.is_tracked) continue; + + const bool locked = solver->clause_locked(*cl, offs); + ClauseStatsExtra& stats_extra = solver->red_stats_extra[cl->stats.extra_pos]; + assert(stats_extra.orig_ID != 0); + assert(stats_extra.orig_ID <= cl->stats.ID); + solver->sqlStats->reduceDB( + solver + , locked + , cl + , reduceDB_called + ); + added_to_db++; + stats_extra.reset_rdb_stats(cl->stats); + } + solver->sqlStats->end_transaction(); + + if (solver->conf.verbosity) { + cout << "c [sql] added to DB " << added_to_db + << " dump-ratio: " << solver->conf.dump_individual_cldata_ratio + << " locked-perc: " << stats_line_percent(num_locked_for_data_gen, all_learnt.size()) + << " non-locked lev0: " << non_locked_lev0 + << solver->conf.print_times(cpuTime()-myTime) + << endl; + } + locked_for_data_gen_total += num_locked_for_data_gen; + locked_for_data_gen_cls += all_learnt.size(); +} +#endif + +void ReduceDB::handle_lev1() +{ + #ifdef VERBOSE_DEBUG + cout << "c handle_lev1()" << endl; + #endif + + uint32_t moved_w0 = 0; + uint32_t used_recently = 0; + uint32_t non_recent_use = 0; + double myTime = cpuTime(); + size_t orig_size = solver->longRedCls[1].size(); + + size_t j = 0; + for(size_t i = 0 + ; i < solver->longRedCls[1].size() + ; i++ + ) { + const ClOffset offset = solver->longRedCls[1][i]; + Clause* cl = solver->cl_alloc.ptr(offset); + #ifdef VERBOSE_DEBUG + cout << "offset: " << offset << " cl->stats.last_touched_any: " << cl->stats.last_touched_any + << " act:" << std::setprecision(9) << cl->stats.activity + << " which_red_array:" << cl->stats.which_red_array << endl + << " -- cl:" << *cl << " tern:" << cl->stats.is_ternary_resolvent + << endl; + #endif + + assert(!cl->stats.locked_for_data_gen); + if (cl->stats.which_red_array == 0) { + solver->longRedCls[0].push_back(offset); + moved_w0++; + } else if (cl->stats.which_red_array == 2) { + assert(false && "we should never move up through any other means"); + } else { + uint32_t must_touch = solver->conf.must_touch_lev1_within; + if (cl->stats.is_ternary_resolvent) { + must_touch *= solver->conf.ternary_keep_mult; //this multiplier is 6 by default + } + if (!solver->clause_locked(*cl, offset) + && cl->stats.last_touched_any + must_touch < solver->sumConflicts + ) { + solver->longRedCls[2].push_back(offset); + cl->stats.which_red_array = 2; + + //when stats are needed, activities are correctly updated + //across all clauses + //WARNING this changes the way things behave during STATS relative to non-STATS! + #ifndef STATS_NEEDED + cl->stats.activity = 0; + solver->bump_cl_act(cl); + #endif + non_recent_use++; + } else { + solver->longRedCls[1][j++] = offset; + used_recently++; + } + } + } + solver->longRedCls[1].resize(j); + + if (solver->conf.verbosity >= 2) { + cout << "c [DBclean lev1]" + << " confl: " << solver->sumConflicts + << " orig size: " << orig_size + << " used recently: " << used_recently + << " not used recently: " << non_recent_use + << " moved w0: " << moved_w0 + << solver->conf.print_times(cpuTime()-myTime) + << endl; + } + + if (solver->sqlStats) { + solver->sqlStats->time_passed_min( + solver + , "dbclean-lev1" + , cpuTime()-myTime + ); + } + total_time += cpuTime()-myTime; +} + +#ifdef FINAL_PREDICTOR +void ReduceDB::pred_move_to_lev1_and_lev0() +{ + //FOREVER + uint32_t mark_forever = solver->conf.pred_forever_chunk; + if (solver->conf.pred_forever_chunk_mult) { + mark_forever *= pow((double)solver->sumConflicts/10000.0, solver->conf.pred_forever_size_pow); + } + + std::sort(solver->longRedCls[2].begin(), solver->longRedCls[2].end(), + SortRedClsPredForever(solver->cl_alloc, solver->red_stats_extra)); + size_t j = 0; + for(uint32_t i = 0; i < solver->longRedCls[2].size(); i ++) { + const ClOffset offset = solver->longRedCls[2][i]; + Clause* cl = solver->cl_alloc.ptr(offset); + const auto& stats_extra = solver->red_stats_extra[cl->stats.extra_pos]; + + bool move = false; + if (solver->conf.pred_forever_cutoff == 0) { + if (i < mark_forever) { + move = true; + } + } else if (stats_extra.pred_forever_use >= solver->conf.pred_forever_cutoff) { + move = true; + } + + if (move) { + moved_from_T2_to_T0++; + cl->stats.which_red_array = 0; + solver->longRedCls[0].push_back(offset); + } else { + solver->longRedCls[2][j++] =solver->longRedCls[2][i]; + } + } + solver->longRedCls[2].resize(j); + + + // LONG + uint32_t mark_long = solver->conf.pred_long_chunk; + //mark_long *= pow((double)solver->sumConflicts/10000.0, solver->conf.pred_forever_size_pow); + + std::sort(solver->longRedCls[2].begin(), solver->longRedCls[2].end(), + SortRedClsPredLong(solver->cl_alloc, solver->red_stats_extra)); + + j = 0; + for(uint32_t i = 0; i < solver->longRedCls[2].size(); i ++) { + const ClOffset offset = solver->longRedCls[2][i]; + Clause* cl = solver->cl_alloc.ptr(offset); + if (i < mark_long) { + moved_from_T2_to_T1++; + cl->stats.which_red_array = 1; + solver->longRedCls[1].push_back(offset); + } else { + solver->longRedCls[2][j++] =solver->longRedCls[2][i]; + } + } + solver->longRedCls[2].resize(j); +} + +void ReduceDB::update_preds(const vector& offs) +{ + int step_size = predictors->get_step_size(); + float* data_orig = (float*)malloc(step_size*offs.size()*sizeof(float)); + memset(data_orig, 0, step_size*offs.size()*sizeof(float)); + float* data = data_orig; + + + uint32_t data_at = 0; + for(size_t i = 0 + ; i < offs.size() + ; i++ + ) { + const ClOffset offset = offs[i]; + Clause* cl = solver->cl_alloc.ptr(offset); + auto& stats_extra = solver->red_stats_extra[cl->stats.extra_pos]; + + double act_ranking_rel = safe_div(stats_extra.act_ranking, commdata.all_learnt_size); + double uip1_ranking_rel = safe_div(stats_extra.uip1_ranking, commdata.all_learnt_size); + double prop_ranking_rel = safe_div(stats_extra.prop_ranking, commdata.all_learnt_size); + double sum_uip1_per_time_ranking_rel = safe_div(stats_extra.sum_uip1_per_time_ranking, commdata.all_learnt_size); + double sum_props_per_time_ranking_rel = safe_div(stats_extra.sum_props_per_time_ranking, commdata.all_learnt_size); + + stats_extra.pred_short_use = 0; + stats_extra.pred_long_use = 0; + stats_extra.pred_forever_use = 0; + assert(stats_extra.introduced_at_conflict <= solver->sumConflicts); + uint64_t age = solver->sumConflicts - stats_extra.introduced_at_conflict; + if (age > solver->conf.every_pred_reduce) { + int ret = predictors->set_up_input( + cl, + solver->sumConflicts, + act_ranking_rel, + uip1_ranking_rel, + prop_ranking_rel, + stats_extra.sum_uip1_per_time_ranking, + stats_extra.sum_props_per_time_ranking, + sum_uip1_per_time_ranking_rel, + sum_props_per_time_ranking_rel, + commdata, + solver, + data + ); + assert(ret == step_size); + data_at++; + data += step_size; + } + } + + predictors->predict_all(data_orig, data_at); + + uint32_t retrieve_at = 0; + for(const auto& offset: offs) { + Clause* cl = solver->cl_alloc.ptr(offset); + auto& stats_extra = solver->red_stats_extra[cl->stats.extra_pos]; + + assert(stats_extra.introduced_at_conflict <= solver->sumConflicts); + uint64_t age = solver->sumConflicts - stats_extra.introduced_at_conflict; + if (age > solver->conf.every_pred_reduce) { + predictors->get_prediction_at(stats_extra, retrieve_at); + retrieve_at++; + } + } + + predictors->finish_all_predict(); + free(data_orig); +} + +void ReduceDB::update_preds_lev2() +{ + double myTime = cpuTime(); + update_preds(solver->longRedCls[2]); + dump_pred_distrib(solver->longRedCls[2], 2); + + if (solver->conf.verbosity >= 2) { + double predTime = cpuTime() - myTime; + cout << "c [DBCL] main predtime: " << predTime << endl; + } +} + +void ReduceDB::clean_lev0_once_in_a_while() +{ + //Deal with FOREVER once in a while + if (num_times_pred_called % solver->conf.pred_forever_check_every_n != + (solver->conf.pred_forever_check_every_n-1) + ) { + return; + } + update_preds(solver->longRedCls[0]); + dump_pred_distrib(solver->longRedCls[0], 0); + + //Clean up FOREVER, move to LONG + const uint32_t checked_every = solver->conf.pred_forever_check_every_n * + solver->conf.every_pred_reduce; + + uint32_t keep_forever = solver->conf.pred_forever_size; + keep_forever *= pow((double)solver->sumConflicts/10000.0, solver->conf.pred_forever_size_pow); + const uint32_t orig_keep_forever = keep_forever; + const uint32_t orig_size = solver->longRedCls[0].size(); + uint32_t force_kept = 0; + + std::sort(solver->longRedCls[0].begin(), solver->longRedCls[0].end(), + SortRedClsPredForever(solver->cl_alloc, solver->red_stats_extra)); + + int j = 0; + for(uint32_t i = 0; i < solver->longRedCls[0].size(); i ++) { + const ClOffset offset = solver->longRedCls[0][i]; + Clause* cl = solver->cl_alloc.ptr(offset); + auto& stats_extra = solver->red_stats_extra[cl->stats.extra_pos]; + assert(!cl->freed()); + + uint32_t time_inside_solver = solver->sumConflicts - stats_extra.introduced_at_conflict; + + bool keep = false; + if ((time_inside_solver < checked_every/2 && + solver->conf.pred_dontmove_until_timeinside == 1) || + (time_inside_solver < checked_every && + solver->conf.pred_dontmove_until_timeinside == 2)) + { +// if ((time_inside_solver < checked_every/2 && +// solver->conf.pred_dontmove_until_timeinside == 1) || +// (time_inside_solver < checked_every && +// solver->conf.pred_dontmove_until_timeinside == 2)) +// { +// kept_in_T0_due_to_dontmove++; +// keep_forever++; +// } + force_kept++; + keep = true; + } + + if (solver->conf.pred_forever_cutoff == 0) { + if (i < keep_forever) { + keep = true; + } + } else if (stats_extra.pred_forever_use >= solver->conf.pred_forever_cutoff) { + keep = true; + } + + if (keep) { + //cout << "stats_extra.pred_forever_use: " << stats_extra.pred_forever_use/(10*1000.0) << endl; + kept_in_T0++; + assert(cl->stats.which_red_array == 0); + solver->longRedCls[0][j++] = solver->longRedCls[0][i]; + } else { + moved_from_T0_to_T1++; + + //if locked, move anyway, even though we are supposed to delete + if (solver->conf.move_from_tier0 == 1 || solver->clause_locked(*cl, offset)) { + solver->longRedCls[1].push_back(offset); + cl->stats.which_red_array = 1; + } else { + solver->watches.smudge((*cl)[0]); + solver->watches.smudge((*cl)[1]); + solver->litStats.redLits -= cl->size(); + + *solver->frat << del << *cl << fin; + cl->setRemoved(); + delayed_clause_free.push_back(offset); + } + } + } + solver->longRedCls[0].resize(j); + + if (solver->conf.verbosity >= 2) { + cout + << "c ---->>> Keep fore: " << std::setw(9) << orig_keep_forever + << " size: " << std::setw(9) << orig_size + << " of which force-kept:" << std::setw(9) << force_kept << endl; + } +} + +void ReduceDB::clean_lev1_once_in_a_while() +{ + //Deal with LONG once in a while + if (num_times_pred_called % solver->conf.pred_long_check_every_n != + (solver->conf.pred_long_check_every_n-1) + ) { + return; + } + + update_preds(solver->longRedCls[1]); + dump_pred_distrib(solver->longRedCls[1], 1); + + const uint32_t checked_every = solver->conf.pred_long_check_every_n * solver->conf.every_pred_reduce; + + + //Clean up LONG + std::sort(solver->longRedCls[1].begin(), solver->longRedCls[1].end(), + SortRedClsPredLong(solver->cl_alloc, solver->red_stats_extra)); + uint32_t keep_long = solver->conf.pred_long_size; + //keep_long *= pow((double)solver->sumConflicts/10000.0, solver->conf.pred_forever_size_pow); + const uint32_t orig_keep_long = keep_long; + const uint32_t orig_size = solver->longRedCls[1].size(); + uint32_t force_kept = 0; + + int j = 0; + for(uint32_t i = 0; i < solver->longRedCls[1].size(); i ++) { + const ClOffset offset = solver->longRedCls[1][i]; + Clause* cl = solver->cl_alloc.ptr(offset); + auto& stats_extra = solver->red_stats_extra[cl->stats.extra_pos]; + assert(!cl->freed()); + + uint32_t time_inside_solver = solver->sumConflicts - stats_extra.introduced_at_conflict; + if (i < keep_long || + (time_inside_solver < checked_every/2 && + solver->conf.pred_dontmove_until_timeinside == 1) || + (time_inside_solver < checked_every && + solver->conf.pred_dontmove_until_timeinside == 2)) + { + if ((time_inside_solver < checked_every/2 && + solver->conf.pred_dontmove_until_timeinside == 1) || + (time_inside_solver < checked_every && + solver->conf.pred_dontmove_until_timeinside == 2)) + { + force_kept++; +// kept_in_T1_due_to_dontmove++; +// keep_long++; + } + + kept_in_T1++; + assert(cl->stats.which_red_array == 1); + solver->longRedCls[1][j++] =solver->longRedCls[1][i]; + } else { + moved_from_T1_to_T2++; + //if locked, we'll move it anyway, since we can't delete + if (solver->conf.move_from_tier1 == 1 || solver->clause_locked(*cl, offset)) { + solver->longRedCls[2].push_back(offset); + cl->stats.which_red_array = 2; + } else { + solver->watches.smudge((*cl)[0]); + solver->watches.smudge((*cl)[1]); + solver->litStats.redLits -= cl->size(); + + *solver->frat << del << *cl << fin; + cl->setRemoved(); + delayed_clause_free.push_back(offset); + } + } + } + solver->longRedCls[1].resize(j); + + if (solver->conf.verbosity >= 2) { + cout + << "c ---->>> Keep long: " << std::setw(9) << orig_keep_long + << " size: " << std::setw(9) << orig_size + << " of which force-kept:" << std::setw(9) << force_kept << endl; + } +} + +void ReduceDB::delete_from_lev2() +{ + // SHORT + uint32_t keep_short = solver->conf.pred_short_size; + if (solver->conf.order_tier2_by == 2) { + std::sort(solver->longRedCls[2].begin(), solver->longRedCls[2].end(), + SortRedClsPredShort(solver->cl_alloc, solver->red_stats_extra)); + } else if (solver->conf.order_tier2_by == 1) { + std::sort(solver->longRedCls[2].begin(), solver->longRedCls[2].end(), + SortRedClsPredLong(solver->cl_alloc, solver->red_stats_extra)); + } else if (solver->conf.order_tier2_by == 0) { + std::sort(solver->longRedCls[2].begin(), solver->longRedCls[2].end(), + SortRedClsPredForever(solver->cl_alloc, solver->red_stats_extra)); + } else { + assert(false); + } + + uint32_t j = 0; + for(uint32_t i = 0; i < solver->longRedCls[2].size(); i ++) { + const ClOffset offset = solver->longRedCls[2][i]; + Clause* cl = solver->cl_alloc.ptr(offset); + auto& stats_extra = solver->red_stats_extra[cl->stats.extra_pos]; + assert(!cl->freed()); + + assert(stats_extra.introduced_at_conflict <= solver->sumConflicts); + const uint64_t age = solver->sumConflicts - stats_extra.introduced_at_conflict; + if (i < keep_short + || solver->clause_locked(*cl, offset) + || age < solver->conf.every_pred_reduce + ) { + if (solver->clause_locked(*cl, offset) + || age < solver->conf.every_pred_reduce) + { + keep_short++; + kept_in_T2_due_to_dontmove++; + } + kept_in_T2++; + solver->longRedCls[2][j++] = solver->longRedCls[2][i]; + } else { + T2_deleted++; + T2_deleted_age += age; + solver->watches.smudge((*cl)[0]); + solver->watches.smudge((*cl)[1]); + solver->litStats.redLits -= cl->size(); + + *solver->frat << del << *cl << fin; + cl->setRemoved(); + delayed_clause_free.push_back(offset); + } + } + solver->longRedCls[2].resize(j); +} + +ReduceDB::ClauseStats ReduceDB::reset_clause_dats(const uint32_t lev) +{ + ClauseStats cl_stat; + uint32_t tot_age = 0; + for(const auto& off: solver->longRedCls[lev]) { + Clause* cl = solver->cl_alloc.ptr(off); + auto& stats_extra = solver->red_stats_extra[cl->stats.extra_pos]; + assert(!cl->freed()); + + assert(stats_extra.introduced_at_conflict <= solver->sumConflicts); + const uint64_t age = solver->sumConflicts - stats_extra.introduced_at_conflict; + tot_age += age; + cl_stat.add_in(*cl, age, stats_extra.orig_size); + stats_extra.reset_rdb_stats(cl->stats); + } + + /*if (solver->conf.verbosity) { + cout << "c [DBCL pred]" + << " lev: " << lev + << " avg age: " << std::fixed << std::setprecision(2) << std::setw(6) + << ratio_for_stat(tot_age, solver->longRedCls[lev].size()) + << endl; + }*/ + + return cl_stat; +} + +void ReduceDB::reset_predict_stats() +{ + ClauseStats this_stats; + + for(uint32_t i = 0; i < 3; i ++) { + this_stats = reset_clause_dats(i); + if (solver->conf.verbosity >= 2) { + this_stats.print(i); + } + cl_stats[i] += this_stats; + } +} + +void ReduceDB::dump_pred_distrib(const vector& offs, uint32_t lev) { + if (!solver->conf.dump_pred_distrib) { + return; + } + std::ofstream distrib_file("pred_distrib.csv", ios::app); + for(const auto& off:offs) { + Clause* cl = solver->cl_alloc.ptr(off); + ClauseStatsExtra& stats_extra = solver->red_stats_extra[cl->stats.extra_pos]; + const uint64_t age = solver->sumConflicts - stats_extra.introduced_at_conflict; + if (age > solver->conf.every_pred_reduce) { + distrib_file + << num_times_pred_called << "," + << lev << "," << age + << "," << stats_extra.pred_short_use + << "," << stats_extra.pred_long_use + << "," << stats_extra.pred_forever_use + << endl; + } + } +} + +void ReduceDB::handle_predictors() +{ + if (solver->conf.dump_pred_distrib && num_times_pred_called == 0) { + std::ofstream distrib_file("pred_distrib.csv"); + distrib_file + << "rdb_called" << "," + << "tier" << "," << "age" + << "," << "pred_short_use" + << "," << "pred_long_use" + << "," << "pred_forever_use" + << endl; + } + num_times_pred_called++; + if (predictors == NULL) { + if (solver->conf.predictor_type == "xgb") { + predictors = new ClPredictorsXGB; + } else if (solver->conf.predictor_type == "lgbm") { + predictors = new ClPredictorsLGBM; + } else if (solver->conf.predictor_type == "py") { + predictors = new ClPredictorsPy; + } else { + cout << "ERROR: You must give either lgbm or xgboost for predictor" << endl; + exit(-1); + } + if (solver->conf.pred_conf_location.empty()) { + if (predictors->load_models_from_buffers() != 0) { + cout << "ERROR: cannot load models from buffers" << endl; + exit(-1); + } + if (solver->conf.verbosity) { + cout << "c [pred] predictor hashes: "; + for(const auto& h: predictors->get_hashes()) { + cout << h << " "; + } + cout << endl; + } + } else { + vector locations; + vector tiers = {"short", "long", "forever"}; + for (uint32_t i = 0; i < 3; i ++) { + locations.push_back(solver->conf.pred_conf_location + "/" + + std::string("predictor-") + + (solver->conf.pred_tables[i] == '0' ? "used_later" : "used_later_anc") + + "-" + + tiers[i] + "-" + + solver->conf.predictor_type + + std::string(".json")); + } + + int ret = predictors->load_models( + locations[0], + locations[1], + locations[2], + solver->conf.predict_best_feat_fname); + + if (ret == 0) { + cout << "ERROR with python array loading!" << endl; + exit(-1); + } + + if (solver->conf.verbosity) { + cout << "c [pred] loaded predictors from: "; + for(const auto& l: locations) { + cout << l << " "; + } + cout << endl; + } + } + } + + assert(delayed_clause_free.empty()); + double myTime = cpuTime(); + + //Pre-reset, calculate common features + vector all_learnt; + for(const auto& cls: solver->longRedCls) { + for(const auto& offs: cls) { + all_learnt.push_back(offs); + } + } + prepare_features(all_learnt); + commdata = ReduceCommonData( + total_props, +// total_glue, + total_uip1_used, + total_sum_uip1_used, + all_learnt.size(), + median_data); + + //Move clauses around + T2_deleted = 0; + moved_from_T1_to_T2 = 0; + kept_in_T1 = 0; + kept_in_T1_due_to_dontmove = 0; + moved_from_T0_to_T1 = 0; + kept_in_T0 = 0; + kept_in_T0_due_to_dontmove = 0; + kept_in_T2 = 0; + kept_in_T2_due_to_dontmove = 0; + T2_deleted_age = 0; + + + moved_from_T2_to_T0 = 0; + moved_from_T2_to_T1 = 0; + + update_preds_lev2(); + pred_move_to_lev1_and_lev0(); + delete_from_lev2(); + clean_lev0_once_in_a_while(); + clean_lev1_once_in_a_while(); + reset_predict_stats(); + + //Cleanup + solver->clean_occur_from_removed_clauses_only_smudged(); + for(ClOffset offset: delayed_clause_free) { + solver->free_cl(offset); + } + delayed_clause_free.clear(); + + //Stats + if (solver->conf.verbosity >= 2) { + cout + << "c [DBCL pred]" + << " short: " << print_value_kilo_mega(solver->longRedCls[2].size()) + << " long: " << print_value_kilo_mega(solver->longRedCls[1].size()) + << " forever: " << print_value_kilo_mega(solver->longRedCls[0].size()) + << endl; + + if (solver->conf.verbosity >= 1) { + cout + << "c [DBCL pred] lev0: " << std::setw(9) << solver->longRedCls[0].size() + << " moved to lev1: " << std::setw(6) << moved_from_T0_to_T1 + << " kept at lev0: " << std::setw(6) << kept_in_T0 + << " -- due to dontmove: " << std::setw(6) << kept_in_T0_due_to_dontmove + << endl + + << "c [DBCL pred] lev1: " << std::setw(9) << solver->longRedCls[1].size() + << " moved to lev2: " << std::setw(6) << moved_from_T1_to_T2 + << " kept at lev1: " << std::setw(6) << kept_in_T1 + << " -- due to dontmove: " << std::setw(6) << kept_in_T1_due_to_dontmove + << endl + + << "c [DBCL pred] lev2: " << std::setw(9) << solver->longRedCls[2].size() + << " m-to-lev1: " << std::setw(6) << moved_from_T2_to_T1 + << " m-to-lev0: " << std::setw(6) << moved_from_T2_to_T0 + << " del: " << std::setw(6) << T2_deleted + << " kept: " << std::setw(6) << kept_in_T2 + << " -- due to dontmove: " << std::setw(6) << kept_in_T2_due_to_dontmove + //<< " del avg age: " << std::setw(6) << safe_div(T2_deleted_age, T2_deleted) + << endl; + } + + cout + << "c [DBCL pred] " + << solver->conf.print_times(cpuTime()-myTime) + << endl; + } + + if (solver->sqlStats) { + solver->sqlStats->time_passed_min( + solver + , "dbclean-lev1" + , cpuTime()-myTime + ); + } + total_time += cpuTime()-myTime; +} +#endif + +void ReduceDB::mark_top_N_clauses_lev2(const uint64_t keep_num) +{ + #ifdef VERBOSE_DEBUG + cout << "Marking top N clauses " << keep_num << endl; + #endif + + size_t marked = 0; + for(size_t i = 0 + ; i < solver->longRedCls[2].size() && marked < keep_num + ; i++ + ) { + const ClOffset offset = solver->longRedCls[2][i]; + Clause* cl = solver->cl_alloc.ptr(offset); + #ifdef VERBOSE_DEBUG + cout << "offset: " << offset << " cl->stats.last_touched_any: " << cl->stats.last_touched_any + << " act:" << std::setprecision(9) << cl->stats.activity + << " which_red_array:" << cl->stats.which_red_array << endl + << " -- cl:" << *cl << " tern:" << cl->stats.is_ternary_resolvent + << endl; + #endif + + if (cl->used_in_xor() + || cl->stats.ttl > 0 + || solver->clause_locked(*cl, offset) + || cl->stats.which_red_array != 2 + ) { + //no need to mark, skip + #ifdef VERBOSE_DEBUG + cout << "Not marking Skipping "<< endl; + #endif + continue; + } + + if (!cl->stats.marked_clause) { + marked++; + cl->stats.marked_clause = true; + #ifdef VERBOSE_DEBUG + cout << "Not marking Skipping "<< endl; + #endif + } + } +} + +bool ReduceDB::cl_needs_removal(const Clause* cl, const ClOffset offset) const +{ + assert(cl->red()); + return !cl->used_in_xor() + && !cl->stats.marked_clause + && cl->stats.ttl == 0 + && !solver->clause_locked(*cl, offset); +} + +void ReduceDB::remove_cl_from_lev2() { + size_t i, j; + for (i = j = 0 + ; i < solver->longRedCls[2].size() + ; i++ + ) { + ClOffset offset = solver->longRedCls[2][i]; + Clause* cl = solver->cl_alloc.ptr(offset); + assert(cl->size() > 2); + + //move to another array + if (cl->stats.which_red_array < 2) { + cl->stats.marked_clause = 0; + solver->longRedCls[cl->stats.which_red_array].push_back(offset); + continue; + } + assert(cl->stats.which_red_array == 2); + + //Check if locked, or marked or ttl-ed + if (cl->stats.marked_clause) { + cl_marked++; + } else if (cl->stats.ttl != 0) { + cl_ttl++; + } else if (solver->clause_locked(*cl, offset)) { + cl_locked_solver++; + } + + if (!cl_needs_removal(cl, offset)) { + if (cl->stats.ttl == 1) { + cl->stats.ttl = 0; + } + solver->longRedCls[2][j++] = offset; + cl->stats.marked_clause = 0; + continue; + } + + //Stats Update + solver->watches.smudge((*cl)[0]); + solver->watches.smudge((*cl)[1]); + solver->litStats.redLits -= cl->size(); + + *solver->frat << del << *cl << fin; + cl->setRemoved(); + #ifdef VERBOSE_DEBUG + cout << "REMOVING offset: " << offset << " cl->stats.last_touched_any: " << cl->stats.last_touched_any + << " act:" << std::setprecision(9) << cl->stats.activity + << " which_red_array:" << cl->stats.which_red_array << endl + << " -- cl:" << *cl << " tern:" << cl->stats.is_ternary_resolvent + << endl; + #endif + delayed_clause_free.push_back(offset); + } + solver->longRedCls[2].resize(j); +} + +ReduceDB::ClauseStats ReduceDB::ClauseStats::operator += (const ClauseStats& other) +{ + total_uip1_used += other.total_uip1_used; + total_props += other.total_props; + total_cls += other.total_cls; + total_age += other.total_age; + total_len += other.total_len; + total_ternary += other.total_ternary; + total_distilled += other.total_distilled; + total_orig_size += other.total_orig_size; + //total_glue += other.total_glue; CANNOT DO, ternaries have no glue + + return *this; +} + +#if defined(STATS_NEEDED) || defined(FINAL_PREDICTOR) || defined(NORMAL_CL_USE_STATS) +void ReduceDB::ClauseStats::add_in(const Clause& cl, const uint64_t age, const uint32_t orig_size) +{ + total_cls++; + total_props += cl.stats.props_made; + total_uip1_used += cl.stats.uip1_used; + total_age += age; + total_len += cl.size(); + total_ternary += cl.stats.is_ternary_resolvent; + total_distilled += cl.distilled; + total_orig_size += orig_size; + //total_glue += cl.stats.glue; CANNOT DO, ternaries have no glue +} +#endif + +void ReduceDB::ClauseStats::print(uint32_t lev) +{ + if (total_cls == 0) { + return; + } + + cout + << "c [DBCL pred]" + << " cl-stats " << lev << "]" + << " (U+P)/cls: " + << std::setw(7) << std::setprecision(4) + << (double)(total_uip1_used)/(double)total_cls + << " avg age: " + << std::setw(7) << std::setprecision(1) + << (double)(total_age)/((double)total_cls*1000) << "K" + << " avg len: " + << std::setw(7) << std::setprecision(1) + << (double)(total_len)/((double)total_cls) + << " tern r: " + << std::setw(4) << std::setprecision(2) + << (double)(total_ternary)/((double)total_cls) + << " dist r: " + << std::setw(4) << std::setprecision(2) + << (double)(total_distilled)/((double)total_cls) + << " shr r: " + << std::setw(4) << std::setprecision(2) + << (double)(total_len)/((double)total_orig_size) + << endl; +} diff --git a/cryptominisat/cppsrc/src/reducedb.h b/cryptominisat/cppsrc/src/reducedb.h new file mode 100644 index 00000000..14b56121 --- /dev/null +++ b/cryptominisat/cppsrc/src/reducedb.h @@ -0,0 +1,145 @@ +/****************************************** +Copyright (C) 2009-2020 Authors of CryptoMiniSat, see AUTHORS file + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. +***********************************************/ + +#ifndef __REDUCEDB_H__ +#define __REDUCEDB_H__ + +#include "clauseallocator.h" +#ifdef FINAL_PREDICTOR +#include "cl_predictors_abs.h" +#endif + +namespace CMSat { + +class Solver; +class ClPredictors; + +struct val_and_pos { + float val; + uint32_t pos; +}; + +class ReduceDB +{ +public: + ReduceDB(Solver* solver); + ~ReduceDB(); + double get_total_time() const { + return total_time; + } + void handle_lev1(); + void handle_lev2(); + void gather_normal_cl_use_stats(); + #ifdef FINAL_PREDICTOR + void handle_predictors(); + #endif + void dump_sql_cl_data(const uint32_t cur_rst_type); + uint32_t reduceDB_called = 0; + + #ifdef STATS_NEEDED + uint64_t locked_for_data_gen_total = 0; + uint64_t locked_for_data_gen_cls = 0; + #endif + + struct ClauseStats + { + uint32_t total_uip1_used = 0; + uint32_t total_props = 0; + uint32_t total_cls = 0; + uint64_t total_age = 0; + uint64_t total_len = 0; + uint32_t total_ternary = 0; + uint32_t total_distilled = 0; + uint64_t total_orig_size = 0; + //uint64_t total_glue = 0; //Cannot calculate, ternaries have no glues! + + void add_in(const Clause& cl, const uint64_t age, const uint32_t orig_size); + ClauseStats operator += (const ClauseStats& other); + void print(uint32_t lev); + }; + vector cl_stats; + +private: + + Solver* solver; + vector delayed_clause_free; + double total_time = 0.0; + + unsigned cl_marked; + unsigned cl_ttl; + unsigned cl_locked_solver; + + size_t last_reducedb_num_conflicts = 0; + bool red_cl_too_young(const Clause* cl) const; + void clear_clauses_stats(vector& clauseset); + ClauseStats reset_clause_dats(const uint32_t lev); + + bool cl_needs_removal(const Clause* cl, const ClOffset offset) const; + void remove_cl_from_lev2(); + + void sort_red_cls(ClauseClean clean_type); + void mark_top_N_clauses_lev2(const uint64_t keep_num); + + #ifdef FINAL_PREDICTOR + ClPredictorsAbst* predictors = NULL; + uint32_t num_times_pred_called = 0; + void update_preds_lev2(); + void pred_move_to_lev1_and_lev0(); + void delete_from_lev2(); + void clean_lev1_once_in_a_while(); + void clean_lev0_once_in_a_while(); + void reset_predict_stats(); + void update_preds(const vector& offs); + ReduceCommonData commdata; + void dump_pred_distrib(const vector& offs, uint32_t lev); + #endif + + const CMSat::ClauseStats& get_median_stat(const vector& all_learnt) const; + const CMSat::ClauseStats& get_median_stat_dat(const vector& all_learnt, const vector& dat) const; + void prepare_features(vector& all_learnt); + //uint64_t total_glue = 0; + uint64_t total_props = 0; + uint64_t total_uip1_used = 0; + uint64_t total_sum_uip1_used = 0; + uint64_t total_sum_props_used = 0; + uint64_t total_time_in_solver = 0; + MedianCommonDataRDB median_data; + uint32_t force_kept_short = 0; + + uint32_t T2_deleted; + uint32_t moved_from_T1_to_T2; + uint32_t kept_in_T1; + uint32_t kept_in_T1_due_to_dontmove; + uint32_t moved_from_T0_to_T1; + uint32_t kept_in_T0; + uint32_t moved_from_T2_to_T0; + uint32_t moved_from_T2_to_T1; + uint32_t kept_in_T0_due_to_dontmove; + uint32_t kept_in_T2; + uint32_t kept_in_T2_due_to_dontmove; + + uint64_t T2_deleted_age; +}; + +} + +#endif //__REDUCEDB_H__ diff --git a/cryptominisat/cppsrc/src/satzilla_features.cpp b/cryptominisat/cppsrc/src/satzilla_features.cpp new file mode 100644 index 00000000..fbb088c7 --- /dev/null +++ b/cryptominisat/cppsrc/src/satzilla_features.cpp @@ -0,0 +1,117 @@ +/****************************************** +Copyright (C) 2009-2020 Authors of CryptoMiniSat, see AUTHORS file + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. +***********************************************/ + +#include "satzilla_features.h" +#include +using std::string; +using std::cout; +using std::endl; + +using namespace CMSat; + + +void SatZillaFeatures::print_stats() const +{ + cout << "c [satzilla_features] "; + cout << "numVars " << numVars << ", "; + cout << "numClauses " << numClauses << ", "; + cout << "var_cl_ratio " << var_cl_ratio << ", "; + + + //Clause distribution + cout << "binary " << binary << ", "; + + cout << "horn " << horn << ", "; + cout << "horn_mean " << horn_mean << ", "; + cout << "horn_std " << horn_std << ", "; + cout << "horn_min " << horn_min << ", "; + cout << "horn_max " << horn_max << ", "; + cout << "horn_spread " << horn_spread << ", "; + + cout << "vcg_var_mean " << vcg_var_mean << ", "; + cout << "vcg_var_std " << vcg_var_std << ", "; + cout << "vcg_var_min " << vcg_var_min << ", "; + cout << "vcg_var_max " << vcg_var_max << ", "; + cout << "vcg_var_spread " << vcg_var_spread << ", "; + + cout << "vcg_cls_mean " << vcg_cls_mean << ", "; + cout << "vcg_cls_std " << vcg_cls_std << ", "; + cout << "vcg_cls_min " << vcg_cls_min << ", "; + cout << "vcg_cls_max " << vcg_cls_max << ", "; + cout << "vcg_cls_spread " << vcg_cls_spread << ", "; + + cout << "pnr_var_mean " << pnr_var_mean << ", "; + cout << "pnr_var_std " << pnr_var_std << ", "; + cout << "pnr_var_min " << pnr_var_min << ", "; + cout << "pnr_var_max " << pnr_var_max << ", "; + cout << "pnr_var_spread " << pnr_var_spread << ", "; + + cout << "pnr_cls_mean " << pnr_cls_mean << ", "; + cout << "pnr_cls_std " << pnr_cls_std << ", "; + cout << "pnr_cls_min " << pnr_cls_min << ", "; + cout << "pnr_cls_max " << pnr_cls_max << ", "; + cout << "pnr_cls_spread " << pnr_cls_spread << ", "; + + //Conflicts + cout << "avg_confl_size " << avg_confl_size << ", "; + cout << "confl_size_min " << confl_size_min << ", "; + cout << "confl_size_max " << confl_size_max << ", "; + cout << "avg_confl_glue " << avg_confl_glue << ", "; + cout << "confl_glue_min " << confl_glue_min << ", "; + cout << "confl_glue_max " << confl_glue_max << ", "; + cout << "avg_num_resolutions " << avg_num_resolutions << ", "; + cout << "num_resolutions_min " << num_resolutions_min << ", "; + cout << "num_resolutions_max " << num_resolutions_max << ", "; + cout << "learnt_bins_per_confl " << learnt_bins_per_confl << ", "; + + //Search + cout << "avg_branch_depth " << avg_branch_depth << ", "; + cout << "branch_depth_min " << branch_depth_min << ", "; + cout << "branch_depth_max " << branch_depth_max << ", "; + cout << "avg_trail_depth_delta " << avg_trail_depth_delta << ", "; + cout << "trail_depth_delta_min " << trail_depth_delta_min << ", "; + cout << "trail_depth_delta_max " << trail_depth_delta_max << ", "; + cout << "avg_branch_depth_delta " << avg_branch_depth_delta << ", "; + cout << "props_per_confl " << props_per_confl << ", "; + cout << "confl_per_restart " << confl_per_restart << ", "; + cout << "decisions_per_conflict " << decisions_per_conflict << ", "; + + //distributions + irred_cl_distrib.print("irred_cl_distrib."); + red_cl_distrib.print("red_cl_distrib."); + + cout << "num_gates_found_last " << num_gates_found_last << ", "; + cout << "num_xors_found_last " << num_xors_found_last; + cout << endl; +} + +void SatZillaFeatures::Distrib::print(const string& pre_print) const +{ + cout << pre_print <<"glue_distr_mean " << glue_distr_mean << ", "; + cout << pre_print <<"glue_distr_var " << glue_distr_var << ", "; + cout << pre_print <<"size_distr_mean " << size_distr_mean << ", "; + cout << pre_print <<"size_distr_var " << size_distr_var << ", "; + cout << pre_print <<"uip_use_distr_mean " << 0 << ", "; + cout << pre_print <<"uip_use_distr_var " << 0 << ", "; + cout << pre_print <<"activity_distr_mean " << activity_distr_mean << ", "; + cout << pre_print <<"activity_distr_var " << activity_distr_var << ", "; +} diff --git a/cryptominisat/cppsrc/src/satzilla_features.h b/cryptominisat/cppsrc/src/satzilla_features.h new file mode 100644 index 00000000..3ac22300 --- /dev/null +++ b/cryptominisat/cppsrc/src/satzilla_features.h @@ -0,0 +1,127 @@ +/****************************************** +Copyright (C) 2009-2020 Authors of CryptoMiniSat, see AUTHORS file + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. +***********************************************/ + +#ifndef SOLVE_FEATURES_H_ +#define SOLVE_FEATURES_H_ + +#include +#include +#include +#include +#include "constants.h" + +using std::numeric_limits; + +namespace CMSat { + +struct SatZillaFeatures +{ + void print_stats() const; + + //Some parameter + double eps = 0.00001; + + //these two are "double" because it's easier to do clustering with + double numVars = 0; + double numClauses = 0; + + double var_cl_ratio = 0; + + //Clause distribution + double binary = 0; + double horn = 0; + double horn_mean = 0; + double horn_std = 0; + double horn_min = numeric_limits::max(); + double horn_max = numeric_limits::min(); + double horn_spread = 0; + + double vcg_var_mean = 0; + double vcg_var_std = 0; + double vcg_var_min = numeric_limits::max(); + double vcg_var_max = numeric_limits::min(); + double vcg_var_spread = 0; + + double vcg_cls_mean = 0; + double vcg_cls_std = 0; + double vcg_cls_min = numeric_limits::max(); + double vcg_cls_max = numeric_limits::min(); + double vcg_cls_spread = 0; + + double pnr_var_mean = 0; + double pnr_var_std = 0; + double pnr_var_min = numeric_limits::max(); + double pnr_var_max = numeric_limits::min(); + double pnr_var_spread = 0; + + double pnr_cls_mean = 0; + double pnr_cls_std = 0; + double pnr_cls_min = numeric_limits::max(); + double pnr_cls_max = numeric_limits::min(); + double pnr_cls_spread = 0; + + //Conflict clauses + double avg_confl_size = 0.0; + double confl_size_min = 0.0; + double confl_size_max = 0.0; + double avg_confl_glue = 0.0; + double confl_glue_min = 0.0; + double confl_glue_max = 0.0; + double avg_num_resolutions = 0.0; + double num_resolutions_min = 0.0; + double num_resolutions_max = 0.0; + double learnt_bins_per_confl = 0; + + //Search + double avg_branch_depth = 0.0; + double branch_depth_min = 0.0; + double branch_depth_max = 0.0; + double avg_trail_depth_delta = 0.0; + double trail_depth_delta_min = 0.0; + double trail_depth_delta_max = 0.0; + double avg_branch_depth_delta = 0.0; + double props_per_confl = 0.0; + double confl_per_restart = 0.0; + double decisions_per_conflict = 0.0; + + //learnt distributions + struct Distrib { + double glue_distr_mean = 0; + double glue_distr_var = 0; + double size_distr_mean = 0; + double size_distr_var = 0; + double activity_distr_mean = 0; //TODO remove + double activity_distr_var = 0; //TODO remove + + void print(const std::string& pre_print) const; + }; + Distrib irred_cl_distrib; + Distrib red_cl_distrib; + + //High-level satzilla_features + uint64_t num_gates_found_last = 0; + uint64_t num_xors_found_last = 0; +}; + +} + +#endif //SOLVE_FEATURES_H_ diff --git a/cryptominisat/cppsrc/src/satzilla_features_calc.cpp b/cryptominisat/cppsrc/src/satzilla_features_calc.cpp new file mode 100644 index 00000000..c50d9578 --- /dev/null +++ b/cryptominisat/cppsrc/src/satzilla_features_calc.cpp @@ -0,0 +1,407 @@ +/****************************************** +Copyright (c) 2016, Yuri Malitsky and Horst Samulowitz +Copyright (C) 2009-2020 Authors of CryptoMiniSat, see AUTHORS file + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. +***********************************************/ + +#include +#include + +#include "solver.h" +#include "sqlstats.h" +#include "satzilla_features_calc.h" + +using std::vector; +using namespace CMSat; + +template +void SatZillaFeaturesCalc::for_one_clause( + const Watched& cl + , const Lit lit + , Function func_each_cl + , Function2 func_each_lit +) const { + unsigned neg_vars = 0; + unsigned pos_vars = 0; + unsigned size = 0; + + switch (cl.getType()) { + case WatchType::watch_binary_t: { + if (cl.red()) { + //only irred cls + break; + } + if (lit > cl.lit2()) { + //only count once + break; + } + + pos_vars += !lit.sign(); + pos_vars += !cl.lit2().sign(); + size = 2; + neg_vars = size - pos_vars; + func_each_cl(size, pos_vars, neg_vars); + func_each_lit(lit, size, pos_vars, neg_vars); + func_each_lit(cl.lit2(), size, pos_vars, neg_vars); + break; + } + case WatchType::watch_bnn_t: + release_assert(false && "Not implemented"); + break; + + case WatchType::watch_clause_t: { + const Clause& clause = *solver->cl_alloc.ptr(cl.get_offset()); + if (clause.red()) { + //only irred cls + break; + } + if (clause[0] < clause[1]) { + //only count once + break; + } + + for (const Lit cl_lit : clause) { + pos_vars += !cl_lit.sign(); + } + size = clause.size(); + neg_vars = size - pos_vars; + func_each_cl(size, pos_vars, neg_vars); + for (const Lit cl_lit : clause) { + func_each_lit(cl_lit, size, pos_vars, neg_vars); + } + break; + } + + case WatchType::watch_idx_t: { + // This should never be here + assert(false); + exit(-1); + break; + } + } +} + +template +void SatZillaFeaturesCalc::for_all_clauses(Function func_each_cl, Function2 func_each_lit) const +{ + for (size_t i = 0; i < solver->nVars() * 2; i++) { + Lit lit = Lit::toLit(i); + for (const Watched & w : solver->watches[lit]) { + for_one_clause(w, lit, func_each_cl, func_each_lit); + } + } +} + +void SatZillaFeaturesCalc::fill_vars_cls() +{ + satzilla_feat.numVars = solver->get_num_free_vars(); + satzilla_feat.numClauses = solver->longIrredCls.size() + solver->binTri.irredBins; + myVars.resize(solver->nVars()); + + auto func_each_cl = [&](unsigned /*size*/, unsigned pos_vars, unsigned /*neg_vars*/) -> bool { + if (pos_vars <= 1 ) { + satzilla_feat.horn += 1; + return true; + } + return false; + }; + auto func_each_lit = [&](Lit lit, unsigned /*size*/, unsigned pos_vars, unsigned /*neg_vars*/) -> void { + if (pos_vars <= 1 ) { + myVars[lit.var()].horn++; + } + + if (!lit.sign()) { + myVars[lit.var()].numPos++; + } + myVars[lit.var()].size++; + }; + for_all_clauses(func_each_cl, func_each_lit); +} + +void SatZillaFeaturesCalc::calculate_clause_stats() +{ + auto empty_func = [](const Lit, unsigned /*size*/, unsigned /*pos_vars*/, unsigned /*neg_vars*/) -> void {}; + auto func_each_cl = [&](unsigned size, unsigned pos_vars, unsigned /*neg_vars*/) -> void { + if (size == 0 ) { + return; + } + + double _size = (double)size / (double)satzilla_feat.numVars; + satzilla_feat.vcg_cls_min = std::min(satzilla_feat.vcg_cls_min, _size); + satzilla_feat.vcg_cls_max = std::max(satzilla_feat.vcg_cls_max, _size); + satzilla_feat.vcg_cls_mean += _size; + + double _pnr = 0.5 + ((2.0 * (double)pos_vars - (double)size) / (2.0 * (double)size)); + satzilla_feat.pnr_cls_min = std::min(satzilla_feat.pnr_cls_min, _pnr); + satzilla_feat.pnr_cls_max = std::max(satzilla_feat.pnr_cls_max, _pnr); + satzilla_feat.pnr_cls_mean += _pnr; + }; + for_all_clauses(func_each_cl, empty_func); + + satzilla_feat.vcg_cls_mean /= (double)satzilla_feat.numClauses; + satzilla_feat.pnr_cls_mean /= (double)satzilla_feat.numClauses; + satzilla_feat.horn /= (double)satzilla_feat.numClauses; + satzilla_feat.binary = float_div(solver->binTri.irredBins, satzilla_feat.numClauses); + + satzilla_feat.vcg_cls_spread = satzilla_feat.vcg_cls_max - satzilla_feat.vcg_cls_min; + satzilla_feat.pnr_cls_spread = satzilla_feat.pnr_cls_max - satzilla_feat.pnr_cls_min; +} + +void SatZillaFeaturesCalc::calculate_variable_stats() +{ + if (satzilla_feat.numVars == 0) + return; + + for ( int vv = 0; vv < (int)myVars.size(); vv++ ) { + if ( myVars[vv].size == 0 ) { + continue; + } + + double _size = myVars[vv].size / (double)satzilla_feat.numClauses; + satzilla_feat.vcg_var_min = std::min(satzilla_feat.vcg_var_min, _size); + satzilla_feat.vcg_var_max = std::max(satzilla_feat.vcg_var_max, _size); + satzilla_feat.vcg_var_mean += _size; + + double _pnr = 0.5 + ((2.0 * myVars[vv].numPos - myVars[vv].size) + / (2.0 * myVars[vv].size)); + satzilla_feat.pnr_var_min = std::min(satzilla_feat.pnr_var_min, _pnr); + satzilla_feat.pnr_var_max = std::max(satzilla_feat.pnr_var_max, _pnr); + satzilla_feat.pnr_var_mean += _pnr; + + double _horn = myVars[vv].horn / (double)satzilla_feat.numClauses; + satzilla_feat.horn_min = std::min(satzilla_feat.horn_min, _horn); + satzilla_feat.horn_max = std::max(satzilla_feat.horn_max, _horn); + satzilla_feat.horn_mean += _horn; + } + + if (satzilla_feat.vcg_var_mean > 0) { + satzilla_feat.vcg_var_mean /= (double)satzilla_feat.numVars; + } + if (satzilla_feat.pnr_var_mean > 0) { + satzilla_feat.pnr_var_mean /= (double)satzilla_feat.numVars; + } + if (satzilla_feat.horn_mean > 0) { + satzilla_feat.horn_mean /= (double)satzilla_feat.numVars; + } + + satzilla_feat.vcg_var_spread = satzilla_feat.vcg_var_max - satzilla_feat.vcg_var_min; + satzilla_feat.pnr_var_spread = satzilla_feat.pnr_var_max - satzilla_feat.pnr_var_min; + satzilla_feat.horn_spread = satzilla_feat.horn_max - satzilla_feat.horn_min; +} + +void SatZillaFeaturesCalc::calculate_extra_clause_stats() +{ + auto empty_func = [](const Lit, unsigned /*size*/, unsigned /*pos_vars*/, unsigned /*neg_vars*/) -> void {}; + auto each_clause = [&](unsigned size, unsigned pos_vars, unsigned /*neg_vars*/) -> void { + if ( size == 0 ) { + return; + } + + double _size = (double)size / (double)satzilla_feat.numVars; + satzilla_feat.vcg_cls_std += (satzilla_feat.vcg_cls_mean - _size) * (satzilla_feat.vcg_cls_mean - _size); + + double _pnr = 0.5 + ((2.0 * (double)pos_vars - (double)size) / (2.0 * (double)size)); + satzilla_feat.pnr_cls_std += (satzilla_feat.pnr_cls_mean - _pnr) * (satzilla_feat.pnr_cls_mean - _pnr); + }; + for_all_clauses(each_clause, empty_func); + + if ( satzilla_feat.vcg_cls_std > satzilla_feat.eps && satzilla_feat.vcg_cls_mean > satzilla_feat.eps ) { + satzilla_feat.vcg_cls_std = std::sqrt(satzilla_feat.vcg_cls_std / (double)satzilla_feat.numClauses) / satzilla_feat.vcg_cls_mean; + } else { + satzilla_feat.vcg_cls_std = 0; + } + if ( satzilla_feat.pnr_cls_std > satzilla_feat.eps && satzilla_feat.pnr_cls_mean > satzilla_feat.eps ) { + satzilla_feat.pnr_cls_std = std::sqrt(satzilla_feat.pnr_cls_std / (double)satzilla_feat.numClauses) / satzilla_feat.pnr_cls_mean; + } else { + satzilla_feat.pnr_cls_std = 0; + } +} + +void SatZillaFeaturesCalc::calculate_extra_var_stats() +{ + if (satzilla_feat.numVars == 0) + return; + + for ( int vv = 0; vv < (int)myVars.size(); vv++ ) { + if ( myVars[vv].size == 0 ) { + continue; + } + + double _size = myVars[vv].size / (double)satzilla_feat.numClauses; + satzilla_feat.vcg_var_std += (satzilla_feat.vcg_var_mean - _size) * (satzilla_feat.vcg_var_mean - _size); + + double _pnr = 0.5 + ((2.0 * myVars[vv].numPos - myVars[vv].size) / (2.0 * myVars[vv].size)); + satzilla_feat.pnr_var_std += (satzilla_feat.pnr_var_mean - _pnr) * (satzilla_feat.pnr_var_mean - _pnr); + + double _horn = myVars[vv].horn / (double)satzilla_feat.numClauses; + satzilla_feat.horn_std += (satzilla_feat.horn_mean - _horn) * (satzilla_feat.horn_mean - _horn); + } + if ( satzilla_feat.vcg_var_std > satzilla_feat.eps && satzilla_feat.vcg_var_mean > satzilla_feat.eps ) { + satzilla_feat.vcg_var_std = std::sqrt(satzilla_feat.vcg_var_std / (double)satzilla_feat.numVars) / satzilla_feat.vcg_var_mean; + } else { + satzilla_feat.vcg_var_std = 0; + } + + if ( satzilla_feat.pnr_var_std > satzilla_feat.eps && satzilla_feat.pnr_var_mean > satzilla_feat.eps + && satzilla_feat.pnr_var_mean != 0 + ) { + satzilla_feat.pnr_var_std = std::sqrt(satzilla_feat.pnr_var_std / (double)satzilla_feat.numVars) / satzilla_feat.pnr_var_mean; + } else { + satzilla_feat.pnr_var_std = 0; + } + + if ( satzilla_feat.horn_std / (double)satzilla_feat.numVars > satzilla_feat.eps && satzilla_feat.horn_mean > satzilla_feat.eps + && satzilla_feat.horn_mean != 0 + ) { + satzilla_feat.horn_std = std::sqrt(satzilla_feat.horn_std / (double)satzilla_feat.numVars) / satzilla_feat.horn_mean; + } else { + satzilla_feat.horn_std = 0; + } +} + +void SatZillaFeaturesCalc::calculate_cl_distributions( + const vector& clauses + , struct SatZillaFeatures::Distrib& distrib_data +) { + if (clauses.empty()) { + return; + } + + double glue_mean = 0; + double glue_var = 0; + + double size_mean = 0; + double size_var = 0; + + double activity_mean = 0; + double activity_var = 0; + + //Calculate means + double cla_inc = solver->get_cla_inc(); + for(ClOffset off: clauses) + { + const Clause& cl = *solver->cl_alloc.ptr(off); + size_mean += cl.size(); + glue_mean += cl.stats.glue; + if (cl.red()) { + activity_mean += (double)cl.stats.activity/cla_inc; + } + } + size_mean /= clauses.size(); + glue_mean /= clauses.size(); + activity_mean /= clauses.size(); + + //Calculate variances + for(ClOffset off: clauses) + { + const Clause& cl = *solver->cl_alloc.ptr(off); + size_var += std::pow(size_mean-cl.size(), 2); + glue_var += std::pow(glue_mean-cl.stats.glue, 2); + activity_var += std::pow(activity_mean-(double)cl.stats.activity/cla_inc, 2); + } + size_var /= clauses.size(); + glue_var /= clauses.size(); + activity_var /= clauses.size(); + + //Assign calculated values + distrib_data.glue_distr_mean = glue_mean; + distrib_data.glue_distr_var = glue_var; + distrib_data.size_distr_mean = size_mean; + distrib_data.size_distr_var = size_var; + distrib_data.activity_distr_mean = activity_mean; + distrib_data.activity_distr_var = activity_var; +} + +void SatZillaFeaturesCalc::normalise_values() +{ + if (satzilla_feat.vcg_var_min == numeric_limits::max()) + satzilla_feat.vcg_var_min = -1; + if (satzilla_feat.vcg_var_max == numeric_limits::min()) + satzilla_feat.vcg_var_max = -1; + + if (satzilla_feat.vcg_cls_min == numeric_limits::max()) + satzilla_feat.vcg_cls_min = -1; + if (satzilla_feat.vcg_cls_max == numeric_limits::min()) + satzilla_feat.vcg_cls_max = -1; + + if (satzilla_feat.pnr_var_min == numeric_limits::max()) + satzilla_feat.pnr_var_min = -1; + if (satzilla_feat.pnr_var_max == numeric_limits::min()) + satzilla_feat.pnr_var_max = -1; + + if (satzilla_feat.horn_min == numeric_limits::max()) + satzilla_feat.horn_min = -1; + if (satzilla_feat.horn_max == numeric_limits::min()) + satzilla_feat.horn_max = -1; + + if (satzilla_feat.pnr_cls_min == numeric_limits::max()) + satzilla_feat.pnr_cls_min = -1; + if (satzilla_feat.pnr_cls_max == numeric_limits::min()) + satzilla_feat.pnr_cls_max = -1; +} + +SatZillaFeatures SatZillaFeaturesCalc::extract() +{ + double start_time = cpuTime(); + fill_vars_cls(); + + satzilla_feat.numVars = 0; + for ( int vv = 0; vv < (int)myVars.size(); vv++ ) { + if ( myVars[vv].size > 0 ) { + satzilla_feat.numVars++; + } + } + if (satzilla_feat.numVars > 0 && satzilla_feat.numClauses > 0) { + satzilla_feat.var_cl_ratio = (double)satzilla_feat.numVars/ (double)satzilla_feat.numClauses; + } + + if (satzilla_feat.numClauses > 0 && satzilla_feat.numVars > 0) { + calculate_clause_stats(); + calculate_variable_stats(); + + calculate_extra_clause_stats(); + calculate_extra_var_stats(); + + if (!solver->longRedCls[0].empty()) { + calculate_cl_distributions(solver->longRedCls[0], satzilla_feat.red_cl_distrib); + } + if (!solver->longIrredCls.empty()) { + calculate_cl_distributions(solver->longIrredCls, satzilla_feat.irred_cl_distrib); + } + } + normalise_values(); + + double time_used = cpuTime() - start_time; + if (solver->conf.verbosity) { + cout << "c [szfeat] satzilla features extracted " + << solver->conf.print_times(time_used) + << endl; + } + + if (solver->sqlStats) { + solver->sqlStats->time_passed_min( + solver + , "satzilla" + , time_used + ); + } + + return satzilla_feat; +} diff --git a/cryptominisat/cppsrc/src/satzilla_features_calc.h b/cryptominisat/cppsrc/src/satzilla_features_calc.h new file mode 100644 index 00000000..b0327659 --- /dev/null +++ b/cryptominisat/cppsrc/src/satzilla_features_calc.h @@ -0,0 +1,82 @@ +/****************************************** +Copyright (C) 2009-2020 Authors of CryptoMiniSat, see AUTHORS file + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. +***********************************************/ + +#ifndef __FEATURES_FAST_H__ +#define __FEATURES_FAST_H__ + +#include +#include +#include +#include "satzilla_features.h" +#include "cloffset.h" +#include "watched.h" +using std::vector; +using std::pair; +using std::make_pair; + +namespace CMSat { + +class Solver; + +struct SatZillaFeaturesCalc { +public: + SatZillaFeaturesCalc(const Solver* _solver) : + solver(_solver) { + } + SatZillaFeatures extract(); + +private: + void fill_vars_cls(); + void calculate_clause_stats(); + void calculate_variable_stats(); + void calculate_extra_var_stats(); + void calculate_extra_clause_stats(); + void normalise_values(); + void calculate_cl_distributions( + const vector& clauses + , struct SatZillaFeatures::Distrib& distrib_data + ); + + + const Solver* solver; + template + void for_one_clause( + const Watched& cl + , const Lit lit + , Function func + , Function2 func_each_lit + ) const; + template + void for_all_clauses(Function for_each_clause, Function2 func_each_lit) const; + struct VARIABLE { + int numPos = 0; + int size = 0; + int horn = 0; + }; + + vector myVars; + SatZillaFeatures satzilla_feat; +}; + +} //end namespace + +#endif //__FEATURES_FAST_H__ diff --git a/cryptominisat/cppsrc/src/sccfinder.cpp b/cryptominisat/cppsrc/src/sccfinder.cpp new file mode 100644 index 00000000..568d2abe --- /dev/null +++ b/cryptominisat/cppsrc/src/sccfinder.cpp @@ -0,0 +1,207 @@ +/****************************************** +Copyright (C) 2009-2020 Authors of CryptoMiniSat, see AUTHORS file + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. +***********************************************/ + +#include +#include +#include + +#include "solvertypes.h" +#include "sccfinder.h" +#include "varreplacer.h" +#include "time_mem.h" +#include "solver.h" +#include "sqlstats.h" + +using namespace CMSat; +using std::cout; +using std::endl; + +SCCFinder::SCCFinder(Solver* _solver) : + globalIndex(0) + , solver(_solver) +{} + +bool SCCFinder::performSCC(uint64_t* bogoprops_given) +{ + assert(binxors.empty()); + runStats.clear(); + runStats.numCalls = 1; + depth_warning_issued = false; + const double myTime = cpuTime(); + + globalIndex = 0; + index.clear(); + index.resize(solver->nVars()*2, numeric_limits::max()); + lowlink.clear(); + lowlink.resize(solver->nVars()*2, numeric_limits::max()); + stackIndicator.clear(); + stackIndicator.resize(solver->nVars()*2, false); + assert(stack.empty()); + + depth = 0; + for (uint32_t vertex = 0; vertex < solver->nVars()*2; vertex++) { + //Start a DFS at each node we haven't visited yet + const uint32_t v = vertex>>1; + if (solver->value(v) != l_Undef) { + continue; + } + assert(depth == 0); + if (index[vertex] == numeric_limits::max()) { + tarjan(vertex); + depth--; + assert(stack.empty()); + } + } + + //Update & print stats + runStats.cpu_time = cpuTime() - myTime; + runStats.foundXorsNew = binxors.size(); + if (solver->conf.verbosity) { + if (solver->conf.verbosity >= 3) + runStats.print(); + else + runStats.print_short(solver); + } + globalStats += runStats; + + if (bogoprops_given) { + *bogoprops_given += runStats.bogoprops; + } + + return solver->okay(); +} + +void SCCFinder::tarjan(const uint32_t vertex) +{ + depth++; + if (depth >= (uint32_t)solver->conf.max_scc_depth) { + if (solver->conf.verbosity && !depth_warning_issued) { + depth_warning_issued = true; + cout << "c [scc] WARNING: reached maximum depth of " << solver->conf.max_scc_depth << endl; + } + return; + } + + const Lit vertLit = Lit::toLit(vertex); + if (solver->varData[vertLit.var()].removed != Removed::none) { + return; + } + + runStats.bogoprops += 1; + index[vertex] = globalIndex; // Set the depth index for v + lowlink[vertex] = globalIndex; + globalIndex++; + stack.push(vertex); // Push v on the stack + stackIndicator[vertex] = true; + + //Go through the watch + watch_subarray_const ws = solver->watches[~vertLit]; + runStats.bogoprops += ws.size()/4; + for (const Watched& w: ws) { + //Only binary clauses matter + if (!w.isBin()) + continue; + + const Lit lit = w.lit2(); + if (solver->value(lit) != l_Undef) { + continue; + } + doit(lit, vertex); + } + + // Is v the root of an SCC? + if (lowlink[vertex] == index[vertex]) { + uint32_t vprime; + tmp.clear(); + do { + assert(!stack.empty()); + vprime = stack.top(); + stack.pop(); + stackIndicator[vprime] = false; + tmp.push_back(vprime); + } while (vprime != vertex); + if (tmp.size() >= 2) { + runStats.bogoprops += 3; + add_bin_xor_in_tmp(); + } + } +} + +void SCCFinder::add_bin_xor_in_tmp() +{ + for (uint32_t i = 1; i < tmp.size(); i++) { + bool rhs = Lit::toLit(tmp[0]).sign() + ^ Lit::toLit(tmp[i]).sign(); + + BinaryXor binxor(Lit::toLit(tmp[0]).var(), Lit::toLit(tmp[i]).var(), rhs); + binxors.insert(binxor); + + //Both are UNDEF, so this is a proper binary XOR + if (solver->value(binxor.vars[0]) == l_Undef + && solver->value(binxor.vars[1]) == l_Undef + ) { + runStats.foundXors++; + #ifdef VERBOSE_DEBUG + cout << "SCC says: " + << binxor.vars[0] +1 + << " XOR " + << binxor.vars[1] +1 + << " = " << binxor.rhs + << endl; + #endif + } + } +} + +void SCCFinder::Stats::print_short(Solver* solver) const +{ + cout + << "c [scc]" + << " new: " << foundXorsNew + << " BP " << bogoprops/(1000*1000) << "M"; + if (solver) { + cout << solver->conf.print_times(cpu_time); + } else { + cout << " T: " << std::setprecision(2) << std::fixed << cpu_time; + } + cout << endl; + + if (solver && solver->sqlStats) { + solver->sqlStats->time_passed_min( + solver + , "scc" + , cpu_time + ); + } +} + +size_t SCCFinder::mem_used() const +{ + size_t mem = 0; + mem += index.capacity()*sizeof(uint32_t); + mem += lowlink.capacity()*sizeof(uint32_t); + mem += stack.size()*sizeof(uint32_t); //TODO under-estimates + mem += stackIndicator.capacity()*sizeof(char); + mem += tmp.capacity()*sizeof(uint32_t); + + return mem; +} diff --git a/cryptominisat/cppsrc/src/sccfinder.h b/cryptominisat/cppsrc/src/sccfinder.h new file mode 100644 index 00000000..2635f6a9 --- /dev/null +++ b/cryptominisat/cppsrc/src/sccfinder.h @@ -0,0 +1,164 @@ +/****************************************** +Copyright (C) 2009-2020 Authors of CryptoMiniSat, see AUTHORS file + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. +***********************************************/ + +#ifndef SCCFINDER_H +#define SCCFINDER_H + +#include "clause.h" +#include +#include + +namespace CMSat { + +class Solver; + +class SCCFinder { + public: + explicit SCCFinder(Solver* _solver); + bool performSCC(uint64_t* bogoprops_given = NULL); + const std::set& get_binxors() const; + size_t get_num_binxors_found() const; + void clear_binxors(); + + struct Stats + { + void clear() + { + Stats _tmp; + *this = _tmp; + } + + uint64_t numCalls = 0; + double cpu_time = 0.0; + uint64_t foundXors = 0; + uint64_t foundXorsNew = 0; + uint64_t bogoprops = 0; + + Stats& operator+=(const Stats& other) + { + numCalls += other.numCalls; + cpu_time += other.cpu_time; + foundXors += other.foundXors; + foundXorsNew += other.foundXorsNew; + bogoprops += other.bogoprops; + + return *this; + } + + void print() const + { + cout << "c ----- SCC STATS --------" << endl; + print_stats_line("c time" + , cpu_time + , float_div(cpu_time, numCalls) + , "per call" + ); + + print_stats_line("c called" + , numCalls + , float_div(foundXorsNew, numCalls) + , "new found per call" + ); + + print_stats_line("c found" + , foundXorsNew + , stats_line_percent(foundXorsNew, foundXors) + , "% of all found" + ); + + print_stats_line("c bogoprops" + , bogoprops + , "% of all found" + ); + + cout << "c ----- SCC STATS END --------" << endl; + } + + void print_short(Solver* solver) const; + }; + + const Stats& get_stats() const; + size_t mem_used() const; + bool depth_warning_triggered() const; + + private: + void tarjan(const uint32_t vertex); + bool depth_warning_issued; + void doit(const Lit lit, const uint32_t vertex); + void add_bin_xor_in_tmp(); + + //temporaries + uint32_t globalIndex; + vector index; + vector lowlink; + std::stack > stack; + vector stackIndicator; + vector tmp; + uint32_t depth; + + Solver* solver; + std::set binxors; + + //Stats + Stats runStats; + Stats globalStats; +}; + +inline void SCCFinder::doit(const Lit lit, const uint32_t vertex) { + // Was successor v' visited? + if (index[lit.toInt()] == numeric_limits::max()) { + tarjan(lit.toInt()); + depth--; + lowlink[vertex] = std::min(lowlink[vertex], lowlink[lit.toInt()]); + } else if (stackIndicator[lit.toInt()]) { + lowlink[vertex] = std::min(lowlink[vertex], lowlink[lit.toInt()]); + } +} + +inline bool SCCFinder::depth_warning_triggered() const +{ + return depth_warning_issued; +} + +inline const SCCFinder::Stats& SCCFinder::get_stats() const +{ + return globalStats; +} + +inline const std::set& SCCFinder::get_binxors() const +{ + return binxors; +} + +inline size_t SCCFinder::get_num_binxors_found() const +{ + return binxors.size(); +} + +inline void SCCFinder::clear_binxors() +{ + binxors.clear(); +} + +} //end namespaceC + +#endif //SCCFINDER_H diff --git a/cryptominisat/cppsrc/src/searcher.cpp b/cryptominisat/cppsrc/src/searcher.cpp new file mode 100644 index 00000000..d5086608 --- /dev/null +++ b/cryptominisat/cppsrc/src/searcher.cpp @@ -0,0 +1,3999 @@ +/****************************************** +Copyright (C) 2009-2020 Authors of CryptoMiniSat, see AUTHORS file + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. +***********************************************/ + +#include "searcher.h" +#include "occsimplifier.h" +#include "time_mem.h" +#include "solver.h" +#include +#include "varreplacer.h" +#include "clausecleaner.h" +#include "propbyforgraph.h" +#include +#include +#include +#include +#include + + +#include "sqlstats.h" +#include "datasync.h" +#include "reducedb.h" +#include "watchalgos.h" +#include "hasher.h" +#include "solverconf.h" +#include "distillerlong.h" +#include "vardistgen.h" +#include "solvertypes.h" +#include "gaussian.h" +#include "distillerbin.h" +#include "distillerlongwithimpl.h" +#include "intree.h" +#include "str_impl_w_impl.h" +#include "subsumeimplicit.h" +#include "sls.h" +#ifdef USE_VALGRIND +#include "valgrind/valgrind.h" +#include "valgrind/memcheck.h" +#endif + +//#define DEBUG_RESOLV +//#define VERBOSE_DEBUG + +using namespace CMSat; +using std::cout; +using std::endl; + +/** +@brief Sets a sane default config and allocates handler classes +*/ +Searcher::Searcher(const SolverConf *_conf, Solver* _solver, std::atomic* _must_interrupt_inter) : + HyperEngine( + _conf + , _solver + , _must_interrupt_inter + ) + , solver(_solver) + , cla_inc(1) +{ + var_inc_vsids = 1; + + more_red_minim_limit_binary_actual = conf.more_red_minim_limit_binary; + hist.setSize(conf.shortTermHistorySize, conf.blocking_restart_trail_hist_length); + cur_max_temp_red_lev2_cls = conf.max_temp_lev2_learnt_clauses; + polarity_mode = conf.polarity_mode; + + next_cls_distill = 5000.0*conf.global_next_multiplier; + next_bins_distill = 12000.0*conf.global_next_multiplier; + next_full_probe = 20000.0*conf.global_next_multiplier; + next_sub_str_with_bin = 25000.0*conf.global_next_multiplier; + next_intree = 50000.0*conf.global_next_multiplier; + next_str_impl_with_impl = 40000.0*conf.global_next_multiplier; + next_sls = 44000.0*conf.global_next_multiplier; +} + +Searcher::~Searcher() +{ + clear_gauss_matrices(true); +} + +void Searcher::new_var( + const bool bva, + const uint32_t orig_outer, + bool insert_varorder) +{ + PropEngine::new_var(bva, orig_outer, insert_varorder); + + if (insert_varorder) { + insert_var_order_all((int)nVars()-1); + #ifdef STATS_NEEDED_BRANCH + level_used_for_cl_arr.insert(level_used_for_cl_arr.end(), 1, 0); + #endif + } +} + +void Searcher::new_vars(size_t n) +{ + PropEngine::new_vars(n); + + for(int i = n-1; i >= 0; i--) { + insert_var_order_all((int)nVars()-i-1); + } + + #ifdef STATS_NEEDED_BRANCH + level_used_for_cl_arr.insert(level_used_for_cl_arr.end(), n, 0); + #endif +} + +void Searcher::save_on_var_memory() +{ + PropEngine::save_on_var_memory(); + + #ifdef STATS_NEEDED_BRANCH + level_used_for_cl_arr.resize(nVars()); + #endif +} + +void Searcher::updateVars( + const vector& /*outerToInter*/ + , const vector& interToOuter +) { + updateArray(var_act_vsids, interToOuter); + updateArray(vmtf_btab, interToOuter); + updateArray(vmtf_links, interToOuter); + + auto upd = [&](uint32_t v) { + if (v != numeric_limits::max()) + v = interToOuter[v]; + }; + + for(auto& l: vmtf_links) { + upd(l.next); + upd(l.prev); + } + upd(vmtf_queue.first); + upd(vmtf_queue.last); + upd(vmtf_queue.unassigned); +} + +//TODO add hint here for FRAT +template +inline void Searcher::add_lit_to_learnt( + const Lit lit + , const uint32_t nDecisionLevel +) { + const uint32_t var = lit.var(); +// cout << "Lit to learnt lit: " << lit << " dec level: " << nDecisionLevel << endl; +// cout << "varData[var].removed: " +// << removed_type_to_string(varData[var].removed) << endl; + assert(varData[var].removed == Removed::none); + + #ifdef STATS_NEEDED_BRANCH + if (!inprocess) { + varData[var].inside_conflict_clause_antecedents++; + varData[var].last_seen_in_1uip = sumConflicts; + } + #endif + + if (varData[var].level == 0) { + if (frat->enabled()) { + assert(value(var) != l_Undef); + assert(unit_cl_IDs[var] != 0); + chain.push_back(unit_cl_IDs[var]); + VERBOSE_PRINT("Chain adding ID: " << unit_cl_IDs[var] << " due to unit clause, var: " << var+1); + } + return; + } + + if (seen[var]) return; + seen[var] = 1; + + if (!inprocess) { + #ifdef STATS_NEEDED_BRANCH + if (varData[var].level != 0 && + !level_used_for_cl_arr[varData[var].level] + ) { + level_used_for_cl_arr[varData[var].level] = 1; + level_used_for_cl.push_back(varData[var].level); + } + #endif + + switch(branch_strategy) { + case branch::vsids: + vsids_bump_var_act(var); + break; + + case branch::rand: + break; + + case branch::vmtf: + implied_by_learnts.push_back(var); + break; + } + } + + if (varData[var].level >= nDecisionLevel) { + pathC++; + } else { + learnt_clause.push_back(lit); + } +} + +inline void Searcher::recursiveConfClauseMin() +{ + uint32_t abstract_level = 0; + for (size_t i = 1; i < learnt_clause.size(); i++) { + //(maintain an abstraction of levels involved in conflict) + abstract_level |= abstractLevel(learnt_clause[i].var()); + } + + size_t i, j; + for (i = j = 1; i < learnt_clause.size(); i++) { + if (varData[learnt_clause[i].var()].reason.isNULL() + || !litRedundant(learnt_clause[i], abstract_level) + ) { + learnt_clause[j++] = learnt_clause[i]; + } + } + learnt_clause.resize(j); +} + +void Searcher::normalClMinim() +{ + size_t i,j; + for (i = j = 1; i < learnt_clause.size(); i++) { + const PropBy& reason = varData[learnt_clause[i].var()].reason; + size_t size; + Lit *lits = NULL; + int32_t ID; + PropByType type = reason.getType(); + if (type == null_clause_t) { + //decision clause + learnt_clause[j++] = learnt_clause[i]; + continue; + } + + switch (type) { + case binary_t: + size = 1; + ID = reason.getID(); + break; + + case clause_t: { + Clause* cl2 = cl_alloc.ptr(reason.get_offset()); + lits = cl2->begin(); + size = cl2->size()-1; + ID = cl2->stats.ID; + break; + } + + case xor_t: { + vector* xor_reason = gmatrices[reason.get_matrix_num()]-> + get_reason(reason.get_row_num(), ID); + lits = xor_reason->data(); + size = xor_reason->size()-1; + sumAntecedentsLits += size; + break; + } + + case bnn_t: { + vector* bnn_reason = get_bnn_reason( + bnns[reason.getBNNidx()], + learnt_clause[i]); + lits = bnn_reason->data(); + size = bnn_reason->size()-1; + sumAntecedentsLits += size; + break; + } + + default: + release_assert(false); + std::exit(-1); + } + + for (size_t k = 0; k < size; k++) { + Lit p; + switch (type) { + case xor_t: + case bnn_t: + case clause_t: + p = lits[k+1]; + break; + + case binary_t: + p = reason.lit2(); + break; + + default: + release_assert(false); + std::exit(-1); + } + + if (!seen[p.var()] && varData[p.var()].level > 0) { + learnt_clause[j++] = learnt_clause[i]; + break; + } else { + VERBOSE_PRINT("Chain adding ID: " << ID << " due to normal CL minim, lit: " << p << " removed"); + chain.push_back(ID); + } + } + } + learnt_clause.resize(j); +} + +void Searcher::debug_print_resolving_clause(const PropBy confl) const +{ +#ifndef DEBUG_RESOLV + //Avoid unused parameter warning + (void) confl; +#else + switch(confl.getType()) { + case binary_t: { + cout << "resolv bin: " << confl.lit2() << endl; + break; + } + + case clause_t: { + Clause* cl = cl_alloc.ptr(confl.get_offset()); + cout << "resolv (long): " << *cl << endl; + break; + } + + case xor_t: { + //in the future, we'll have XOR clauses. Not yet. + assert(false); + exit(-1); + break; + } + + case null_clause_t: { + assert(false); + break; + } + } +#endif +} + +void Searcher::update_glue_from_analysis(Clause* cl) +{ + assert(cl->red()); + if (cl->stats.is_ternary_resolvent) { + return; + } + const unsigned new_glue = calc_glue(*cl); + + if (new_glue < cl->stats.glue) { + if (cl->stats.glue <= conf.protect_cl_if_improved_glue_below_this_glue_for_one_turn) { + cl->stats.ttl = 1; + #if defined(STATS_NEEDED) + red_stats_extra[cl->stats.extra_pos].ttl_stats = cl->stats.glue - new_glue; + #endif + } + cl->stats.glue = new_glue; + + #ifndef FINAL_PREDICTOR + if (cl->stats.locked_for_data_gen) { + assert(cl->stats.which_red_array == 0); + } else if (new_glue <= conf.glue_put_lev0_if_below_or_eq) { + //move to lev0 if very low glue + cl->stats.which_red_array = 0; + } else if (new_glue <= conf.glue_put_lev1_if_below_or_eq + && conf.glue_put_lev1_if_below_or_eq != 0 + ) { + //move to lev1 if low glue + cl->stats.which_red_array = 1; + } + #endif + } +} + +template +void Searcher::add_lits_to_learnt( + const PropBy confl + , const Lit p + , uint32_t nDecisionLevel +) { + VERBOSE_DEBUG_DO(debug_print_resolving_clause(confl)); + sumAntecedents++; + + Lit* lits = NULL; + size_t size = 0; + int32_t ID; + switch (confl.getType()) { + case binary_t : { + ID = confl.getID(); + sumAntecedentsLits += 2; + VERBOSE_PRINT("resolving with cl:" << p << " , " << confl.lit2() << " -- ID: " << ID); + + if (confl.isRedStep()) { + #if defined(STATS_NEEDED) || defined(FINAL_PREDICTOR) + antec_data.binRed++; + #endif + stats.resolvs.binRed++; + } else { + #if defined(STATS_NEEDED) || defined(FINAL_PREDICTOR) + antec_data.binIrred++; + #endif + stats.resolvs.binIrred++; + } + break; + } + + case clause_t : { + Clause* cl = cl_alloc.ptr(confl.get_offset()); + ID = cl->stats.ID; + assert(!cl->getRemoved()); + lits = cl->begin(); + size = cl->size(); + sumAntecedentsLits += cl->size(); + VERBOSE_PRINT("resolving with cl:" << *cl); + + if (cl->red()) { + stats.resolvs.longRed++; + #if defined(STATS_NEEDED) || defined(FINAL_PREDICTOR) + antec_data.longRed++; + antec_data.glue_long_reds.push(cl->stats.glue); + #endif + } else { + stats.resolvs.longIrred++; + #if defined(STATS_NEEDED) || defined(FINAL_PREDICTOR) + antec_data.longIrred++; + #endif + } + #if defined(NORMAL_CL_USE_STATS) + cl->stats.uip1_used++; + #endif + #if defined(STATS_NEEDED) || defined(FINAL_PREDICTOR) + antec_data.size_longs.push(cl->size()); + if (!inprocess) cl->stats.uip1_used++; + #endif + + //If STATS_NEEDED then bump acitvity of ALL clauses + //and set stats on all clauses + if (!inprocess + && cl->red() + #if !defined(STATS_NEEDED) && !defined(FINAL_PREDICTOR) + && cl->stats.which_red_array != 0 + #endif + ) { + if (conf.update_glues_on_analyze) update_glue_from_analysis(cl); + + #if !defined(STATS_NEEDED) && !defined(FINAL_PREDICTOR) + if (cl->stats.which_red_array == 1) + #endif + cl->stats.last_touched_any = sumConflicts; + + //If stats or predictor, bump all because during final + //we will need this data and during dump when stats is on + //we also need this data. + #if !defined(STATS_NEEDED) && !defined(FINAL_PREDICTOR) + if (cl->stats.which_red_array == 2) + #endif + bump_cl_act(cl); + } + break; + } + + case xor_t: { + auto xor_reason = gmatrices[confl.get_matrix_num()]->get_reason(confl.get_row_num(), ID); + lits = xor_reason->data(); + size = xor_reason->size(); + sumAntecedentsLits += size; + VERBOSE_PRINT("resolving with cl:" << *xor_reason << " -- ID: " << ID); + break; + } + + case bnn_t: { + vector* bnn_reason = get_bnn_reason(bnns[confl.getBNNidx()], p); + lits = bnn_reason->data(); + size = bnn_reason->size(); + sumAntecedentsLits += size; + ID = 0; // so we don't get a warning, assert below + assert(!frat->enabled()); + break; + } + + case null_clause_t: + default: + assert(false && "Error in conflict analysis (otherwise should be UIP)"); + } + VERBOSE_PRINT("Chain adding ID: " << ID << " due to resolution on lit: " << p); + chain.push_back(ID); + + size_t i = 0; + bool cont = true; + Lit x = lit_Undef; + while(cont) { + switch (confl.getType()) { + case binary_t: + if (i == 0) { + x = failBinLit; + } else { + x = confl.lit2(); + cont = false; + } + break; + + case bnn_t: + case clause_t: + case xor_t: + x = lits[i]; + if (i == size-1) { + cont = false; + } + break; + + case null_clause_t: + assert(false); + break; + } + if (p == lit_Undef || i > 0) { + add_lit_to_learnt(x, nDecisionLevel); + } + i++; + } +} + +template +void Searcher::minimize_learnt_clause() +{ + const size_t origSize = learnt_clause.size(); + + toClear = learnt_clause; + if (conf.doRecursiveMinim) { + recursiveConfClauseMin(); + } else { + normalClMinim(); + } + for (const Lit lit: toClear) { + seen[lit.var()] = 0; + } + toClear.clear(); + + stats.recMinCl += ((origSize - learnt_clause.size()) > 0); + stats.recMinLitRem += origSize - learnt_clause.size(); +} + +inline void Searcher::minimize_using_bins() +{ + if (conf.doMinimRedMore + && learnt_clause.size() > 1 + ) { + stats.permDiff_attempt++; + stats.moreMinimLitsStart += learnt_clause.size(); + MYFLAG++; + const auto& ws = watches[~learnt_clause[0]]; + uint32_t nb = 0; + for (const Watched& w: ws) { + if (w.isBin()) { + Lit imp = w.lit2(); + if (permDiff[imp.var()] == MYFLAG && value(imp) == l_True) { + nb++; + permDiff[imp.var()] = MYFLAG - 1; + } + } else { + break; + } + } + uint32_t l = learnt_clause.size() - 1; + if (nb > 0) { + for (uint32_t i = 1; i < learnt_clause.size() - nb; i++) { + if (permDiff[learnt_clause[i].var()] != MYFLAG) { + Lit p = learnt_clause[l]; + learnt_clause[l] = learnt_clause[i]; + learnt_clause[i] = p; + l--; + i--; + } + } + learnt_clause.resize(learnt_clause.size()-nb); + stats.permDiff_success++; + stats.permDiff_rem_lits+=nb; + } + stats.moreMinimLitsEnd += learnt_clause.size(); + } +} + +void Searcher::print_fully_minimized_learnt_clause() const +{ + if (conf.verbosity >= 6) { + cout << "Final clause: " << learnt_clause << endl; + for (uint32_t i = 0; i < learnt_clause.size(); i++) { + cout << "lev learnt_clause[" << i << "]:" << varData[learnt_clause[i].var()].level << endl; + } + } +} + +size_t Searcher::find_backtrack_level_of_learnt() +{ + if (learnt_clause.size() <= 1) + return 0; + else { + uint32_t max_i = 1; + for (uint32_t i = 2; i < learnt_clause.size(); i++) { + if (level(learnt_clause[i]) > level(learnt_clause[max_i])) + max_i = i; + } + std::swap(learnt_clause[max_i], learnt_clause[1]); + return varData[learnt_clause[1].var()].level; + } +} + +template +void Searcher::create_learnt_clause(PropBy confl) +{ + pathC = 0; + int index = trail.size() - 1; + Lit p = lit_Undef; + implied_by_learnts.clear(); + + // Get decision level to go back to + Lit lit0 = lit_Error; + switch (confl.getType()) { + case binary_t : { + lit0 = failBinLit; + break; + } + case xor_t: { + int32_t ID; + auto cl = gmatrices[confl.get_matrix_num()]->get_reason(confl.get_row_num(), ID); + lit0 = (*cl)[0]; + break; + } + case bnn_t : { + vector* cl = get_bnn_reason(bnns[confl.getBNNidx()], lit_Undef); + lit0 = (*cl)[0]; + break; + } + case clause_t : { + Clause* cl = cl_alloc.ptr(confl.get_offset()); + lit0 = (*cl)[0]; + break; + } + default: + assert(false); + } + uint32_t nDecisionLevel = varData[lit0.var()].level; + + // 1st UIP clause generation + learnt_clause.push_back(lit_Undef); //make space for ~p + do { + VERBOSE_PRINT("p is: " << p); + add_lits_to_learnt(confl, p, nDecisionLevel); + + // Select next implication to look at + do { + while (!seen[trail[index--].lit.var()]); + p = trail[index+1].lit; + assert(p != lit_Undef); + } while(trail[index+1].lev < nDecisionLevel); + + confl = varData[p.var()].reason; + assert(varData[p.var()].level > 0); + + //This clears out vars that haven't been added to learnt_clause, + //but their 'seen' has been set + seen[p.var()] = 0; + + //Okay, one more path done + pathC--; + } while (pathC > 0); + assert(pathC == 0); + learnt_clause[0] = ~p; +} + +void Searcher::simple_create_learnt_clause( + PropBy confl, + vector& out_learnt, + bool True_confl +) { + int until = -1; + int mypathC = 0; + Lit p = lit_Undef; + int index = trail.size() - 1; + assert(decisionLevel() == 1); + + do { + switch (confl.getType()) { + case binary_t: { + if (p == lit_Undef && True_confl == false) { + Lit q = failBinLit; + if (!seen[q.var()]) { + seen[q.var()] = 1; + mypathC++; + } + } + Lit q = confl.lit2(); + if (!seen[q.var()]) { + seen[q.var()] = 1; + mypathC++; + } + break; + } + + case bnn_t: + case xor_t: + case clause_t: { + Lit* c; + uint32_t sz; + if (confl.getType() == clause_t) { + auto cl = solver->cl_alloc.ptr(confl.get_offset()); + c = cl->getData(); + sz = cl->size(); + } else if (confl.getType() == bnn_t) { + auto cl = get_bnn_reason(bnns[confl.getBNNidx()], p); + c = cl->data(); + sz = cl->size(); + } else { + int32_t ID; + assert(confl.getType() == xor_t); + vector* cl = gmatrices[confl.get_matrix_num()]-> + get_reason(confl.get_row_num(), ID); + c = cl->data(); + sz = cl->size(); + } + + // if True_confl==true, then choose p begin with the 1st index of c + for (uint32_t j = (p == lit_Undef && True_confl == false) ? 0 : 1 + ; j < sz + ; j++ + ) { + Lit q = c[j]; + assert(q.var() < seen.size()); + if (!seen[q.var()]) { + seen[q.var()] = 1; + mypathC++; + } + } + break; + } + + case null_clause_t: + assert(confl.isNULL()); + out_learnt.push_back(~p); + break; + } + // if not break, while() will come to the index of trail blow 0, and fatal error occur; + if (mypathC == 0) { + break; + } + + // Select next clause to look at: + while (!seen[trail[index--].lit.var()]); + // if the reason cr from the 0-level assigned var, we must break avoid move forth further; + // but attention that maybe seen[x]=1 and never be clear. However makes no matter; + if ((int)trail_lim[0] > index + 1 + && until == -1 + ) { + until = out_learnt.size(); + } + p = trail[index + 1].lit; + confl = varData[p.var()].reason; + + //under normal circumstances this does not happen, but here, it can + //reason is undefined for level 0 + if (varData[p.var()].level == 0) { + confl = PropBy(); + } + seen[p.var()] = 0; + mypathC--; + } while (mypathC >= 0); + + if (until != -1) + out_learnt.resize(until); +} + +void Searcher::print_debug_resolution_data(const PropBy confl) +{ +#ifndef DEBUG_RESOLV + //Avoid unused parameter warning + (void) confl; +#else + cout << "Before resolution, trail is: " << endl; + print_trail(); + cout << "Conflicting clause: " << confl << endl; + cout << "Fail bin lit: " << failBinLit << endl; +#endif +} + +struct vmtf_bump_sort { + vmtf_bump_sort (const vector& _vmtf_btab): + vmtf_btab(_vmtf_btab) + {} + + bool operator () (const uint32_t & a, const uint32_t & b) const + { + return vmtf_btab[a] < vmtf_btab[b]; + } + + const vector& vmtf_btab; +}; + +template +void Searcher::analyze_conflict( + const PropBy confl, + uint32_t& out_btlevel, + uint32_t& glue, + [[maybe_unused]] uint32_t& glue_before_minim, + [[maybe_unused]] uint32_t& size_before_minim +) { + //Set up environment + #if defined(STATS_NEEDED_BRANCH) || defined(FINAL_PREDICTOR_BRANCH) + assert(level_used_for_cl.empty()); + #ifdef SLOW_DEBUG + for(auto& x: level_used_for_cl_arr) { + assert(x == 0); + } + #endif + #endif + + #if defined(STATS_NEEDED) || defined(FINAL_PREDICTOR) + antec_data.clear(); + #endif + + learnt_clause.clear(); + chain.clear(); + assert(toClear.empty()); + implied_by_learnts.clear(); + assert(decisionLevel() > 0); + + print_debug_resolution_data(confl); + create_learnt_clause(confl); + stats.litsRedNonMin += learnt_clause.size(); + #if defined(STATS_NEEDED) || defined(FINAL_PREDICTOR) + glue_before_minim = calc_glue(learnt_clause); + size_before_minim = learnt_clause.size(); + #endif + minimize_learnt_clause(); + stats.litsRedFinal += learnt_clause.size(); + + //further minimisation 1 -- short, small glue clauses + glue = numeric_limits::max(); + if (learnt_clause.size() <= conf.max_size_more_minim) { + glue = calc_glue(learnt_clause); + if (glue <= conf.max_glue_more_minim) { + minimize_using_bins(); + } + } + if (glue == numeric_limits::max()) { + glue = calc_glue(learnt_clause); + } + print_fully_minimized_learnt_clause(); + + if (glue <= (conf.glue_put_lev0_if_below_or_eq+2)) { + bool doit = false; + if (conf.doMinimRedMoreMore == 1 && learnt_clause.size() <= conf.max_size_more_minim) { + doit = true; + } + if (conf.doMinimRedMoreMore == 2 && learnt_clause.size() > conf.max_size_more_minim) { + doit = true; + } + if (conf.doMinimRedMoreMore == 3) { + doit = true; + } + if (doit) { + minimise_redundant_more_more(learnt_clause); + glue = calc_glue(learnt_clause); + } + } + + #ifdef STATS_NEEDED_BRANCH + for(const Lit l: learnt_clause) { + varData[l.var()].inside_conflict_clause++; + varData[l.var()].inside_conflict_clause_glue += glue; + } + vars_used_for_cl.clear(); + for(auto& lev: level_used_for_cl) { + vars_used_for_cl.push_back(trail[trail_lim[lev-1]].lit.var()); + assert(varData[trail[trail_lim[lev-1]].lit.var()].reason == PropBy()); + assert(level_used_for_cl_arr[lev] == 1); + level_used_for_cl_arr[lev] = 0; + } + level_used_for_cl.clear(); + #endif + + out_btlevel = find_backtrack_level_of_learnt(); + if (!inprocess) { + switch(branch_strategy) { + case branch::vsids: + break; + + case branch::vmtf: + std::sort(implied_by_learnts.begin(), + implied_by_learnts.end(), + vmtf_bump_sort(vmtf_btab)); + + for (const auto& v: implied_by_learnts) vmtf_bump_queue(v); + implied_by_learnts.clear(); + break; + + default: + break; + } + } + sumConflictClauseLits += learnt_clause.size(); +} + +bool Searcher::litRedundant(const Lit p, uint32_t abstract_levels) +{ + #ifdef DEBUG_LITREDUNDANT + cout << "c " << __func__ << " called" << endl; + #endif + + analyze_stack.clear(); + analyze_stack.push(p); + uint32_t old_chain_size = chain.size(); + + size_t top = toClear.size(); + while (!analyze_stack.empty()) { + #ifdef DEBUG_LITREDUNDANT + cout << "At point in litRedundant: " << analyze_stack.top() << endl; + #endif + + Lit p_analyze = analyze_stack.top(); + const PropBy reason = varData[analyze_stack.top().var()].reason; + PropByType type = reason.getType(); + analyze_stack.pop(); + + //Must have a reason + assert(!reason.isNULL()); + + int32_t ID; + size_t size; + Lit* lits = NULL; + switch (type) { + case clause_t: { + Clause* cl = cl_alloc.ptr(reason.get_offset()); + lits = cl->begin(); + size = cl->size()-1; + ID = cl->stats.ID; + break; + } + + case xor_t: { + vector* xcl = gmatrices[reason.get_matrix_num()]-> + get_reason(reason.get_row_num(), ID); + lits = xcl->data(); + size = xcl->size()-1; + break; + } + + case bnn_t: { + vector* cl = get_bnn_reason( + bnns[reason.getBNNidx()], + Lit(p_analyze.var(), value(p_analyze.var()) == l_False)); + lits = cl->data(); + size = cl->size()-1; + break; + } + + case binary_t: + size = 1; + ID = reason.getID(); + break; + + case null_clause_t: + default: + release_assert(false); + } + + for (size_t i = 0 + ; i < size + ; i++ + ) { + Lit p2; + switch (type) { + case xor_t: + case bnn_t: + case clause_t: + p2 = lits[i+1]; + break; + + case binary_t: + p2 = reason.lit2(); + break; + + case null_clause_t: + default: + release_assert(false); + } + stats.recMinimCost++; + + if (!seen[p2.var()] && varData[p2.var()].level > 0) { + if (!varData[p2.var()].reason.isNULL() + && (abstractLevel(p2.var()) & abstract_levels) != 0 + ) { + seen[p2.var()] = 1; + analyze_stack.push(p2); + toClear.push_back(p2); + + chain.push_back(ID); + VERBOSE_PRINT("TMP Chain adding ID: " << ID << " due to minimization, litRed on var: " << p2); + } else { + //Return to where we started before function executed + for (size_t j = top; j < toClear.size(); j++) { + seen[toClear[j].var()] = 0; + } + toClear.resize(top); + + VERBOSE_PRINT("Chain clearing past " << chain.size()-old_chain_size << " TMPs."); + chain.resize(old_chain_size); + return false; + } + } + } + } + VERBOSE_PRINT("Chain TMPs were OK, not clearing"); + + return true; +} +template void Searcher::analyze_conflict(const PropBy confl + , uint32_t& out_btlevel + , uint32_t& glue + , uint32_t& glue_before_minim + , uint32_t& size_before_minim +); +template void Searcher::analyze_conflict(const PropBy confl + , uint32_t& out_btlevel + , uint32_t& glue + , uint32_t& glue_before_minim + , uint32_t& size_before_minim +); + +bool Searcher::subset(const vector& A, const Clause& B) +{ + //Set seen + for (uint32_t i = 0; i != B.size(); i++) + seen[B[i].toInt()] = 1; + + bool ret = true; + for (uint32_t i = 0; i != A.size(); i++) { + if (!seen[A[i].toInt()]) { + ret = false; + break; + } + } + + //Clear seen + for (uint32_t i = 0; i != B.size(); i++) + seen[B[i].toInt()] = 0; + + return ret; +} + +void Searcher::analyze_final_confl_with_assumptions(const Lit p, vector& out_conflict) +{ + out_conflict.clear(); + out_conflict.push_back(p); + + if (decisionLevel() == 0) { + return; + } + + //It's been set at level 0. The seen[] may not be large enough to do + //seen[p.var()] -- we might have mem-saved that + if (varData[p.var()].level == 0) { + return; + } + + seen[p.var()] = 1; + + assert(!trail_lim.empty()); + for (int64_t i = (int64_t)trail.size() - 1; i >= (int64_t)trail_lim[0]; i--) { + const uint32_t x = trail[i].lit.var(); + if (seen[x]) { + const PropBy reason = varData[x].reason; + if (reason.isNULL()) { + assert(varData[x].level > 0); + out_conflict.push_back(~trail[i].lit); + } else { + int32_t ID; + switch(reason.getType()) { + case PropByType::clause_t : { + const Clause& cl = *cl_alloc.ptr(reason.get_offset()); + ID = cl.stats.ID; + assert(value(cl[0]) == l_True); + for(const Lit lit: cl) { + if (varData[lit.var()].level > 0) { + seen[lit.var()] = 1; + } + } + break; + } + + case PropByType::bnn_t : { + vector* cl = get_bnn_reason( + bnns[reason.getBNNidx()], lit_Undef); + for(const Lit lit: *cl) { + if (varData[lit.var()].level > 0) { + seen[lit.var()] = 1; + } + } + break; + } + + case PropByType::binary_t: { + const Lit lit = reason.lit2(); + if (varData[lit.var()].level > 0) { + seen[lit.var()] = 1; + } + ID = reason.getID(); + break; + } + + case PropByType::xor_t: { + vector* cl = gmatrices[reason.get_matrix_num()]-> + get_reason(reason.get_row_num(), ID); + assert(value((*cl)[0]) == l_True); + for(const Lit lit: *cl) { + if (varData[lit.var()].level > 0) { + seen[lit.var()] = 1; + } + } + break; + } + + case PropByType::null_clause_t: { + assert(false); + } + } + } + seen[x] = 0; + } + } + seen[p.var()] = 0; + + learnt_clause = out_conflict; + minimize_using_bins(); + out_conflict = learnt_clause; +} + +void Searcher::update_assump_conflict_to_orig_outside(vector& out_conflict) +{ + if (assumptions.empty()) { + return; + } + + vector inter_assumptions; + for(const auto& ass: assumptions) { + inter_assumptions.push_back( + AssumptionPair(map_outer_to_inter(ass.lit_outer), ass.lit_orig_outside)); + } + + std::sort(inter_assumptions.begin(), inter_assumptions.end()); + std::sort(out_conflict.begin(), out_conflict.end()); + assert(out_conflict.size() <= assumptions.size()); + //They now are in the order where we can go through them linearly + + /*cout << "out_conflict: " << out_conflict << endl; + cout << "assumptions: "; + for(AssumptionPair p: assumptions) { + cout << "inter: " << p.lit_inter << " , outer: " << p.lit_orig_outside << " , "; + } + cout << endl;*/ + + uint32_t at_assump = 0; + uint32_t j = 0; + for(size_t i = 0; i < out_conflict.size(); i++) { + Lit lit = out_conflict[i]; + + //lit_outer is actually INTER here, because we updated above + while(lit != ~inter_assumptions[at_assump].lit_outer) { + at_assump++; + assert(at_assump < inter_assumptions.size() && "final conflict contains literals that are not from the assumptions!"); + } + assert(lit == ~inter_assumptions[at_assump].lit_outer); + + //in case of symmetry breaking, we can be in trouble + //then, the orig_outside is actually lit_Undef + //in these cases, the symmetry breaking literal needs to be taken out + if (inter_assumptions[at_assump].lit_orig_outside != lit_Undef) { + //Update to correct outside lit + out_conflict[j++] = ~inter_assumptions[at_assump].lit_orig_outside; + } + } + out_conflict.resize(j); +} + +void Searcher::check_blocking_restart() +{ + if (conf.do_blocking_restart + && sumConflicts > conf.lower_bound_for_blocking_restart + && hist.glueHist.isvalid() + && hist.trailDepthHistLonger.isvalid() + && decisionLevel() > 0 + && trail_lim.size() > 0 + && trail.size() > hist.trailDepthHistLonger.avg()*conf.blocking_restart_multip + ) { + hist.glueHist.clear(); + if (!blocked_restart) { + stats.blocked_restart_same++; + } + blocked_restart = true; + stats.blocked_restart++; + } +} + +void Searcher::print_order_heap() +{ + switch(branch_strategy) { + case branch::vsids: + cout << "vsids heap size: " << order_heap_vsids.size() << endl; + cout << "vsids acts: "; + for(auto x: var_act_vsids) { + cout << std::setprecision(12) << x << " "; + } + cout << endl; + cout << "VSIDS order heap: " << endl; + order_heap_vsids.print_heap(); + break; + + case branch::rand: + cout << "rand heap size: " << order_heap_rand.size() << endl; + cout << "rand order heap: " << endl; + order_heap_rand.print_heap(); + break; + + case branch::vmtf: + cout << "vmtf order printing not implemented yet." << endl; + break; + } +} + +void Searcher::check_need_gauss_jordan_disable() +{ + for(uint32_t i = 0; i < gqueuedata.size(); i++) { + auto& gqd = gqueuedata[i]; + if (gqd.disabled) continue; + + if (conf.gaussconf.autodisable && + !conf.xor_detach_reattach && + gmatrices[i]->must_disable(gqd) + ) gqd.disabled = true; + + gqd.reset(); + gmatrices[i]->update_cols_vals_set(); + } +} + +lbool Searcher::search() +{ + assert(ok); + #ifdef SLOW_DEBUG + check_no_zero_ID_bins(); + check_no_duplicate_lits_anywhere(); + check_order_heap_sanity(); + #endif + const double myTime = cpuTime(); + + //Stats reset & update + stats.numRestarts++; + hist.clear(); + hist.reset_glueHist_size(conf.shortTermHistorySize); + + assert(solver->prop_at_head()); + + //Loop until restart or finish (SAT/UNSAT) + PropBy confl; + lbool search_ret = l_Undef; + +// VERBOSE_PRINT(print_order_heap()); + while (!params.needToStopSearch + || !confl.isNULL() //always finish the last conflict + ) { + confl = PropBy(); + #ifdef USE_GPU + confl = solver->datasync->pop_clauses(); + #endif + if (!solver->okay()) { + search_ret = l_False; + goto end; + } + if (confl.isNULL()) { + confl = propagate(); + } + + if (!confl.isNULL()) { + #if defined(STATS_NEEDED) || defined(FINAL_PREDICTOR) + hist.trailDepthHist.push(trail.size()); + #endif + hist.trailDepthHistLonger.push(trail.size()); + if (!handle_conflict(confl)) { + search_ret = l_False; + goto end; + } + check_need_restart(); + check_need_gauss_jordan_disable(); + } else { + assert(ok); + if (decisionLevel() == 0) { + SLOW_DEBUG_DO(for(const auto& bnn: bnns) if (bnn) assert(solver->check_bnn_sane(*bnn));); + if (!clean_clauses_if_needed()) { + search_ret = l_False; + goto end; + } + } + reduce_db_if_needed(); + lbool dec_ret; + if (fast_backw.fast_backw_on) { + dec_ret = new_decision_fast_backw(); + } else { + dec_ret = new_decision(); + } + if (dec_ret != l_Undef) { + search_ret = dec_ret; + goto end; + } + } + } + max_confl_this_restart -= (int64_t)params.conflictsDoneThisRestart; + + cancelUntil(0); + confl = propagate(); + if (!confl.isNULL()) { + ok = false; + search_ret = l_False; + goto end; + } + assert(solver->prop_at_head()); + if (!solver->datasync->syncData()) { + search_ret = l_False; + goto end; + } + assert(search_ret == l_Undef); + SLOW_DEBUG_DO(check_no_zero_ID_bins()); + SLOW_DEBUG_DO(check_no_duplicate_lits_anywhere()); + SLOW_DEBUG_DO(assert(check_order_heap_sanity())); + + end: + print_restart_stat(); + dump_search_loop_stats(myTime); + return search_ret; +} + +void Searcher::dump_search_sql(const double myTime) +{ + if (solver->sqlStats) { + solver->sqlStats->time_passed_min( + solver + , "search" + , cpuTime()-myTime + ); + } +} + +/** +@brief Picks a new decision variable to branch on + +@returns l_Undef if it should restart instead. l_False if it reached UNSAT + (through simplification) +*/ +template +lbool Searcher::new_decision() +{ +#ifdef SLOW_DEBUG + assert(solver->prop_at_head()); +#endif + Lit next = lit_Undef; + while (decisionLevel() < assumptions.size()) { + // Perform user provided assumption: + const Lit p = map_outer_to_inter(assumptions[decisionLevel()].lit_outer); + #ifdef SLOW_DEBUG + assert(varData[p.var()].removed == Removed::none); + #endif + + if (value(p) == l_True) { + // Dummy decision level: + new_decision_level(); + } else if (value(p) == l_False) { + analyze_final_confl_with_assumptions(~p, conflict); + return l_False; + } else { + assert(p.var() < nVars()); + stats.decisionsAssump++; + next = p; + break; + } + } + + if (next == lit_Undef) { + // New variable decision: + next = pickBranchLit(); + + //No decision taken, because it's SAT + if (next == lit_Undef) + return l_True; + + //Update stats + stats.decisions++; + sumDecisions++; + } + + // Increase decision level and enqueue 'next' + assert(value(next) == l_Undef); + new_decision_level(); + enqueue(next); + + return l_Undef; +} + +void Searcher::update_history_stats( + size_t backtrack_level, + uint32_t glue, + uint32_t connects_num_communities +) { + assert(decisionLevel() > 0); + + //short-term averages + hist.branchDepthHist.push(decisionLevel()); + #if defined(STATS_NEEDED) || defined(FINAL_PREDICTOR) + hist.backtrackLevelHist.push(backtrack_level); + hist.branchDepthHistQueue.push(decisionLevel()); + hist.numResolutionsHist.push(antec_data.num()); + #endif + hist.branchDepthDeltaHist.push(decisionLevel() - backtrack_level); + hist.conflSizeHist.push(learnt_clause.size()); + hist.trailDepthDeltaHist.push(trail.size() - trail_lim[backtrack_level]); + + //long-term averages + #if defined(STATS_NEEDED) || defined(FINAL_PREDICTOR) + hist.numResolutionsHistLT.push(antec_data.num()); + hist.decisionLevelHistLT.push(decisionLevel()); + const uint32_t overlap = antec_data.sum_size()-(antec_data.num()-1)-learnt_clause.size(); + hist.antec_data_sum_sizeHistLT.push(antec_data.sum_size()); + hist.overlapHistLT.push(overlap); + #endif + hist.backtrackLevelHistLT.push(backtrack_level); + hist.conflSizeHistLT.push(learnt_clause.size()); + hist.trailDepthHistLT.push(trail.size()); + if (params.rest_type == Restart::glue) { + hist.glueHistLTLimited.push( + std::min(glue, conf.max_glue_cutoff_gluehistltlimited)); + } + hist.glueHistLT.push(glue); + hist.glueHist.push(glue); + hist.connects_num_communities_histLT.push(connects_num_communities); + + //Global stats from cnf.h + sumClLBD += glue; + sumClSize += learnt_clause.size(); +} + +template +void Searcher::attach_and_enqueue_learnt_clause( + Clause* cl, const uint32_t level, const bool enq, + const uint64_t ID) +{ + VERBOSE_DEBUG_DO(print_learning_debug_info(ID)); + switch (learnt_clause.size()) { + case 0: + assert(false); + case 1: + //Unit learnt + stats.learntUnits++; + if (enq) { + assert(level == 0); + uint32_t v = learnt_clause[0].var(); + if (frat->enabled()) { + assert(unit_cl_IDs[v] == 0); + assert(ID != 0); + unit_cl_IDs[v] = ID; + } + enqueue(learnt_clause[0], level, PropBy(), false); + } + break; + case 2: + //Binary learnt + stats.learntBins++; + //solver->datasync->signalNewBinClause(learnt_clause); + solver->attach_bin_clause(learnt_clause[0], learnt_clause[1], true, ID, enq); + if (enq) enqueue(learnt_clause[0], level, PropBy(learnt_clause[1], true, ID)); + break; + + default: + //Long learnt + stats.learntLongs++; + solver->attachClause(*cl, enq); + if (enq) enqueue(learnt_clause[0], level, PropBy(cl_alloc.get_offset(cl))); + #if !defined(STATS_NEEDED) && !defined(FINAL_PREDICTOR) + if (cl->stats.which_red_array == 2) + #endif + bump_cl_act(cl); + + #ifdef STATS_NEEDED + red_stats_extra[cl->stats.extra_pos].antec_data = antec_data; + #endif + + break; + } +} + +void Searcher::print_learning_debug_info(const int32_t ID) const +{ + cout + << "Learning: " << learnt_clause << " ID: " << ID + << " -- reverting var " << learnt_clause[0].var()+1 + << " to " << !learnt_clause[0].sign() + << endl; +} + +void Searcher::print_learnt_clause() const +{ + if (conf.verbosity >= 6) { + cout + << "c learnt clause: " + ; + for(Lit l: learnt_clause) { + cout << l << ": " << value(l) << " "; + } + cout << endl; + } +} + +#ifdef STATS_NEEDED_BRANCH +void Searcher::dump_var_for_learnt_cl(const uint32_t v, + const uint64_t clid, + const bool is_decision) +{ + //When it's a decision clause, the REAL clause could have already + //set some variable to having been propagated (due to asserting clause) + //so this assert() no longer holds for all literals + assert(is_decision || varData[v].reason == PropBy()); + if (varData[v].dump) { + uint64_t outer_var = map_inter_to_outer(v); + solver->sqlStats->dec_var_clid( + outer_var + , varData[v].sumConflicts_at_picktime + , clid + ); + } +} +#endif + +#ifdef STATS_NEEDED +void Searcher::dump_sql_clause_data( + const uint32_t glue + , const uint32_t size + , const uint32_t glue_before_minim + , const uint32_t size_before_minim + , const uint32_t old_decision_level + , const uint64_t clid + , const bool is_decision + , const uint32_t connects_num_communities +) { + + #ifdef STATS_NEEDED_BRANCH + if (is_decision) { + for(Lit l: learnt_clause) { + dump_var_for_learnt_cl(l.var(), clid, is_decision); + } + } else { + for(uint32_t v: vars_used_for_cl) { + dump_var_for_learnt_cl(v, clid, is_decision); + } + } + #endif + + solver->sqlStats->clause_stats( + solver + , clid + , restartID + , glue + , glue_before_minim + , size + , size_before_minim + , decisionLevel() + , antec_data + , old_decision_level + , trail.size() + , params.conflictsDoneThisRestart + , (int)params.rest_type + , hist + , is_decision + , connects_num_communities + ); +} +#endif + +#ifdef FINAL_PREDICTOR +void Searcher::set_clause_data( + Clause* cl + , const uint32_t orig_glue + , const uint32_t glue_before_minim + , const uint32_t old_decision_level +) { + assert(cl->red()); + auto& stats_extra = red_stats_extra[cl->stats.extra_pos]; + + //definitely a BUG here I think -- should be 2*antec_data.num(), no? + //however, it's the same as how it's dumped in sqlitestats.cpp + //stats_extra.num_overlap_literals = antec_data.sum_size()-(antec_data.num()-1)-cl->size(); + + + stats_extra.glueHist_longterm_avg = hist.glueHist.getLongtTerm().avg(); + stats_extra.glueHist_avg = hist.glueHist.avg_nocheck(); + stats_extra.trail_depth_level = trail.size(); + stats_extra.glue_before_minim = glue_before_minim; + stats_extra.overlapHistLT_avg = hist.overlapHistLT.avg(); + stats_extra.num_total_lits_antecedents = antec_data.sum_size(); + stats_extra.num_antecedents = antec_data.num(); + stats_extra.numResolutionsHistLT_avg = hist.numResolutionsHistLT.avg(); + stats_extra.conflSizeHist_avg = hist.conflSizeHist.avg(); + stats_extra.glueHistLT_avg = hist.glueHistLT.avg(); + stats_extra.antecedents_binred = antec_data.binRed; + stats_extra.antecedents_binIrred = antec_data.binIrred; + + stats_extra.orig_glue = orig_glue; +// stats_extra.conflSizeHistLT_avg = hist.conflSizeHistLT.avg(); +// stats_extra.branchDepthHistQueue_avg = hist.branchDepthHistQueue.avg_nocheck(); + +} +#endif + +#ifdef STATS_NEEDED +template +uint32_t Searcher::calc_connects_num_communities(const T& cl) +{ + assert(toClear.empty()); + uint32_t connects_num_communities = 0; + for(const auto l: cl) { + uint32_t comm = varData[l.var()].community_num; + if (comm == numeric_limits::max()) { + continue; + } + assert(comm < solver->nVars()); + if (!seen[comm]) { + connects_num_communities++; + toClear.push_back(Lit(comm, 0)); + seen[comm] = 1; + } + } + + for(auto& t: toClear) { + seen[t.var()] = 0; + } + toClear.clear(); + + return connects_num_communities; +} + +template uint32_t Searcher::calc_connects_num_communities(const Clause& cl); +#endif + +Clause* Searcher::handle_last_confl( + const uint32_t glue, + [[maybe_unused]] const uint32_t old_decision_level, + [[maybe_unused]] const uint32_t glue_before_minim, + [[maybe_unused]] const uint32_t size_before_minim, + [[maybe_unused]] const bool is_decision, + [[maybe_unused]] const uint32_t connects_num_communities, + int32_t& ID +) { + #ifdef STATS_NEEDED + bool to_track = false; + double myrnd = mtrand.randDblExc(); + //Unfortunately, we have to change the ratio data dumped as time goes on + //or we run out of space on CNFs that take millions(!) of conflicts + //to solve, such as e_rphp035_05.cnf + double decaying_ratio = (8000.0*1000.0)/((double)sumConflicts+1); + if (decaying_ratio > 1.0) { + decaying_ratio = 1.0; + } else { + //Make it more-than-linearly less + decaying_ratio = ::pow(decaying_ratio, 1.1); + } + if (learnt_clause.size() > 2 && myrnd <= (conf.dump_individual_cldata_ratio*decaying_ratio)) { + to_track = true; + } + #endif + + Clause* cl; + ID = ++clauseID; + *frat << add << ID << learnt_clause; + if (!chain.empty()) { + *frat << DratFlag::chain; + for(auto const& c: chain) *frat << c; + } + *frat << fin; + VERBOSE_PRINT("Chain ID created: " << ID); + + if (learnt_clause.size() <= 2) { + cl = NULL; + } else { + cl = cl_alloc.Clause_new(learnt_clause + , sumConflicts + , ID + ); + cl->isRed = true; + cl->stats.glue = glue; + cl->stats.ID = ID; + #if defined(STATS_NEEDED) || defined(FINAL_PREDICTOR) + red_stats_extra.push_back(ClauseStatsExtra()); + cl->stats.extra_pos = red_stats_extra.size()-1; + auto& ext_stats = red_stats_extra[cl->stats.extra_pos]; + ext_stats.introduced_at_conflict = sumConflicts; + ext_stats.orig_glue = glue; + ext_stats.orig_size = cl->size(); + #endif + #ifdef STATS_NEEDED + cl->stats.is_tracked = to_track; + if (cl->stats.is_tracked) ext_stats.orig_ID = ID; + if (sqlStats) sqlStats->update_id(ID, ID); // this is how we know it's tracked + #endif + cl->stats.activity = 0.0f; + ClOffset offset = cl_alloc.get_offset(cl); + unsigned which_arr = 2; + + #ifdef STATS_NEEDED + ext_stats.connects_num_communities = connects_num_communities; + ext_stats.orig_connects_num_communities = connects_num_communities; + cl->stats.locked_for_data_gen = + mtrand.randDblExc() < conf.lock_for_data_gen_ratio; + #endif + + + #ifndef FINAL_PREDICTOR + if (cl->stats.locked_for_data_gen) { + which_arr = 0; + } else if (glue <= conf.glue_put_lev0_if_below_or_eq) { + which_arr = 0; + } else if ( + glue <= conf.glue_put_lev1_if_below_or_eq + && conf.glue_put_lev1_if_below_or_eq != 0 + ) { + which_arr = 1; + } else { + which_arr = 2; + } + #else + which_arr = 2; + #endif + + if (which_arr == 0) { + stats.red_cl_in_which0++; + } + + cl->stats.which_red_array = which_arr; + solver->longRedCls[cl->stats.which_red_array].push_back(offset); + } + + #ifdef STATS_NEEDED + if (solver->sqlStats + && frat + && conf.dump_individual_restarts_and_clauses + && to_track + ) { + assert(cl); //we only dump non-binaries to SQL + dump_this_many_cldata_in_stream--; + dump_sql_clause_data( + glue + , learnt_clause.size() + , glue_before_minim + , size_before_minim + , old_decision_level + , ID + , is_decision + , connects_num_communities + ); + } + #endif + + if (cl) { + #ifdef FINAL_PREDICTOR + set_clause_data(cl, glue, glue_before_minim, old_decision_level); + #endif + cl->stats.is_decision = is_decision; + } + + return cl; +} + +bool Searcher::handle_conflict(PropBy confl) +{ + stats.conflicts++; + hist.num_conflicts_this_restart++; + sumConflicts++; + for(uint32_t i = 0; i < longRedCls.size(); i++) { + longRedClsSizes[i] += longRedCls[i].size(); + } + params.conflictsDoneThisRestart++; + + ConflictData data = find_conflict_level(confl); + if (data.nHighestLevel == 0) { + if (conf.verbosity >= 10) { + cout << "c find_conflict_level() gives 0, so UNSAT for whole formula. decLevel: " << decisionLevel() << endl; + } + // the propagate() will not add the UNSAT clause if it's not decision level 0 + if (decisionLevel() != 0) { + *frat << add << ++clauseID << fin; + unsat_cl_ID = clauseID; + } + solver->ok = false; + return false; + } + + uint32_t backtrack_level; + uint32_t glue; + uint32_t glue_before_minim; + uint32_t size_before_minim; + analyze_conflict( + confl + , backtrack_level //return backtrack level here + , glue //return glue here + , glue_before_minim //return glue before minimization here + , size_before_minim //return glue before minimization here + ); + solver->datasync->signal_new_long_clause(learnt_clause); + #ifdef USE_GPU + solver->datasync->trySendAssignmentToGpu(); + #endif + + uint32_t connects_num_communities = 0; + #ifdef STATS_NEEDED + connects_num_communities = calc_connects_num_communities(learnt_clause); + #endif + print_learnt_clause(); + + update_history_stats(backtrack_level, glue, connects_num_communities); + uint32_t old_decision_level = decisionLevel(); + + //Add decision-based clause in case it's short + decision_clause.clear(); + if (conf.do_decision_based_cl + && learnt_clause.size() > conf.decision_based_cl_min_learned_size + && decisionLevel() <= conf.decision_based_cl_max_levels + && decisionLevel() >= 2 + ) { + chain.clear(); + for(int i = (int)trail_lim.size()-1; i >= 0; i--) { + Lit l = ~trail[trail_lim[i]].lit; + if (!seen[l.toInt()]) { + decision_clause.push_back(l); + seen[l.toInt()] = 1; + } + } + for(Lit l: decision_clause) { + seen[l.toInt()] = 0; + assert(varData[l.var()].reason == PropBy()); + } + } + + // check chrono backtrack condition + if (conf.diff_declev_for_chrono > -1 + && bnns.empty() + && (((int)decisionLevel() - (int)backtrack_level) >= conf.diff_declev_for_chrono) + ) { + chrono_backtrack++; + cancelUntil(data.nHighestLevel -1); + } else { + non_chrono_backtrack++; + cancelUntil(backtrack_level); + } + + assert(value(learnt_clause[0]) == l_Undef); + glue = std::min(glue, numeric_limits::max()); + int32_t ID; + Clause* cl = handle_last_confl( + glue, + old_decision_level, + glue_before_minim, + size_before_minim, + false, // is decision? + connects_num_communities, + ID + ); + attach_and_enqueue_learnt_clause(cl, backtrack_level, true, ID); + + //Add decision-based clause + if (decision_clause.size() > 0) { + chain.clear(); + int i = decision_clause.size(); + while(--i >= 0) { + if (value(decision_clause[i]) == l_True + || value(decision_clause[i]) == l_Undef + ) { + break; + } + } + std::swap(decision_clause[0], decision_clause[i]); + + learnt_clause = decision_clause; + print_learnt_clause(); + cl = handle_last_confl( + learnt_clause.size(), // glue is the number of decisions, i.e. the size of decision clause + old_decision_level, + learnt_clause.size(), // minimized glue is the same as glue before minim + learnt_clause.size(), + true, // is decision? + #ifdef STATS_NEEDED + calc_connects_num_communities(learnt_clause), + #else + 0, + #endif + ID + ); + attach_and_enqueue_learnt_clause(cl, backtrack_level, false, ID); + } + + if (branch_strategy == branch::vsids) { + vsids_decay_var_act(); + } + decayClauseAct(); + + return true; +} + +void Searcher::resetStats() +{ + startTime = cpuTime(); + + //Rest solving stats + stats.clear(); + propStats.clear(); + #ifdef STATS_NEEDED + lastSQLPropStats = propStats; + lastSQLGlobalStats = stats; + #endif + + lastCleanZeroDepthAssigns = trail.size(); +} + +#ifdef STATS_NEEDED +void Searcher::check_calc_satzilla_features(bool force) +{ + if (last_satzilla_feature_calc_confl == 0 + || (last_satzilla_feature_calc_confl + solver->conf.every_pred_reduce) < sumConflicts + || force + ) { + last_satzilla_feature_calc_confl = sumConflicts+1; + if (nVars() > 2 + && longIrredCls.size() > 1 + && (binTri.irredBins + binTri.redBins) > 1 + ) { + solver->last_solve_satzilla_feature = solver->calculate_satzilla_features(); + } + } +} +#endif + +#ifdef STATS_NEEDED_BRANCH +void Searcher::check_calc_vardist_features(bool force) +{ + if (!solver->sqlStats) { + return; + } + + if (last_vardist_feature_calc_confl == 0 + || (last_vardist_feature_calc_confl + solver->conf.every_pred_reduce) < sumConflicts + || force + ) { + last_vardist_feature_calc_confl = sumConflicts+1; + VarDistGen v(solver); + v.calc(); + latest_vardist_feature_calc++; + v.dump(); + } +} +#endif + +void Searcher::print_restart_header() +{ + //Print restart output header + if (((lastRestartPrintHeader == 0 && sumConflicts > 200) || + (lastRestartPrintHeader + 1600000) < sumConflicts) + && conf.verbosity + ) { + cout + << "c" + << " " << std::setw(4) << "res" + << " " << std::setw(4) << "pol" + << " " << std::setw(4) << "bran" + << " " << std::setw(5) << "nres" + << " " << std::setw(5) << "conf" + << " " << std::setw(5) << "freevar" + << " " << std::setw(5) << "IrrL" + << " " << std::setw(5) << "IrrB" + << " " << std::setw(7) << "l/longC" + << " " << std::setw(7) << "l/allC"; + + for(size_t i = 0; i < longRedCls.size(); i++) { + cout << " " << std::setw(4) << "RedL" << i; + } + + cout + << " " << std::setw(5) << "RedB" + << " " << std::setw(7) << "l/longC" + << " " << std::setw(7) << "l/allC" + << endl; + lastRestartPrintHeader = sumConflicts+1; + } +} + +void Searcher::print_restart_stat_line() const +{ + print_restart_stats_base(); + if (conf.print_full_restart_stat) { + solver->print_clause_stats(); + hist.print(); + } else { + solver->print_clause_stats(); + } + + cout << endl; +} + +void Searcher::print_restart_stats_base() const +{ + cout << "c rst " + << " " << std::setw(4) << restart_type_to_short_string(params.rest_type) + << " " << std::setw(4) << polarity_mode_to_short_string(polarity_mode) + << " " << std::setw(4) << branch_strategy_str_short + << " " << std::setw(5) << sumRestarts(); + + if (sumConflicts > 20000) { + cout << " " << std::setw(4) << sumConflicts/1000 << "K"; + } else { + cout << " " << std::setw(5) << sumConflicts; + } + + cout << " " << std::setw(7) << solver->get_num_free_vars(); +} + +struct MyInvSorter { + bool operator()(size_t num, size_t num2) + { + return num > num2; + } +}; + +struct MyPolarData +{ + MyPolarData (size_t _pos, size_t _neg, size_t _flipped) : + pos(_pos) + , neg(_neg) + , flipped(_flipped) + {} + + size_t pos; + size_t neg; + size_t flipped; + + bool operator<(const MyPolarData& other) const + { + return (pos + neg) > (other.pos + other.neg); + } +}; + +#ifdef STATS_NEEDED +inline void Searcher::dump_restart_sql(rst_dat_type type, int64_t clauseID) +{ + //don't dump twice for var + if (type == rst_dat_type::var) { + if (last_dumped_conflict_rst_data_for_var == solver->sumConflicts) { + return; + } + last_dumped_conflict_rst_data_for_var = solver->sumConflicts; + } + + //Propagation stats + PropStats thisPropStats = propStats - lastSQLPropStats; + SearchStats thisStats = stats - lastSQLGlobalStats; + solver->sqlStats->restart( + restartID + , params.rest_type + , thisPropStats + , thisStats + , solver + , this + , type + , (int64_t)clauseID + ); + + if (type == rst_dat_type::norm) { + lastSQLPropStats = propStats; + lastSQLGlobalStats = stats; + } +} +#endif + +void Searcher::print_restart_stat() +{ + //Print restart stat + if (conf.verbosity + && !conf.print_all_restarts +// && ((lastRestartPrint + conf.print_restart_line_every_n_confl) +// < sumConflicts) + ) { + print_restart_stat_line(); + lastRestartPrint = sumConflicts; + } +} + +void Searcher::reset_temp_cl_num() +{ + cur_max_temp_red_lev2_cls = conf.max_temp_lev2_learnt_clauses; +} + +void Searcher::reduce_db_if_needed() +{ + #ifdef NORMAL_CL_USE_STATS + if (conf.every_pred_reduce != 0 + && sumConflicts >= next_pred_reduce + ) { + solver->reduceDB->gather_normal_cl_use_stats(); + next_pred_reduce = sumConflicts + conf.every_pred_reduce; + } + #endif + + #if defined(STATS_NEEDED) || defined(FINAL_PREDICTOR) + if (conf.every_pred_reduce != 0 + && sumConflicts >= next_pred_reduce + ) { + #ifdef STATS_NEEDED + if (solver->sqlStats) { + solver->reduceDB->dump_sql_cl_data((int)params.rest_type); + } + #endif + #ifdef FINAL_PREDICTOR + solver->reduceDB->handle_predictors(); + cl_alloc.consolidate(solver); + #endif + next_pred_reduce = sumConflicts + conf.every_pred_reduce; + } + #endif + + #ifndef FINAL_PREDICTOR + if (conf.every_lev1_reduce != 0 + && sumConflicts >= next_lev1_reduce + ) { + solver->reduceDB->handle_lev1(); + next_lev1_reduce = sumConflicts + conf.every_lev1_reduce; + } + + if (conf.every_lev2_reduce != 0) { + if (sumConflicts >= next_lev2_reduce) { + solver->reduceDB->handle_lev2(); + cl_alloc.consolidate(solver); + next_lev2_reduce = sumConflicts + conf.every_lev2_reduce; + } + } else { + if (longRedCls[2].size() > cur_max_temp_red_lev2_cls) { + solver->reduceDB->handle_lev2(); + cur_max_temp_red_lev2_cls *= conf.inc_max_temp_lev2_red_cls; + cl_alloc.consolidate(solver); + } + } + #endif +} + +bool Searcher::clean_clauses_if_needed() +{ + #ifdef SLOW_DEBUG + assert(decisionLevel() == 0); + assert(qhead == trail.size()); + #endif + + const size_t newZeroDepthAss = trail.size() - lastCleanZeroDepthAssigns; + if (newZeroDepthAss > 0 + && simpDB_props < 0 + && newZeroDepthAss > ((double)nVars()*0.05) + ) { + if (conf.verbosity >= 2) { + cout << "c newZeroDepthAss : " << newZeroDepthAss + << " -- " + << (double)newZeroDepthAss/(double)nVars()*100.0 + << " % of active vars" + << endl; + } + lastCleanZeroDepthAssigns = trail.size(); + if (!solver->clauseCleaner->remove_and_clean_all()) { + return false; + } + + cl_alloc.consolidate(solver); + simpDB_props = (litStats.redLits + litStats.irredLits)<<5; + } + + return okay(); +} + +void Searcher::rebuildOrderHeap() +{ + if (conf.verbosity) { + cout << "c [branch] rebuilding order heap for all branchings. Current branching: " << + branch_type_to_string(branch_strategy) << endl; + } + vector vs; + vs.reserve(nVars()); + for (uint32_t v = 0; v < nVars(); v++) { + if (varData[v].removed != Removed::none + || (value(v) != l_Undef && varData[v].level == 0) + ) { + continue; + } else { + vs.push_back(v); + } + } + + VERBOSE_PRINT("c [branch] Rebuilding VSDIS order heap"); + order_heap_vsids.build(vs); + + VERBOSE_PRINT("c [branch] Rebuilding RAND order heap"); + order_heap_rand.build(vs); + + VERBOSE_PRINT("c [branch] Rebuilding VMTF order heap"); + rebuildOrderHeapVMTF(vs); +} + +void Searcher::rebuildOrderHeapVMTF(vector& vs) +{ + std::sort(vs.begin(), vs.end(), + [&](const uint32_t& a, const uint32_t& b) -> bool + { + return vmtf_btab[a] < vmtf_btab[b]; //reverse order is needed for enqueue alter + }); + + vmtf_queue = Queue(); + vmtf_btab.clear(); + vmtf_links.clear(); + vmtf_btab.insert(vmtf_btab.end(), nVars(), 0); + vmtf_links.insert(vmtf_links.end(), nVars(), Link()); + + for(auto const& v: vs) vmtf_init_enqueue(v); +} + +struct branch_type_total{ + branch_type_total() {} + branch_type_total (CMSat::branch _branch, + string _descr, string _descr_short) : + branch(_branch), + descr(_descr), + descr_short(_descr_short) + {} + explicit branch_type_total(CMSat::branch _branch) : + branch(_branch) + {} + + CMSat::branch branch = CMSat::branch::vsids; + string descr; + string descr_short; +}; + +void Searcher::setup_branch_strategy() +{ + if (sumConflicts < branch_strategy_change) return; + branch_strategy_change += 5000; + branch_strategy_change *= 1.1; + branch_strategy_at++; + + size_t smallest = 0; + size_t start = 0; + vector select; + if (conf.verbosity >= 3) { + cout << "c [branch] orig text: " << conf.branch_strategy_setup << endl; + cout << "c [branch] selection: "; + } + + while(smallest !=std::string::npos) { + smallest = std::string::npos; + + size_t vsids = conf.branch_strategy_setup.find("vsids", start); + smallest = std::min(vsids, smallest); + + size_t vmtf = conf.branch_strategy_setup.find("vmtf", start); + smallest = std::min(vmtf, smallest); + + size_t rand = conf.branch_strategy_setup.find("rand", start); + smallest = std::min(rand, smallest); + + if (smallest == std::string::npos) { + break; + } + + if (conf.verbosity >= 3 && !select.empty()) { + cout << "+"; + } + + + if (smallest == vsids) { + select.push_back(branch_type_total(branch::vsids, "VSIDS", "vs")); + if (conf.verbosity >= 3) cout << select[select.size()-1].descr; + } + else if (smallest == vmtf) { + select.push_back(branch_type_total(branch::vmtf, "VMTF", "vmt")); + if (conf.verbosity >= 3) cout << select[select.size()-1].descr; + } + else if (smallest == rand) { + select.push_back(branch_type_total(branch::rand, "RAND", "rand")); + if (conf.verbosity >= 3) cout << select[select.size()-1].descr; + } else { + assert(false); + } + + //Search for next one. The strings are quite distinct, this works. + start = smallest + 3; + } + if (conf.verbosity >= 3) { + cout << " -- total: " << select.size() << endl; + } + + assert(!select.empty()); + + uint32_t which = branch_strategy_at % select.size(); + const auto old_branch_strategy = branch_strategy; + branch_strategy = select[which].branch; + branch_strategy_str = select[which].descr; + branch_strategy_str_short = select[which].descr_short; + setup_restart_strategy(true); + + verb_print(1, "[branch]" + << " adjusting to: " << branch_type_to_string(branch_strategy) + << " (from: " << branch_type_to_string(old_branch_strategy) << ")" + << " var_decay:" << var_decay + << " descr: " << select[which].descr); +} + +inline void Searcher::dump_search_loop_stats(double myTime) +{ + #if defined(STATS_NEEDED) + check_calc_satzilla_features(); + #if defined(STATS_NEEDED_BRANCH) + check_calc_vardist_features(); + #endif + #endif + + print_restart_header(); + dump_search_sql(myTime); + if (conf.verbosity && conf.print_all_restarts) { + print_restart_stat_line(); + } + #ifdef STATS_NEEDED + if (sqlStats + && conf.dump_individual_restarts_and_clauses + ) { + dump_restart_sql(rst_dat_type::norm); + } + #endif + restartID++; +} + +bool Searcher::must_abort(const lbool status) { + if (status != l_Undef) { + if (conf.verbosity >= 6) { + cout + << "c Returned status of search() is " << status << " at confl:" + << sumConflicts + << endl; + } + return true; + } + + if (stats.conflicts >= max_confl_per_search_solve_call) { + if (conf.verbosity >= 3) { + cout + << "c search over max conflicts" + << endl; + } + return true; + } + + if (cpuTime() >= conf.maxTime) { + if (conf.verbosity >= 3) { + cout + << "c search over max time" + << endl; + } + return true; + } + + if (solver->must_interrupt_asap()) { + if (conf.verbosity >= 3) { + cout + << "c search interrupting as requested" + << endl; + } + return true; + } + + return false; +} + +void Searcher::setup_polarity_strategy() +{ + if (sumConflicts < polarity_strategy_change) return; + polarity_strategy_change = sumConflicts + 5000; + polarity_strategy_change *= 1.01; + polarity_strategy_at++; + + if ((polarity_strategy_at % 8) == 0) { + for(auto& v: varData) { + unif_uint_dist(u, 1); + v.best_polarity = u(mtrand); + v.stable_polarity = u(mtrand); + v.saved_polarity = u(mtrand); + } + } + + //Set to default first + polarity_mode = conf.polarity_mode; + if (conf.polarity_mode == PolarityMode::polarmode_automatic) { + longest_trail_ever_stable = 0; + + if ((polarity_strategy_at % 4) == 0) { + polarity_mode = PolarityMode::polarmode_best; + params.rest_type = Restart::geom; + increasing_phase_size = (double)increasing_phase_size * conf.restart_inc; + max_confl_this_restart = increasing_phase_size; + } + if ((polarity_strategy_at % 4) == 1) polarity_mode = PolarityMode::polarmode_stable; + if ((polarity_strategy_at % 4) == 2) polarity_mode = PolarityMode::polarmode_best_inv; + if ((polarity_strategy_at % 4) == 3) polarity_mode = PolarityMode::polarmode_saved; +// if ((polarity_strategy_at % 5) == 4) polarity_mode = PolarityMode::polarmode_neg; +// if ((polarity_strategy_at % 5) == 4) polarity_mode = PolarityMode::polarmode_pos; + } + + if (conf.verbosity >= 2) { + cout << "c [polar]" + << " polar mode: " << polarity_mode_to_long_string(polarity_mode) + << " polarity_strategy: " << polarity_strategy_at + + << endl; + } +} + +void Searcher::sls_if_needed() +{ + assert(okay()); + assert(decisionLevel() == 0); + if (conf.doSLS && + // If XORs are detached, or there are BNNs, SLS will not work as intended + // HOWEVER, it seems to STILL help, likely by setting values randomly +// detached_xor_clauses && +// detached_xor_repr_cls.empty() && +// bnns.empty() && + sumConflicts > next_sls) + { + SLS sls(solver); + const lbool ret = sls.run(num_sls_called); + assert(ret != l_False); + num_sls_called++; + next_sls = sumConflicts + 44000.0*conf.global_next_multiplier; + } +} + +bool Searcher::intree_if_needed() +{ + assert(okay()); + assert(decisionLevel() == 0); + bool ret = okay(); + + if (!bnns.empty()) conf.do_hyperbin_and_transred = false; + if (conf.doIntreeProbe && conf.doFindAndReplaceEqLits && !conf.never_stop_search && + sumConflicts > next_intree + ) { + ret &= solver->clear_gauss_matrices(); + if (ret) ret &= solver->intree->intree_probe(); + if (ret) ret &= solver->find_and_init_all_matrices(); + next_intree = sumConflicts + 65000.0*conf.global_next_multiplier; + } + + return ret; +} + +bool Searcher::str_impl_with_impl_if_needed() +{ + assert(okay()); + bool ret = okay(); + + if (conf.doStrSubImplicit && + sumConflicts > next_str_impl_with_impl) + { + ret &= solver->dist_impl_with_impl->str_impl_w_impl(); + if (ret) solver->subsumeImplicit->subsume_implicit(); + next_str_impl_with_impl = sumConflicts + 60000.0*conf.global_next_multiplier; + } + + return ret; +} + +bool Searcher::distill_bins_if_needed() +{ + assert(okay()); + bool ret = okay(); + + if (conf.do_distill_bin_clauses && + sumConflicts > next_bins_distill) + { + ret = solver->distill_bin_cls->distill(); + next_bins_distill = sumConflicts + 20000.0*conf.global_next_multiplier; + } + return ret; +} + +bool Searcher::sub_str_with_bin_if_needed() +{ + assert(okay()); + bool ret = okay(); + + //Subsumes and strengthens long clauses with binary clauses + if (conf.do_distill_clauses && + sumConflicts > next_sub_str_with_bin) + { + ret = solver->dist_long_with_impl->distill_long_with_implicit(true); + next_sub_str_with_bin = sumConflicts + 25000.0*conf.global_next_multiplier; + } + + return ret; +} + +lbool Searcher::distill_clauses_if_needed() +{ + assert(decisionLevel() == 0); + if (conf.do_distill_clauses && + sumConflicts > next_cls_distill) + { + if (!solver->distill_long_cls->distill(true, false)) { + return l_False; + } + next_cls_distill = sumConflicts + 15000.0*conf.global_next_multiplier; + } + + return l_Undef; +} + +lbool Searcher::full_probe_if_needed() +{ + assert(decisionLevel() == 0); + if (conf.do_full_probe && !conf.never_stop_search && + sumConflicts > next_full_probe + ) { + full_probe_iter++; + if (!solver->full_probe(full_probe_iter % 2)) { + return l_False; + } + next_full_probe = sumConflicts + 20000.0*conf.global_next_multiplier; + } + + return l_Undef; +} + +lbool Searcher::solve( + const uint64_t _max_confls +) { + assert(ok); + assert(qhead == trail.size()); + max_confl_per_search_solve_call = _max_confls; + if (fast_backw.fast_backw_on && fast_backw.cur_max_confl == 0) { + fast_backw.cur_max_confl = sumConflicts + fast_backw.max_confl; + fast_backw.start_sumConflicts = sumConflicts; + } + num_search_called++; + #ifdef SLOW_DEBUG + //When asking for a lot of simple soluitons, search() gets called a lot + check_no_removed_or_freed_cl_in_watch(); + #endif + + if (conf.verbosity >= 6) { + cout + << "c Searcher::solve() called" + << endl; + } + + resetStats(); + lbool status = l_Undef; + + setup_branch_strategy(); + setup_restart_strategy(false); + setup_polarity_strategy(); + #ifdef STATS_NEEDED + check_calc_satzilla_features(true); + #endif + #ifdef STATS_NEEDED_BRANCH + check_calc_vardist_features(true); + #endif + + SLOW_DEBUG_DO(assert(fast_backw.fast_backw_on || solver->check_order_heap_sanity())); + while(stats.conflicts < max_confl_per_search_solve_call + && status == l_Undef + ) { + if (!conf.never_stop_search && + (distill_clauses_if_needed() == l_False + || full_probe_if_needed() == l_False + || !distill_bins_if_needed() + || !sub_str_with_bin_if_needed() + || !str_impl_with_impl_if_needed() + || !intree_if_needed()) + ) { + status = l_False; + goto end; + } + SLOW_DEBUG_DO(assert(solver->check_order_heap_sanity())); + sls_if_needed(); + + assert(watches.get_smudged_list().empty()); + params.clear(); + params.max_confl_to_do = max_confl_per_search_solve_call-stats.conflicts; + status = search(); + if (status == l_Undef) { + setup_branch_strategy(); + setup_restart_strategy(false); + setup_polarity_strategy(); + adjust_restart_strategy_cutoffs(); + } + SLOW_DEBUG_DO(assert(fast_backw.fast_backw_on || solver->check_order_heap_sanity())); + + if (must_abort(status)) goto end; + } + + end: + finish_up_solve(status); + + return status; +} + +double Searcher::luby(double y, int x) +{ + int size = 1; + int seq; + for (seq = 0 + ; size < x + 1 + ; seq++ + ) { + size = 2 * size + 1; + } + + while (size - 1 != x) { + size = (size - 1) >> 1; + seq--; + x = x % size; + } + + return std::pow(y, seq); +} + +void Searcher::setup_restart_strategy(bool force) +{ + if (!force && sumConflicts < restart_strategy_change) return; + restart_strategy_at++; + restart_strategy_change = sumConflicts + 30000; + restart_strategy_change *= 1.2; + + increasing_phase_size = conf.restart_first; + max_confl_this_restart = conf.restart_first; + if (conf.restartType == Restart::fixed) { + params.rest_type = Restart::fixed; + max_confl_this_restart = conf.fixed_restart_num_confl; + } else if (conf.restartType == Restart::never) { + params.rest_type = Restart::never; + max_confl_this_restart = numeric_limits::max(); + } else { + if (branch_strategy == branch::vsids) restart_strategy_at = 2; + if (branch_strategy == branch::vmtf) restart_strategy_at = (restart_strategy_at % 2); + + if (conf.restartType == Restart::glue) restart_strategy_at = 0; + if (conf.restartType == Restart::luby) restart_strategy_at = 1; + if (conf.restartType == Restart::geom) restart_strategy_at = 2; + + if (restart_strategy_at == 0) { + params.rest_type = Restart::glue; + max_confl_this_restart = conf.ratio_glue_geom *increasing_phase_size; + } else if (restart_strategy_at == 1) { + params.rest_type = Restart::luby; + luby_loop_num = 0; + max_confl_this_restart = luby(2, luby_loop_num) * (double)conf.restart_first; + luby_loop_num++; + } else if (restart_strategy_at == 2) { + params.rest_type = Restart::geom; + increasing_phase_size = (double)increasing_phase_size * conf.restart_inc; + max_confl_this_restart = increasing_phase_size; + } + } + + verb_print(2, "[restart] adjusting strategy. " + << " restart_strategy_change:" << restart_strategy_change + << " restart_strategy_at: " << restart_strategy_at + << " chosen: " << restart_type_to_string(params.rest_type)); + + print_local_restart_budget(); +} + +void Searcher::adjust_restart_strategy_cutoffs() +{ + //Haven't finished the phase. Keep rolling. + if (max_confl_this_restart > 0) + return; + + switch (params.rest_type) { + //max_confl_this_restart -- for this phase of search + //increasing_phase_size - a value that rolls and increases + // it's start at conf.restart_first and never + // reset + case Restart::luby: + max_confl_this_restart = luby(2, luby_loop_num) * (double)conf.restart_first; + luby_loop_num++; + break; + + case Restart::geom: + increasing_phase_size = (double)increasing_phase_size * conf.restart_inc; + max_confl_this_restart = increasing_phase_size; + break; + + case Restart::glue: + max_confl_this_restart = conf.ratio_glue_geom *increasing_phase_size; + break; + + case Restart::fixed: + max_confl_this_restart = conf.fixed_restart_num_confl; + break; + + case Restart::never: + max_confl_this_restart = 1000ULL*1000ULL*1000ULL; + break; + + default: + release_assert(false); + } + + print_local_restart_budget(); +} + +inline void Searcher::print_local_restart_budget() +{ + if (conf.verbosity >= 2 || conf.print_all_restarts) { + cout << "c [restart] at confl " << solver->sumConflicts << " -- " + << " local restart type: " + << std::left << std::setw(10) << getNameOfRestartType(params.rest_type) + << " budget: " << std::setw(9) << max_confl_this_restart + << std::right + << " branching: " << std::setw(2) << branch_type_to_string(branch_strategy) + << " decay: " + << std::setw(4) << std::setprecision(4) << var_decay + << endl; + } +} + +void Searcher::check_need_restart() +{ + if ((stats.conflicts & 0xff) == 0xff) { + //It's expensive to check the time all the time + if (cpuTime() > conf.maxTime) { + params.needToStopSearch = true; + } + + if (must_interrupt_asap()) { + if (conf.verbosity >= 3) + cout << "c must_interrupt_asap() is set, restartig as soon as possible!" << endl; + params.needToStopSearch = true; + } + } + + //dynamic + if (params.rest_type == Restart::glue) { + check_blocking_restart(); + if (hist.glueHist.isvalid() + && conf.local_glue_multiplier * hist.glueHist.avg() > hist.glueHistLTLimited.avg() + ) { + params.needToStopSearch = true; + } + } + + //respect restart phase's limit + if ((int64_t)params.conflictsDoneThisRestart > max_confl_this_restart) { + params.needToStopSearch = true; + } + + //respect Searcher's limit + if (params.conflictsDoneThisRestart > params.max_confl_to_do) { + if (conf.verbosity >= 3) { + cout + << "c Over limit of conflicts for this restart" + << " -- restarting as soon as possible!" << endl; + } + params.needToStopSearch = true; + } + + #ifdef VERBOSE_DEBUG + if (params.needToStopSearch) { + cout << "c needToStopSearch set" << endl; + } + #endif +} + +void Searcher::print_solution_varreplace_status() const +{ + for(size_t var = 0; var < nVarsOuter(); var++) { + if (varData[var].removed == Removed::replaced + || varData[var].removed == Removed::elimed + ) { + assert(value(var) == l_Undef || varData[var].level == 0); + } + + if (conf.verbosity >= 6 + && varData[var].removed == Removed::replaced + && value(var) != l_Undef + ) { + cout + << "var: " << var + << " value: " << value(var) + << " level:" << varData[var].level + << " type: " << removed_type_to_string(varData[var].removed) + << endl; + } + } +} + +void Searcher::print_solution_type(const lbool status) const +{ + if (conf.verbosity >= 6) { + if (status == l_True) { + cout << "Solution from Searcher is SAT" << endl; + } else if (status == l_False) { + cout << "Solution from Searcher is UNSAT" << endl; + cout << "OK is: " << okay() << endl; + } else { + cout << "Solutions from Searcher is UNKNOWN" << endl; + } + } +} + +void Searcher::finish_up_solve(const lbool status) +{ + print_solution_type(status); + if (conf.verbosity >= 2 && status != l_Undef) { + print_matrix_stats(); + } + + if (status == l_True) { + SLOW_DEBUG_DO(assert(fast_backw.fast_backw_on || solver->check_order_heap_sanity())); + assert(solver->prop_at_head()); + model = assigns; + cancelUntil(0); + assert(decisionLevel() == 0); + + //due to chrono BT we need to propagate once more + PropBy confl = propagate(); + assert(confl.isNULL()); + assert(solver->prop_at_head()); + #ifdef SLOW_DEBUG + print_solution_varreplace_status(); + #endif + } else if (status == l_False) { + if (conflict.size() == 0) { + ok = false; + } + cancelUntil(0); + if (okay()) { + //due to chrono BT we need to propagate once more + PropBy confl = propagate(); + assert(confl.isNULL()); + } + } else if (status == l_Undef) { + assert(decisionLevel() == 0); + assert(solver->prop_at_head()); + } + + stats.cpu_time = cpuTime() - startTime; + if (conf.verbosity >= 4) { + cout << "c Searcher::solve() finished" + << " status: " << status + << " numConflicts : " << stats.conflicts + << " SumConfl: " << sumConflicts + << " max_confl_per_search_solve_call:" << max_confl_per_search_solve_call + << endl; + } + + print_iteration_solving_stats(); +} + +void Searcher::print_iteration_solving_stats() +{ + if (conf.verbosity >= 3) { + cout << "c ------ THIS ITERATION SOLVING STATS -------" << endl; + stats.print(propStats.propagations, conf.do_print_times); + propStats.print(stats.cpu_time); + print_stats_line("c props/decision" + , float_div(propStats.propagations, stats.decisions) + ); + print_stats_line("c props/conflict" + , float_div(propStats.propagations, stats.conflicts) + ); + cout << "c ------ THIS ITERATION SOLVING STATS -------" << endl; + } +} + +inline Lit Searcher::pickBranchLit() +{ + VERBOSE_PRINT("picking decision variable, dec. level: " << decisionLevel()); + + uint32_t v = var_Undef; + while(true) { + switch (branch_strategy) { + case branch::vsids: + v = pick_var_vsids(); + break; + case branch::vmtf: + v = vmtf_pick_var(); + break; + case branch::rand: { + v = order_heap_rand.get_random_element(mtrand); + while (v != var_Undef && value(v) != l_Undef) { + v = order_heap_rand.get_random_element(mtrand); + } + break; + } + default: { + release_assert(false); + break; + } + } + if (v == var_Undef) break; + if (varData[v].removed == Removed::replaced) { + //cout << "v: " << v << endl; + vmtf_dequeue(v); + continue; + } + assert(varData[v].removed == Removed::none); + break; + } + + Lit next; + if (v != var_Undef) { + next = Lit(v, !pick_polarity(v)); + } else { + next = lit_Undef; + } + + SLOW_DEBUG_DO(assert(next == lit_Undef || solver->varData[next.var()].removed == Removed::none)); + VERBOSE_PRINT("Picked decision var: " << next); + + return next; +} + +uint32_t Searcher::pick_var_vsids() +{ + uint32_t v = var_Undef; + while (v == var_Undef || value(v) != l_Undef) { + if (order_heap_vsids.empty()) return var_Undef; //Satisfying assignment found. + v = order_heap_vsids.removeMin(); + } + return v; +} + +void Searcher::binary_based_morem_minim(vector& cl) +{ + int64_t limit = more_red_minim_limit_binary_actual; + const size_t first_n_lits_of_cl = + std::min(conf.max_num_lits_more_more_red_min, cl.size()); + for (size_t at_lit = 0; at_lit < first_n_lits_of_cl; at_lit++) { + Lit lit = cl[at_lit]; + //Already removed this literal + if (seen[lit.toInt()] == 0) + continue; + + //Watchlist-based minimisation + watch_subarray_const ws = watches[lit]; + for (const Watched* i = ws.begin() , *end = ws.end() + ; i != end && limit > 0 + ; i++ + ) { + limit--; + if (i->isBin()) { + if (seen[(~i->lit2()).toInt()]) { + stats.binTriShrinkedClause++; + seen[(~i->lit2()).toInt()] = 0; + } + continue; + } + break; + } + } +} + +void Searcher::minimise_redundant_more_more(vector& cl) +{ + stats.furtherShrinkAttempt++; + for (const Lit lit: cl) { + seen[lit.toInt()] = 1; + } + + binary_based_morem_minim(cl); + + //Finally, remove the literals that have seen[literal] = 0 + //Here, we can count do stats, etc. + bool changedClause = false; + vector::iterator i = cl.begin(); + vector::iterator j= i; + + //never remove the 0th literal -- TODO this is a bad thing + //we should be able to remove this, but I can't figure out how to + //reorder the clause then + seen[cl[0].toInt()] = 1; + for (vector::iterator end = cl.end(); i != end; ++i) { + if (seen[i->toInt()]) { + *j++ = *i; + } else { + changedClause = true; + } + seen[i->toInt()] = 0; + } + stats.furtherShrinkedSuccess += changedClause; + cl.resize(cl.size() - (i-j)); +} + +uint64_t Searcher::sumRestarts() const +{ + return stats.numRestarts + solver->get_stats().numRestarts; +} + +size_t Searcher::hyper_bin_res_all(const bool check_for_set_values) +{ + size_t added = 0; + + for(auto const& b: solver->needToAddBinClause) { + lbool val1 = value(b.getLit1()); + lbool val2 = value(b.getLit2()); + + verb_print(6, + "Attached hyper-bin: " + << b.getLit1() << "(val: " << val1 << " )" + << ", " << b.getLit2() << "(val: " << val2 << " )"); + + //If binary is satisfied, skip + if (check_for_set_values + && (val1 == l_True || val2 == l_True) + ) { + continue; + } + + if (check_for_set_values) { + assert(val1 == l_Undef && val2 == l_Undef); + } + + auto const ID = ++clauseID; + *solver->frat << add << ID << b.getLit1() << b.getLit2() << fin; + solver->attach_bin_clause(b.getLit1(), b.getLit2(), true, ID, false); + added++; + } + solver->needToAddBinClause.clear(); + + return added; +} + +std::pair Searcher::remove_useless_bins(bool except_marked) +{ + size_t removedIrred = 0; + size_t removedRed = 0; + + if (conf.doTransRed) { + for(auto const& b: uselessBin) { + propStats.otfHyperTime += 2; + verb_print(10, "Removing binary clause: " << b + << " except marked: " << except_marked); + propStats.otfHyperTime += solver->watches[b.getLit1()].size()/2; + propStats.otfHyperTime += solver->watches[b.getLit2()].size()/2; + bool removed; + if (except_marked) { + bool rem1 = removeWBin_except_marked( + solver->watches, b.getLit1(), b.getLit2(), b.isRed(), b.getID()); + bool rem2 = removeWBin_except_marked( + solver->watches, b.getLit2(), b.getLit1(), b.isRed(), b.getID()); + assert(rem1 == rem2); + removed = rem1; + } else { + removeWBin(solver->watches, b.getLit1(), b.getLit2(), b.isRed(), b.getID()); + removeWBin(solver->watches, b.getLit2(), b.getLit1(), b.isRed(), b.getID()); + removed = true; + } + if (!removed) continue; + + //Update stats + if (b.isRed()) { + solver->binTri.redBins--; + removedRed++; + } else { + solver->binTri.irredBins--; + removedIrred++; + } + *frat << del << b.getID() << b.getLit1() << b.getLit2() << fin; + + #ifdef VERBOSE_DEBUG_FULLPROP + cout << "Removed bin: " + << b.getLit1() << " , " << b.getLit2() + << " , red: " << b.isRed() << endl; + #endif + } + } + uselessBin.clear(); + + return std::make_pair(removedIrred, removedRed); +} + +template +PropBy Searcher::propagate() { + PropBy ret = propagate_any_order(); + + //Drat -- If declevel 0 propagation, we have to add the unitaries + if (decisionLevel() == 0 && + (frat->enabled() || conf.simulate_frat) + ) { + if (!ret.isNULL()) { + *frat << add << ++clauseID << fin; + assert(unsat_cl_ID == 0); + unsat_cl_ID = clauseID; + } + } + + return ret; +} +template PropBy Searcher::propagate(); +template PropBy Searcher::propagate(); +template PropBy Searcher::propagate(); +template PropBy Searcher::propagate(); + +size_t Searcher::mem_used() const +{ + size_t mem = HyperEngine::mem_used(); + mem += var_act_vsids.capacity()*sizeof(double); + mem += order_heap_vsids.mem_used(); + mem += order_heap_rand.mem_used(); + mem += vmtf_btab.capacity()*sizeof(uint64_t); + mem += vmtf_links.capacity()*sizeof(Link); + mem += learnt_clause.capacity()*sizeof(Lit); + mem += hist.mem_used(); + mem += conflict.capacity()*sizeof(Lit); + mem += model.capacity()*sizeof(lbool); + mem += analyze_stack.mem_used(); + mem += assumptions.capacity()*sizeof(Lit); + + return mem; +} + +void Searcher::fill_assumptions_set() +{ + #ifdef SLOW_DEBUG + for(auto x: varData) { + assert(x.assumption == l_Undef); + } + #endif + + for(const AssumptionPair lit_pair: assumptions) { + const Lit lit = map_outer_to_inter(lit_pair.lit_outer); + varData[lit.var()].assumption = lit.sign() ? l_False : l_True; + } +} + +void Searcher::unfill_assumptions_set() +{ + for(const AssumptionPair lit_pair: assumptions) { + const Lit lit = map_outer_to_inter(lit_pair.lit_outer); + varData[lit.var()].assumption = l_Undef; + } + + #ifdef SLOW_DEBUG + for(auto x: varData) { + assert(x.assumption == l_Undef); + } + #endif +} + +void Searcher::vsids_decay_var_act() +{ + assert(branch_strategy == branch::vsids); + var_inc_vsids *= (1.0 / var_decay); +} + +void Searcher::consolidate_watches(const bool full) +{ + double t = cpuTime(); + if (full) { + watches.full_consolidate(); + } else { + watches.consolidate(); + } + double time_used = cpuTime() - t; + + if (conf.verbosity) { + cout + << "c [consolidate] " + << (full ? "full" : "mini") + << conf.print_times(time_used) + << endl; + } + + std::stringstream ss; + ss << "consolidate " << (full ? "full" : "mini") << " watches"; + if (sqlStats) { + sqlStats->time_passed_min( + solver + , ss.str() + , time_used + ); + } +} + +inline void Searcher::update_polarities_on_backtrack(const uint32_t btlevel) +{ + if (polarity_mode == PolarityMode::polarmode_stable && + longest_trail_ever_stable < trail.size()) + { + for(const auto t: trail) { + if (t.lit == lit_Undef) continue; + varData[t.lit.var()].stable_polarity = !t.lit.sign(); + } + longest_trail_ever_stable = trail.size(); + } + + if (polarity_mode == PolarityMode::polarmode_best + && longest_trail_ever_best < trail.size()) + { + for(const auto t: trail) { + if (t.lit == lit_Undef) continue; + varData[t.lit.var()].best_polarity = !t.lit.sign(); + } + longest_trail_ever_best = trail.size(); + } + + if (polarity_mode == PolarityMode::polarmode_best_inv + && longest_trail_ever_inv < trail.size()) + { + for(const auto t: trail) { + if (t.lit == lit_Undef) continue; + varData[t.lit.var()].inv_polarity = !t.lit.sign(); + } + longest_trail_ever_inv = trail.size(); + } + + if (polarity_mode == PolarityMode::polarmode_saved) { + for(uint32_t i = trail_lim[btlevel]; i < trail.size(); i++) { + const auto t = trail[i]; + if (t.lit == lit_Undef) continue; + varData[t.lit.var()].saved_polarity = !t.lit.sign(); + } + } +} + + +//Normal running +template +void Searcher::cancelUntil(uint32_t level); + +//During inprocessing, dont update anyting really (probing, distilling) +template +void Searcher::cancelUntil(uint32_t level); + +template +void Searcher::cancelUntil(uint32_t blevel) +{ + #ifdef VERBOSE_DEBUG + cout << "Canceling until level " << blevel; + if (blevel > 0) cout << " sublevel: " << trail_lim[blevel]; + cout << endl; + #endif + + if (decisionLevel() > blevel) { + if (!inprocess) { + update_polarities_on_backtrack(blevel); + #ifdef USE_GPU + solver->datasync->unsetFromGpu(blevel); + #endif + } + + for (uint32_t i = 0; i < gmatrices.size(); i++) + if (gmatrices[i] && !gqueuedata[i].disabled) + gmatrices[i]->canceling(); + + uint32_t i = trail_lim[blevel]; + uint32_t j = i; + for (; i < trail.size() + ; i++ + ) { + VERBOSE_PRINT("Canceling lit " << trail[i].lit << " sublevel: " << i); + + const uint32_t var = trail[i].lit.var(); + assert(value(var) != l_Undef); + + //Clear out BNN reason on backtrack + if (varData[var].reason.isBNN() && + varData[var].reason.bnn_reason_set()) + { + uint32_t reason_idx = varData[var].reason.get_bnn_reason(); + bnn_reasons_empty_slots.push_back(reason_idx); + varData[var].reason = PropBy(); + } + if (!bnns.empty()) reverse_prop(trail[i].lit); + + #ifdef STATS_NEEDED_BRANCH + if (!inprocess) { + varData[var].last_canceled = sumConflicts; + } + if (!inprocess && varData[var].reason == PropBy()) { + //we want to dump & this was a decision var + uint64_t sumConflicts_during = sumConflicts - varData[var].sumConflicts_at_picktime; + uint64_t sumDecisions_during = sumDecisions - varData[var].sumDecisions_at_picktime; + uint64_t sumPropagations_during = sumPropagations - varData[var].sumPropagations_at_picktime; + uint64_t sumAntecedents_during = sumAntecedents - varData[var].sumAntecedents_at_picktime; + uint64_t sumAntecedentsLits_during = sumAntecedentsLits - varData[var].sumAntecedentsLits_at_picktime; + uint64_t sumConflictClauseLits_during = sumConflictClauseLits - varData[var].sumConflictClauseLits_at_picktime; + uint64_t sumDecisionBasedCl_during = sumDecisionBasedCl - varData[var].sumDecisionBasedCl_at_picktime; + uint64_t sumClLBD_during = sumClLBD - varData[var].sumClLBD_at_picktime; + uint64_t sumClSize_during = sumClSize - varData[var].sumClSize_at_picktime; + double rel_activity_at_fintime = + std::log2(var_act_vsids[var]+10e-300)/std::log2(max_vsids_act+10e-300); + + uint64_t inside_conflict_clause_during = + varData[var].inside_conflict_clause - varData[var].inside_conflict_clause_at_picktime; + + uint64_t inside_conflict_clause_glue_during = + varData[var].inside_conflict_clause_glue - varData[var].inside_conflict_clause_glue_at_picktime; + + uint64_t inside_conflict_clause_antecedents_during = + varData[var].inside_conflict_clause_antecedents - + varData[var].inside_conflict_clause_antecedents_at_picktime; + + if (varData[var].dump) { + uint64_t outer_var = map_inter_to_outer(var); + + solver->sqlStats->var_data_fintime( + solver + , outer_var + , varData[var] + , rel_activity_at_fintime + ); + } + + //if STATS_NEEDED we only update for decisions, otherwise, all the time + varData[var].sumConflicts_below_during += sumConflicts_during; + varData[var].sumDecisions_below_during += sumDecisions_during; + varData[var].sumPropagations_below_during += sumPropagations_during; + varData[var].sumAntecedents_below_during += sumAntecedents_during; + varData[var].sumAntecedentsLits_below_during += sumAntecedentsLits_during; + varData[var].sumConflictClauseLits_below_during += sumConflictClauseLits_during; + varData[var].sumDecisionBasedCl_below_during += sumDecisionBasedCl_during; + varData[var].sumClLBD_below_during += sumClLBD_during; + varData[var].sumClSize_below_during += sumClSize_during; + + varData[var].inside_conflict_clause_during += + inside_conflict_clause_during; + + varData[var].inside_conflict_clause_glue_during += inside_conflict_clause_glue_during; + + varData[var].inside_conflict_clause_antecedents_during += + inside_conflict_clause_antecedents_during; + } + #endif + + + if (trail[i].lev <= blevel) { + trail[j++] = trail[i]; + } else { + assigns[var] = l_Undef; + if (do_insert_var_order) insert_var_order(var); + } + } + trail.resize(j); + qhead = trail_lim[blevel]; + trail_lim.resize(blevel); + } + + #ifdef VERBOSE_DEBUG + cout << "Canceling finished. Now at level: " << decisionLevel(); + if (trail.size() > 0) { + cout << " sublevel: " << trail.size()-1; + } + cout << endl; + #endif +} + +void Searcher::cancelUntil_light() +{ + assert(decisionLevel() == 1); + uint32_t i = trail_lim[0]; + for (; i < trail.size() + ; i++ + ) { + VERBOSE_PRINT("Canceling lit " << trail[i].lit << " sublevel: " << i); + const uint32_t var = trail[i].lit.var(); + assert(value(var) != l_Undef); + assigns[var] = l_Undef; + } + trail.resize(trail_lim[0]); + qhead = trail_lim[0]; + trail_lim.resize(0); +} + +void Searcher::check_var_in_branch_strategy(const uint32_t var, const branch str) const +{ + bool found = false; + switch(str) { + case branch::vsids: + found = order_heap_vsids.inHeap(var); + break; + + case branch::rand: + found = order_heap_rand.inHeap(var); + break; + + case branch::vmtf: + uint32_t at = vmtf_queue.unassigned; + while (at != numeric_limits::max()) { + if (at == var) { + found = true; + break; + } + at = vmtf_links[at].prev; + } + break; + } + + if (!found) { + cout << "ERROR: cannot find internal var " << var+1 + << " in branch strategy: " << branch_type_to_string(str) << endl; + } + release_assert(found); +} + +void Searcher::check_all_in_vmtf_branch_strategy(const vector& vars) +{ + for(auto const& v: vars) { + assert(v < seen.size()); + seen[v] = 1; + } + + uint32_t at = vmtf_queue.unassigned; + while (at != numeric_limits::max()) { + seen[at] = 0; + at = vmtf_links[at].prev; + } + + for(auto const&v: vars) { + if (seen[v] == 1) { + cout << "ERROR: cannot find internal var " << v+1 + << " in VMTF" << endl; + release_assert(false); + } + } +} + +ConflictData Searcher::find_conflict_level(PropBy& pb) +{ + ConflictData data; + + if (pb.getType() == PropByType::binary_t) { + data.nHighestLevel = varData[failBinLit.var()].level; + + if (data.nHighestLevel == decisionLevel() + && varData[pb.lit2().var()].level == decisionLevel() + ) { + return data; + } + + uint32_t highestId = 0; + // find the largest decision level in the clause + uint32_t nLevel = varData[pb.lit2().var()].level; + if (nLevel > data.nHighestLevel) { + highestId = 1; + data.nHighestLevel = nLevel; + } + + //TODO + // we might want to swap here if highestID is not 0 + if (highestId != 0) { + Lit back = pb.lit2(); + pb = PropBy(failBinLit, pb.isRedStep(), pb.getID()); + failBinLit = back; + } + + } else { + Lit* clause = NULL; + uint32_t size = 0; + ClOffset offs; + int32_t ID; + switch(pb.getType()) { + case PropByType::clause_t: { + offs = pb.get_offset(); + Clause& conflCl = *cl_alloc.ptr(offs); + clause = conflCl.getData(); + size = conflCl.size(); + ID = conflCl.stats.ID; + break; + } + + case PropByType::xor_t: { + vector* cl = gmatrices[pb.get_matrix_num()]-> + get_reason(pb.get_row_num(), ID); + clause = cl->data(); + size = cl->size(); + break; + } + + case PropByType::bnn_t: { + vector* cl = get_bnn_reason( + bnns[pb.getBNNidx()], lit_Undef); + clause = cl->data(); + size = cl->size(); + break; + } + + case PropByType::binary_t: + case PropByType::null_clause_t: + assert(false); + break; + } + + data.nHighestLevel = varData[clause[0].var()].level; + if (data.nHighestLevel == decisionLevel() + && varData[clause[1].var()].level == decisionLevel() + ) { + return data; + } + + uint32_t highestId = 0; + // find the largest decision level in the clause + for (uint32_t nLitId = 1; nLitId < size; ++nLitId) { + uint32_t nLevel = varData[clause[nLitId].var()].level; + if (nLevel > data.nHighestLevel) { + highestId = nLitId; + data.nHighestLevel = nLevel; + } + } + + if (highestId != 0) { + std::swap(clause[0], clause[highestId]); + if (highestId > 1 && pb.getType() == clause_t) { + removeWCl(watches[clause[highestId]], pb.get_offset()); + watches[clause[0]].push(Watched(offs, clause[1])); + } + } + } + + return data; +} + +inline bool Searcher::check_order_heap_sanity() +{ + if (conf.sampling_vars) { + for(uint32_t outside_var: *conf.sampling_vars) { + uint32_t outer_var = map_to_with_bva(outside_var); + outer_var = solver->varReplacer->get_var_replaced_with_outer(outer_var); + uint32_t int_var = map_outer_to_inter(outer_var); + + assert(varData[int_var].removed == Removed::none); + + if (int_var < nVars() && + varData[int_var].removed == Removed::none && + value(int_var) == l_Undef + ) { + check_var_in_branch_strategy(int_var, branch::vsids); + check_var_in_branch_strategy(int_var, branch::rand); + check_var_in_branch_strategy(int_var, branch::vmtf); + } + } + } + + vector tmp; + for(size_t i = 0; i < nVars(); i++) + { + if (varData[i].removed == Removed::none && value(i) == l_Undef) { + tmp.push_back(i); + check_var_in_branch_strategy(i, branch::vsids); + check_var_in_branch_strategy(i, branch::rand); + } + } + check_all_in_vmtf_branch_strategy(tmp); + + assert(order_heap_vsids.heap_property()); + assert(order_heap_rand.heap_property()); + + return true; +} + +bool Searcher::clear_gauss_matrices(const bool destruct) +{ + if (!destruct) { + if (!solver->fully_undo_xor_detach()) return false; + TBUDDY_DO(if (frat->enabled()) for(auto& g: gmatrices) g->finalize_frat()); + } + + xor_clauses_updated = true; + for(uint32_t i = 0; i < gqueuedata.size(); i++) { + auto gqd = gqueuedata[i]; + if (conf.verbosity >= 2) { + cout + << "c [mat" << i << "] num_props : " + << print_value_kilo_mega(gqd.num_props) << endl + << "c [mat" << i << "] num_conflicts : " + << print_value_kilo_mega(gqd.num_conflicts) << endl; + } + } + + if (conf.verbosity) print_matrix_stats(); + for(EGaussian* g: gmatrices) g->move_back_xor_clauses(); + for(EGaussian* g: gmatrices) delete g; + for(auto& w: gwatches) w.clear(); + gmatrices.clear(); + gqueuedata.clear(); + TBUDDY_DO(free_bdds(xorclauses)); + TBUDDY_DO(free_bdds(xorclauses_unused)); + xorclauses.clear(); // we rely on xorclauses_orig now + xorclauses_unused.clear(); + if (!destruct) { + for(const auto& x: xorclauses_orig) { + xorclauses.push_back(x); + #ifdef USE_TBUDDY + xorclauses.back().bdd = NULL; + frat->flush(); + if (frat->enabled()) solver->xorclauses.back().create_bdd_xor(); + #endif + } + } + + return okay(); +} + +void Searcher::print_matrix_stats() +{ + for(EGaussian* g: gmatrices) { + if (g) { + g->print_matrix_stats(conf.verbosity); + } + } +} + +void Searcher::check_assumptions_sanity() +{ + for(AssumptionPair& lit_pair: assumptions) { + Lit inter_lit = map_outer_to_inter(lit_pair.lit_outer); + assert(inter_lit.var() < varData.size()); + assert(varData[inter_lit.var()].removed == Removed::none); + if (varData[inter_lit.var()].assumption == l_Undef) { + cout << "Assump " << inter_lit << " has .assumption : " + << varData[inter_lit.var()].assumption << endl; + } + assert(varData[inter_lit.var()].assumption != l_Undef); + } +} + +void Searcher::bump_var_importance_all(const uint32_t var) +{ + vsids_bump_var_act(var); + vmtf_bump_queue(var); +} + + +void Searcher::bump_var_importance(const uint32_t var) +{ + switch(branch_strategy) { + case branch::vsids: + vsids_bump_var_act(var); + break; + + case branch::rand: + break; + + case branch::vmtf: + // TODO this cannot be done, due to btab sorting requirements + //vmtf_bump_queue(var); + break; + } +} + +void Searcher::create_new_fast_backw_assumption() +{ + //Reset conflict limit + fast_backw.cur_max_confl = sumConflicts + fast_backw.max_confl; + //max_confl_this_restart = params.conflictsDoneThisRestart + fast_backw.max_confl; + + //Remove indic + const Lit indic = fast_backw._assumptions->at(fast_backw._assumptions->size()-1); + assert(!indic.sign()); + fast_backw._assumptions->pop_back(); + + //Backtrack + if (decisionLevel() >= fast_backw._assumptions->size()) { + cancelUntil(fast_backw._assumptions->size()); + } + + //Add TRUE/FALSE duo + uint32_t var = fast_backw.indic_to_var->at(indic.var()); + *fast_backw.test_indic = indic.var(); + *fast_backw.test_var = var; + //cout << "Testing: " << *fast_backw.test_var << endl; + Lit l = Lit(var, false); + fast_backw._assumptions->push_back(l); + + Lit l2 = Lit(var+fast_backw.orig_num_vars, true); + fast_backw._assumptions->push_back(l2); +} + +lbool Searcher::new_decision_fast_backw() +{ + Lit next = lit_Undef; + start: + while (decisionLevel() < fast_backw._assumptions->size()) { + // Perform user provided assumption: + Lit p = fast_backw._assumptions->at(decisionLevel()); + p = solver->varReplacer->get_lit_replaced_with_outer(p); + p = map_outer_to_inter(p); + assert(varData[p.var()].removed == Removed::none); + + if (value(p) == l_True) { + // Dummy decision level: + new_decision_level(); + } else if (value(p) == l_False) { + //Deal with top 2 TRUE/FALSE +// cout << "Testing ret: " << l_False << endl; + fast_backw._assumptions->pop_back(); + fast_backw._assumptions->pop_back(); + fast_backw.non_indep_vars->push_back(*fast_backw.test_var); + + //We reached the bottom + if (fast_backw._assumptions->size() == fast_backw.indep_vars->size()) { + *fast_backw.test_indic = var_Undef; + *fast_backw.test_var = var_Undef; + return l_True; + } + + create_new_fast_backw_assumption(); + + continue; + } else { + assert(p.var() < nVars()); + stats.decisionsAssump++; + next = p; + break; + } + } + + if (next == lit_Undef) { + // New variable decision: + next = pickBranchLit(); + + //1) No decision taken, because it's SAT + //2) We are out of conflicts + //Either way, it's basically independent + if (next == lit_Undef|| sumConflicts > fast_backw.cur_max_confl) { + if (sumConflicts > fast_backw.cur_max_confl) { + fast_backw.indep_because_ran_out_of_confl++; + } + if (sumConflicts-fast_backw.start_sumConflicts > 150ULL*1000ULL) { + fast_backw.max_confl /= 2; + fast_backw.start_sumConflicts = sumConflicts; + if (fast_backw.max_confl < 50) fast_backw.max_confl = 50; +// cout << "HALF" << endl; + } else { +// cout << "DIFF: " << (sumConflicts-fast_backw.start_sumConflicts)/1000 << " k" << endl; + } + + //Let's fix this up. + //backtrack until last. + fast_backw._assumptions->pop_back(); + fast_backw._assumptions->pop_back(); + + //Add this indic to the middle of assumptions. + { + vector backup; + backup.reserve(fast_backw._assumptions->size()+3); + + const uint32_t splice_into = fast_backw.indep_vars->size(); + for(uint32_t i = 0; i < splice_into; i++) { + backup.push_back(fast_backw._assumptions->at(i)); + } + fast_backw.indep_vars->push_back(*fast_backw.test_var); + backup.push_back(Lit(*fast_backw.test_indic, false)); + for(uint32_t i = splice_into; i < fast_backw._assumptions->size(); i++) { + const auto x = fast_backw._assumptions->at(i); + backup.push_back(x); + } + std::swap(*fast_backw._assumptions, backup); + cancelUntil(splice_into); + } + + //We reached the bottom + if (fast_backw._assumptions->size() == fast_backw.indep_vars->size()) { + *fast_backw.test_var = var_Undef; + *fast_backw.test_indic = var_Undef; + return l_True; + } + + create_new_fast_backw_assumption(); + goto start; + } + + //Update stats + stats.decisions++; + sumDecisions++; + } + + // Increase decision level and enqueue 'next' + assert(value(next) == l_Undef); + new_decision_level(); + enqueue(next); + + return l_Undef; +} + +void Searcher::find_largest_level(Lit* lits, uint32_t count, uint32_t start) +{ + for (uint32_t i = start; i < count; i++) { + if (value(lits[i]) == l_Undef) { + std::swap(lits[i], lits[start]); + return; + } + if (level(lits[i]) > level(lits[start])) { + std::swap(lits[i], lits[start]); + } + } +} + +void Searcher::set_seed(const uint32_t seed) +{ + mtrand.seed(seed); +} + +#ifdef USE_GPU +// Learns the clause, and attach it +// May lead to canceling to backtracking if this clause leads to an implication at a level strictly lower +// than the current level +// returns a non-undef cref if this clause is in conflict +PropBy Searcher::insert_gpu_clause(Lit* lits, uint32_t count) +{ + std::sort(lits, lits+count); + uint32_t j = 0; + for(uint32_t i = 1; i < count; i ++) { + if (lits[i] == lits[j]) { + continue; + } + if (lits[i] == ~lits[j]) { + //already satisfied + return PropBy(); + } + j++; + lits[j] = lits[i]; + } + count = j+1; + + //Clear it of 0-level assigned literals + j = 0; + for(uint32_t i = 0; i < count; i ++) { + const Lit l = lits[i]; + if (varData[l.var()].level == 0) { + if (value(l) == l_True) { + return PropBy(); + } + if (value(l) == l_False) { + continue; + } + } + lits[j] = lits[i]; + j++; + } + count = j; + + // if only one literal isn't false, it will be in 0 of lits + // if only two literals aren't set, they will be in 0 and 1 of lits + find_largest_level(lits, count, 0); + if (count > 1) { + find_largest_level(lits, count, 1); + } + + //Make sure it doesn't have BVA/elimed/etc. variables + //Make sure TRUE literal is at the beginning + bool sat = false; + for(uint32_t i = 0; i < count; i ++) { + //Variable has been removed already + if (varData[lits[i].var()].removed != Removed::none) { + return PropBy(); + } + + //Can't deal with BVA variables + if (varData[lits[i].var()].is_bva) { + assert(false && "This should not be possible, other threads should not be sending BVA vars!"); + return PropBy(); + } + + if (value(lits[i]) == l_True) { + std::swap(lits[i], lits[0]); + sat = true; + } + } + +// cout << "cl-aft: "; +// for(uint32_t i = 0; i < count; i ++) { +// cout << lits[i] << ":" << value(lits[i]) << "(" << level(lits[i]) << ") "; +// } +// cout << endl; + + + //Empty clause + if (count == 0) { + cancelUntil(0); + solver->ok = false; + return PropBy(); + } + + //Unit clause + if (count == 1) { + /*cancelUntil(0); + enqueue(lits[0]);*/ + return PropBy(); + } + + // It's already satisfied + // Or at least 2 are unset + // ---> We only attach the clause + if (sat || + (value(lits[0]) == l_Undef && value(lits[1]) == l_Undef) ) + { + learn_gpu_clause(lits, count); + return PropBy(); + } + + // All are l_False, this is a conflict + if (value(lits[0]) == l_False) + { + #ifdef SLOW_DEBUG + for (uint32_t i = 0; i < count; i++) { + assert(value(lits[i]) == l_False); + } + #endif + + //Go back to highest level + cancelUntil(level(lits[0])); + + #ifdef SLOW_DEBUG + for (uint32_t i = 0; i < count; i++) { + assert(value(lits[i]) == l_False); + } + #endif + return learn_gpu_clause(lits, count); + } + + // lit 0 is implied by the rest -- i.e. lit[0] is l_Undef, rest is l_False + cancelUntil(level(lits[1])); + + #ifdef SLOW_DEBUG + assert(value(lits[0]) == l_Undef); + for (uint32_t i = 1; i < count; i++) { + assert(value(lits[i]) == l_False); + } + #endif + + PropBy by = learn_gpu_clause(lits, count); + enqueue(lits[0], decisionLevel(), by); + return PropBy(); +} + +PropBy Searcher::learn_gpu_clause(Lit* lits, uint32_t count) +{ + if (count > 2) { + tmp_gpu_clause.resize(count); + for(uint32_t i = 0; i < count; i++) { + tmp_gpu_clause[i] = lits[i]; + } + + Clause* cl = cl_alloc.Clause_new(tmp_gpu_clause, sumConflicts); + ClOffset off = cl_alloc.get_offset(cl); + + cl->stats.glue = count; + cl->stats.which_red_array = 2; + cl->stats.activity = 0.0f; + cl->isRed = true; + + longRedCls[cl->stats.which_red_array].push_back(off); + bump_cl_act(cl); + litStats.redLits += count; + + attachClause(*cl, false); + //TODO red_stats_extra + + return PropBy(cl_alloc.get_offset(cl)); + } + + //Binary, and lits[0] may be propagated due to lits[1] + assert(count == 2); + attach_bin_clause(lits[0], lits[1], false, ++clauseID, false); + binTri.irredBins++; + failBinLit = lits[0]; + return PropBy(lits[1], false); +} + +#endif diff --git a/cryptominisat/cppsrc/src/searcher.h b/cryptominisat/cppsrc/src/searcher.h new file mode 100644 index 00000000..1d4c3366 --- /dev/null +++ b/cryptominisat/cppsrc/src/searcher.h @@ -0,0 +1,650 @@ +/****************************************** +Copyright (C) 2009-2020 Authors of CryptoMiniSat, see AUTHORS file + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. +***********************************************/ + +#ifndef __SEARCHER_H__ +#define __SEARCHER_H__ + +#include + +#include "constants.h" +#include "propengine.h" +#include "solvertypes.h" +#include "time_mem.h" +#include "hyperengine.h" +#include "simplefile.h" +#include "searchstats.h" +#include "searchhist.h" + +#ifdef CMS_TESTING_ENABLED +#include "gtest/gtest_prod.h" +#endif + +namespace CMSat { + +class Solver; +class SQLStats; +class VarReplacer; +class EGaussian; +class DistillerLong; + +using std::string; + +struct VariableVariance +{ + double avgDecLevelVarLT = 0; + double avgTrailLevelVarLT= 0; + double avgDecLevelVar = 0; + double avgTrailLevelVar = 0; +}; + +struct ConflictData { + uint32_t nHighestLevel; +}; + +class Searcher : public HyperEngine +{ + public: + Searcher(const SolverConf* _conf, Solver* solver, std::atomic* _must_interrupt_inter); + virtual ~Searcher(); + /////////////////////////////// + // Solving + // + lbool solve( + uint64_t max_confls + ); + void finish_up_solve(lbool status); + bool clean_clauses_if_needed(); + #ifdef STATS_NEEDED + void check_calc_satzilla_features(bool force = false); + #endif + #ifdef STATS_NEEDED_BRANCH + void check_calc_vardist_features(bool force = false); + #endif + void dump_search_loop_stats(double myTime); + bool must_abort(lbool status); + PropBy insert_gpu_clause(Lit* lits, uint32_t count); + uint64_t luby_loop_num = 0; + void set_seed(const uint32_t seed); + + + vector model; + vector conflict; /// + PropBy propagate(); + + /////////////////////////////// + // Stats + //Restart print status + uint64_t lastRestartPrint = 0; + uint64_t lastRestartPrintHeader = 0; + void print_restart_stat(); + void print_iteration_solving_stats(); + void print_restart_header(); + void print_restart_stat_line() const; + void print_restart_stats_base() const; + void print_clause_stats() const; + uint64_t sumRestarts() const; + const SearchHist& getHistory() const; + void print_local_restart_budget(); + + size_t hyper_bin_res_all(const bool check_for_set_values = true); + std::pair remove_useless_bins(bool except_marked = false); + + ///Returns l_Undef if not inside, l_True/l_False otherwise + lbool var_inside_assumptions(const uint32_t var) const + { + #ifdef SLOW_DEBUG + assert(var < nVars()); + #endif + return varData[var].assumption; + } + lbool lit_inside_assumptions(const Lit lit) const + { + #ifdef SLOW_DEBUG + assert(lit.var() < nVars()); + #endif + if (varData[lit.var()].assumption == l_Undef) { + return l_Undef; + } else { + lbool val = varData[lit.var()].assumption; + return val ^ lit.sign(); + } + } + + //ChronoBT + template + void cancelUntil(uint32_t level); /// + void bump_cl_act(Clause* cl); + void simple_create_learnt_clause( + PropBy confl, + vector& out_learnt, + bool True_confl + ); + + #ifdef STATS_NEEDED + void dump_restart_sql(rst_dat_type type, int64_t clauseID = -1); + uint64_t last_dumped_conflict_rst_data_for_var = numeric_limits::max(); + template + uint32_t calc_connects_num_communities(const T& cl); + #endif + + ///////////////////// + // Branching + ///////////////////// + double var_inc_vsids; + void insert_var_order(const uint32_t x, const branch type); + void insert_var_order(const uint32_t x); + void insert_var_order_all(const uint32_t x); + vector implied_by_learnts; //for glue-based extra var activity bumping + template + lbool new_decision(); + Lit pickBranchLit(); + uint32_t pick_var_vsids(); + void vsids_decay_var_act(); + template void vsids_bump_var_act(const uint32_t v); + double backup_random_var_freq = -1; ///& vars); + uint32_t branch_strategy_change = 0; + uint32_t branch_strategy_at = 0; + void setup_branch_strategy(); + void rebuildOrderHeap(); + void rebuildOrderHeapVMTF(vector& vs); + void print_order_heap(); + void clear_order_heap() + { + order_heap_vsids.clear(); + order_heap_rand.clear(); + } + uint32_t branch_strategy_num = 0; + void bump_var_importance(const uint32_t var); + void bump_var_importance_all(const uint32_t var); + + ///////////////// + // Polarities + bool pick_polarity(const uint32_t var); + void setup_polarity_strategy(); + void update_polarities_on_backtrack(const uint32_t btlevel); + uint32_t polarity_strategy_at = 0; + uint32_t polarity_strategy_change = 0; + + //Stats + SearchStats stats; + SearchHist hist; + + protected: + Solver* solver; + lbool search(); + + // Distill + uint64_t next_cls_distill = 0; + lbool distill_clauses_if_needed(); + uint64_t next_bins_distill = 0; + bool distill_bins_if_needed(); + + // Str impl with impl + uint64_t next_str_impl_with_impl = 0; + bool str_impl_with_impl_if_needed(); + + // Full Probe + uint64_t next_full_probe = 0; + uint64_t full_probe_iter = 0; + lbool full_probe_if_needed(); + + // sub-str with bin + uint64_t next_sub_str_with_bin = 0; + bool sub_str_with_bin_if_needed(); + + // sub-str with bin + uint64_t next_intree = 0; + bool intree_if_needed(); + + // SLS + uint64_t next_sls = 0; + void sls_if_needed(); + + // Fast backward for Arjun + lbool new_decision_fast_backw(); + void create_new_fast_backw_assumption(); + + /////////////// + // Variables + /////////////// + void new_var( + const bool bva, + const uint32_t orig_outer, + const bool insert_varorder + ) override; + void new_vars(const size_t n) override; + void save_on_var_memory(); + void updateVars( + const vector& outerToInter + , const vector& interToOuter + ); + + //Misc + void add_in_partial_solving_stats(); + + + void fill_assumptions_set(); + void update_assump_conflict_to_orig_outside(vector& out_conflict); + + ///////////////////// + // Learning + ///////////////////// + vector learnt_clause; + vector decision_clause; + template + void analyze_conflict( + PropBy confl //The conflict that we are investigating + , uint32_t& out_btlevel //backtrack level + , uint32_t &glue //glue of the learnt clause + , uint32_t &glue_before_minim //glue of the unminimised learnt clause + , uint32_t &size_before_minim //size of the unminimised learnt clause + ); + bool handle_conflict(PropBy confl);// Handles the conflict clause + void update_history_stats( + size_t backtrack_level, + uint32_t glue, + uint32_t connects_num_communities); + template + void attach_and_enqueue_learnt_clause( + Clause* cl, + const uint32_t level, + const bool enqueue, + const uint64_t ID); + void print_learning_debug_info(const int32_t ID) const; + void print_learnt_clause() const; + template + void add_lits_to_learnt(const PropBy confl, const Lit p, uint32_t nDecisionLevel); + template + void create_learnt_clause(PropBy confl); + void debug_print_resolving_clause(const PropBy confl) const; + template + void add_lit_to_learnt(Lit lit, const uint32_t nDecisionLevel); + void analyze_final_confl_with_assumptions(const Lit p, vector& out_conflict); + void update_glue_from_analysis(Clause* cl); + template + void minimize_learnt_clause(); + void minimize_using_bins(); + void print_fully_minimized_learnt_clause() const; + size_t find_backtrack_level_of_learnt(); + Clause* otf_subsume_last_resolved_clause(Clause* last_resolved_long_cl); + void print_debug_resolution_data(const PropBy confl); + int pathC; + uint64_t more_red_minim_limit_binary_actual; + #if defined(STATS_NEEDED) || defined(FINAL_PREDICTOR) + AtecedentData antec_data; + #endif + Clause* handle_last_confl( + const uint32_t glue + , const uint32_t old_decision_level + , const uint32_t glue_before_minim + , const uint32_t size_before_minim + , const bool is_decision + , const uint32_t connects_num_communities + , int32_t& ID + ); + + ///////////////////// + // Search Stats + ///////////////////// + const SearchStats& get_stats() const; + size_t mem_used() const; + void reset_temp_cl_num(); + void resetStats(); //For connection with Solver + double startTime; /// tmp_gpu_clause; + PropBy learn_gpu_clause(Lit* lits, uint32_t count); + + ////////////// + // Debug + ////////////// + void print_solution_varreplace_status() const; + + ////////////// + // Conflict minimisation + bool litRedundant(Lit p, uint32_t abstract_levels); + void recursiveConfClauseMin(); + void normalClMinim(); + MyStack analyze_stack; + uint32_t abstractLevel(const uint32_t x) const; + bool subset(const vector& A, const Clause& B); //Used for on-the-fly subsumption. Does A subsume B? Uses 'seen' to do its work + void minimise_redundant_more_more(vector& cl); + void binary_based_morem_minim(vector& cl); + + friend class Gaussian; + friend class DistillerLong; + #ifdef CMS_TESTING_ENABLED + FRIEND_TEST(SearcherTest, pickpolar_rnd); + FRIEND_TEST(SearcherTest, pickpolar_pos); + FRIEND_TEST(SearcherTest, pickpolar_neg); + FRIEND_TEST(SearcherTest, pickpolar_auto); + FRIEND_TEST(SearcherTest, pickpolar_auto_not_changed_by_simp); + #endif + + //Clause activites + double cla_inc; + template void decayClauseAct(); + + //SQL + void dump_search_sql(const double myTime); + void set_clause_data( + Clause* cl + , const uint32_t glue + , const uint32_t glue_before_minim + , const uint32_t old_decision_level); + #ifdef STATS_NEEDED + PropStats lastSQLPropStats; + SearchStats lastSQLGlobalStats; + void dump_sql_clause_data( + const uint32_t glue, + const uint32_t size, + const uint32_t glue_before_minim, + const uint32_t size_before_minim, + const uint32_t old_decision_level, + const uint64_t clid, + const bool decision_cl, + const uint32_t connects_num_communities + ); + int dump_this_many_cldata_in_stream = 0; + void dump_var_for_learnt_cl(const uint32_t v, + const uint64_t clid, + const bool is_decision); + #endif + + #if defined(STATS_NEEDED_BRANCH) || defined(FINAL_PREDICTOR_BRANCH) + vector level_used_for_cl; + vector vars_used_for_cl; + vector level_used_for_cl_arr; + #endif + + //Other + void print_solution_type(const lbool status) const; + + //Last time we clean()-ed the clauses, the number of zero-depth assigns was this many + size_t lastCleanZeroDepthAssigns; +}; + +inline uint32_t Searcher::abstractLevel(const uint32_t x) const +{ + return ((uint32_t)1) << (varData[x].level & 31); +} + +inline const SearchStats& Searcher::get_stats() const +{ + return stats; +} + +inline const SearchHist& Searcher::getHistory() const +{ + return hist; +} + +inline void Searcher::add_in_partial_solving_stats() +{ + stats.cpu_time = cpuTime() - startTime; +} + +inline void Searcher::insert_var_order(const uint32_t x) +{ + insert_var_order(x, branch_strategy); +} + +inline void Searcher::insert_var_order(const uint32_t var, const branch type) +{ + #ifdef SLOW_DEUG + assert(varData[x].removed == Removed::none + && "All variables should be decision vars unless removed"); + #endif + + switch(type) { + case branch::vsids: + if (!order_heap_vsids.inHeap(var)) { + order_heap_vsids.insert(var); + } + break; + + case branch::vmtf: + // For VMTF we need to update the 'queue.unassigned' pointer in case this + // variables sits after the variable to which 'queue.unassigned' currently + // points. See our SAT'15 paper for more details on this aspect. + // + VERBOSE_PRINT("vmtf Inserting back: " << var + << " vmtf_queue.vmtf_bumped: " << vmtf_queue.vmtf_bumped + << " vmtf_btab[var]: " << vmtf_btab[var]); + + if (vmtf_queue.vmtf_bumped < vmtf_btab[var]) { + vmtf_update_queue_unassigned(var); + } + break; + + case branch::rand: + if (!order_heap_rand.inHeap(var)) { + order_heap_rand.insert(var); + } + break; + default: + assert(false); + exit(-1); + break; + } + +} + +inline void Searcher::insert_var_order_all(const uint32_t x) +{ + assert(!order_heap_vsids.inHeap(x)); + SLOW_DEBUG_DO(assert(varData[x].removed == Removed::none && + "All variables should be decision vars unless removed")); + order_heap_vsids.insert(x); + + assert(!order_heap_rand.inHeap(x)); + order_heap_rand.insert(x); + + vmtf_init_enqueue(x); +} + +template +inline void Searcher::bump_cl_act(Clause* cl) +{ + if (inprocess) + return; + + assert(!cl->getRemoved()); + + double new_val = cla_inc + (double)cl->stats.activity; + cl->stats.activity = (float)new_val; + if (max_cl_act < new_val) { + max_cl_act = new_val; + } + + + if (cl->stats.activity > 1e20F ) { + // Rescale. For STATS_NEEDED we rescale ALL + #if !defined(STATS_NEEDED) && !defined (FINAL_PREDICTOR) + for(ClOffset offs: longRedCls[2]) { + cl_alloc.ptr(offs)->stats.activity *= static_cast(1e-20); + } + #else + for(auto& lrcs: longRedCls) { + for(ClOffset offs: lrcs) { + cl_alloc.ptr(offs)->stats.activity *= static_cast(1e-20); + } + } + #endif + cla_inc *= 1e-20; + max_cl_act *= 1e-20; + assert(cla_inc != 0); + } +} + +template +inline void Searcher::decayClauseAct() +{ + if (inprocess) + return; + + cla_inc *= (1 / conf.clause_decay); +} + +inline bool Searcher::pick_polarity(const uint32_t var) +{ + switch(polarity_mode) { + case PolarityMode::polarmode_neg: + return false; + + case PolarityMode::polarmode_pos: + return true; + + case PolarityMode::polarmode_rnd: { + return rnd_uint(mtrand, 1); + } + + case PolarityMode::polarmode_automatic: + assert(false); + + case PolarityMode::polarmode_stable: + return varData[var].stable_polarity; + + case PolarityMode::polarmode_best_inv: + return !varData[var].inv_polarity; + + case PolarityMode::polarmode_best: + return varData[var].best_polarity; + + case PolarityMode::polarmode_saved: + return varData[var].saved_polarity; + + #ifdef WEIGHTED_SAMPLING + case PolarityMode::polarmode_weighted: { + double rnd = mtrand.randDblExc(); + return rnd < varData[var].weight; + } + #endif + + default: + assert(false); + } + + return true; +} + +template +inline void Searcher::vsids_bump_var_act(const uint32_t var) +{ + if (inprocess) return; + var_act_vsids[var] += var_inc_vsids; + max_vsids_act = std::max(max_vsids_act, var_act_vsids[var]); + + #ifdef SLOW_DEBUG + bool rescaled = false; + #endif + if (var_act_vsids[var] > 1e100) { + SLOW_DEBUG_DO(rescaled = true); + for (auto& v: var_act_vsids) v *= 1e-100; + max_vsids_act *= 1e-100; + var_inc_vsids *= 1e-100; + } + + // Update order_heap with respect to new activity + if (order_heap_vsids.inHeap(var)) { + order_heap_vsids.decrease(var); + } + + SLOW_DEBUG_DO(if (rescaled) assert(order_heap_vsids.heap_property())); +} + +} //end namespace + +#endif //__SEARCHER_H__ diff --git a/cryptominisat/cppsrc/src/searchhist.h b/cryptominisat/cppsrc/src/searchhist.h new file mode 100644 index 00000000..8a30faa6 --- /dev/null +++ b/cryptominisat/cppsrc/src/searchhist.h @@ -0,0 +1,160 @@ +/****************************************** +Copyright (C) 2009-2020 Authors of CryptoMiniSat, see AUTHORS file + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. +***********************************************/ + +#ifndef _SEARCHHIST_H_ +#define _SEARCHHIST_H_ + +#include +#include "avgcalc.h" +#include "boundedqueue.h" +#include +using std::cout; +using std::endl; + +namespace CMSat { + +//History +struct SearchHist { + //About the search + uint32_t num_conflicts_this_restart = 0; + AvgCalc branchDepthHist; ///< Avg branch depth in current restart + AvgCalc branchDepthDeltaHist; + + AvgCalc backtrackLevelHistLT; + AvgCalc trailDepthHistLT; + AvgCalc connects_num_communities_histLT; + + bqueue trailDepthHistLonger; /// trailDepthDeltaHist; /// glueHist; ///< Conflict glue history (this restart only) + AvgCalc glueHistLT; ///< Conflict glue history (all restarts) + AvgCalc glueHistLTLimited; //As before, but ONLY glue-based restart, max 50 glue + + AvgCalc conflSizeHist; ///< Conflict size history (this restart only) + AvgCalc conflSizeHistLT; ///< Conflict size history (all restarts) + AvgCalc numResolutionsHistLT; + + #if defined(STATS_NEEDED) || defined(FINAL_PREDICTOR) + bqueue backtrackLevelHist; + AvgCalc overlapHistLT; + AvgCalc antec_data_sum_sizeHistLT; + AvgCalc numResolutionsHist; ///< Number of resolutions during conflict analysis of THIS restart + AvgCalc decisionLevelHistLT; + bqueue branchDepthHistQueue; + bqueue trailDepthHist; + #endif + + size_t mem_used() const + { + uint64_t used = sizeof(SearchHist); + used += sizeof(AvgCalc)*16; + used += sizeof(AvgCalc)*4; + used += sizeof(AvgCalc)*2; + used += sizeof(AvgCalc)*2; + used += glueHist.usedMem(); + used += trailDepthHistLonger.usedMem(); + #if defined(STATS_NEEDED) || defined(FINAL_PREDICTOR) + used += backtrackLevelHist.usedMem(); + used += branchDepthHistQueue.usedMem(); + #endif + + return used; + } + + void clear() + { + //About the search + num_conflicts_this_restart = 0; + branchDepthHist.clear(); + branchDepthDeltaHist.clear(); + trailDepthDeltaHist.clear(); + + //conflict generated + glueHist.clear(); + conflSizeHist.clear(); + + #if defined(STATS_NEEDED) || defined(FINAL_PREDICTOR) + numResolutionsHist.clear(); + trailDepthHist.clear(); + branchDepthHistQueue.clear(); + #endif + } + + void reset_glueHist_size(size_t shortTermHistorySize) + { + glueHist.clearAndResize(shortTermHistorySize); + #if defined(STATS_NEEDED) || defined(FINAL_PREDICTOR) + backtrackLevelHist.clearAndResize(shortTermHistorySize); + trailDepthHist.clearAndResize(shortTermHistorySize); + branchDepthHistQueue.clearAndResize(shortTermHistorySize); + #endif + } + + void setSize(const size_t shortTermHistorySize, const size_t blocking_trail_hist_size) + { + glueHist.clearAndResize(shortTermHistorySize); + trailDepthHistLonger.clearAndResize(blocking_trail_hist_size); + #if defined(STATS_NEEDED) || defined(FINAL_PREDICTOR) + backtrackLevelHist.clearAndResize(shortTermHistorySize); + trailDepthHist.clearAndResize(shortTermHistorySize); + branchDepthHistQueue.clearAndResize(shortTermHistorySize); + #endif + } + + void print() const + { + cout + << " glue" + << " " + #ifdef STATS_NEEDED + << std::right << glueHist.getLongtTerm().avgPrint(1, 5) + #endif + << "/" << std::left << glueHistLT.avgPrint(1, 5) + + << " confllen" + << " " << std::right << conflSizeHist.avgPrint(1, 5) + << "/" << std::left << conflSizeHistLT.avgPrint(1, 5) + + << " branchd" + << " " << std::right << branchDepthHist.avgPrint(1, 5) + << " branchdd" + + << " " << std::right << branchDepthDeltaHist.avgPrint(1, 4) + + #ifdef STATS_NEEDED + << " traild" + << " " << std::right << trailDepthHist.getLongtTerm().avgPrint(0, 7) + #endif + + << " traildd" + << " " << std::right << trailDepthDeltaHist.avgPrint(0, 5) + ; + + cout << std::right; + } +}; + +} //end namespace + +#endif //_SEARCHHIST_H_ diff --git a/cryptominisat/cppsrc/src/searchstats.cpp b/cryptominisat/cppsrc/src/searchstats.cpp new file mode 100644 index 00000000..eed62e92 --- /dev/null +++ b/cryptominisat/cppsrc/src/searchstats.cpp @@ -0,0 +1,308 @@ +/****************************************** +Copyright (C) 2009-2020 Authors of CryptoMiniSat, see AUTHORS file + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. +***********************************************/ + +#include "searchstats.h" + +using namespace CMSat; + +SearchStats& SearchStats::operator+=(const SearchStats& other) +{ + numRestarts += other.numRestarts; + blocked_restart += other.blocked_restart; + blocked_restart_same += other.blocked_restart_same; + + //Decisions + decisions += other.decisions; + decisionsAssump += other.decisionsAssump; + decisionsRand += other.decisionsRand; + decisionFlippedPolar += other.decisionFlippedPolar; + + //Conflict minimisation stats + litsRedNonMin += other.litsRedNonMin; + litsRedFinal += other.litsRedFinal; + recMinCl += other.recMinCl; + recMinLitRem += other.recMinLitRem; + + permDiff_attempt += other.permDiff_attempt; + permDiff_rem_lits += other.permDiff_rem_lits; + permDiff_success += other.permDiff_success; + + furtherShrinkAttempt += other.furtherShrinkAttempt; + binTriShrinkedClause += other.binTriShrinkedClause; + furtherShrinkedSuccess += other.furtherShrinkedSuccess; + + + moreMinimLitsStart += other.moreMinimLitsStart; + moreMinimLitsEnd += other.moreMinimLitsEnd; + recMinimCost += other.recMinimCost; + + //Red stats + learntUnits += other.learntUnits; + learntBins += other.learntBins; + learntLongs += other.learntLongs; + otfSubsumed += other.otfSubsumed; + otfSubsumedImplicit += other.otfSubsumedImplicit; + otfSubsumedLong += other.otfSubsumedLong; + otfSubsumedRed += other.otfSubsumedRed; + otfSubsumedLitsGained += other.otfSubsumedLitsGained; + red_cl_in_which0 += other.red_cl_in_which0; + + //Hyper-bin & transitive reduction + advancedPropCalled += other.advancedPropCalled; + hyperBinAdded += other.hyperBinAdded; + transReduRemIrred += other.transReduRemIrred; + transReduRemRed += other.transReduRemRed; + + //Stat structs + resolvs += other.resolvs; + conflicts += other.conflicts; + + //Time + cpu_time += other.cpu_time; + + return *this; +} + +SearchStats& SearchStats::operator-=(const SearchStats& other) +{ + numRestarts -= other.numRestarts; + blocked_restart -= other.blocked_restart; + blocked_restart_same -= other.blocked_restart_same; + + //Decisions + decisions -= other.decisions; + decisionsAssump -= other.decisionsAssump; + decisionsRand -= other.decisionsRand; + decisionFlippedPolar -= other.decisionFlippedPolar; + + //Conflict minimisation stats + litsRedNonMin -= other.litsRedNonMin; + litsRedFinal -= other.litsRedFinal; + recMinCl -= other.recMinCl; + recMinLitRem -= other.recMinLitRem; + + permDiff_attempt -= other.permDiff_attempt; + permDiff_rem_lits -= other.permDiff_rem_lits; + permDiff_success -= other.permDiff_success; + + furtherShrinkAttempt -= other.furtherShrinkAttempt; + binTriShrinkedClause -= other.binTriShrinkedClause; + furtherShrinkedSuccess -= other.furtherShrinkedSuccess; + + moreMinimLitsStart -= other.moreMinimLitsStart; + moreMinimLitsEnd -= other.moreMinimLitsEnd; + recMinimCost -= other.recMinimCost; + + //Red stats + learntUnits -= other.learntUnits; + learntBins -= other.learntBins; + learntLongs -= other.learntLongs; + otfSubsumed -= other.otfSubsumed; + otfSubsumedImplicit -= other.otfSubsumedImplicit; + otfSubsumedLong -= other.otfSubsumedLong; + otfSubsumedRed -= other.otfSubsumedRed; + otfSubsumedLitsGained -= other.otfSubsumedLitsGained; + red_cl_in_which0 -= other.red_cl_in_which0; + + //Hyper-bin & transitive reduction + advancedPropCalled -= other.advancedPropCalled; + hyperBinAdded -= other.hyperBinAdded; + transReduRemIrred -= other.transReduRemIrred; + transReduRemRed -= other.transReduRemRed; + + //Stat structs + resolvs -= other.resolvs; + conflicts -= other.conflicts; + + //Time + cpu_time -= other.cpu_time; + + return *this; +} + +SearchStats SearchStats::operator-(const SearchStats& other) const +{ + SearchStats result = *this; + result -= other; + return result; +} + +void SearchStats::printCommon(uint64_t props, bool do_print_times) const +{ + print_stats_line("c restarts" + , numRestarts + , float_div(conflicts, numRestarts) + , "confls per restart" + + ); + print_stats_line("c blocked restarts" + , blocked_restart + , float_div(blocked_restart, numRestarts) + , "per normal restart" + + ); + if (do_print_times) + print_stats_line("c time", cpu_time); + print_stats_line("c decisions", decisions + , stats_line_percent(decisionsRand, decisions) + , "% random" + ); + + print_stats_line("c propagations" + , print_value_kilo_mega(props, false) + , print_value_kilo_mega(ratio_for_stat(props, cpu_time), false), + "props/s"); + + print_stats_line("c decisions/conflicts" + , float_div(decisions, conflicts) + ); +} + +void SearchStats::print_short(uint64_t props, bool do_print_times) const +{ + //Restarts stats + printCommon(props, do_print_times); + print_stats_line("c conflicts", conflicts); + print_stats_line("c conf lits non-minim" + , litsRedNonMin + , float_div(litsRedNonMin, conflicts) + , "lit/confl" + ); + + print_stats_line("c conf lits final" + , float_div(litsRedFinal, conflicts) + ); + + print_stats_line("c red which0" + , red_cl_in_which0 + , stats_line_percent(red_cl_in_which0, conflicts) + , "% of confl" + ); +} + +void SearchStats::print(uint64_t props, bool do_print_times) const +{ + printCommon(props, do_print_times); + print_stats_line("c conflicts", conflicts); + + /*assert(numConflicts + == conflsBin + conflsTri + conflsLongIrred + conflsLongRed);*/ + + cout << "c LEARNT stats" << endl; + print_stats_line("c units learnt" + , learntUnits + , stats_line_percent(learntUnits, conflicts) + , "% of conflicts"); + + print_stats_line("c bins learnt" + , learntBins + , stats_line_percent(learntBins, conflicts) + , "% of conflicts"); + + print_stats_line("c long learnt" + , learntLongs + , stats_line_percent(learntLongs, conflicts) + , "% of conflicts" + ); + + print_stats_line("c red which0" + , red_cl_in_which0 + , stats_line_percent(red_cl_in_which0, conflicts) + , "% of confl" + ); + + cout << "c SEAMLESS HYPERBIN&TRANS-RED stats" << endl; + print_stats_line("c advProp called" + , advancedPropCalled + ); + print_stats_line("c hyper-bin add bin" + , hyperBinAdded + , ratio_for_stat(hyperBinAdded, advancedPropCalled) + , "bin/call" + ); + print_stats_line("c trans-red rem irred bin" + , transReduRemIrred + , ratio_for_stat(transReduRemIrred, advancedPropCalled) + , "bin/call" + ); + print_stats_line("c trans-red rem red bin" + , transReduRemRed + , ratio_for_stat(transReduRemRed, advancedPropCalled) + , "bin/call" + ); + + cout << "c CONFL LITS stats" << endl; + print_stats_line("c orig " + , litsRedNonMin + , ratio_for_stat(litsRedNonMin, conflicts) + , "lit/confl" + ); + + print_stats_line("c recurs-min effective" + , recMinCl + , stats_line_percent(recMinCl, conflicts) + , "% attempt successful" + ); + + print_stats_line("c recurs-min lits" + , recMinLitRem + , stats_line_percent(recMinLitRem, litsRedNonMin) + , "% less overall" + ); + + print_stats_line("c permDiff call%" + , stats_line_percent(permDiff_attempt, conflicts) + , stats_line_percent(permDiff_success, permDiff_attempt) + , "% attempt successful" + ); + + print_stats_line("c permDiff lits-rem" + , permDiff_rem_lits + , ratio_for_stat(permDiff_rem_lits, permDiff_attempt) + , "less lits/cl on attempts" + ); + + + print_stats_line("c further-min call%" + , stats_line_percent(furtherShrinkAttempt, conflicts) + , stats_line_percent(furtherShrinkedSuccess, furtherShrinkAttempt) + , "% attempt successful" + ); + + print_stats_line("c bintri-min lits" + , binTriShrinkedClause + , stats_line_percent(binTriShrinkedClause, litsRedNonMin) + , "% less overall" + ); + + print_stats_line("c final avg" + , ratio_for_stat(litsRedFinal, conflicts) + ); + + //General stats + //print_stats_line("c Memory used", (double)mem_used / 1048576.0, " MB"); + #if !defined(_MSC_VER) && defined(RUSAGE_THREAD) + print_stats_line("c single-thread CPU time", cpu_time, " s"); + #else + print_stats_line("c all-threads sum CPU time", cpu_time, " s"); + #endif +} diff --git a/cryptominisat/cppsrc/src/searchstats.h b/cryptominisat/cppsrc/src/searchstats.h new file mode 100644 index 00000000..c4118f87 --- /dev/null +++ b/cryptominisat/cppsrc/src/searchstats.h @@ -0,0 +1,107 @@ +/****************************************** +Copyright (C) 2009-2020 Authors of CryptoMiniSat, see AUTHORS file + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. +***********************************************/ + +#ifndef __SEARCHSTATS_H__ +#define __SEARCHSTATS_H__ + +#include + +#include "solvertypes.h" +#include "clause.h" + +namespace CMSat { + +class SearchStats +{ +public: + void clear() + { + SearchStats tmp; + *this = tmp; + } + + SearchStats& operator+=(const SearchStats& other); + SearchStats& operator-=(const SearchStats& other); + SearchStats operator-(const SearchStats& other) const; + void printCommon(uint64_t props, bool do_print_times) const; + void print_short(uint64_t props, bool do_print_times) const; + void print(uint64_t props, bool do_print_times) const; + + //Restart stats + uint64_t blocked_restart = 0; + uint64_t blocked_restart_same = 0; + uint64_t numRestarts = 0; + + //Decisions + uint64_t decisions = 0; + uint64_t decisionsAssump = 0; + uint64_t decisionsRand = 0; + uint64_t decisionFlippedPolar = 0; + + //Clause shrinking + uint64_t litsRedNonMin = 0; + uint64_t litsRedFinal = 0; + uint64_t recMinCl = 0; + uint64_t recMinLitRem = 0; + uint64_t permDiff_attempt = 0; + uint64_t permDiff_success = 0; + uint64_t permDiff_rem_lits = 0; + + uint64_t furtherShrinkAttempt = 0; + uint64_t binTriShrinkedClause = 0; + uint64_t furtherShrinkedSuccess = 0; + uint64_t moreMinimLitsStart = 0; + uint64_t moreMinimLitsEnd = 0; + uint64_t recMinimCost = 0; + + //Learnt clause stats + uint64_t learntUnits = 0; + uint64_t learntBins = 0; + uint64_t learntLongs = 0; + uint64_t otfSubsumed = 0; + uint64_t otfSubsumedImplicit = 0; + uint64_t otfSubsumedLong = 0; + uint64_t otfSubsumedRed = 0; + uint64_t otfSubsumedLitsGained = 0; + uint64_t red_cl_in_which0 = 0; + + //Hyper-bin & transitive reduction + uint64_t advancedPropCalled = 0; + uint64_t hyperBinAdded = 0; + uint64_t transReduRemIrred = 0; + uint64_t transReduRemRed = 0; + + //SatZillaFeatures + uint64_t num_xors_found_last = 0; + uint64_t num_gates_found_last = 0; + + //Resolution Stats + AtecedentData resolvs; + uint32_t conflicts = 0; + + //Time + double cpu_time = 0.0; +}; + +} + +#endif //__SEARCHSTATS_H__ diff --git a/cryptominisat/cppsrc/src/shareddata.h b/cryptominisat/cppsrc/src/shareddata.h new file mode 100644 index 00000000..a1f45737 --- /dev/null +++ b/cryptominisat/cppsrc/src/shareddata.h @@ -0,0 +1,120 @@ +/****************************************** +Copyright (C) 2009-2020 Authors of CryptoMiniSat, see AUTHORS file + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. +***********************************************/ + +#ifndef SHARED_DATA_H +#define SHARED_DATA_H + +#include "solvertypesmini.h" +#ifdef USE_GPU +#include "gpuShareLib/GpuClauseSharer.h" +#endif + +#include +#include +#include +using std::vector; +using std::mutex; + +namespace CMSat { + +class SharedData +{ + public: + SharedData(const uint32_t _num_threads) : + num_threads(_num_threads) + { + #ifdef USE_GPU + csOpts.verbosity = 0; + gpuClauseSharer = GpuShare::makeGpuClauseSharerPtr(csOpts); + #endif + cur_thread_id.store(0); + } + + ~SharedData() + { + #ifdef USE_GPU + delete gpuClauseSharer; + #endif + } + + struct Spec { + Spec() : + data(new vector) + {} + + Spec(const Spec&) = delete; + Spec& operator=(const Spec&) = delete; + + Spec(Spec&& other) + #ifndef _MSC_VER + noexcept + #endif + : + data(std::move(other.data)) + { + other.data = NULL; + } + ~Spec() { + clear(); + } + vector* data = NULL; + + void clear() + { + delete data; + data = NULL; + } + }; + + #ifdef USE_GPU + GpuShare::GpuClauseSharerOptions csOpts; + GpuShare::GpuClauseSharer* gpuClauseSharer = NULL; + #else + vector bins; + std::mutex bin_mutex; + #endif + + vector value; + std::mutex unit_mutex; + std::atomic cur_thread_id; + uint32_t num_threads; + + size_t calc_memory_use_bins() + { + size_t mem = 0; + mem += value.capacity()*sizeof(lbool); + #ifndef USE_GPU + mem += bins.capacity()*sizeof(Spec); + for(size_t i = 0; i < bins.size(); i++) { + if (bins[i].data) { + mem += bins[i].data->capacity()*sizeof(Lit); + mem += sizeof(vector); + } + } + #endif + return mem; + } +}; + +} + +#endif //SHARED_DATA_H diff --git a/cryptominisat/cppsrc/src/signalcode.cpp b/cryptominisat/cppsrc/src/signalcode.cpp new file mode 100644 index 00000000..a238e4ad --- /dev/null +++ b/cryptominisat/cppsrc/src/signalcode.cpp @@ -0,0 +1,69 @@ +/* +Copyright (C) 2009-2020 Authors of CryptoMiniSat, see AUTHORS file + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. +*/ + +#include "signalcode.h" +#include "time_mem.h" +#include "cryptominisat.h" +#if !defined (_MSC_VER) +#include +#endif + + +using namespace CMSat; + +SATSolver* solverToInterrupt; +int need_clean_exit; +std::string redDumpFname; +std::string irredDumpFname; + +using std::cout; +using std::endl; + +void SIGINT_handler(int) +{ + SATSolver* solver = solverToInterrupt; + cout << "c " << endl; + std::cerr << "*** INTERRUPTED ***" << endl; + if (!redDumpFname.empty() || !irredDumpFname.empty() || need_clean_exit) { + solver->interrupt_asap(); + std::cerr + << "*** Please wait. We need to interrupt cleanly" << endl + << "*** This means we might need to finish some calculations" + << endl; + } else { + if (solver->nVars() > 0) { + //if (conf.verbosity) { + solver->add_in_partial_solving_stats(); + solver->print_stats(wallclock_time_started); + //} + } else { + cout + << "No clauses or variables were put into the solver, exiting without stats" + << endl; + } + #if defined (_MSC_VER) + exit(1); + #else + _exit(1); + #endif + } +} diff --git a/cryptominisat/cppsrc/src/signalcode.h b/cryptominisat/cppsrc/src/signalcode.h new file mode 100644 index 00000000..f1b92a19 --- /dev/null +++ b/cryptominisat/cppsrc/src/signalcode.h @@ -0,0 +1,38 @@ +/* +Copyright (C) 2009-2020 Authors of CryptoMiniSat, see AUTHORS file + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. +*/ + +#ifndef SIGNALCODE_H_ +#define SIGNALCODE_H_ + +#include + +namespace CMSat { + class SATSolver; +} +using namespace CMSat; + +extern SATSolver* solverToInterrupt; +extern int need_clean_exit; +extern double wallclock_time_started; +void SIGINT_handler(int); + +#endif //SIGNALCODE_H_ diff --git a/cryptominisat/cppsrc/src/simplefile.h b/cryptominisat/cppsrc/src/simplefile.h new file mode 100644 index 00000000..19e63f28 --- /dev/null +++ b/cryptominisat/cppsrc/src/simplefile.h @@ -0,0 +1,173 @@ +/****************************************** +Copyright (C) 2009-2020 Authors of CryptoMiniSat, see AUTHORS file + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. +***********************************************/ + +#ifndef __SIMPLEFILE_H__ +#define __SIMPLEFILE_H__ + +#include +#include +#include +#include +using std::ios; + +#include "solvertypes.h" + +namespace CMSat { + +class SimpleOutFile +{ +public: + void start(const string& fname) + { + outf = new std::ofstream(fname.c_str(), ios::out | ios::binary); + outf->exceptions(~std::ios::goodbit); + //buffer.resize(100000000); + //outf->rdbuf()->pubsetbuf(&buffer.front(), buffer.size()); + } + + ~SimpleOutFile() + { + delete outf; + } + + void put_uint32_t(const uint32_t val) + { + put(&val, 4); + } + + void put_lbool(const lbool val) + { + put(&val, sizeof(lbool)); + } + + void put_uint64_t(const uint64_t val) + { + put(&val, 8); + } + + void put_lit(const Lit l) + { + put_uint32_t(l.toInt()); + } + + template + void put_vector(const vector& d) + { + put_uint64_t(d.size()); + if (d.size() == 0) + return; + + put(d.data(), d.size() * sizeof(T)); + } + + template + void put_struct(const T& d) + { + put(&d, sizeof(T)); + } + +private: + std::ofstream* outf = NULL; + //vector buffer; + + void put(const void* ptr, size_t num) + { + outf->write((const char*)ptr, num); + } +}; + +class SimpleInFile +{ +public: + void start(const string& fname) + { + try { + inf = new std::ifstream(fname.c_str(), ios::in | ios::binary); + inf->exceptions(~std::ios::goodbit); + } catch (...) { + cout << "Error opening file " << fname.c_str() << endl; + exit(-1); + } + } + + ~SimpleInFile() + { + delete inf; + } + + uint32_t get_uint32_t() + { + uint32_t val = 0; + inf->read((char*)&val, 4); + return val; + } + + uint64_t get_uint64_t() + { + uint64_t val = 0; + inf->read((char*)&val, 8); + return val; + } + + Lit get_lit() + { + uint32_t l = get_uint32_t(); + return Lit::toLit(l); + } + + lbool get_lbool() + { + lbool l; + inf->read((char*)&l, sizeof(lbool)); + return l; + } + + template + void get_vector(vector& d) + { + assert(d.empty()); + uint64_t sz = get_uint64_t(); + if (sz == 0) + return; + + d.resize(sz); + get_raw(&d[0], d.size(), sizeof(T)); + } + + template + void get_struct(T& d) + { + inf->read((char*)&d, sizeof(T)); + } + +private: + std::ifstream* inf = NULL; + + void get_raw(void* ptr, size_t num, size_t elem_sz) + { + inf->read((char*)ptr, num*elem_sz); + } +}; + +} + +#endif //__SIMPLEFILE_H__ diff --git a/cryptominisat/cppsrc/src/sls.cpp b/cryptominisat/cppsrc/src/sls.cpp new file mode 100644 index 00000000..6efe7c8c --- /dev/null +++ b/cryptominisat/cppsrc/src/sls.cpp @@ -0,0 +1,99 @@ +/****************************************** +Copyright (C) 2009-2020 Authors of CryptoMiniSat, see AUTHORS file + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. +***********************************************/ + +#include "sls.h" +#include "solver.h" +#include "ccnr_cms.h" + +using namespace CMSat; + +SLS::SLS(Solver* _solver) : + solver(_solver) +{} + +SLS::~SLS() +{} + +lbool SLS::run(const uint32_t num_sls_called) +{ + return run_ccnr(num_sls_called); +} + +lbool SLS::run_ccnr(const uint32_t num_sls_called) +{ + CMS_ccnr ccnr(solver); + double mem_needed_mb = (double)approx_mem_needed()/(1000.0*1000.0); + double maxmem = solver->conf.sls_memoutMB*solver->conf.var_and_mem_out_mult; + if (mem_needed_mb < maxmem) { + lbool ret = ccnr.main(num_sls_called); + return ret; + } + + verb_print(1, "[sls] would need " + << std::setprecision(2) << std::fixed << mem_needed_mb + << " MB but that's over limit of " << std::fixed << maxmem + << " MB -- skipping"); + + return l_Undef; +} + +uint64_t SLS::approx_mem_needed() +{ + uint32_t numvars = solver->nVars(); + uint32_t numclauses = solver->longIrredCls.size() + solver->binTri.irredBins; + uint64_t numliterals = solver->litStats.irredLits + solver->binTri.irredBins*2; + uint64_t needed = 0; + + //LIT storage (all clause data) + needed += (solver->litStats.irredLits+solver->binTri.irredBins*2)*sizeof(Lit); + + //This is just an estimation of yalsat's memory needs. + + //clause + needed += sizeof(Lit *) * numclauses; + //clsize + needed += sizeof(uint32_t) * numclauses; + + //false_cls + needed += sizeof(uint32_t) * numclauses; + //map_cl_to_false_cls + needed += sizeof(uint32_t) * numclauses; + //numtruelit + needed += sizeof(uint32_t) * numclauses; + + //occurrence + needed += sizeof(uint32_t *) * (2 * numvars); + //numoccurrence + needed += sizeof(uint32_t) * (2 * numvars); + //assigns + needed += sizeof(lbool) * numvars; + //breakcount + needed += sizeof(uint32_t) * numvars; + //makecount + needed += sizeof(uint32_t) * numvars; + + //occur_list_alloc + needed += sizeof(uint32_t) * numliterals; + + + return needed; +} diff --git a/cryptominisat/cppsrc/src/sls.h b/cryptominisat/cppsrc/src/sls.h new file mode 100644 index 00000000..ff58c7ea --- /dev/null +++ b/cryptominisat/cppsrc/src/sls.h @@ -0,0 +1,47 @@ +/****************************************** +Copyright (C) 2009-2020 Authors of CryptoMiniSat, see AUTHORS file + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. +***********************************************/ + +#ifndef SLS_H_ +#define SLS_H_ + +#include "solvertypes.h" + +namespace CMSat { + +class Solver; + +class SLS { +public: + SLS(Solver* solver); + ~SLS(); + lbool run(const uint32_t num_sls_called); + +private: + Solver* solver; + + lbool run_ccnr(const uint32_t num_sls_called); + uint64_t approx_mem_needed(); +}; + +} //end namespace CMSat + +#endif //SLS_H_ diff --git a/cryptominisat/cppsrc/src/solutionextender.cpp b/cryptominisat/cppsrc/src/solutionextender.cpp new file mode 100644 index 00000000..bcb092f8 --- /dev/null +++ b/cryptominisat/cppsrc/src/solutionextender.cpp @@ -0,0 +1,213 @@ +/****************************************** +Copyright (C) 2009-2020 Authors of CryptoMiniSat, see AUTHORS file + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. +***********************************************/ + +#include "solutionextender.h" +#include "solver.h" +#include "varreplacer.h" +#include "occsimplifier.h" + +//#define VERBOSE_DEBUG_SOLUTIONEXTENDER + +using namespace CMSat; + +SolutionExtender::SolutionExtender(Solver* _solver, OccSimplifier* _simplifier) : + solver(_solver) + , simplifier(_simplifier) +{ +} + +//Model at this point has OUTER variables +void SolutionExtender::extend() +{ + if (solver->conf.verbosity >= 10) { + cout << "c Exteding solution -- SolutionExtender::extend()" << endl; + } + + #ifdef SLOW_DEBUG + for(uint32_t i = 0; i < solver->varData.size(); i++) { + uint32_t v_inter = solver->map_outer_to_inter(i); + if ( + //decomposed's solution has beed added already, it SHOULD be set + //but everything else is NOT OK + (solver->varData[v_inter].removed != Removed::none + && solver->varData[v_inter].removed != Removed::clashed + ) + && solver->model[i] != l_Undef + ) { + cout << "ERROR: variable " << i + 1 + << " set even though it's removed: " + << removed_type_to_string(solver->varData[v_inter].removed) << endl; + //solver->model[i] = l_Undef; + assert(solver->model[i] == l_Undef); + } + } + #endif + + //Extend variables already set + solver->varReplacer->extend_model_already_set(); + if (simplifier) simplifier->extend_model(this); + + //clause has been added with "lit, ~lit" so var must be set + for(size_t i = 0; i < solver->undef_must_set_vars.size(); i++) { + if (solver->undef_must_set_vars[i] + && solver->model_value(i) == l_Undef + ) { + solver->model[i] = l_False; + } + } + + //All variables, not just those set + solver->varReplacer->extend_model_set_undef(); +} + +inline bool SolutionExtender::satisfied(const vector< Lit >& lits) const +{ + for(const Lit lit: lits) { + if (solver->model_value(lit) == l_True) + return true; + } + + return false; +} + +//called with _outer_ variable in "elimedOn" +void SolutionExtender::dummyElimed(const uint32_t elimedOn) +{ + #ifdef VERBOSE_DEBUG_SOLUTIONEXTENDER + cout + << "dummy elimed lit (outer) " + << elimedOn + 1 + << endl; + #endif + + #ifdef SLOW_DEBUG + const uint32_t elimedOn_inter = solver->map_outer_to_inter(elimedOn); + assert(solver->varData[elimedOn_inter].removed == Removed::elimed); + #endif + + //Elimed clauses set its value already + if (solver->model_value(elimedOn) != l_Undef) + return; + + solver->model[elimedOn] = l_False; + + //If var is replacing something else, it MUST be set. + if (solver->varReplacer->var_is_replacing(elimedOn)) { + solver->varReplacer->extend_model(elimedOn); + } +} + +bool SolutionExtender::addClause(const vector& lits, const uint32_t elimedOn) +{ + #ifdef VERBOSE_DEBUG_SOLUTIONEXTENDER + cout + << "outer clause: " + << lits + << endl; + #endif + + #ifdef SLOW_DEBUG + const uint32_t elimed_on_inter = solver->map_outer_to_inter(elimedOn); + assert(solver->varData[elimed_on_inter].removed == Removed::elimed); + assert(contains_var(lits, elimedOn)); + #endif + + //Try to extend through setting variables that have been elimed but + //were not required to be set until now + /*for(Lit l: lits) { + if (solver->model_value(l) == l_Undef + && var_has_been_elimed[l.var()] + ) { + solver->model[l.var()] = l.sign() ? l_False : l_True; + solver->varReplacer->extend_model(l.var()); + return false; + } + }*/ + + //Try to set var that hasn't been set +// for(Lit l: lits) { +// uint32_t v_inter = solver->map_outer_to_inter(l.var()); +// if (solver->model_value(l) == l_Undef +// && solver->varData[v_inter].removed == Removed::none +// ) { +// solver->model[l.var()] = l.sign() ? l_False : l_True; +// solver->varReplacer->extend_model(l.var()); +// return false; +// } +// } + + if (solver->conf.verbosity >= 10) { + for(Lit lit: lits) { + Lit lit_inter = solver->map_outer_to_inter(lit); + cout + << lit << ": " << solver->model_value(lit) + << "(elim: " << removed_type_to_string(solver->varData[lit_inter.var()].removed) << ")" + << ", "; + } + cout << "elimed on: " << elimedOn+1 << endl; + } + + if (solver->model_value(elimedOn) != l_Undef) { + cout << "ERROR: Model value for var " << elimedOn+1 << " is " + << solver->model_value(elimedOn) + << " but that doesn't satisfy a v-elim clause on the stack!" + << " clause is: " << lits + << endl; + + for(Lit l: lits) { + uint32_t v_inter = solver->map_outer_to_inter(l.var()); + cout << "Value of " << l << " : " << solver-> model_value(l) + << " removed: " << removed_type_to_string(solver->varData[v_inter].removed) + << endl; + } + } + assert(solver->model_value(elimedOn) == l_Undef); + + //satisfy this one clause + Lit actual_lit = lit_Undef; + for(Lit l: lits) { + lbool model_value = solver-> model_value(l); + assert(model_value != l_True); + if (l.var() == elimedOn) { + actual_lit = l; + } else { + if (model_value == l_Undef) { + } else { + assert(model_value == l_False); + } + } + } + assert(actual_lit != lit_Undef); + lbool val = actual_lit.sign() ? l_False : l_True; + solver->model[elimedOn] = val; + + if (solver->conf.verbosity >= 10) { + cout << "Extending VELIM cls. -- setting model for var " + << elimedOn + 1 << " to " << solver->model[elimedOn] << endl; + } + solver->varReplacer->extend_model(elimedOn); + + assert(satisfied(lits)); + + //it's been set now + return true; +} diff --git a/cryptominisat/cppsrc/src/solutionextender.h b/cryptominisat/cppsrc/src/solutionextender.h new file mode 100644 index 00000000..f0cf0e0b --- /dev/null +++ b/cryptominisat/cppsrc/src/solutionextender.h @@ -0,0 +1,72 @@ +/****************************************** +Copyright (C) 2009-2020 Authors of CryptoMiniSat, see AUTHORS file + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. +***********************************************/ + +#ifndef __SOLUTIONEXTENDER_H__ +#define __SOLUTIONEXTENDER_H__ + +#include "solvertypes.h" +#include "clause.h" +#include "watcharray.h" + +namespace CMSat { + +#ifdef VERBOSE_DEBUG +#define VERBOSE_DEBUG_RECONSTRUCT +#endif + +class Solver; +class OccSimplifier; + +class SolutionExtender +{ + public: + SolutionExtender(Solver* _solver, OccSimplifier* simplifier); + void extend(); + bool addClause(const vector& lits, const uint32_t elimedOn); + void dummyElimed(const uint32_t elimedOn); + + private: + Solver* solver; + OccSimplifier* simplifier; + + bool satisfied(const vector& lits) const; + bool contains_var( + const vector& lits + , const uint32_t tocontain + ) const; +}; + +inline bool SolutionExtender::contains_var( + const vector& lits + , const uint32_t tocontain +) const { + for(const Lit lit: lits) { + if (lit.var() == tocontain) + return true; + } + + return false; +} + +} //end namespace + +#endif //__SOLUTIONEXTENDER_H__ diff --git a/cryptominisat/cppsrc/src/solutionextender_old-h b/cryptominisat/cppsrc/src/solutionextender_old-h new file mode 100644 index 00000000..83f3c0d2 --- /dev/null +++ b/cryptominisat/cppsrc/src/solutionextender_old-h @@ -0,0 +1,87 @@ +/****************************************** +Copyright (c) 2016, Mate Soos + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. +***********************************************/ + +#ifndef __SOLUTIONEXTENDER_H__ +#define __SOLUTIONEXTENDER_H__ + +#include "solvertypes.h" +#include "clause.h" +#include "watcharray.h" + +namespace CMSat { + +#ifdef VERBOSE_DEBUG +#define VERBOSE_DEBUG_RECONSTRUCT +#endif + +class Solver; + +class SolutionExtender +{ + public: + SolutionExtender(Solver* _solver, const vector& _assigns); + void extend(); + bool addClause(const vector& lits, const Lit blockedOn = lit_Undef); + void enqueue(const Lit lit); + + lbool value(const Lit lit) const + { + return assigns[lit.var()] ^ lit.sign(); + } + + lbool value(const uint32_t var) const + { + return assigns[var]; + } + + private: + void replaceSet(Lit toSet); + void replaceBackwardSet(const Lit toSet); + bool propagateCl(const Clause* cl, const Lit blockedOn); + bool propagate(); + bool prop_bin_cl( + Watched*& i + , const Lit p + ); + bool satisfiedNorm(const vector& lits) const; + bool satisfiedXor(const vector& lits, const bool rhs) const; + Lit pickBranchLit(); + + uint32_t nVarsOuter() const + { + return assigns.size(); + } + + //To reduce mem alloc overhead + vector tmpLits; + + + Solver* solver; + vector clausesToFree; + uint32_t qhead; + vector trail; + vector assigns; +}; + +} //end namespace + +#endif //__SOLUTIONEXTENDER_H__ diff --git a/cryptominisat/cppsrc/src/solver.cpp b/cryptominisat/cppsrc/src/solver.cpp new file mode 100644 index 00000000..a9ba9694 --- /dev/null +++ b/cryptominisat/cppsrc/src/solver.cpp @@ -0,0 +1,5625 @@ +/****************************************** +Copyright (C) 2009-2020 Authors of CryptoMiniSat, see AUTHORS file + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. +***********************************************/ + +#include "solver.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#ifdef ARJUN_SERIALIZE +#include +#include +#include +#include +#include +#endif + +#include "varreplacer.h" +#include "time_mem.h" +#include "searcher.h" +#include "occsimplifier.h" +#include "distillerlong.h" +#include "distillerbin.h" +#include "distillerlitrem.h" +#include "clausecleaner.h" +#include "solutionextender.h" +#include "varupdatehelper.h" +#include "completedetachreattacher.h" +#include "subsumestrengthen.h" +#include "watchalgos.h" +#include "clauseallocator.h" +#include "subsumeimplicit.h" +#include "distillerlongwithimpl.h" +#include "str_impl_w_impl.h" +#include "datasync.h" +#include "reducedb.h" +#include "sccfinder.h" +#include "intree.h" +#include "satzilla_features_calc.h" +#include "GitSHA1.h" +#include "trim.h" +#include "streambuffer.h" +#include "gaussian.h" +#include "sqlstats.h" +#include "frat.h" +#include "xorfinder.h" +#include "cardfinder.h" +#include "sls.h" +#include "matrixfinder.h" +#include "lucky.h" +#include "get_clause_query.h" +#include "community_finder.h" +#include "oracle/oracle.h" +extern "C" { +#include "picosat/picosat.h" +} +#include "cryptominisat.h" + +#ifdef USE_BREAKID +#include "cms_breakid.h" +#endif + +#ifdef USE_BOSPHORUS +#include "cms_bosphorus.h" +#endif + +using namespace CMSat; +using std::cout; +using std::endl; + +#ifdef USE_SQLITE3 +#include "sqlitestats.h" +#endif + +//#define FRAT_DEBUG + +//#define DEBUG_RENUMBER + +//#define DEBUG_IMPLICIT_PAIRS_TRIPLETS + +Solver::Solver(const SolverConf *_conf, std::atomic* _must_interrupt_inter) : + Searcher(_conf, this, _must_interrupt_inter) +{ + sqlStats = NULL; + intree = new InTree(this); + +#ifdef USE_BREAKID + if (conf.doBreakid) { + breakid = new BreakID(this); + } +#endif + + if (conf.perform_occur_based_simp) { + occsimplifier = new OccSimplifier(this); + } + if (conf.doFindCard) { + card_finder = new CardFinder(this); + } + distill_long_cls = new DistillerLong(this); + distill_bin_cls = new DistillerBin(this); + distill_lit_rem = new DistillerLitRem(this); + dist_long_with_impl = new DistillerLongWithImpl(this); + dist_impl_with_impl = new StrImplWImpl(this); + clauseCleaner = new ClauseCleaner(this); + varReplacer = new VarReplacer(this); + if (conf.doStrSubImplicit) { + subsumeImplicit = new SubsumeImplicit(this); + } + datasync = new DataSync(this, NULL); + Searcher::solver = this; + reduceDB = new ReduceDB(this); + + set_up_sql_writer(); + next_lev1_reduce = conf.every_lev1_reduce; + next_lev2_reduce = conf.every_lev2_reduce; + #if defined(STATS_NEEDED) || defined(FINAL_PREDICTOR) + next_pred_reduce = conf.every_pred_reduce; + #endif + + check_xor_cut_config_sanity(); +} + +Solver::~Solver() +{ + delete sqlStats; + delete intree; + delete occsimplifier; + delete distill_long_cls; + delete distill_lit_rem; + delete distill_bin_cls; + delete dist_long_with_impl; + delete dist_impl_with_impl; + delete clauseCleaner; + delete varReplacer; + delete subsumeImplicit; + delete datasync; + delete reduceDB; +#ifdef USE_BREAKID + delete breakid; +#endif + delete card_finder; +} + +void Solver::set_sqlite( + [[maybe_unused]] const string filename +) { + #ifdef USE_SQLITE3 + sqlStats = new SQLiteStats(filename); + if (!sqlStats->setup(this)) exit(-1); + if (conf.verbosity >= 4) { + cout << "c Connected to SQLite server" << endl; + } + if (frat->enabled()) frat->set_sqlstats_ptr(sqlStats); + #else + std::cerr << "SQLite support was not compiled in, cannot use it. Exiting." + << endl; + std::exit(-1); + #endif +} + +void Solver::set_shared_data(SharedData* shared_data) +{ + datasync->set_shared_data(shared_data); +} + +bool Solver::add_xor_clause_inter( + const vector& lits + , bool rhs + , const bool attach + , bool addDrat + , bool red +) { + VERBOSE_PRINT("add_xor_clause_inter: " << lits << " rhs: " << rhs); + assert(ok); + assert(!attach || qhead == trail.size()); + assert(decisionLevel() == 0); + + vector ps(lits); + for(Lit& lit: ps) { + if (lit.sign()) { + rhs ^= true; + lit ^= true; + } + } + clean_xor_no_prop(ps, rhs); + + if (ps.size() >= (0x01UL << 28)) throw CMSat::TooLongClauseError(); + + if (ps.empty()) { + if (rhs) { + *frat << add << ++clauseID << fin; + ok = false; + } + return ok; + } + + ps[0] ^= rhs; + + //cout << "without rhs is: " << ps << endl; + add_every_combination_xor(ps, attach, addDrat, red); + if (ps.size() > 2) { + xor_clauses_updated = true; + xorclauses.push_back(Xor(ps, rhs, tmp_xor_clash_vars)); + xorclauses_orig.push_back(Xor(ps, rhs, tmp_xor_clash_vars)); + TBUDDY_DO(if (frat->enabled()) xorclauses.back().create_bdd_xor()); + TBUDDY_DO(if (frat->enabled()) xorclauses_orig.back().create_bdd_xor()); + } + + return ok; +} + +void Solver::add_every_combination_xor( + const vector& lits + , const bool attach + , const bool addDrat + , const bool red +) { + VERBOSE_PRINT("add_every_combination: " << lits); + + size_t at = 0; + vector xorlits; + tmp_xor_clash_vars.clear(); + Lit lastlit_added = lit_Undef; + while(at != lits.size()) { + xorlits.clear(); + size_t last_at = at; + for(; at < last_at+conf.xor_var_per_cut && at < lits.size(); at++) { + xorlits.push_back(lits[at]); + } + + //Connect to old cut + if (lastlit_added != lit_Undef) { + xorlits.push_back(lastlit_added); + } else if (at < lits.size()) { + xorlits.push_back(lits[at]); + at++; + } + + if (at + 1 == lits.size()) { + xorlits.push_back(lits[at]); + at++; + } + + //New lit to connect to next cut + if (at != lits.size()) { + new_var(true); + const uint32_t newvar = nVars()-1; + tmp_xor_clash_vars.push_back(newvar); + const Lit toadd = Lit(newvar, false); + xorlits.push_back(toadd); + lastlit_added = toadd; + } + + add_xor_clause_inter_cleaned_cut(xorlits, attach, addDrat, red); + if (!ok) break; + } +} + +void Solver::add_xor_clause_inter_cleaned_cut( + const vector& lits + , const bool attach + , const bool addDrat + , const bool red +) { + VERBOSE_PRINT("add_xor_clause_inter_cleaned_cut: " << lits); + vector new_lits; + for(size_t i = 0; i < (1ULL<> at)&1; + new_lits.push_back(lits[at] ^ xorwith); + } + //cout << "Added. " << new_lits << endl; + Clause* cl = add_clause_int( + new_lits, //lits + red, //redundant? + NULL, //clause stats + attach, //attach it? + NULL, //get back the final set of literals + addDrat //add to FRAT? + ); + + if (cl) { + cl->set_used_in_xor(true); + cl->set_used_in_xor_full(true); + if (red) { + longRedCls[2].push_back(cl_alloc.get_offset(cl)); + } else { + longIrredCls.push_back(cl_alloc.get_offset(cl)); + } + } + + if (!ok) + return; + } +} + +unsigned Solver::num_bits_set(const size_t x, const unsigned max_size) const +{ + unsigned bits_set = 0; + for(size_t i = 0; i < max_size; i++) { + if ((x>>i)&1) { + bits_set++; + } + } + + return bits_set; +} + +//Deals with INTERNAL variables +bool Solver::sort_and_clean_clause( + vector& ps + , const vector& origCl + , const bool red + , const bool sorted +) { + if (!sorted) { + std::sort(ps.begin(), ps.end()); + } + Lit p = lit_Undef; + uint32_t i, j; + for (i = j = 0; i != ps.size(); i++) { + if (value(ps[i]) == l_True) { + return false; + } else if (ps[i] == ~p) { + if (!red) { + uint32_t var = p.var(); + var = map_inter_to_outer(var); + if (undef_must_set_vars.size() < var+1) { + undef_must_set_vars.resize(var+1, false); + } + undef_must_set_vars[var] = true; + } + return false; + } else if (value(ps[i]) != l_False && ps[i] != p) { + ps[j++] = p = ps[i]; + + if (!fresh_solver && varData[p.var()].removed != Removed::none) { + cout << "ERROR: clause " << origCl << " contains literal " + << p << " whose variable has been removed (removal type: " + << removed_type_to_string(varData[p.var()].removed) + << " var-updated lit: " + << varReplacer->get_var_replaced_with(p) + << ")" + << endl; + + //Variables that have been eliminated cannot be added internally + //as part of a clause. That's a bug + assert(varData[p.var()].removed == Removed::none); + } + } + } + ps.resize(ps.size() - (i - j)); + return true; +} + +/** +@brief Adds a clause to the problem. MUST only be called internally + +This code is very specific in that it must NOT be called with variables in +"ps" that have been replaced, eliminated, etc. Also, it must not be called +when the wer are in an UNSAT (!ok) state, for example. Use it carefully, +and only internally + +Deals with INTERNAL variables +*/ +Clause* Solver::add_clause_int( + const vector& lits + , const bool red + , const ClauseStats* const cl_stats + , const bool attach_long + , vector* finalLits + , bool addDrat + , const Lit frat_first + , const bool sorted + , const bool remove_frat +) { + assert(okay()); + assert(decisionLevel() == 0); + assert(!attach_long || qhead == trail.size()); + VERBOSE_PRINT("add_clause_int clause " << lits); + + add_clause_int_tmp_cl = lits; + vector& ps = add_clause_int_tmp_cl; + if (!sort_and_clean_clause(ps, lits, red, sorted)) { + if (finalLits) { + finalLits->clear(); + } + if (remove_frat) { + *frat << del << cl_stats->ID << lits << fin; + } + return NULL; + } + VERBOSE_PRINT("add_clause_int final clause: " << ps); + + //If caller required final set of lits, return it. + if (finalLits) *finalLits = ps; + + int32_t ID; + if (remove_frat) { + assert(cl_stats); + assert(frat_first == lit_Undef); + assert(addDrat); + ID = cl_stats->ID; + if (ps != lits) { + ID = ++clauseID; + *frat << add << ID << ps << fin; + *frat << del << cl_stats->ID << lits << fin; + } + } else { + ID = ++clauseID; + if (addDrat) { + size_t i = 0; + if (frat_first != lit_Undef) { + assert(ps.size() > 0); + if (frat_first != lit_Undef) { + for(i = 0; i < ps.size(); i++) { + if (ps[i] == frat_first) { + break; + } + } + } + std::swap(ps[0], ps[i]); + } + + *frat << add << ID << ps << fin; + if (frat_first != lit_Undef) { + std::swap(ps[0], ps[i]); + } + } + } + + //Handle special cases + switch (ps.size()) { + case 0: + assert(unsat_cl_ID == 0); + unsat_cl_ID = clauseID; + ok = false; + if (conf.verbosity >= 6) { + cout + << "c solver received clause through addClause(): " + << lits + << " that became an empty clause at toplevel --> UNSAT" + << endl; + } + return NULL; + case 1: + assert(decisionLevel() == 0); + enqueue(ps[0]); + *frat << del << ID << ps[0] << fin; // double unit delete + if (attach_long) { + ok = (propagate().isNULL()); + } + + return NULL; + case 2: + attach_bin_clause(ps[0], ps[1], red, ID); + return NULL; + + default: + Clause* c = cl_alloc.Clause_new(ps, sumConflicts, ID); + c->isRed = red; + if (cl_stats) { + c->stats = *cl_stats; + STATS_DO(if (ID != c->stats.ID && sqlStats && c->stats.is_tracked) sqlStats->update_id(c->stats.ID, ID)); + c->stats.ID = ID; + } + if (red && cl_stats == NULL) { + assert(false && "does this happen at all? should it happen??"); + #if defined(STATS_NEEDED) || defined(FINAL_PREDICTOR) + //TODO red_stats_extra setup: glue, size, introduced_at_conflict + #endif + } + + //In class 'OccSimplifier' we don't need to attach normall + if (attach_long) { + attachClause(*c); + } else { + if (red) { + litStats.redLits += ps.size(); + } else { + litStats.irredLits += ps.size(); + } + } + + return c; + } +} + +//Deals with INTERNAL variables +// return TRUE if needs to be removed +void Solver::sort_and_clean_bnn(BNN& bnn) +{ + std::sort(bnn.begin(), bnn.end()); + Lit p = lit_Undef; + uint32_t i, j; + for (i = j = 0; i < bnn.size(); i++) { + if (value(bnn[i]) == l_True) { + bnn.cutoff --; + continue; + } else if (value(bnn[i]) == l_False) { + continue; + } else if (bnn[i].var() == p.var() + && bnn[i].sign() == !p.sign() + ) { + p = lit_Undef; + bnn.cutoff--; //either way it's a +1 on the LHS + j--; + continue; + } else { + bnn[j++] = p = bnn[i]; + + if (!fresh_solver && varData[p.var()].removed != Removed::none) { + cout << "ERROR: BNN " << bnn << " contains literal " + << p << " whose variable has been removed (removal type: " + << removed_type_to_string(varData[p.var()].removed) + << " var-updated lit: " + << varReplacer->get_var_replaced_with(p) + << ")" + << endl; + + //Variables that have been eliminated cannot be added internally + //as part of a clause. That's a bug + assert(varData[p.var()].removed == Removed::none); + } + } + } + bnn.resize(j); + + if (!bnn.set && value(bnn.out) != l_Undef) { + if (value(bnn.out) == l_False) { + for(auto& l: bnn) { + l = ~l; + } + bnn.cutoff = (int)bnn.size()+1-bnn.cutoff; + } + bnn.set = true; + bnn.out = lit_Undef; + } +} + +void Solver::attach_bnn(const uint32_t bnn_idx) +{ + BNN* bnn = bnns[bnn_idx]; + +// cout << "Attaching BNN: " << *bnn << endl; + + for(const auto& l: *bnn) { + watches[l].push(Watched(bnn_idx, WatchType::watch_bnn_t, bnn_pos_t)); + watches[~l].push(Watched(bnn_idx, WatchType::watch_bnn_t, bnn_neg_t)); + + } + if (!bnn->set) { + watches[bnn->out].push(Watched(bnn_idx, WatchType::watch_bnn_t, bnn_out_t)); + watches[~bnn->out].push(Watched(bnn_idx, WatchType::watch_bnn_t, bnn_out_t)); + } +} + +//Input BNN *must* be already clean +bool Solver::bnn_to_cnf(BNN& bnn) +{ + // It must have already been evaluated + assert(bnn.set || value(bnn.out) == l_Undef); + + vector lits; + if (bnn.set && bnn.cutoff == 1) { + assert(bnn.size() > 1); + lits.clear(); + lits.insert(lits.end(), bnn.begin(), bnn.end()); + Clause* cl = add_clause_int(lits); + assert(ok); + if (cl != NULL) { + longIrredCls.push_back(cl_alloc.get_offset(cl)); + } + return true; + } + + if (!bnn.set && bnn.cutoff == 1) { + lits.clear(); + lits.insert(lits.end(), bnn.begin(), bnn.end()); + lits.push_back(~bnn.out); + Clause* cl = add_clause_int(lits); + if (cl != NULL) { + longIrredCls.push_back(cl_alloc.get_offset(cl)); + } + for(Lit l: bnn) { + lits.clear(); + lits.push_back(~l); + lits.push_back(bnn.out); + Clause* cl2 = add_clause_int(lits); + assert(cl2 == NULL); + } + return true; + } + + if (!bnn.set && bnn.cutoff == (int)bnn.size()) { + lits.clear(); + for(const Lit& l: bnn) { + lits.push_back(~l); + } + lits.push_back(bnn.out); + Clause* cl = add_clause_int(lits); + if (cl != NULL) { + longIrredCls.push_back(cl_alloc.get_offset(cl)); + } + for(const Lit& l: bnn) { + lits.clear(); + lits.push_back(l); + lits.push_back(~bnn.out); + Clause* cl2 = add_clause_int(lits); + assert(cl2 == NULL); + } + return true; + } + + if (bnn.cutoff == 2 && bnn.size() == 3) { + //input is a v b v c <-> d + //creates: + //a v b v -d + //a v c v -d + //b v c v -d + //---- + //-a v -b v d + //-a v -c v d + //-b v -c v d + //------ + //when bnn.set, we don't need the 2nd part + /// (and -d is not in 1st part) + + for(uint32_t rev = 0; rev < 2; rev++) { + //if it's set, don't do the rev + if (bnn.set && rev == 1) { + break; + } + for(uint32_t i = 0; i < 3; i++) { + lits.clear(); + for (uint32_t i2 = 0; i2 < 3; i2++) { + if (i != i2) { + lits.push_back(bnn[i2] ^ (bool)rev); + } + } + if (!bnn.set) { + lits.push_back(~bnn.out ^ (bool)rev); + } + Clause* cl2 = add_clause_int(lits); + if (cl2 != NULL) + longIrredCls.push_back(cl_alloc.get_offset(cl2)); + } + } + return true; + } + + + return false; +} + +void Solver::add_bnn_clause_inter( + vector& lits, + const int32_t cutoff, + Lit out) +{ + assert(ok); + uint32_t num_req = sizeof(BNN) + lits.size()*sizeof(Lit); + void* mem = malloc(num_req); + BNN* bnn = new (mem) BNN(lits, cutoff, out); + + sort_and_clean_bnn(*bnn); + bnn->undefs = bnn->size(); + bnn->ts = 0; + lbool ret = bnn_eval(*bnn); + if (ret != l_Undef) { + if (ret == l_False) { + ok = false; + free(bnn); + return; + } + free(bnn); + bnn = NULL; + } + + if (bnn != NULL) { + assert(check_bnn_sane(*bnn)); + if (bnn_to_cnf(*bnn)) { + free(bnn); + bnn = NULL; + } else { + bnns.push_back(bnn); + attach_bnn(bnns.size()-1); + } + } + ok = propagate().isNULL(); +} + +void Solver::attachClause( + const Clause& cl + , const bool checkAttach +) { + #if defined(FRAT_DEBUG) + if (frat) { + *frat << add << cl << fin; + } + #endif + + //Update stats + if (cl.red()) { + litStats.redLits += cl.size(); + } else { + litStats.irredLits += cl.size(); + } + + //Call Solver's function for heavy-lifting + PropEngine::attachClause(cl, checkAttach); +} + +void Solver::attach_bin_clause( + const Lit lit1 + , const Lit lit2 + , const bool red + , const int32_t ID + , [[maybe_unused]] const bool checkUnassignedFirst +) { + //Update stats + if (red) { + binTri.redBins++; + } else { + binTri.irredBins++; + } + + //Call Solver's function for heavy-lifting + PropEngine::attach_bin_clause(lit1, lit2, red, ID, checkUnassignedFirst); +} + +void Solver::detachClause(const Clause& cl, const bool removeDrat) +{ + if (removeDrat) { + *frat << del << cl << fin; + } + + assert(cl.size() > 2); + detach_modified_clause(cl[0], cl[1], cl.size(), &cl); +} + +void Solver::detachClause(const ClOffset offset, const bool removeDrat) +{ + Clause* cl = cl_alloc.ptr(offset); + detachClause(*cl, removeDrat); +} + +void Solver::detach_modified_clause( + const Lit lit1 + , const Lit lit2 + , const uint32_t origSize + , const Clause* address +) { + //Update stats + if (address->red()) + litStats.redLits -= origSize; + else + litStats.irredLits -= origSize; + + //Call heavy-lifter + PropEngine::detach_modified_clause(lit1, lit2, address); +} + +//Takes OUTSIDE variables and makes them INTERNAL, replaces them, etc. +bool Solver::addClauseHelper(vector& ps) +{ + //If already UNSAT, just return + if (!ok) + return false; + + //Sanity checks + assert(decisionLevel() == 0); + assert(qhead == trail.size()); + + //Check for too long clauses + if (ps.size() > (0x01UL << 28)) { + cout << "Too long clause!" << endl; + throw CMSat::TooLongClauseError(); + } + + for (Lit& lit: ps) { + //Check for too large variable number + if (lit.var() >= nVarsOuter()) { + std::cerr + << "ERROR: Variable " << lit.var() + 1 + << " inserted, but max var is " + << nVarsOuter() + << endl; + std::exit(-1); + } + + //Undo var replacement + if (!fresh_solver) { + const Lit updated_lit = varReplacer->get_lit_replaced_with_outer(lit); + if (conf.verbosity >= 12 + && lit != updated_lit + ) { + cout + << "EqLit updating outer lit " << lit + << " to outer lit " << updated_lit + << endl; + } + lit = updated_lit; + + //Map outer to inter, and add re-variable if need be + if (map_outer_to_inter(lit).var() >= nVars()) { + new_var(false, lit.var(), false); + } + } + } + + if (!fresh_solver) + renumber_outer_to_inter_lits(ps); + + #ifdef SLOW_DEBUG + //Check renumberer + for (const Lit lit: ps) { + const Lit updated_lit = varReplacer->get_lit_replaced_with(lit); + assert(lit == updated_lit); + } + #endif + + //Uneliminate vars + if (!fresh_solver + && (get_num_vars_elimed() > 0 || detached_xor_clauses) + ) { + for (const Lit lit: ps) { + if (detached_xor_clauses + && varData[lit.var()].removed == Removed::clashed + ) { + if (!fully_undo_xor_detach()) return false; + assert(varData[lit.var()].removed == Removed::none); + } + + if (conf.perform_occur_based_simp + && varData[lit.var()].removed == Removed::elimed + ) { + if (!occsimplifier->uneliminate(lit.var())) return false; + } + } + } + + #ifdef SLOW_DEBUG + //Check + for (Lit& lit: ps) { + const Lit updated_lit = varReplacer->get_lit_replaced_with(lit); + assert(lit == updated_lit); + } + #endif + + return true; +} + +bool Solver::add_clause_outer_copylits(const vector& lits) +{ + vector ps = lits; + return Solver::add_clause_outer(ps); +} + +// Takes OUTER (NOT *outside*) variables +// Input is ORIGINAL clause. +bool Solver::add_clause_outer(vector& ps, bool red) +{ + if (conf.perform_occur_based_simp && occsimplifier->getAnythingHasBeenElimed()) { + std::cerr + << "ERROR: Cannot add new clauses to the system if blocking was" + << " enabled. Turn it off from conf.doBlockClauses" + << endl; + std::exit(-1); + } + + ClauseStats clstats; + clstats.ID = ++clauseID; + *frat << origcl << clstats.ID << ps << fin; + if (red) clstats.which_red_array = 2; + + #ifdef VERBOSE_DEBUG + cout << "Adding clause " << ps << endl; + #endif //VERBOSE_DEBUG + const size_t origTrailSize = trail.size(); + + if (!addClauseHelper(ps)) { + *frat << del << clstats.ID << ps << fin; + return false; + } + + std::sort(ps.begin(), ps.end()); + if (red) assert(!frat->enabled() && "Cannot have both FRAT and adding of redundant clauses"); + Clause *cl = add_clause_int( + ps + , red //redundant? + , &clstats + , true //yes, attach + , NULL + , true //add frat? + , lit_Undef + , true //sorted + , true //remove old clause from proof if we changed it + ); + + if (cl != NULL) { + ClOffset offset = cl_alloc.get_offset(cl); + if (!red) longIrredCls.push_back(offset); + else longRedCls[2].push_back(offset); + } + + zeroLevAssignsByCNF += trail.size() - origTrailSize; + + return ok; +} + +void Solver::test_renumbering() const +{ + //Check if we renumbered the variables in the order such as to make + //the unknown ones first and the known/eliminated ones second + bool uninteresting = false; + bool problem = false; + for(size_t i = 0; i < nVars(); i++) { + //cout << "val[" << i << "]: " << value(i); + + if (value(i) != l_Undef) + uninteresting = true; + + if (varData[i].removed == Removed::elimed + || varData[i].removed == Removed::replaced + ) { + uninteresting = true; + //cout << " removed" << endl; + } else { + //cout << " non-removed" << endl; + } + + if (value(i) == l_Undef + && varData[i].removed != Removed::elimed + && varData[i].removed != Removed::replaced + && uninteresting + ) { + problem = true; + } + } + assert(!problem && "We renumbered the variables in the wrong order!"); +} + +void Solver::renumber_clauses(const vector& outerToInter) +{ + //Clauses' abstractions have to be re-calculated + for(ClOffset offs: longIrredCls) { + Clause* cl = cl_alloc.ptr(offs); + updateLitsMap(*cl, outerToInter); + cl->setStrenghtened(); + } + + for(auto& lredcls: longRedCls) { + for(ClOffset off: lredcls) { + Clause* cl = cl_alloc.ptr(off); + updateLitsMap(*cl, outerToInter); + cl->setStrenghtened(); + } + } + + //Clauses' abstractions have to be re-calculated + xor_clauses_updated = true; + for(Xor& x: xorclauses) { + updateVarsMap(x.vars, outerToInter); + updateVarsMap(x.clash_vars, outerToInter); + } + + for(Xor& x: xorclauses_unused) { + updateVarsMap(x.vars, outerToInter); + updateVarsMap(x.clash_vars, outerToInter); + } + + for(Xor& x: xorclauses_orig) { + updateVarsMap(x.vars, outerToInter); + updateVarsMap(x.clash_vars, outerToInter); + } + + for(auto& v: removed_xorclauses_clash_vars) { + v = getUpdatedVar(v, outerToInter); + } + + for(auto& bnn: bnns) { + if (bnn == NULL) { + continue; + } + assert(!bnn->isRemoved); + updateLitsMap(*bnn, outerToInter); + if (!bnn->set) { + bnn->out = getUpdatedLit(bnn->out, outerToInter); + } + } +} + +size_t Solver::calculate_interToOuter_and_outerToInter( + vector& outerToInter + , vector& interToOuter +) { + size_t at = 0; + vector useless; + size_t numEffectiveVars = 0; + for(size_t i = 0; i < nVars(); i++) { + if (value(i) != l_Undef + || varData[i].removed == Removed::elimed + || varData[i].removed == Removed::replaced + ) { + useless.push_back(i); + continue; + } + + outerToInter[i] = at; + interToOuter[at] = i; + at++; + numEffectiveVars++; + } + + //Fill the rest with variables that have been removed/eliminated/set + for(vector::const_iterator + it = useless.begin(), end = useless.end() + ; it != end + ; ++it + ) { + outerToInter[*it] = at; + interToOuter[at] = *it; + at++; + } + assert(at == nVars()); + + //Extend to nVarsOuter() --> these are just the identity transformation + for(size_t i = nVars(); i < nVarsOuter(); i++) { + outerToInter[i] = i; + interToOuter[i] = i; + } + + return numEffectiveVars; +} + +double Solver::calc_renumber_saving() +{ + uint32_t num_used = 0; + for(size_t i = 0; i < nVars(); i++) { + if (value(i) != l_Undef + || varData[i].removed == Removed::elimed + || varData[i].removed == Removed::replaced + ) { + continue; + } + num_used++; + } + double saving = 1.0-(double)num_used/(double)nVars(); + return saving; +} + +//Beware. Cannot be called while Searcher is running. +bool Solver::renumber_variables(bool must_renumber) +{ + assert(okay()); + assert(decisionLevel() == 0); + #ifdef SLOWDEBUG + for(const auto& x: xorclauses) for(const auto& v: x) assert(v < nVars()); + for(const auto& x: xorclauses_unused) for(const auto& v: x) assert(v < nVars()); + for(const auto& x: xorclauses_orig) for(const auto& v: x) assert(v < nVars()); + #endif + + if (nVars() == 0) return okay(); + if (!must_renumber && calc_renumber_saving() < 0.2) return okay(); + if (!clear_gauss_matrices()) return false; + + double myTime = cpuTime(); + if (!clauseCleaner->remove_and_clean_all()) return false; + + //outerToInter[10] = 0 ---> what was 10 is now 0. + vector outerToInter(nVarsOuter()); + vector interToOuter(nVarsOuter()); + + size_t numEffectiveVars = + calculate_interToOuter_and_outerToInter(outerToInter, interToOuter); + + //Create temporary outerToInter2 + vector interToOuter2(nVarsOuter()*2); + for(size_t i = 0; i < nVarsOuter(); i++) { + interToOuter2[i*2] = interToOuter[i]*2; + interToOuter2[i*2+1] = interToOuter[i]*2+1; + } + + renumber_clauses(outerToInter); + CNF::updateVars(outerToInter, interToOuter, interToOuter2); + PropEngine::updateVars(outerToInter, interToOuter); + Searcher::updateVars(outerToInter, interToOuter); +#ifdef USE_BREAKID + if (breakid) { + breakid->updateVars(outerToInter, interToOuter); + } +#endif + + //Update sub-elements' vars + varReplacer->updateVars(outerToInter, interToOuter); + datasync->updateVars(outerToInter, interToOuter); + + //Tests + test_renumbering(); + test_reflectivity_of_renumbering(); + + //Print results + const double time_used = cpuTime() - myTime; + if (conf.verbosity) { + cout + << "c [renumber]" + << conf.print_times(time_used) + << endl; + } + if (sqlStats) { + sqlStats->time_passed_min( + solver + , "renumber" + , time_used + ); + } + + if (conf.doSaveMem) { + save_on_var_memory(numEffectiveVars); + } + + #ifdef SLOWDEBUG + for(const auto& x: xorclauses) { + for(const auto& v: x.vars) { + assert(v < nVars()); + } + } + + for(const auto& x: xorclauses_unused) { + for(const auto& v: x.vars) { + assert(v < nVars()); + } + } + #endif + + //NOTE order heap is now wrong, but that's OK, it will be restored from + //backed up activities and then rebuilt at the start of Searcher + + return okay(); +} + +void Solver::new_vars(size_t n) +{ + if (n == 0) { + return; + } + + Searcher::new_vars(n); + varReplacer->new_vars(n); + + if (conf.perform_occur_based_simp) { + occsimplifier->new_vars(n); + } + + datasync->new_vars(n); +} + +void Solver::new_var( + const bool bva, + const uint32_t orig_outer, + const bool insert_varorder) +{ + Searcher::new_var(bva, orig_outer, insert_varorder); + + varReplacer->new_var(orig_outer); + + if (conf.perform_occur_based_simp) { + occsimplifier->new_var(orig_outer); + } + + if (orig_outer == numeric_limits::max()) { + datasync->new_var(bva); + } + + //Too expensive + //test_reflectivity_of_renumbering(); +} + +void Solver::save_on_var_memory(const uint32_t newNumVars) +{ + //print_mem_stats(); + + const double myTime = cpuTime(); + minNumVars = newNumVars; + Searcher::save_on_var_memory(); + + varReplacer->save_on_var_memory(); + if (occsimplifier) { + occsimplifier->save_on_var_memory(); + } + datasync->save_on_var_memory(); + + const double time_used = cpuTime() - myTime; + if (sqlStats) { + sqlStats->time_passed_min( + this + , "save var mem" + , time_used + ); + } + //print_mem_stats(); +} + +void Solver::set_assumptions() +{ + assert(assumptions.empty()); + #ifdef SLOW_DEBUG + for(const auto& x: varData) { assert(x.assumption == l_Undef); } + #endif + + conflict.clear(); + if (get_num_bva_vars() > 0) { + back_number_from_outside_to_outer(outside_assumptions); + inter_assumptions_tmp = back_number_from_outside_to_outer_tmp; + } else { + inter_assumptions_tmp = outside_assumptions; + } + addClauseHelper(inter_assumptions_tmp); + assert(inter_assumptions_tmp.size() == outside_assumptions.size()); + + assumptions.resize(inter_assumptions_tmp.size()); + for(size_t i = 0; i < inter_assumptions_tmp.size(); i++) { + Lit outside_lit = lit_Undef; + const Lit inter_lit = inter_assumptions_tmp[i]; + if (i < outside_assumptions.size()) { + outside_lit = outside_assumptions[i]; + } + + const Lit outer_lit = map_inter_to_outer(inter_lit); + assumptions[i] = AssumptionPair(outer_lit, outside_lit); + } + + fill_assumptions_set(); +} + +void Solver::add_assumption(const Lit assump) +{ + assert(varData[assump.var()].assumption == l_Undef); + assert(varData[assump.var()].removed == Removed::none); + assert(value(assump) == l_Undef); + + Lit outer_lit = map_inter_to_outer(assump); + assumptions.push_back(AssumptionPair(outer_lit, lit_Undef)); + varData[assump.var()].assumption = assump.sign() ? l_False : l_True; +} + +void Solver::check_model_for_assumptions() const +{ + for(const AssumptionPair& lit_pair: assumptions) { + const Lit outside_lit = lit_pair.lit_orig_outside; + if (outside_lit.var() == var_Undef) { + //This is an assumption that is a BVA variable + //Currently, this can only be BreakID + continue; + } + assert(outside_lit.var() < model.size()); + + if (model_value(outside_lit) == l_Undef) { + std::cerr + << "ERROR, lit " << outside_lit + << " was in the assumptions, but it wasn't set at all!" + << endl; + } + assert(model_value(outside_lit) != l_Undef); + + if (model_value(outside_lit) != l_True) { + std::cerr + << "ERROR, lit " << outside_lit + << " was in the assumptions, but it was set to: " + << model_value(outside_lit) + << endl; + } + assert(model_value(outside_lit) == l_True); + } +} + +void Solver::check_recursive_minimization_effectiveness(const lbool status) +{ + const SearchStats& srch_stats = Searcher::get_stats(); + if (status == l_Undef + && conf.doRecursiveMinim + && srch_stats.recMinLitRem + srch_stats.litsRedNonMin > 100000 + ) { + double remPercent = + float_div(srch_stats.recMinLitRem, srch_stats.litsRedNonMin)*100.0; + + double costPerGained = float_div(srch_stats.recMinimCost, remPercent); + if (costPerGained > 200ULL*1000ULL*1000ULL) { + conf.doRecursiveMinim = false; + if (conf.verbosity) { + cout + << "c recursive minimization too costly: " + << std::fixed << std::setprecision(0) << (costPerGained/1000.0) + << "Kcost/(% lits removed) --> disabling" + << std::setprecision(2) + << endl; + } + } else { + if (conf.verbosity) { + cout + << "c recursive minimization cost OK: " + << std::fixed << std::setprecision(0) << (costPerGained/1000.0) + << "Kcost/(% lits removed)" + << std::setprecision(2) + << endl; + } + } + } +} + +void Solver::check_minimization_effectiveness(const lbool status) +{ + const SearchStats& search_stats = Searcher::get_stats(); + if (status == l_Undef + && conf.doMinimRedMore + && search_stats.moreMinimLitsStart > 100000 + ) { + double remPercent = float_div( + search_stats.moreMinimLitsStart-search_stats.moreMinimLitsEnd, + search_stats.moreMinimLitsStart)*100.0; + + //TODO take into account the limit on the number of first literals, too + if (remPercent < 1.0) { + conf.doMinimRedMore = false; + if (conf.verbosity) { + cout + << "c more minimization effectiveness low: " + << std::fixed << std::setprecision(2) << remPercent + << " % lits removed --> disabling" + << endl; + } + } else if (remPercent > 7.0) { + more_red_minim_limit_binary_actual = 3*conf.more_red_minim_limit_binary; + if (conf.verbosity) { + cout + << "c more minimization effectiveness good: " + << std::fixed << std::setprecision(2) << remPercent + << " % --> increasing limit to 3x" + << endl; + } + } else { + more_red_minim_limit_binary_actual = conf.more_red_minim_limit_binary; + if (conf.verbosity) { + cout + << "c more minimization effectiveness OK: " + << std::fixed << std::setprecision(2) << remPercent + << " % --> setting limit to norm" + << endl; + } + } + } +} + +void Solver::extend_solution(const bool only_sampling_solution) +{ + #ifdef DEBUG_IMPLICIT_STATS + check_stats(); + #endif + + #ifdef SLOW_DEBUG + //Check that sampling vars are all assigned + if (conf.sampling_vars) { + for(uint32_t outside_var: *conf.sampling_vars) { + uint32_t outer_var = map_to_with_bva(outside_var); + outer_var = varReplacer->get_var_replaced_with_outer(outer_var); + uint32_t int_var = map_outer_to_inter(outer_var); + + assert(varData[int_var].removed == Removed::none); + + if (int_var < nVars() && varData[int_var].removed == Removed::none) { + assert(model[int_var] != l_Undef); + } + } + } + #endif + + if (detached_xor_clauses && !only_sampling_solution) { + extend_model_to_detached_xors(); + } + + const double myTime = cpuTime(); + updateArrayRev(model, interToOuterMain); + + if (!only_sampling_solution) { + SolutionExtender extender(this, occsimplifier); + extender.extend(); + } else { + varReplacer->extend_model_already_set(); + } + + //map back without BVA + if (get_num_bva_vars() != 0) { + model = map_back_vars_to_without_bva(model); + } + + if (only_sampling_solution && conf.sampling_vars) { + for(uint32_t var: *conf.sampling_vars) { + if (model[var] == l_Undef) { + cout << "ERROR: variable " << var+1 << " is set as sampling but is unset!" << endl; + cout << "NOTE: var " << var + 1 << " has removed value: " + << removed_type_to_string(varData[var].removed) + << " and is set to " << value(var) << endl; + + if (varData[var].removed == Removed::replaced) { + uint32_t v2 = varReplacer->get_var_replaced_with(var); + cout << " --> replaced with var " << v2 + 1 << " whose value is: " << value(v2) << endl; + } + } + assert(model[var] != l_Undef); + } + } + + check_model_for_assumptions(); + if (sqlStats) { + sqlStats->time_passed_min( + this + , "extend solution" + , cpuTime()-myTime + ); + } +} + +void Solver::set_up_sql_writer() +{ + if (!sqlStats) { + return; + } + + bool ret = sqlStats->setup(this); + if (!ret) { + std::cerr + << "c ERROR: SQL was required (with option '--sql 2'), but couldn't connect to SQL server." << endl; + std::exit(-1); + } +} + +void Solver::check_xor_cut_config_sanity() const +{ + if (conf.xor_var_per_cut < 1) { + std::cerr << "ERROR: Too low cutting number: " << conf.xor_var_per_cut << ". Needs to be at least 1." << endl; + exit(-1); + } + + if (MAX_XOR_RECOVER_SIZE < 4) { + std::cerr << "ERROR: MAX_XOR_RECOVER_SIZE must be at least 4. It's currently: " << MAX_XOR_RECOVER_SIZE << endl; + exit(-1); + } + + if (conf.xor_var_per_cut+2 > MAX_XOR_RECOVER_SIZE) { + std::cerr << "ERROR: Too high cutting number, we will not be able to recover cut XORs due to MAX_XOR_RECOVER_SIZE only being " << MAX_XOR_RECOVER_SIZE << endl; + exit(-1); + } +} + +void Solver::check_and_upd_config_parameters() +{ + if (conf.max_glue_cutoff_gluehistltlimited > 1000) { + cout << "ERROR: 'Maximum supported glue size is currently 1000" << endl; + exit(-1); + } + + if (conf.shortTermHistorySize <= 0) { + std::cerr << "ERROR: You MUST give a short term history size (\"--gluehist\") greater than 0!" << endl; + exit(-1); + } + + if ((frat->enabled() || conf.simulate_frat)) { + if (!conf.do_hyperbin_and_transred) { + if (conf.verbosity) { + cout + << "c OTF hyper-bin is needed for BProp in FRAT, turning it back" + << endl; + } + conf.do_hyperbin_and_transred = true; + } + + #ifdef USE_BREAKID + if (conf.doBreakid) { + if (conf.verbosity) { + cout + << "c BreakID is not supported with FRAT, turning it off" + << endl; + } + conf.doBreakid = false; + } + #endif + + #ifdef USE_BOSPHORUS + if (conf.do_bosphorus) { + if (conf.verbosity) { + cout + << "c Bosphorus is not supported with FRAT, turning it off" + << endl; + } + conf.do_bosphorus = false; + } + #endif + } + + #ifdef SLOW_DEBUG + if (conf.sampling_vars) + { + for(uint32_t v: *conf.sampling_vars) { + assert(v < nVarsOutside()); + } + } + #endif + + if (conf.blocking_restart_trail_hist_length == 0) { + std::cerr << "ERROR: Blocking restart length must be at least 0" << endl; + exit(-1); + } + + check_xor_cut_config_sanity(); +} + +lbool Solver::simplify_problem_outside(const string* strategy) +{ + #ifdef SLOW_DEBUG + if (ok) { + assert(check_order_heap_sanity()); + check_implicit_stats(); + check_wrong_attach(); + find_all_attach(); + test_all_clause_attached(); + } + #endif + + conf.global_timeout_multiplier = conf.orig_global_timeout_multiplier; + solveStats.num_simplify_this_solve_call = 0; + set_assumptions(); + + lbool status = l_Undef; + if (!ok) { + status = l_False; + goto end; + } + check_and_upd_config_parameters(); + datasync->rebuild_bva_map(); + #ifdef USE_BREAKID + if (breakid) { + breakid->start_new_solving(); + } + #endif + + //ignore "no simplify" if explicitly called + if (nVars() > 0 /*&& conf.do_simplify_problem*/) { + bool backup_sls = conf.doSLS; + bool backup_breakid = conf.doBreakid; + conf.doSLS = false; + conf.doBreakid = false; + status = simplify_problem(false, strategy ? *strategy : conf.simplify_schedule_nonstartup); + conf.doSLS = backup_sls; + conf.doBreakid = backup_breakid; + } + + end: + unfill_assumptions_set(); + assumptions.clear(); + conf.conf_needed = true; + return status; +} + +void Solver::reset_for_solving() +{ + longest_trail_ever_best = 0; + longest_trail_ever_inv = 0; + fresh_solver = false; + polarity_strategy_change = 0; + increasing_phase_size = conf.restart_first; + set_assumptions(); + #ifdef SLOW_DEBUG + if (ok) { + assert(check_order_heap_sanity()); + check_implicit_stats(); + find_all_attach(); + check_no_duplicate_lits_anywhere(); + } + #endif + + solveStats.num_solve_calls++; + check_and_upd_config_parameters(); + + //Reset parameters + luby_loop_num = 0; + conf.global_timeout_multiplier = conf.orig_global_timeout_multiplier; + solveStats.num_simplify_this_solve_call = 0; + if (conf.verbosity >= 6) { + cout << "c " << __func__ << " called" << endl; + } + datasync->rebuild_bva_map(); +} + +void my_bddinthandler(int e) +{ + switch(e) { + case -1: cout << "ERROR reported by tbuddy: BDD_MEMORY (-1) /* Out of memory */" << endl; break; + case -2: cout << "ERROR reported by tbuddy: VAR (-2) /* Unknown variable */" << endl; break; + case -3: cout << "ERROR reported by tbuddy: RANGE (-3) /* Variable value out of range (not in domain) */" << endl; break; + case -4: cout << "ERROR reported by tbuddy: DEREF (-4) /* Removing external reference to unknown node */" << endl; break; + case -5: cout << "ERROR reported by tbuddy: RUNNING (-5) /* Called bdd_init() twice whithout bdd_done() */" << endl; break; + case -6: cout << "ERROR reported by tbuddy: FILE (-6) /* Some file operation failed */" << endl; break; + case -7: cout << "ERROR reported by tbuddy: FORMAT (-7) /* Incorrect file format */" << endl; break; + case -8: cout << "ERROR reported by tbuddy: ORDER (-8) /* Vars. not in order for vector based functions */" << endl; break; + case -9: cout << "ERROR reported by tbuddy: BREAK (-9) /* User called break */" << endl; break; + case -10: cout << "ERROR reported by tbuddy: VARNUM (-10) /* Different number of vars. for vector pair */" << endl; break; + case -11: cout << "ERROR reported by tbuddy: NODES (-11) /* Tried to set max. number of nodes to be fewer than there already has been allocated */" << endl; break; + case -12: cout << "ERROR reported by tbuddy: BDD_OP (-12) /* Unknown operator */" << endl; break; + case -13: cout << "ERROR reported by tbuddy: BDD_VARSET (-13) /* Illegal variable set */" << endl; break; + case -14: cout << "ERROR reported by tbuddy: BDD_VARBLK (-14) /* Bad variable block operation */" << endl; break; + case -15: cout << "ERROR reported by tbuddy: BDD_DECVNUM (-15) /* Trying to decrease the number of variables */" << endl; break; + case -16: cout << "ERROR reported by tbuddy: BDD_REPLACE (-16) /* Replacing to already existing variables */" << endl; break; + case -17: cout << "ERROR reported by tbuddy: BDD_NODENUM (-17) /* Number of nodes reached user defined maximum */" << endl; break; + case -18: cout << "ERROR reported by tbuddy: BDD_ILLBDD (-18) /* Illegal bdd argument */" << endl; break; + case -19: cout << "ERROR reported by tbuddy: BDD_SIZE (-19) /* Illegal size argument */" << endl; break; + + case -20: cout << "ERROR reported by tbuddy: BVEC_SIZE (-20) /* Mismatch in bitvector size */" << endl; break; + case -21: cout << "ERROR reported by tbuddy: BVEC_SHIFT (-21) /* Illegal shift-left/right parameter */" << endl; break; + case -22: cout << "ERROR reported by tbuddy: BVEC_DIVZERO (-22) /* Division by zero */" << endl; break; + + + case -23: cout << "ERROR reported by tbuddy: ILIST_ALLOC (-23) /* Invalid allocation for ilist */" << endl; break; + case -24: cout << "ERROR reported by tbuddy: TBDD_PROOF (-24) /* Couldn't complete proof of justification */" << endl; break; + case -26: cout << "ERROR reported by tbuddy: BDD_ERRNUM 26 /* ?? */" << endl; break; + } + + assert(false); +} + +lbool Solver::solve_with_assumptions( + const vector* _assumptions, + const bool only_sampling_solution +) { + if (frat->enabled()) { + frat->set_sqlstats_ptr(sqlStats); + int32_t* v = new int; + *v = nVars()+1; + #ifdef USE_TBUDDY + if (frat->enabled()) { + frat->flush(); + tbdd_init_frat(frat->getFile(), v, &clauseID); + tbdd_set_verbose(0); + bdd_error_hook(my_bddinthandler); + } + #endif + } + move_to_outside_assumps(_assumptions); + reset_for_solving(); + + //Check if adding the clauses caused UNSAT + lbool status = l_Undef; + if (!ok) { + assert(conflict.empty()); + status = l_False; + if (conf.verbosity >= 6) { + cout << "c Solver status " << status << " on startup of solve()" << endl; + } + goto end; + } + assert(prop_at_head()); + assert(okay()); + #ifdef USE_BREAKID + if (breakid) breakid->start_new_solving(); + #endif + + //Simplify in case simplify_at_startup is set + if (status == l_Undef + && nVars() > 0 + && conf.do_simplify_problem + && conf.simplify_at_startup + && (solveStats.num_simplify == 0 || conf.simplify_at_every_startup) + ) { + status = simplify_problem( + !conf.full_simplify_at_startup, + !conf.full_simplify_at_startup ? conf.simplify_schedule_startup : conf.simplify_schedule_nonstartup); + } + + #ifdef STATS_NEEDED + if (status == l_Undef) { + CommunityFinder comm_finder(this); + comm_finder.compute(); + } + #endif + + if (status == l_Undef) status = iterate_until_solved(); + + end: + if (sqlStats) sqlStats->finishup(status); + handle_found_solution(status, only_sampling_solution); + unfill_assumptions_set(); + assumptions.clear(); + conf.max_confl = numeric_limits::max(); + conf.maxTime = numeric_limits::max(); + datasync->finish_up_mpi(); + conf.conf_needed = true; + set_must_interrupt_asap(); + assert(decisionLevel()== 0); + assert(!ok || prop_at_head()); + if (_assumptions == NULL || _assumptions->empty()) { + #ifdef USE_BREAKID + if (assumptions.empty()) { + verb_print(1, "[breakid] Under BreakID it's UNSAT. Assumed lit: " << breakid->get_assumed_lit()); + } else + #endif + { + if (status == l_False) { + assert(!okay()); + } + } + } + + write_final_frat_clauses(); + + return status; +} + +void Solver::write_final_frat_clauses() +{ + if (!frat->enabled()) return; + assert(decisionLevel() == 0); + *frat << "write final start\n"; + + *frat << "vrepl finalize begin\n"; + if (varReplacer) varReplacer->delete_frat_cls(); + + *frat << "gmatrix finalize frat begin\n"; + TBUDDY_DO(for(auto& g: gmatrices) g->finalize_frat()); + + *frat << "free bdds begin\n"; + TBUDDY_DO(solver->free_bdds(solver->xorclauses_orig)); + TBUDDY_DO(solver->free_bdds(solver->xorclauses)); + TBUDDY_DO(solver->free_bdds(solver->xorclauses_unused)); + + + *frat << "tbdd_done() next\n"; + frat->flush(); + TBUDDY_DO(tbdd_done()); + + // -1 indicates tbuddy already added the empty clause + *frat << "empty clause next (if we found it)\n"; + if (!okay() && unsat_cl_ID != -1) { + assert(unsat_cl_ID != 0); + *frat << finalcl << unsat_cl_ID << fin; + } + + *frat << "finalization of unit clauses next\n"; + for(uint32_t i = 0; i < nVars(); i ++) { + if (unit_cl_IDs[i] != 0) { + assert(value(i) != l_Undef); + Lit l = Lit(i, value(i) == l_False); + *frat << finalcl << unit_cl_IDs[i] << l << fin; + } + } + + *frat << "finalization of binary clauses next\n"; + for(uint32_t i = 0; i < nVars()*2; i++) { + Lit l = Lit::toLit(i); + for(const auto& w: watches[l]) { + //only do once per binary + if (w.isBin() && w.lit2() < l) { + *frat << finalcl << w.get_ID() << l << w.lit2() << fin; + } + } + } + + *frat << "finalization of redundant clauses next\n"; + for(const auto& cls: longRedCls) { + for(const auto offs: cls) { + Clause* cl = cl_alloc.ptr(offs); + *frat << finalcl << *cl << fin; + } + } + *frat << "finalization of irredundant clauses next\n"; + for(const auto& offs: longIrredCls) { + Clause* cl = cl_alloc.ptr(offs); + *frat << finalcl << *cl << fin; + } + frat->flush(); +} + +void Solver::dump_memory_stats_to_sql() +{ + if (!sqlStats) { + return; + } + + const double my_time = cpuTime(); + + sqlStats->mem_used( + this + , "solver" + , my_time + , mem_used()/(1024*1024) + ); + + sqlStats->mem_used( + this + , "vardata" + , my_time + , mem_used_vardata()/(1024*1024) + ); + + sqlStats->mem_used( + this + , "longclauses" + , my_time + , CNF::mem_used_longclauses()/(1024*1024) + ); + + sqlStats->mem_used( + this + , "watch-alloc" + , my_time + , watches.mem_used_alloc()/(1024*1024) + ); + + sqlStats->mem_used( + this + , "watch-array" + , my_time + , watches.mem_used_array()/(1024*1024) + ); + + sqlStats->mem_used( + this + , "renumber" + , my_time + , CNF::mem_used_renumberer()/(1024*1024) + ); + + if (occsimplifier) { + sqlStats->mem_used( + this + , "occsimplifier" + , my_time + , occsimplifier->mem_used()/(1024*1024) + ); + + sqlStats->mem_used( + this + , "bva" + , my_time + , occsimplifier->mem_used_bva()/(1024*1024) + ); + } + + sqlStats->mem_used( + this + , "varreplacer" + , my_time + , varReplacer->mem_used()/(1024*1024) + ); + + double vm_mem_used = 0; + const uint64_t rss_mem_used = memUsedTotal(vm_mem_used); + sqlStats->mem_used( + this + , "rss" + , my_time + , rss_mem_used/(1024*1024) + ); + sqlStats->mem_used( + this + , "vm" + , my_time + , vm_mem_used/(1024*1024) + ); +} + +uint64_t Solver::calc_num_confl_to_do_this_iter(const size_t iteration_num) const +{ + double iter_num = std::min(iteration_num, 100ULL); + double mult = std::pow(conf.num_conflicts_of_search_inc, iter_num); + mult = std::min(mult, conf.num_conflicts_of_search_inc_max); + uint64_t num_conflicts_of_search = (double)conf.num_conflicts_of_search*mult; + if (conf.never_stop_search) { + num_conflicts_of_search = 600ULL*1000ULL*1000ULL; + } + if (conf.max_confl >= sumConflicts) { + num_conflicts_of_search = std::min( + num_conflicts_of_search + , conf.max_confl - sumConflicts + ); + } else { + num_conflicts_of_search = 0; + } + + return num_conflicts_of_search; +} + + +lbool Solver::iterate_until_solved() +{ + lbool status = l_Undef; + size_t iteration_num = 0; + + while (status == l_Undef + && !must_interrupt_asap() + && cpuTime() < conf.maxTime + && sumConflicts < conf.max_confl + ) { + iteration_num++; + if (conf.verbosity >= 2) print_clause_size_distrib(); + dump_memory_stats_to_sql(); + + const uint64_t num_confl = calc_num_confl_to_do_this_iter(iteration_num); + if (num_confl == 0) break; + if (!find_and_init_all_matrices()) { + status = l_False; + goto end; + } + status = Searcher::solve(num_confl); + + //Check for effectiveness + check_recursive_minimization_effectiveness(status); + check_minimization_effectiveness(status); + + //Update stats + sumSearchStats += Searcher::get_stats(); + sumPropStats += propStats; + propStats.clear(); + Searcher::resetStats(); + check_too_many_in_tier0(); + + //Solution has been found + if (status != l_Undef) { + break; + } + + //If we are over the limit, exit + if (sumConflicts >= conf.max_confl + || cpuTime() > conf.maxTime + || must_interrupt_asap() + ) { + break; + } + + if (conf.do_simplify_problem) { + status = simplify_problem(false, conf.simplify_schedule_nonstartup); + } + } + + #ifdef STATS_NEEDED + //To record clauses when we finish up + if (status != l_Undef) { + dump_clauses_at_finishup_as_last(); + if (conf.verbosity) { + cout << "c [sql] dumping all remaining clauses as cl_last_in_solver" << endl; + } + } + #endif + + end: + return status; +} + +void Solver::check_too_many_in_tier0() +{ + //For both of these, it makes no sense: + // * for STATS_NEEDED, we have many in Tier0 because of locking-in + // * for FINAL_PREDICT Tier0 works completely differently + #if defined(STATS_NEEDED) || defined(FINAL_PREDICTOR) + return; + #endif + + if (conf.glue_put_lev0_if_below_or_eq == 2 + || sumConflicts < conf.min_num_confl_adjust_glue_cutoff + || adjusted_glue_cutoff_if_too_many + || conf.adjust_glue_if_too_many_tier0 >= 1.0 + ) { + return; + } + + double perc = float_div(sumSearchStats.red_cl_in_which0, sumConflicts); + if (perc > conf.adjust_glue_if_too_many_tier0) { + conf.glue_put_lev0_if_below_or_eq--; + adjusted_glue_cutoff_if_too_many = true; + if (conf.verbosity) { + cout << "c Adjusted glue cutoff to " << conf.glue_put_lev0_if_below_or_eq + << " due to too many low glues: " << perc*100.0 << " %" << endl; + } + } +} + +void Solver::handle_found_solution(const lbool status, const bool only_sampling_solution) +{ + double mytime = cpuTime(); + if (status == l_True) { + extend_solution(only_sampling_solution); + cancelUntil(0); + assert(prop_at_head()); + + #ifdef DEBUG_ATTACH_MORE + find_all_attach(); + test_all_clause_attached(); + #endif + } else if (status == l_False) { + cancelUntil(0); + + for(const Lit lit: conflict) { + if (value(lit) == l_Undef) { + assert(var_inside_assumptions(lit.var()) != l_Undef); + } + } + if (conf.conf_needed) { + update_assump_conflict_to_orig_outside(conflict); + } + } + + #ifdef USE_BREAKID + if (breakid) { + breakid->finished_solving(); + } + #endif + + //Too slow when running lots of small queries + #ifdef DEBUG_IMPLICIT_STATS + check_implicit_stats(); + #endif + + if (sqlStats) { + sqlStats->time_passed_min(this, "solution extend", cpuTime() - mytime); + } +} + +lbool Solver::execute_inprocess_strategy( + const bool startup + , const string& strategy +) { + //std::string input = "abc,def,ghi"; + std::istringstream ss(strategy + ", "); + std::string token; + std::string occ_strategy_tokens; + + while(std::getline(ss, token, ',')) { + if (sumConflicts >= conf.max_confl + || cpuTime() > conf.maxTime + || must_interrupt_asap() + || nVars() == 0 + || !okay() + ) { + break; + } + + assert(watches.get_smudged_list().empty()); + assert(prop_at_head()); + assert(okay()); + #ifdef SLOW_DEBUG + check_no_zero_ID_bins(); + check_wrong_attach(); + check_stats(); + check_no_duplicate_lits_anywhere(); + check_assumptions_sanity(); + #endif + + token = trim(token); + std::transform(token.begin(), token.end(), token.begin(), ::tolower); + if (!occ_strategy_tokens.empty() && token.substr(0,3) != "occ") { + if (conf.perform_occur_based_simp + && bnns.empty() + && occsimplifier + ) { + occ_strategy_tokens = trim(occ_strategy_tokens); + if (conf.verbosity) { + cout << "c --> Executing OCC strategy token(s): '" + << occ_strategy_tokens << "'\n"; + } + occsimplifier->simplify(startup, occ_strategy_tokens); + } + occ_strategy_tokens.clear(); + if (sumConflicts >= conf.max_confl + || cpuTime() > conf.maxTime + || must_interrupt_asap() + || nVars() == 0 + || !ok + ) { + break; + } + #ifdef SLOW_DEBUG + check_stats(); + check_assumptions_sanity(); + #endif + } + + if (conf.verbosity && token.substr(0,3) != "occ" && token != "") { + cout << "c --> Executing strategy token: " << token << '\n'; + } + + if (token == "scc-vrepl") { + if (conf.doFindAndReplaceEqLits) { + varReplacer->replace_if_enough_is_found( + std::floor((double)get_num_free_vars()*0.001)); + } + } else if (token == "oracle-vivif-sparsify") { + bool finished = false; + if (nVars() > 10 && oracle_vivif(finished)) { + if (finished) oracle_sparsify(); + } + } else if (token == "oracle-vivif") { + bool finished = false; + if (nVars() > 10) oracle_vivif(finished); + } else if (token == "oracle-sparsify") { + bool finished = false; + backbone_simpl(30LL*1000LL, true, finished); + if (nVars() > 10) { if (finished) oracle_sparsify(); + } + } else if (token == "backbone") { + bool finished = false; + backbone_simpl(30LL*1000LL, true, finished); + } else if (token == "must-scc-vrepl") { + if (conf.doFindAndReplaceEqLits) { + varReplacer->replace_if_enough_is_found(); + } + } else if (token == "full-probe") { + if (!full_probe(false)) return l_False; + } else if (token == "card-find") { + if (conf.doFindCard) { + card_finder->find_cards(); + exit(0); + } + } else if (token == "sub-impl") { + //subsume BIN with BIN + if (conf.doStrSubImplicit) { + subsumeImplicit->subsume_implicit(); + } + } else if (token == "sls") { + assert(false && "unsupported"); + } else if (token == "lucky") { + assert(false && "unsupported"); +// Lucky lucky(solver); +// lucky.doit(); + } else if (token == "intree-probe") { + if (!bnns.empty()) conf.do_hyperbin_and_transred = false; + if (conf.doIntreeProbe && conf.doFindAndReplaceEqLits) intree->intree_probe(); + } else if (token == "sub-str-cls-with-bin") { + //Subsumes and strengthens long clauses with binary clauses + if (conf.do_distill_clauses) { + dist_long_with_impl->distill_long_with_implicit(true); + } + } else if (token == "sub-cls-with-bin") { + //Subsumes and strengthens long clauses with binary clauses + if (conf.do_distill_clauses) { + dist_long_with_impl->distill_long_with_implicit(false); + } + } else if (token == "distill-bins") { + if (conf.do_distill_bin_clauses) { + distill_bin_cls->distill(); + } + } else if (token == "distill-litrem") { + if (conf.do_distill_clauses) { + distill_lit_rem->distill_lit_rem(); + } + } else if (token == "distill-cls") { + //Enqueues literals in long + tri clauses two-by-two and propagates + if (conf.do_distill_clauses) { + distill_long_cls->distill(false, false); + } + } else if (token == "clean-cls") { + clauseCleaner->remove_and_clean_all(); + } else if (token == "distill-cls-onlyrem") { + //Enqueues literals in long + tri clauses two-by-two and propagates + if (conf.do_distill_clauses) { + distill_long_cls->distill(false, true); + } + } else if (token == "must-distill-cls") { + //Enqueues literals in long + tri clauses two-by-two and propagates + if (conf.do_distill_clauses) { + for(const auto& offs: longIrredCls) { + Clause* cl = cl_alloc.ptr(offs); + cl->distilled = 0; + cl->tried_to_remove = 0; + } + distill_long_cls->distill(false, false); + } + } else if (token == "must-distill-cls-onlyrem") { + //Enqueues literals in long + tri clauses two-by-two and propagates + if (conf.do_distill_clauses) { + for(const auto& offs: longIrredCls) { + Clause* cl = cl_alloc.ptr(offs); + cl->tried_to_remove = 0; + } + distill_long_cls->distill(false, true); + } + } else if (token == "str-impl") { + if (conf.doStrSubImplicit) { + dist_impl_with_impl->str_impl_w_impl(); + } + } else if (token == "cl-consolidate") { + cl_alloc.consolidate(this, conf.must_always_conslidate, true); + } else if (token == "louvain-comms") { + #ifdef STATS_NEEDED + CommunityFinder comm_finder(this); + comm_finder.compute(); + #endif + } else if (token == "renumber" || token == "must-renumber") { + if (conf.doRenumberVars && !frat->enabled()) { + if (!renumber_variables(token == "must-renumber" || conf.must_renumber)) { + return l_False; + } + } + } else if (token == "breakid") { + if (conf.doBreakid + && !(frat->enabled() || conf.simulate_frat) + && (solveStats.num_simplify == 0 || + (solveStats.num_simplify % conf.breakid_every_n == (conf.breakid_every_n-1))) + ) { + #ifdef USE_BREAKID + if (!breakid->doit()) { + return l_False; + } + #else + if (conf.verbosity) { + cout << "c [breakid] BreakID not compiled in, skipping" << endl; + } + #endif + } + } else if (token == "bosphorus") { + if (conf.do_bosphorus + && (solveStats.num_simplify == 0 || + (solveStats.num_simplify % conf.bosphorus_every_n == (conf.bosphorus_every_n-1))) + ) { + #ifdef USE_BOSPHORUS + CMSBosphorus bosph(this); + bosph.doit(); + #else + if (conf.verbosity) { + cout << "c [bosphorus] Bosphorus not compiled in, skipping" << endl; + } + #endif + } + } else if (token == "") { + //Nothing, just an empty comma, ignore + } else if (token.substr(0,3) == "occ") { + occ_strategy_tokens += token + ", "; + //cout << "occ_strategy_tokens now: " << occ_strategy_tokens << endl; + } else { + cout << "ERROR: strategy '" << token << "' not recognised!" << endl; + exit(-1); + } + + SLOW_DEBUG_DO(check_stats()); + if (!okay()) return l_False; + SLOW_DEBUG_DO(check_wrong_attach()); + } + + return okay() ? l_Undef : l_False; +} + +/** +@brief The function that brings together almost all CNF-simplifications +*/ +lbool Solver::simplify_problem(const bool startup, const string& strategy) +{ + assert(okay()); + #ifdef DEBUG_IMPLICIT_STATS + check_stats(); + #endif + #ifdef DEBUG_ATTACH_MORE + test_all_clause_attached(); + find_all_attach(); + assert(check_order_heap_sanity()); + #endif + #ifdef DEBUG_MARKED_CLAUSE + assert(no_marked_clauses()); + #endif + + if (solveStats.num_simplify_this_solve_call >= conf.max_num_simplify_per_solve_call) { + return l_Undef; + } + + lbool ret = l_Undef; + clear_order_heap(); + set_clash_decision_vars(); + if (!clear_gauss_matrices()) return l_False; + + if (conf.verbosity >= 6) { + cout + << "c " << __func__ << " called" + << endl; + } + + if (ret == l_Undef) { + ret = execute_inprocess_strategy(startup, strategy); + } + assert(ret != l_True); + + //Free unused watch memory + free_unused_watches(); + + if (conf.verbosity >= 6) { + cout << "c " << __func__ << " finished" << endl; + } + conf.global_timeout_multiplier *= conf.global_timeout_multiplier_multiplier; + conf.global_timeout_multiplier = + std::min( + conf.global_timeout_multiplier, + conf.orig_global_timeout_multiplier*conf.global_multiplier_multiplier_max + ); + if (conf.verbosity) + cout << "c global_timeout_multiplier: " << std::setprecision(4) << conf.global_timeout_multiplier << endl; + + solveStats.num_simplify++; + solveStats.num_simplify_this_solve_call++; + + assert(!(ok == false && ret != l_False)); + if (ret == l_False) { + return l_False; + } + + assert(ret == l_Undef); + check_stats(); + check_implicit_propagated(); + //NOTE: + // we have to rebuild HERE, or we'd rebuild every time solve() + // is called, which is called form the outside, sometimes 1000x + // in one second + rebuildOrderHeap(); + #ifdef DEBUG_ATTACH_MORE + find_all_attach(); + test_all_clause_attached(); + #endif + check_wrong_attach(); + + return ret; +} + +void CMSat::Solver::print_stats( + const double cpu_time, + const double cpu_time_total, + const double wallclock_time_started) const +{ + if (conf.verbStats >= 1) { + cout << "c ------- FINAL TOTAL SEARCH STATS ---------" << endl; + } + + if (conf.do_print_times) { + print_stats_line("c UIP search time" + , sumSearchStats.cpu_time + , stats_line_percent(sumSearchStats.cpu_time, cpu_time) + , "% time" + ); + } + + if (conf.verbStats > 1) { + print_full_stats(cpu_time, cpu_time_total, wallclock_time_started); + } + print_norm_stats(cpu_time, cpu_time_total, wallclock_time_started); +} + +void Solver::print_stats_time( + const double cpu_time, + const double cpu_time_total, + const double wallclock_time_started) const +{ + if (conf.do_print_times) { + print_stats_line("c Total time (this thread)", cpu_time); + if (cpu_time != cpu_time_total) { + print_stats_line("c Total time (all threads)", cpu_time_total); + if (wallclock_time_started != 0.0) { + print_stats_line("c Wall clock time: ", (real_time_sec() - wallclock_time_started)); + } + } + } +} + +void Solver::print_norm_stats( + const double cpu_time, + const double cpu_time_total, + const double wallclock_time_started) const +{ + sumSearchStats.print_short(sumPropStats.propagations, conf.do_print_times); + print_stats_line("c props/decision" + , float_div(propStats.propagations, sumSearchStats.decisions) + ); + print_stats_line("c props/conflict" + , float_div(propStats.propagations, sumConflicts) + ); + + print_stats_line("c 0-depth assigns", trail.size() + , stats_line_percent(trail.size(), nVars()) + , "% vars" + ); + print_stats_line("c 0-depth assigns by CNF" + , zeroLevAssignsByCNF + , stats_line_percent(zeroLevAssignsByCNF, nVars()) + , "% vars" + ); + + print_stats_line("c reduceDB time" + , reduceDB->get_total_time() + , stats_line_percent(reduceDB->get_total_time(), cpu_time) + , "% time" + ); + + //OccSimplifier stats + if (conf.perform_occur_based_simp) { + if (conf.do_print_times) + print_stats_line("c OccSimplifier time" + , occsimplifier->get_stats().total_time(occsimplifier) + , stats_line_percent(occsimplifier->get_stats().total_time(occsimplifier) ,cpu_time) + , "% time" + ); + occsimplifier->get_stats().print_extra_times(); + occsimplifier->get_sub_str()->get_stats().print_short(this); + } + print_stats_line("c SCC time" + , varReplacer->get_scc_finder()->get_stats().cpu_time + , stats_line_percent(varReplacer->get_scc_finder()->get_stats().cpu_time, cpu_time) + , "% time" + ); + varReplacer->get_scc_finder()->get_stats().print_short(NULL); + varReplacer->print_some_stats(cpu_time); + + //varReplacer->get_stats().print_short(nVars()); + print_stats_line("c distill long time" + , distill_long_cls->get_stats().time_used + , stats_line_percent(distill_long_cls->get_stats().time_used, cpu_time) + , "% time" + ); + print_stats_line("c distill bin time" + , distill_bin_cls->get_stats().time_used + , stats_line_percent(distill_bin_cls->get_stats().time_used, cpu_time) + , "% time" + ); + + print_stats_line("c strength cache-irred time" + , dist_long_with_impl->get_stats().irredWatchBased.cpu_time + , stats_line_percent(dist_long_with_impl->get_stats().irredWatchBased.cpu_time, cpu_time) + , "% time" + ); + print_stats_line("c strength cache-red time" + , dist_long_with_impl->get_stats().redWatchBased.cpu_time + , stats_line_percent(dist_long_with_impl->get_stats().redWatchBased.cpu_time, cpu_time) + , "% time" + ); + + if (sumConflicts > 0) { + for(uint32_t i = 0; i < longRedCls.size(); i ++) { + std::stringstream ss; + ss << "c avg cls in red " << i; + print_stats_line(ss.str() + , (double)longRedClsSizes[i]/(double)sumConflicts + ); + } + #if defined(STATS_NEEDED) || defined (FINAL_PREDICTOR) || defined(NORMAL_CL_USE_STATS) + for(uint32_t i = 0; i < longRedCls.size(); i++) { + reduceDB->cl_stats[i].print(i); + } + #endif + } + + #ifdef STATS_NEEDED + print_stats_line( + "c DB locked ratio", + stats_line_percent(reduceDB->locked_for_data_gen_total, reduceDB->locked_for_data_gen_cls) + ); + #endif + + if (conf.do_print_times) { + print_stats_line("c Conflicts in UIP" + , sumConflicts + , float_div(sumConflicts, cpu_time) + , "confl/time_this_thread" + ); + } else { + print_stats_line("c Conflicts in UIP", sumConflicts); + } + double vm_usage; + std::string max_mem_usage; + double max_rss_mem_mb = (double)memUsedTotal(vm_usage, &max_mem_usage)/(1024UL*1024UL); + if (max_mem_usage.empty()) { + print_stats_line("c Mem used" + , max_rss_mem_mb + , "MB" + ); + } else { + print_stats_line("c Max Memory (rss) used" + , max_mem_usage + ); +// print_stats_line("c Virt mem used at exit" +// , vm_usage/(1024UL*1024UL) +// , "MB" +// ); + } + print_stats_time(cpu_time, cpu_time_total, wallclock_time_started); +} + +void Solver::print_full_stats( + const double cpu_time, + const double /*cpu_time_total*/, + const double /*wallclock_time_started*/) const +{ + cout << "c All times are for this thread only except if explicitly specified" << endl; + sumSearchStats.print(sumPropStats.propagations, conf.do_print_times); + sumPropStats.print(sumSearchStats.cpu_time); + //reduceDB->get_total_time().print(cpu_time); + + //OccSimplifier stats + if (conf.perform_occur_based_simp) { + occsimplifier->get_stats().print(nVarsOuter(), occsimplifier); + occsimplifier->get_sub_str()->get_stats().print(); + } + + //TODO after TRI to LONG conversion + /*if (occsimplifier && conf.doGateFind) { + occsimplifier->print_gatefinder_stats(); + }*/ + + varReplacer->get_scc_finder()->get_stats().print(); + varReplacer->get_stats().print(nVarsOuter()); + varReplacer->print_some_stats(cpu_time); + distill_bin_cls->get_stats().print(nVarsOuter()); + dist_long_with_impl->get_stats().print(); + + if (conf.doStrSubImplicit) { + subsumeImplicit->get_stats().print(""); + } + print_mem_stats(); +} + +uint64_t Solver::print_watch_mem_used(const uint64_t rss_mem_used) const +{ + size_t alloc = watches.mem_used_alloc(); + print_stats_line("c Mem for watch alloc" + , alloc/(1024UL*1024UL) + , "MB" + , stats_line_percent(alloc, rss_mem_used) + , "%" + ); + + size_t array = watches.mem_used_array(); + print_stats_line("c Mem for watch array" + , array/(1024UL*1024UL) + , "MB" + , stats_line_percent(array, rss_mem_used) + , "%" + ); + + return alloc + array; +} + +size_t Solver::mem_used() const +{ + size_t mem = 0; + mem += Searcher::mem_used(); + mem += outside_assumptions.capacity()*sizeof(Lit); + + return mem; +} + +uint64_t Solver::mem_used_vardata() const +{ + uint64_t mem = 0; + mem += assigns.capacity()*sizeof(lbool); + mem += varData.capacity()*sizeof(VarData); + + return mem; +} + +void Solver::print_mem_stats() const +{ + double vm_mem_used = 0; + const uint64_t rss_mem_used = memUsedTotal(vm_mem_used); + print_stats_line("c Mem used" + , rss_mem_used/(1024UL*1024UL) + , "MB" + ); + uint64_t account = 0; + + account += print_mem_used_longclauses(rss_mem_used); + account += print_watch_mem_used(rss_mem_used); + + size_t mem = 0; + mem += mem_used_vardata(); + print_stats_line("c Mem for assings&vardata" + , mem/(1024UL*1024UL) + , "MB" + , stats_line_percent(mem, rss_mem_used) + , "%" + ); + account += mem; + + mem = mem_used(); + print_stats_line("c Mem for search&solve" + , mem/(1024UL*1024UL) + , "MB" + , stats_line_percent(mem, rss_mem_used) + , "%" + ); + account += mem; + + mem = CNF::mem_used_renumberer(); + print_stats_line("c Mem for renumberer" + , mem/(1024UL*1024UL) + , "MB" + , stats_line_percent(mem, rss_mem_used) + , "%" + ); + account += mem; + + if (occsimplifier) { + mem = occsimplifier->mem_used(); + print_stats_line("c Mem for occsimplifier" + , mem/(1024UL*1024UL) + , "MB" + , stats_line_percent(mem, rss_mem_used) + , "%" + ); + account += mem; + } + + mem = varReplacer->mem_used(); + print_stats_line("c Mem for varReplacer&SCC" + , mem/(1024UL*1024UL) + , "MB" + , stats_line_percent(mem, rss_mem_used) + , "%" + ); + account += mem; + + if (subsumeImplicit) { + mem = subsumeImplicit->mem_used(); + print_stats_line("c Mem for impl subsume" + , mem/(1024UL*1024UL) + , "MB" + , stats_line_percent(mem, rss_mem_used) + , "%" + ); + account += mem; + } + + + mem = distill_long_cls->mem_used(); + mem += dist_long_with_impl->mem_used(); + mem += dist_impl_with_impl->mem_used(); + print_stats_line("c Mem for 3 distills" + , mem/(1024UL*1024UL) + , "MB" + , stats_line_percent(mem, rss_mem_used) + , "%" + ); + account += mem; + + print_stats_line("c Accounted for mem (rss)" + , stats_line_percent(account, rss_mem_used) + , "%" + ); + print_stats_line("c Accounted for mem (vm)" + , stats_line_percent(account, vm_mem_used) + , "%" + ); +} + +void Solver::print_clause_size_distrib() +{ + size_t size3 = 0; + size_t size4 = 0; + size_t size5 = 0; + size_t sizeLarge = 0; + for(vector::const_iterator + it = longIrredCls.begin(), end = longIrredCls.end() + ; it != end + ; ++it + ) { + Clause* cl = cl_alloc.ptr(*it); + switch(cl->size()) { + case 0: + case 1: + case 2: + assert(false); + break; + case 3: + size3++; + break; + case 4: + size4++; + break; + case 5: + size5++; + break; + default: + sizeLarge++; + break; + } + } + + cout + << "c clause size stats." + << " size3: " << size3 + << " size4: " << size4 + << " size5: " << size5 + << " larger: " << sizeLarge << endl; +} + + +vector Solver::get_zero_assigned_lits(const bool backnumber, + const bool only_nvars) const +{ + vector lits; + assert(decisionLevel() == 0); + size_t until; + if (only_nvars) { + until = nVars(); + } else { + until = assigns.size(); + } + for(size_t i = 0; i < until; i++) { + if (assigns[i] != l_Undef) { + Lit lit(i, assigns[i] == l_False); + + //Update to higher-up + lit = varReplacer->get_lit_replaced_with(lit); + if (varData[lit.var()].is_bva == false) { + if (backnumber) { + lits.push_back(map_inter_to_outer(lit)); + } else { + lits.push_back(lit); + } + + } + + //Everything it repaces has also been set + const vector vars = varReplacer->get_vars_replacing(lit.var()); + for(const uint32_t var: vars) { + if (varData[var].is_bva) + continue; + + Lit tmp_lit = Lit(var, false); + assert(varReplacer->get_lit_replaced_with(tmp_lit).var() == lit.var()); + if (lit != varReplacer->get_lit_replaced_with(tmp_lit)) { + tmp_lit ^= true; + } + assert(lit == varReplacer->get_lit_replaced_with(tmp_lit)); + + if (backnumber) { + lits.push_back(map_inter_to_outer(tmp_lit)); + } else { + lits.push_back(tmp_lit); + } + } + } + } + + //Remove duplicates. Because of above replacing-mimicing algo + //multipe occurrences of literals can be inside + std::sort(lits.begin(), lits.end()); + vector::iterator it = std::unique (lits.begin(), lits.end()); + lits.resize( std::distance(lits.begin(),it) ); + + //Update to outer without BVA + if (backnumber) { + vector my_map = build_outer_to_without_bva_map(); + updateLitsMap(lits, my_map); + for(const Lit lit: lits) { + assert(lit.var() < nVarsOutside()); + } + } + + return lits; +} + +bool Solver::verify_model_implicit_clauses() const +{ + uint32_t wsLit = 0; + for (watch_array::const_iterator + it = watches.begin(), end = watches.end() + ; it != end + ; ++it, wsLit++ + ) { + Lit lit = Lit::toLit(wsLit); + watch_subarray_const ws = *it; + + for (Watched w: ws) { + if (w.isBin() + && model_value(lit) != l_True + && model_value(w.lit2()) != l_True + ) { + cout + << "bin clause: " + << lit << " , " << w.lit2() + << " not satisfied!" + << endl; + + cout + << "value of unsat bin clause: " + << value(lit) << " , " << value(w.lit2()) + << endl; + + return false; + } + } + } + + return true; +} + +bool Solver::verify_model_long_clauses(const vector& cs) const +{ + #ifdef VERBOSE_DEBUG + cout << "Checking clauses whether they have been properly satisfied." << endl; + #endif + + bool verificationOK = true; + + for (vector::const_iterator + it = cs.begin(), end = cs.end() + ; it != end + ; ++it + ) { + Clause& cl = *cl_alloc.ptr(*it); + for (uint32_t j = 0; j < cl.size(); j++) + if (model_value(cl[j]) == l_True) + goto next; + + cout << "unsatisfied clause: " << cl << endl; + verificationOK = false; + next: + ; + } + + return verificationOK; +} + +bool Solver::verify_model() const +{ + bool verificationOK = true; + verificationOK &= verify_model_long_clauses(longIrredCls); + for(auto& lredcls: longRedCls) { + verificationOK &= verify_model_long_clauses(lredcls); + } + verificationOK &= verify_model_implicit_clauses(); + + if (conf.verbosity && verificationOK) { + cout + << "c Verified " + << longIrredCls.size() + longRedCls.size() + + binTri.irredBins + binTri.redBins + << " clause(s)." + << endl; + } + + return verificationOK; +} + +size_t Solver::get_num_nonfree_vars() const +{ + size_t nonfree = 0; + if (decisionLevel() == 0) { + nonfree += trail.size(); + } else { + nonfree += trail_lim[0]; + } + + if (occsimplifier) { + if (conf.perform_occur_based_simp) { + nonfree += occsimplifier->get_num_elimed_vars(); + } + } + nonfree += varReplacer->get_num_replaced_vars(); + + return nonfree; +} + +size_t Solver::get_num_free_vars() const +{ + return nVarsOuter() - get_num_nonfree_vars(); +} + +void Solver::print_clause_stats() const +{ + //Irredundant + cout << " " << print_value_kilo_mega(longIrredCls.size()); + cout << " " << print_value_kilo_mega(binTri.irredBins); + cout + << " " << std::setw(7) << std::fixed << std::setprecision(2) + << ratio_for_stat(litStats.irredLits, longIrredCls.size()) + << " " << std::setw(7) << std::fixed << std::setprecision(2) + << ratio_for_stat(litStats.irredLits + binTri.irredBins*2 + , longIrredCls.size() + binTri.irredBins) + ; + + //Redundant + size_t tot = 0; + for(auto& lredcls: longRedCls) { + cout << " " << print_value_kilo_mega(lredcls.size()); + tot += lredcls.size(); + } + + cout << " " << print_value_kilo_mega(binTri.redBins); + cout + << " " << std::setw(7) << std::fixed << std::setprecision(2) + << ratio_for_stat(litStats.redLits, tot) + << " " << std::setw(7) << std::fixed << std::setprecision(2) + << ratio_for_stat(litStats.redLits + binTri.redBins*2 + , tot + binTri.redBins) + ; +} + +const char* Solver::get_version_sha1() +{ + return CMSat::get_version_sha1(); +} + +const char* Solver::get_version_tag() +{ + return CMSat::get_version_tag(); +} + +const char* Solver::get_compilation_env() +{ + return CMSat::get_compilation_env(); +} + +void Solver::print_watch_list(watch_subarray_const ws, const Lit lit) const +{ + cout << "Watch[" << lit << "]: "<< endl; + for (const Watched *it = ws.begin(), *end = ws.end() + ; it != end + ; ++it + ) { + if (it->isClause()) { + Clause* cl = cl_alloc.ptr(it->get_offset()); + cout + << "-> Clause: " << *cl + << " red: " << cl->red() + << " xor: " << cl->used_in_xor() + << " full-xor: " << cl->used_in_xor_full() + << " xor-detached: " << cl->_xor_is_detached; + } + if (it->isBin()) { + cout + << "-> BIN: " << lit << ", " << it->lit2() + << " red: " << it->red(); + } + cout << endl; + } + cout << "FIN" << endl; +} + +void Solver::check_implicit_propagated() const +{ + const double myTime = cpuTime(); + size_t wsLit = 0; + for(watch_array::const_iterator + it = watches.begin(), end = watches.end() + ; it != end + ; ++it, wsLit++ + ) { + const Lit lit = Lit::toLit(wsLit); + watch_subarray_const ws = *it; + for(const Watched *it2 = ws.begin(), *end2 = ws.end() + ; it2 != end2 + ; it2++ + ) { + //Satisfied, or not implicit, skip + if (value(lit) == l_True + || it2->isClause() + ) { + continue; + } + + const lbool val1 = value(lit); + const lbool val2 = value(it2->lit2()); + + //Handle binary + if (it2->isBin()) { + if (val1 == l_False) { + if (val2 != l_True) { + cout << "not prop BIN: " + << lit << ", " << it2->lit2() + << " (red: " << it2->red() + << endl; + } + assert(val2 == l_True); + } + + if (val2 == l_False) + assert(val1 == l_True); + } + } + } + const double time_used = cpuTime() - myTime; + if (sqlStats) { + sqlStats->time_passed_min( + this + , "check implicit propagated" + , time_used + ); + } +} + +size_t Solver::get_num_vars_elimed() const +{ + if (conf.perform_occur_based_simp) { + return occsimplifier->get_num_elimed_vars(); + } else { + return 0; + } +} + +void Solver::free_unused_watches() +{ + size_t wsLit = 0; + for (watch_array::iterator + it = watches.begin(), end = watches.end() + ; it != end + ; ++it, wsLit++ + ) { + Lit lit = Lit::toLit(wsLit); + if (varData[lit.var()].removed == Removed::elimed + || varData[lit.var()].removed == Removed::replaced + ) { + watch_subarray ws = *it; + assert(ws.empty()); + ws.clear(); + } + } + + if ((sumConflicts - last_full_watch_consolidate) > conf.full_watch_consolidate_every_n_confl) { + last_full_watch_consolidate = sumConflicts; + consolidate_watches(true); + } else { + consolidate_watches(false); + } +} + +bool Solver::fully_enqueue_these(const vector& toEnqueue) +{ + assert(ok); + assert(decisionLevel() == 0); + for(const auto& lit: toEnqueue) { + if (!fully_enqueue_this(lit)) { + return false; + } + } + + return true; +} + +bool Solver::fully_enqueue_this(const Lit lit) +{ + assert(decisionLevel() == 0); + assert(ok); + + const lbool val = value(lit); + if (val == l_Undef) { + assert(varData[lit.var()].removed == Removed::none); + enqueue(lit); + ok = propagate().isNULL(); + + if (!ok) { + return false; + } + } else if (val == l_False) { + *frat << add << ++clauseID << fin; + ok = false; + return false; + } + return true; +} + +void Solver::new_external_var() +{ + new_var(false); +} + +void Solver::new_external_vars(size_t n) +{ + new_vars(n); +} + +void Solver::add_in_partial_solving_stats() +{ + Searcher::add_in_partial_solving_stats(); + sumSearchStats += Searcher::get_stats(); + sumPropStats += propStats; +} + +bool Solver::add_clause_outside(const vector& lits, bool red) +{ + if (!ok) return false; + + SLOW_DEBUG_DO(check_too_large_variable_number(lits)); //we check for this during back-numbering + back_number_from_outside_to_outer(lits); + return add_clause_outer(back_number_from_outside_to_outer_tmp, red); +} + +bool Solver::full_probe(const bool bin_only) +{ + assert(okay()); + assert(decisionLevel() == 0); + + const size_t orig_num_free_vars = solver->get_num_free_vars(); + double myTime = cpuTime(); + int64_t start_bogoprops = solver->propStats.bogoProps; + int64_t bogoprops_to_use = + solver->conf.full_probe_time_limitM*1000ULL*1000ULL + *solver->conf.global_timeout_multiplier; + uint64_t probed = 0; + const auto orig_repl = varReplacer->get_num_replaced_vars(); + *solver->frat << __PRETTY_FUNCTION__ << " start\n"; + + vector vars; + for(uint32_t i = 0; i < nVars(); i++) { + Lit l(i, false); + if (value(l) == l_Undef && varData[i].removed == Removed::none) + vars.push_back(i); + } + std::shuffle(vars.begin(), vars.end(), mtrand); + + for(auto const& v: vars) { + if ((int64_t)solver->propStats.bogoProps > start_bogoprops + bogoprops_to_use) + break; + + uint32_t min_props; + Lit l(v, false); + + //we have seen it in every combination, nothing will be learnt + if (seen2[l.var()] == 3) continue; + + if (value(l) == l_Undef && + varData[v].removed == Removed::none) + { + probed++; + lbool ret; + if (bin_only) ret = probe_inter(l, min_props); + else ret = probe_inter(l, min_props); + if (ret == l_False) goto cleanup; + + if (conf.verbosity >= 5) { + const double time_remain = 1.0-float_div( + (int64_t)solver->propStats.bogoProps-start_bogoprops, bogoprops_to_use); + cout << "c probe time remain: " << time_remain << " probed: " << probed + << " set: " << (orig_num_free_vars - solver->get_num_free_vars()) + << " T: " << (cpuTime() - myTime) + << endl; + } + } + } + + cleanup: + std::fill(seen2.begin(), seen2.end(), 0); + + const double time_used = cpuTime() - myTime; + const double time_remain = 1.0-float_div( + (int64_t)solver->propStats.bogoProps-start_bogoprops, bogoprops_to_use); + const bool time_out = ((int64_t)solver->propStats.bogoProps > start_bogoprops + bogoprops_to_use); + + verb_print(1, + "[full-probe] " + << " bin_only: " << bin_only + << " set: " + << (orig_num_free_vars - solver->get_num_free_vars()) + << " repl: " << (varReplacer->get_num_replaced_vars() - orig_repl) + << solver->conf.print_times(time_used, time_out, time_remain)); + + + if (solver->sqlStats) { + solver->sqlStats->time_passed( + solver + , "full-probe" + , time_used + , time_out + , time_remain + ); + } + *solver->frat << __PRETTY_FUNCTION__ << " end\n"; + + return okay(); +} + +template +lbool Solver::probe_inter(const Lit l, uint32_t& min_props) +{ + propStats.bogoProps+=2; + + //Probe l + uint32_t old_trail_size = trail.size(); + new_decision_level(); + enqueue_light(l); + PropBy p = propagate_light(); + min_props = trail.size() - old_trail_size; + for(uint32_t i = old_trail_size+1; i < trail.size(); i++) { + toClear.push_back(trail[i].lit); + //seen[x] == 0 -> not propagated + //seen[x] == 1 -> propagated as POS + //seen[x] == 2 -> propagated as NEG + const auto var = trail[i].lit.var(); + seen[var] = 1+(int)trail[i].lit.sign(); + seen2[var] |= 1+(int)trail[i].lit.sign(); + } + cancelUntil_light(); + + //Check result + if (!p.isNULL()) { + enqueue(~l); + p = propagate(); + if (!p.isNULL()) { + ok = false; + } + goto end; + } + + //Probe ~l + old_trail_size = trail.size(); + new_decision_level(); + enqueue_light(~l); + p = propagate_light(); + min_props = std::min(min_props, trail.size() - old_trail_size); + probe_inter_tmp.clear(); + for(uint32_t i = old_trail_size+1; i < trail.size(); i++) { + Lit lit = trail[i].lit; + uint32_t var = trail[i].lit.var(); + seen2[var] |= 1+(int)trail[i].lit.sign(); + if (seen[var] == 0) continue; + + if (lit.sign() == seen[var]-1) { + //Same sign both times (set value of literal) + probe_inter_tmp.push_back(lit); + } else { + //Inverse sign in the 2 cases (literal equivalence) + probe_inter_tmp.push_back(lit_Undef); + probe_inter_tmp.push_back(~lit); + } + } + cancelUntil_light(); + + //Check result + if (!p.isNULL()) { + enqueue(l); + p = propagate(); + if (!p.isNULL()) { + ok = false; + } + goto end; + } + + //Deal with bothprop + for(uint32_t i = 0; i < probe_inter_tmp.size(); i++) { + Lit bp_lit = probe_inter_tmp[i]; + if (bp_lit != lit_Undef) { + //I am not going to deal with the messy version of it already being set + if (value(bp_lit) == l_Undef) { + *solver->frat << add << ++clauseID << ~l << bp_lit << fin; + const int32_t c1 = clauseID; + *solver->frat << add << ++clauseID << l << bp_lit << fin; + const int32_t c2 = clauseID; + enqueue(bp_lit); + *solver->frat << del << c1 << ~l << bp_lit << fin; + *solver->frat << del << c2 << l << bp_lit << fin; + } + } else { + //First we must propagate all the enqueued facts + p = propagate(); + if (!p.isNULL()) { + ok = false; + goto end; + } + + //Add binary XOR + i++; + bp_lit = probe_inter_tmp[i]; + vector lits(2); + lits[0] = l; + lits[1] = bp_lit; + ok = add_xor_clause_inter(lits, false, true, true, true); + if (!ok) { + goto end; + } + } + } + + //Propagate all enqueued facts due to bprop + p = propagate(); + if (!p.isNULL()) { + ok = false; + goto end; + } + + end: + for(auto clear_l: toClear) { + seen[clear_l.var()] = 0; + } + toClear.clear(); + return ok ? l_Undef : l_False; +} + +lbool Solver::probe_outside(Lit l, uint32_t& min_props) +{ + assert(decisionLevel() == 0); + assert(l.var() < nVarsOutside()); + + if (!ok) { + return l_False; + } + + l = map_to_with_bva(l); + l = varReplacer->get_lit_replaced_with_outer(l); + l = map_outer_to_inter(l); + if (varData[l.var()].removed != Removed::none) { + //TODO + return l_Undef; + } + if (value(l) != l_Undef) { + return l_Undef; + } + + return probe_inter(l, min_props); +} + +bool Solver::add_xor_clause_outside(const vector& vars, bool rhs) +{ + if (!ok) { + return false; + } + + vector lits(vars.size()); + for(size_t i = 0; i < vars.size(); i++) { + lits[i] = Lit(vars[i], false); + } + #ifdef SLOW_DEBUG //we check for this during back-numbering + check_too_large_variable_number(lits); + #endif + + back_number_from_outside_to_outer(lits); + addClauseHelper(back_number_from_outside_to_outer_tmp); + add_xor_clause_inter(back_number_from_outside_to_outer_tmp, rhs, true, false); + + return ok; +} + +bool Solver::add_bnn_clause_outside( + const vector& lits, + const int32_t cutoff, + Lit out) +{ + if (!ok) { + return false; + } + + #ifdef SLOW_DEBUG //we check for this during back-numbering + check_too_large_variable_number(lits); + #endif + + vector lits2(lits); + if (out != lit_Undef) { + lits2.push_back(out); + } + back_number_from_outside_to_outer(lits2); + addClauseHelper(back_number_from_outside_to_outer_tmp); + if (out != lit_Undef) { + out = back_number_from_outside_to_outer_tmp.back(); + back_number_from_outside_to_outer_tmp.pop_back(); + } + + add_bnn_clause_inter( + back_number_from_outside_to_outer_tmp, cutoff, out); + + return ok; +} + +void Solver::check_too_large_variable_number(const vector& lits) const +{ + for (const Lit lit: lits) { + if (lit.var() >= nVarsOutside()) { + std::cerr + << "ERROR: Variable " << lit.var() + 1 + << " inserted, but max var is " + << nVarsOutside() + << endl; + assert(false); + std::exit(-1); + } + release_assert(lit.var() < nVarsOutside() + && "Clause inserted, but variable inside has not been declared with PropEngine::new_var() !"); + + if (lit.var() >= var_Undef) { + std::cerr << "ERROR: Variable number " << lit.var() + << "too large. PropBy is limiting us, sorry" << endl; + assert(false); + std::exit(-1); + } + } +} + +void Solver::bva_changed() +{ + datasync->rebuild_bva_map(); +} + +vector > Solver::get_all_binary_xors() const +{ + vector > bin_xors = varReplacer->get_all_binary_xors_outer(); + + //Update to outer without BVA + vector > ret; + const vector my_map = build_outer_to_without_bva_map(); + for(std::pair p: bin_xors) { + if (p.first.var() < my_map.size() + && p.second.var() < my_map.size() + ) { + ret.push_back(std::make_pair( + getUpdatedLit(p.first, my_map) + , getUpdatedLit(p.second, my_map) + )); + } + } + + for(const auto& val: ret) { + assert(val.first.var() < nVarsOutside()); + assert(val.second.var() < nVarsOutside()); + } + + return ret; +} + +void Solver::update_assumptions_after_varreplace() +{ + #ifdef SLOW_DEBUG + for(AssumptionPair& lit_pair: assumptions) { + const Lit inter_lit = map_outer_to_inter(lit_pair.lit_outer); + assert(inter_lit.var() < varData.size()); + if (varData[inter_lit.var()].assumption == l_Undef) { + cout << "Assump " << inter_lit << " has .assumption : " + << varData[inter_lit.var()].assumption << endl; + } + assert(varData[inter_lit.var()].assumption != l_Undef); + } + #endif + + //Update assumptions + for(AssumptionPair& lit_pair: assumptions) { + const Lit orig = lit_pair.lit_outer; + lit_pair.lit_outer = varReplacer->get_lit_replaced_with_outer(orig); + + //remove old from set + add new to set + if (orig != lit_pair.lit_outer) { + const Lit old_inter_lit = map_outer_to_inter(orig); + const Lit new_inter_lit = map_outer_to_inter(lit_pair.lit_outer); + varData[old_inter_lit.var()].assumption = l_Undef; + varData[new_inter_lit.var()].assumption = + new_inter_lit.sign() ? l_False: l_True; + } + } + + #ifdef SLOW_DEBUG + check_assumptions_sanity(); + #endif +} + +//TODO later, this can be removed, get_num_free_vars() is MUCH cheaper to +//compute but may have some bugs here-and-there +uint32_t Solver::num_active_vars() const +{ + uint32_t numActive = 0; + uint32_t removed_replaced = 0; + uint32_t removed_set = 0; + uint32_t removed_elimed = 0; + uint32_t removed_non_decision = 0; + for(uint32_t var = 0; var < nVarsOuter(); var++) { + if (value(var) != l_Undef) { + if (varData[var].removed != Removed::none) + { + cout << "ERROR: var " << var + 1 << " has removed: " + << removed_type_to_string(varData[var].removed) + << " but is set to " << value(var) << endl; + assert(varData[var].removed == Removed::none); + exit(-1); + } + removed_set++; + continue; + } + switch(varData[var].removed) { + case Removed::clashed: + continue; + case Removed::elimed : + removed_elimed++; + continue; + case Removed::replaced: + removed_replaced++; + continue; + case Removed::none: + break; + } + if (varData[var].removed != Removed::none) { + removed_non_decision++; + } + numActive++; + } + assert(removed_non_decision == 0); + if (occsimplifier) { + assert(removed_elimed == occsimplifier->get_num_elimed_vars()); + } else { + assert(removed_elimed == 0); + } + + assert(removed_set == ((decisionLevel() == 0) ? trail.size() : trail_lim[0])); + + assert(removed_replaced == varReplacer->get_num_replaced_vars()); + assert(numActive == get_num_free_vars()); + + return numActive; +} + +#ifdef STATS_NEEDED +SatZillaFeatures Solver::calculate_satzilla_features() +{ + latest_satzilla_feature_calc++; + SatZillaFeaturesCalc extract(this); + SatZillaFeatures satzilla_feat = extract.extract(); + satzilla_feat.avg_confl_size = hist.conflSizeHistLT.avg(); + satzilla_feat.avg_confl_glue = hist.glueHistLT.avg(); + satzilla_feat.avg_num_resolutions = hist.numResolutionsHistLT.avg(); + satzilla_feat.avg_trail_depth_delta = hist.trailDepthDeltaHist.avg(); + satzilla_feat.avg_branch_depth = hist.branchDepthHist.avg(); + satzilla_feat.avg_branch_depth_delta = hist.branchDepthDeltaHist.avg(); + + satzilla_feat.confl_size_min = hist.conflSizeHistLT.getMin(); + satzilla_feat.confl_size_max = hist.conflSizeHistLT.getMax(); + satzilla_feat.confl_glue_min = hist.glueHistLT.getMin(); + satzilla_feat.confl_glue_max = hist.glueHistLT.getMax(); + satzilla_feat.branch_depth_min = hist.branchDepthHist.getMin(); + satzilla_feat.branch_depth_max = hist.branchDepthHist.getMax(); + satzilla_feat.trail_depth_delta_min = hist.trailDepthDeltaHist.getMin(); + satzilla_feat.trail_depth_delta_max = hist.trailDepthDeltaHist.getMax(); + satzilla_feat.num_resolutions_min = hist.numResolutionsHistLT.getMin(); + satzilla_feat.num_resolutions_max = hist.numResolutionsHistLT.getMax(); + + if (sumPropStats.propagations != 0 + && sumConflicts != 0 + && sumSearchStats.numRestarts != 0 + ) { + satzilla_feat.props_per_confl = (double)sumConflicts / (double)sumPropStats.propagations; + satzilla_feat.confl_per_restart = (double)sumConflicts / (double)sumSearchStats.numRestarts; + satzilla_feat.decisions_per_conflict = (double)sumSearchStats.decisions / (double)sumConflicts; + satzilla_feat.learnt_bins_per_confl = (double)sumSearchStats.learntBins / (double)sumConflicts; + } + + satzilla_feat.num_gates_found_last = sumSearchStats.num_gates_found_last; + satzilla_feat.num_xors_found_last = sumSearchStats.num_xors_found_last; + + if (conf.verbosity > 2) { + satzilla_feat.print_stats(); + } + + if (sqlStats) { + sqlStats->satzilla_features(this, this, satzilla_feat); + } + + return satzilla_feat; +} +#endif + +void Solver::check_implicit_stats(const bool onlypairs) const +{ + //Don't check if in crazy mode + #ifdef NDEBUG + return; + #endif + const double myTime = cpuTime(); + + //Check number of red & irred binary clauses + uint64_t thisNumRedBins = 0; + uint64_t thisNumIrredBins = 0; + + size_t wsLit = 0; + for(watch_array::const_iterator + it = watches.begin(), end = watches.end() + ; it != end + ; ++it, wsLit++ + ) { + watch_subarray_const ws = *it; + for(const Watched* it2 = ws.begin(), *end2 = ws.end() + ; it2 != end2 + ; it2++ + ) { + if (it2->isBin()) { + #ifdef DEBUG_IMPLICIT_PAIRS_TRIPLETS + Lit lits[2]; + lits[0] = Lit::toLit(wsLit); + lits[1] = it2->lit2(); + std::sort(lits, lits + 2); + findWatchedOfBin(watches, lits[0], lits[1], it2->red(), it2->get_ID()); + findWatchedOfBin(watches, lits[1], lits[0], it2->red(), it2->get_ID()); + #endif + + if (it2->red()) + thisNumRedBins++; + else + thisNumIrredBins++; + + continue; + } + } + } + + if (onlypairs) { + goto end; + } + + if (thisNumIrredBins/2 != binTri.irredBins) { + std::cerr + << "ERROR:" + << " thisNumIrredBins/2: " << thisNumIrredBins/2 + << " thisNumIrredBins: " << thisNumIrredBins + << " binTri.irredBins: " << binTri.irredBins + << endl; + } + assert(thisNumIrredBins % 2 == 0); + assert(thisNumIrredBins/2 == binTri.irredBins); + + if (thisNumRedBins/2 != binTri.redBins) { + std::cerr + << "ERROR:" + << " thisNumRedBins/2: " << thisNumRedBins/2 + << " thisNumRedBins: " << thisNumRedBins + << " binTri.redBins: " << binTri.redBins + << endl; + } + assert(thisNumRedBins % 2 == 0); + assert(thisNumRedBins/2 == binTri.redBins); + + end: + + const double time_used = cpuTime() - myTime; + if (sqlStats) { + sqlStats->time_passed_min( + this + , "check implicit stats" + , time_used + ); + } +} + +void Solver::check_stats(const bool allowFreed) const +{ + //If in crazy mode, don't check + #ifdef NDEBUG + return; + #endif + + check_implicit_stats(); + + const double myTime = cpuTime(); + uint64_t numLitsIrred = count_lits(longIrredCls, false, allowFreed); + if (numLitsIrred != litStats.irredLits) { + std::cerr << "ERROR: " << endl + << "->numLitsIrred: " << numLitsIrred << endl + << "->litStats.irredLits: " << litStats.irredLits << endl; + } + + uint64_t numLitsRed = 0; + for(auto& lredcls: longRedCls) { + numLitsRed += count_lits(lredcls, true, allowFreed); + } + if (numLitsRed != litStats.redLits) { + std::cerr << "ERROR: " << endl + << "->numLitsRed: " << numLitsRed << endl + << "->litStats.redLits: " << litStats.redLits << endl; + } + assert(numLitsRed == litStats.redLits); + assert(numLitsIrred == litStats.irredLits); + + const double time_used = cpuTime() - myTime; + if (sqlStats) { + sqlStats->time_passed_min( + this + , "check literal stats" + , time_used + ); + } +} + +void Solver::add_sql_tag(const string& name, const string& val) +{ + if (sqlStats) { + sqlStats->add_tag(std::make_pair(name, val)); + } +} + +vector Solver::get_toplevel_units_internal(bool outer_numbering) const +{ + assert(!outer_numbering); + vector units; + for(size_t i = 0; i < nVars(); i++) { + if (value(i) != l_Undef) { + Lit l = Lit(i, value(i) == l_False); + units.push_back(l); + } + } + + return units; +} + +vector Solver::get_recovered_xors(const bool xor_together_xors) +{ + vector xors_ret; + if (!okay()) return xors_ret; + if (!clear_gauss_matrices()) return xors_ret; + + lbool ret = execute_inprocess_strategy(false, "occ-xor"); + if (ret == l_False) return xors_ret; + + auto xors = xorclauses; + xors.insert(xors.end(), xorclauses_unused.begin(), xorclauses_unused.end()); + if (xor_together_xors) { + XorFinder finder(NULL, this); + finder.xor_together_xors(xors); + renumber_xors_to_outside(xors, xors_ret); + return xors_ret; + } else { + renumber_xors_to_outside(xors, xors_ret); + return xors_ret; + } +} + +void Solver::renumber_xors_to_outside(const vector& xors, vector& xors_ret) +{ + const vector outer_to_without_bva_map = build_outer_to_without_bva_map(); + + if (conf.verbosity >= 5) { + cout << "XORs before outside numbering:" << endl; + for(auto& x: xors) { + cout << x << endl; + } + } + + for(auto& x: xors) { + bool OK = true; + for(const auto v: x.get_vars()) { + if (varData[v].is_bva) { + OK = false; + break; + } + } + if (!OK) { + continue; + } + + vector t = xor_outer_numbered(x.get_vars()); + for(auto& v: t) { + v = outer_to_without_bva_map[v]; + } + xors_ret.push_back(Xor(t, x.rhs, vector())); + } +} + +bool Solver::find_and_init_all_matrices() +{ + *solver->frat << __PRETTY_FUNCTION__ << " start\n"; + if (!xor_clauses_updated && (!detached_xor_clauses || !assump_contains_xor_clash())) { + if (conf.verbosity >= 2) { + cout << "c [find&init matx] XORs not updated, and either (XORs are not detached OR assumps does not contain clash variable) -> or not performing matrix init. Matrices: " << gmatrices.size() << endl; + } + return true; + } + if (conf.verbosity >= 1) cout << "c [find&init matx] performing matrix init" << endl; + + bool can_detach; + if (!clear_gauss_matrices()) return false; + + /*Reattach needed in case we are coming in again, after adding new XORs + we might turn off a previously turned on matrix + which means we wouldn't re-attach those XORs + -> but we fixed this in matrixfinder, where we FORCE a Gauss to be ON + in case it contains a previously detached XOR + */ + //fully_undo_xor_detach(); + + MatrixFinder mfinder(solver); + ok = mfinder.find_matrices(can_detach); + if (!ok) return false; + if (!init_all_matrices()) return false; + + if (conf.verbosity >= 2) { + cout << "c calculating no_irred_contains_clash..." << endl; + bool no_irred_contains_clash = no_irred_nonxor_contains_clash_vars(); + + cout + << "c [gauss]" + << " xorclauses_unused: " << xorclauses_unused.size() + << " can detach: " << can_detach + << " no irred with clash: " << no_irred_contains_clash + << endl; + + cout << "c unused xors follow." << endl; + for(const auto& x: xorclauses_unused) { + cout << "c " << x << endl; + } + cout << "c FIN" << endl; + + cout << "c used xors follow." << endl; + for(const auto& x: xorclauses) { + cout << "c " << x << endl; + } + cout << "c FIN" << endl; + } + + bool ret_no_irred_nonxor_contains_clash_vars; + if (can_detach && + conf.xor_detach_reattach && + !conf.gaussconf.autodisable && + (ret_no_irred_nonxor_contains_clash_vars=no_irred_nonxor_contains_clash_vars()) + ) { + detach_xor_clauses(mfinder.clash_vars_unused); + unset_clash_decision_vars(xorclauses); + rebuildOrderHeap(); + if (conf.xor_detach_verb) print_watchlist_stats(); + + } else { + if (conf.xor_detach_reattach && + (conf.verbosity >= 1 || conf.xor_detach_verb) && conf.doFindXors) + { + cout + << "c WHAAAAT Detach issue. All below must be 1 to work ---" << endl + << "c -- can_detach: " << (bool)can_detach << endl + << "c -- mfinder.no_irred_nonxor_contains_clash_vars(): " + << ret_no_irred_nonxor_contains_clash_vars << endl + << "c -- !conf.gaussconf.autodisable: " << (bool)(!conf.gaussconf.autodisable) << endl + << "c -- conf.xor_detach_reattach: " << (bool)conf.xor_detach_reattach << endl; + print_watchlist_stats(); + } + } + + #ifdef SLOW_DEBUG + for(size_t i = 0; i< gmatrices.size(); i++) { + if (gmatrices[i]) { + gmatrices[i]->check_watchlist_sanity(); + assert(gmatrices[i]->get_matrix_no() == i); + } + } + #endif + + xor_clauses_updated = false; + *solver->frat << __PRETTY_FUNCTION__ << " end\n"; + return true; +} + +bool Solver::init_all_matrices() +{ + assert(okay()); + assert(decisionLevel() == 0); + + assert(gmatrices.size() == gqueuedata.size()); + for (uint32_t i = 0; i < gmatrices.size(); i++) { + auto& g = gmatrices[i]; + bool created = false; + if (!g->full_init(created)) return false; + assert(okay()); + + if (!created) { + gqueuedata[i].disabled = true; + delete g; + if (conf.verbosity > 5) { + cout << "DELETED matrix" << endl; + } + g = NULL; + } + } + + uint32_t j = 0; + bool modified = false; + for (uint32_t i = 0; i < gqueuedata.size(); i++) { + if (gmatrices[i] != NULL) { + gmatrices[j] = gmatrices[i]; + gmatrices[j]->update_matrix_no(j); + gqueuedata[j] = gqueuedata[i]; + + if (modified) { + for (size_t var = 0; var < nVars(); var++) { + for(GaussWatched* k = gwatches[var].begin(); + k != gwatches[var].end(); + k++) + { + if (k->matrix_num == i) { + k->matrix_num = j; + } + } + } + } + j++; + } else { + modified = true; + } + } + gqueuedata.resize(j); + gmatrices.resize(j); + + return okay(); +} + +void Solver::start_getting_small_clauses( + const uint32_t max_len, const uint32_t max_glue, bool red, bool bva_vars, + bool simplified) +{ + assert(get_clause_query == NULL); + get_clause_query = new GetClauseQuery(this); + get_clause_query->start_getting_small_clauses(max_len, max_glue, red, bva_vars, simplified); + +} + +void Solver::get_all_irred_clauses(vector& out) +{ + assert(get_clause_query == NULL); + get_clause_query = new GetClauseQuery(this); + get_clause_query->get_all_irred_clauses(out); + delete get_clause_query; + get_clause_query = NULL; +} + +bool Solver::get_next_small_clause(vector& out, bool all_in_one) +{ + assert(get_clause_query); + return get_clause_query->get_next_small_clause(out, all_in_one); +} + +void Solver::end_getting_small_clauses() +{ + assert(get_clause_query); + get_clause_query->end_getting_small_clauses(); + delete get_clause_query; + get_clause_query = NULL; +} + +vector Solver::translate_sampl_set(const vector& sampl_set) +{ + assert(get_clause_query); + return get_clause_query->translate_sampl_set(sampl_set); +} + +void Solver::add_empty_cl_to_frat() +{ + assert(false); +// *frat << add +// #ifdef STATS_NEEDED +// << 0 +// << sumConflicts +// #endif +// << fin; +// frat->flush(); +} + +void Solver::check_assigns_for_assumptions() const +{ + for (const auto& ass: assumptions) { + const Lit inter = map_outer_to_inter(ass.lit_outer); + if (value(inter) != l_True) { + cout << "ERROR: Internal assumption " << inter + << " is not set to l_True, it's set to: " << value(inter) + << endl; + assert(lit_inside_assumptions(inter) == l_True); + } + assert(value(inter) == l_True); + } +} + +bool Solver::check_assumptions_contradict_foced_assignment() const +{ + for (auto& ass: assumptions) { + const Lit inter = map_outer_to_inter(ass.lit_outer); + if (value(inter) == l_False) { + return true; + } + } + return false; +} + +void Solver::set_var_weight( +#ifdef WEIGHTED_SAMPLING +const Lit lit, const double weight +#else +const Lit, const double +#endif +) { + #ifdef WEIGHTED_SAMPLING + //cout << "set weight called lit: " << lit << " w: " << weight << endl; + assert(lit.var() < nVars()); + if (weights_given.size() < nVars()) { + weights_given.resize(nVars(), GivenW()); + } + + if ((weights_given[lit.var()].pos && !lit.sign()) + || (weights_given[lit.var()].neg && lit.sign()) + ) { + cout << "ERROR: Giving weights twice for literal: " << lit << endl; + exit(-1); + return; + } + + if (!weights_given[lit.var()].neg && !lit.sign()) { + weights_given[lit.var()].pos = true; + varData[lit.var()].weight = weight; + return; + } + + if (!weights_given[lit.var()].pos && lit.sign()) { + weights_given[lit.var()].neg = true; + varData[lit.var()].weight = weight; + return; + } + + if (!lit.sign()) { + //this is the pos + weights_given[lit.var()].pos = true; + double neg = varData[lit.var()].weight; + double pos = weight; + varData[lit.var()].weight = pos/(pos + neg); + } else { + //this is the neg + weights_given[lit.var()].neg = true; + double neg = weight; + double pos = varData[lit.var()].weight; + varData[lit.var()].weight = pos/(pos + neg); + } + #else + cout << "ERROR: set_var_weight() only supported if you compile with -DWEIGHTED_SAMPLING=ON" << endl; + exit(-1); + #endif +} + +vector Solver::get_vsids_scores() const +{ + auto scores(var_act_vsids); + + //Map to outer + vector scores_outer(nVarsOuter(), 0); + for(uint32_t i = 0; i < scores.size(); i ++) { + uint32_t outer = map_inter_to_outer(i); + scores_outer[outer] = scores[i]; + } + + //Map to outside + if (get_num_bva_vars() != 0) { + scores_outer = map_back_vars_to_without_bva(scores_outer); + } + return scores_outer; +} + +bool Solver::implied_by(const std::vector& lits, + std::vector& out_implied) +{ + if (get_num_bva_vars() != 0) { + cout << "ERROR: get_num_bva_vars(): " << get_num_bva_vars() << endl; + assert(false && "ERROR: BVA is currently not allowed at implied_by(), please turn it off"); + //out_implied = map_back_vars_to_without_bva(out_implied); + exit(-1); + } +// if (solver->occsimplifier->get_num_elimed_vars() > 0) { +// assert(false && "ERROR, you must not have any eliminated variables when calling implied_by -- otherwise, we cannot guarantee all implied variables are found"); +// exit(-1); +// } + + out_implied.clear(); + if (!okay()) { + return false; + } + + implied_by_tmp_lits = lits; + if (!addClauseHelper(implied_by_tmp_lits)) { + return false; + } + + assert(decisionLevel() == 0); + for(Lit p: implied_by_tmp_lits) { + if (value(p) == l_Undef) { + new_decision_level(); + enqueue(p); + } + if (value(p) == l_False) { + cancelUntil(0); + return false; + } + } + + if (decisionLevel() == 0) { + return true; + } + + PropBy x = propagate(); + if (!x.isNULL()) { + //UNSAT due to prop + cancelUntil(0); + return false; + } + //DO NOT add the "optimization" to return when nothing got propagated + //replaced variables CAN be added!!! + + out_implied.reserve(trail.size()-trail_lim[0]); + for(uint32_t i = trail_lim[0]; i < trail.size(); i++) { + if (trail[i].lit.var() < nVars()) { + out_implied.push_back(trail[i].lit); + } + } + cancelUntil(0); + + //Map to outer + for(auto& l: out_implied) { + l = map_inter_to_outer(l); + } + varReplacer->extend_pop_queue(out_implied); + return true; +} + +void Solver::reset_vsids() +{ + for(auto& x: var_act_vsids) x = 0; +} + +#ifdef STATS_NEEDED +void Solver::stats_del_cl(Clause* cl) +{ + if (cl->stats.is_tracked && sqlStats) { + const ClauseStatsExtra& stats_extra = solver->red_stats_extra[cl->stats.extra_pos]; + assert(stats_extra.orig_ID != 0); + assert(stats_extra.orig_ID <= cl->stats.ID); + sqlStats->cl_last_in_solver(this, stats_extra.orig_ID); + } +} + +void Solver::stats_del_cl(ClOffset offs) +{ + Clause* cl = cl_alloc.ptr(offs); + stats_del_cl(cl); +} +#endif + +void Solver::detach_xor_clauses( + const set& clash_vars_unused) +{ + detached_xor_clauses = true; + double myTime = cpuTime(); + + /////////////// + //Set up seen + // '1' means it's part of an UNUSED xor + // '2' means it's a CLASH of a USED xor + /////////////// + for(const auto& x: xorclauses_unused) { + for(const uint32_t v: x) { + seen[v] = 1; + } + } + for(const auto& v: clash_vars_unused) { + seen[v] = 1; + } + for(uint32_t v: removed_xorclauses_clash_vars) { + seen[v] = 1; + } + + //Clash on USED xor + for(auto& x: xorclauses) { + x.detached = true; + for(const uint32_t v: x.clash_vars) { + assert(seen[v] == 0); + seen[v] = 2; + } + } + + /////////////// + //Go through watchlist + /////////////// + uint32_t detached = 0; + uint32_t deleted = 0; + vector delayed_clause_free; + for(uint32_t x = 0; x < nVars()*2; x++) { + Lit l = Lit::toLit(x); + uint32_t j = 0; + for(uint32_t i = 0; i < watches[l].size(); i++) { + const Watched& w = watches[l][i]; + assert(!w.isIdx()); + if (w.isBin()) { + if (!w.red()) { + watches[l][j++] = w; + continue; + } else { + //Redundant. let's check if it deals with clash vars of + // XORs that will be removed. + if (seen[l.var()] == 2 || seen[w.lit2().var()] == 2) { + if (l < w.lit2()) { + //Only once, hence the check + binTri.redBins--; + deleted++; + } + continue; + } else { + watches[l][j++] = w; + continue; + } + } + } + + if (w.isBNN()) { + watches[l][j++] = w; + continue; + } + + assert(w.isClause()); + ClOffset offs = w.get_offset(); + Clause* cl = cl_alloc.ptr(offs); + assert(!cl->freed()); + if (cl->getRemoved() || cl->_xor_is_detached) { + //We have already went through this clause, and set it to be removed/detached + continue; + } + + bool torem = false; + bool todel = false; + if (cl->used_in_xor() && cl->used_in_xor_full()) { + torem = true; + + //Except if if it's part of an unused XOR. Then skip + //TODO: we should use the same check as in no_irred + for(const Lit lit: *cl) { + if (seen[lit.var()] == 1) torem = false; + } + } else { + //It has a USED XOR's clash var, delete + //obviously, must be redundant + for(const Lit lit: *cl) { + if (seen[lit.var()] == 2) todel = true; + } + if (todel) { + //cout << "cl: " << *cl << endl; + assert(cl->red()); + } + } + + //CL can be detached + if (torem) { + assert(!cl->_xor_is_detached); + detached++; + detached_xor_repr_cls.push_back(offs); + cl->_xor_is_detached = true; + //cout << "XOR-detaching cl: " << *cl << endl; + continue; + } + + //This is a rendundant clause that has to be removed + //for things to be correct (it clashes with an XOR) + if (todel) { + assert(cl->red()); + cl->setRemoved(); + litStats.redLits -= cl->size(); + delayed_clause_free.push_back(offs); + deleted++; + continue; + } + + watches[l][j++] = w; + } + watches[l].resize(j); + } + + if (deleted > 0) { + uint32_t j = 0; + for(uint32_t i = 0; i < longIrredCls.size(); i++) { + ClOffset offs = longIrredCls[i]; + Clause* cl = cl_alloc.ptr(offs); + if (!cl->getRemoved()) { + longIrredCls[j++] = offs; + } + } + longIrredCls.resize(j); + + for(auto& cls: longRedCls) { + j = 0; + for(uint32_t i = 0; i < cls.size(); i++) { + ClOffset offs = cls[i]; + Clause* cl = cl_alloc.ptr(offs); + if (!cl->getRemoved()) { + cls[j++] = offs; + } + } + cls.resize(j); + } + + for(ClOffset offset: delayed_clause_free) { + free_cl(offset); + } + delayed_clause_free.clear(); + } + assert(delayed_clause_free.empty()); + + /////////////// + //Reset seen + /////////////// + for(const auto& x: xorclauses_unused) { + for(const uint32_t v: x) { + seen[v] = 0; + } + } + + for(const auto& v: clash_vars_unused) { + seen[v] = 0; + } + + for(uint32_t v: removed_xorclauses_clash_vars) { + seen[v] = 0; + } + + for(const auto& x: xorclauses) { + for(const uint32_t v: x.clash_vars) { + seen[v] = 0; + + if (!watches[Lit(v, false)].empty()) { + print_watch_list(watches[Lit(v, false)], Lit(v, false)); + } + if (!watches[Lit(v, true)].empty()) { + print_watch_list(watches[Lit(v, true)], Lit(v, true)); + } + assert(watches[Lit(v, false)].empty()); + assert(watches[Lit(v, true)].empty()); + } + } + + if (conf.verbosity >= 1 || conf.xor_detach_verb) { + cout + << "c [gauss] XOR-encoding clauses" + << " detached: " << detached + << " deleted: " << deleted + << conf.print_times(cpuTime() - myTime) + << endl; + } +} + +bool Solver::fully_undo_xor_detach() +{ + assert(okay()); + assert(decisionLevel() == 0); + + if (!detached_xor_clauses) { + assert(detached_xor_repr_cls.empty()); + if (conf.verbosity >= 1 || conf.xor_detach_verb) { + cout + << "c [gauss] XOR-encoding clauses are not detached, so no need to reattach them." + << endl; + } + return okay(); + } + set_clash_decision_vars(); + rebuildOrderHeap(); + + double myTime = cpuTime(); + uint32_t reattached = 0; + uint32_t removed = 0; + for(const auto& offs: detached_xor_repr_cls) { + Clause* cl = cl_alloc.ptr(offs); + assert(cl->_xor_is_detached); + assert(cl->used_in_xor() && cl->used_in_xor_full()); + assert(!cl->red()); + + cl->_xor_is_detached = false; + const uint32_t origSize = cl->size(); + + reattached++; + const bool rem_or_unsat = clauseCleaner->full_clean(*cl); + if (rem_or_unsat) { + removed++; + litStats.irredLits -= origSize; + cl->setRemoved(); + if (!okay()) break; + continue; + } else { + litStats.irredLits -= origSize - cl->size(); + assert(cl->size() > 2); + PropEngine::attachClause(*cl, true); + } + } + detached_xor_repr_cls.clear(); + + if (removed > 0) { + uint32_t j = 0; + for(uint32_t i = 0; i < longIrredCls.size(); i ++) { + ClOffset offs = longIrredCls[i]; + Clause* cl = cl_alloc.ptr(offs); + if (cl->getRemoved()) { + cl_alloc.clauseFree(offs); + } else { + longIrredCls[j++] = offs; + } + } + longIrredCls.resize(j); + } + + for(auto& x: xorclauses) x.detached = false; + + detached_xor_clauses = false; + if (okay()) ok = propagate().isNULL(); + + if (conf.verbosity >= 1 || conf.xor_detach_verb) { + cout + << "c [gauss] XOR-encoding clauses reattached: " << reattached + << conf.print_times(cpuTime() - myTime) + << endl; + } + + return okay(); +} + +void Solver::unset_clash_decision_vars(const vector& xors) +{ + vector clash_vars; + for(const auto& x: xors) { + for(const auto& v: x.clash_vars) { + if (!seen[v]) { + clash_vars.push_back(v); + seen[v] = 1; + } + } + } + + for(const auto& v: clash_vars) { + seen[v] = 0; + varData[v].removed = Removed::clashed; + } +} + +void Solver::set_clash_decision_vars() +{ + for(auto& v: varData) { + if (v.removed == Removed::clashed) { + v.removed = Removed::none; + } + } +} + +//TODO: this is horrifically SLOW!!! +void Solver::extend_model_to_detached_xors() +{ + double myTime = cpuTime(); + + uint32_t set_var = 0; + uint32_t more_vars_unset = 1; + uint32_t iter = 0; + while (more_vars_unset > 0) { + more_vars_unset = 0; + iter++; + for(const auto& offs: detached_xor_repr_cls) { + const Clause* cl = cl_alloc.ptr(offs); + assert(cl->_xor_is_detached); + uint32_t unset_vars = 0; + Lit unset = lit_Undef; + for(Lit l: *cl) { + if (model_value(l) == l_True) { + unset_vars = 0; + break; + } + if (model_value(l) == l_Undef) { + unset = l; + unset_vars++; + } + } + if (unset_vars == 1) { + model[unset.var()] = unset.sign() ? l_False : l_True; + set_var++; + } + if (unset_vars > 1) { + more_vars_unset++; + } + } + } + + #ifdef SLOW_DEBUG + for(const auto& offs: detached_xor_repr_cls) { + const Clause* cl = cl_alloc.ptr(offs); + bool val = false; + uint32_t undef_present = false; + for(const auto l: *cl) { + if (model_value(l) == l_Undef) { + undef_present++; + } + if (model_value(l) == l_True) { + val = true; + break; + } + } + if (!val) { + cout << "ERROR: XOR-Detached clause not satisfied: " << *cl << " -- undef present: " << undef_present << endl; + assert(false); + } + } + + for(const auto& x: xorclauses) { + bool val = !x.rhs; + for(uint32_t v: x) { + if (model_value(v) == l_Undef) { + cout << "ERROR: variable " << v+1 << " in XOR: " << x << " is UNDEF!" << endl; + assert(false); + } + assert(model_value(v) != l_Undef); + val ^= model_value(v) == l_True; + } + if (!val) { + cout << "ERROR:Value of following XOR is not TRUE: " << x << endl; + assert(false); + } + } + #endif + + //Set the rest randomly + uint32_t random_set = 0; + for(const auto& offs: detached_xor_repr_cls) { + const Clause* cl = cl_alloc.ptr(offs); + assert(cl->_xor_is_detached); + for(Lit l: *cl) { + if (model_value(l) == l_Undef) { + model[l.var()] = l_False; + random_set++; + } + } + } + + if (conf.verbosity >= 1) { + cout + << "c [gauss] extended XOR clash vars." + << " set: " << set_var + << " double-undef: " << more_vars_unset + << " iters: " << iter + << " random_set: " << random_set + << conf.print_times(cpuTime() - myTime) + << endl; + } +} + +bool Solver::no_irred_nonxor_contains_clash_vars() +{ + bool ret = true; + + //seen 1: it's a variable that's a clash variable + //seen 2: it's a variable in an XOR + + //Set variables that are part of an XOR + for(const auto& x: xorclauses) { + //REAL vars + for(uint32_t v: x) { + seen[v] = 2; + } + } + + //Set variables that are clashing + for(const auto& x: xorclauses) { + //CLASH vars + for(uint32_t v: x.clash_vars) { + //assert(seen[v] != 2); -- actually, it could be (weird, but possible) + //in these cases, we should treat it as a clash var (more safe) + seen[v] = 1; +// cout << "c clash var: " << v + 1 << endl; + } + } + + for(const auto& v: removed_xorclauses_clash_vars) { + seen[v] = 1; + } + + for(const auto& l: assumptions) { + const Lit p = map_outer_to_inter(l.lit_outer); + if (seen[p.var()] == 1) { + //We cannot have a clash variable that's an assumption + //it would enqueue the assumption variable but it's a clash + //var and that's not supposed to be in the trail at all. + ret = false; + break; + } + } + + for(uint32_t i = 0; i < longIrredCls.size() && ret; i++) { + const ClOffset offs = longIrredCls[i]; + const Clause* cl = cl_alloc.ptr(offs); + + //contains NO clash var, never an issue + //contains at least 1 clash var AND no real vars, MUST be an issue + //contains at least 1 clash var AND some not all real vars--> MUST be an issue + //contains at least 1 clash var AND only real vars--> must be a FULL XOR to be OK + + if (cl->red()) { + continue; + } + + uint32_t num_real_vars = 0; + uint32_t num_clash_vars = 0; + for(const Lit l: *cl) { + if (seen[l.var()] == 1) { + num_clash_vars++; +// if (!(cl->used_in_xor() && cl->used_in_xor_full())) { +// cout << "clash : " << l << endl; +// } + } + else if (seen[l.var()] == 2) { + num_real_vars++; +// if (!(cl->used_in_xor() && cl->used_in_xor_full())) { +// cout << "real : " << l << endl; +// } + } + else if (value(l) != l_Undef) { + num_real_vars++; + } + } + if (num_clash_vars == 0) { + continue; + } + + if (cl->used_in_xor() && cl->used_in_xor_full() && num_clash_vars+num_real_vars == cl->size()) { + continue; + } + + //non-full XORs or other non-XOR clause + if (conf.verbosity >= 3 || conf.xor_detach_verb) { + cout << "c CL with clash: " << *cl + << " red: " << cl->red() + << " xor: " << cl->used_in_xor() + << " full-xor: " << cl->used_in_xor_full() + << " num_clash_vars: " << num_clash_vars + << " num_real_vars: " << num_real_vars + << " size: " << cl->size() + << " missing: " << (cl->size()-num_clash_vars-num_real_vars) + << endl; + for(const Lit l: *cl) { + if (seen[l.var()] == 1) { + cout << "c clash lit: " << l + << " value: " << value(l) << endl; + } + } + for(const Lit l: *cl) { + if (seen[l.var()] == 0) { + cout << "c neither clash nor real: " << l + << " value: " << value(l) << endl; + } + } + + } + ret = false; + } + + for(uint32_t i = 0; i < nVars()*2 && ret; i++) { + Lit l = Lit::toLit(i); + const auto& ws = watches[l]; + for(const auto& w: ws) { + if (w.isBin() && !w.red()) { + if (seen[l.var()]==1 || seen[w.lit2().var()]==1) { + if (conf.verbosity >= 3 || conf.xor_detach_verb) { + cout << "c BIN with clash: " << l << " " << w.lit2() << endl; + } + ret = false; + break; + } + } + } + } + + for(const auto& x: xorclauses) { + //REAL vars + for(uint32_t v: x) { + seen[v] = 0; + } + + //CLASH vars + for(uint32_t v: x.clash_vars) { + seen[v] = 0; +// cout << "c clash var: " << v + 1 << endl; + } + } + + for(const auto& v: removed_xorclauses_clash_vars) { + seen[v] = 0; + } + + return ret; +} + +bool Solver::assump_contains_xor_clash() +{ + assert(detached_xor_clauses); + //Set variables that are clashing + for(const auto& x: xorclauses) { + for(uint32_t v: x.clash_vars) { + seen[v] = 1; + } + } + + for(const auto& v: removed_xorclauses_clash_vars) { + seen[v] = 1; + } + + bool ret = false; + for(const auto& l: assumptions) { + const Lit p = map_outer_to_inter(l.lit_outer); + if (seen[p.var()] == 1) { + //We cannot have a clash variable that's an assumption + //it would enqueue the assumption variable but it's a clash + //var and that's not supposed to be in the trail at all. + ret = true; + break; + } + } + + for(const auto& x: xorclauses) { + for(uint32_t v: x.clash_vars) { + seen[v] = 0; + } + } + + for(const auto& v: removed_xorclauses_clash_vars) { + seen[v] = 0; + } + + return ret; +} + +vector Solver::get_recovered_or_gates() +{ + assert(get_num_bva_vars() == 0 && "not implemented for BVA"); + if (!okay()) { + return vector(); + } + + vector or_gates = occsimplifier->recover_or_gates(); + + for(auto& g: or_gates) { + g.rhs = map_inter_to_outer(g.rhs); + for(auto& l: g.lits) l = map_inter_to_outer(l); + } + + return or_gates; +} + +vector Solver::get_recovered_ite_gates() +{ + assert(get_num_bva_vars() == 0 && "not implemented for BVA"); + if (!okay()) { + return vector(); + } + + vector or_gates = occsimplifier->recover_ite_gates(); + + for(auto& g: or_gates) { + g.rhs = map_inter_to_outer(g.rhs); + for(auto& l: g.lhs) { + l = map_inter_to_outer(l); + } + } + + return or_gates; +} + +vector Solver::remove_definable_by_irreg_gate(const vector& vars) +{ + if (!okay()) return vector{}; + return occsimplifier->remove_definable_by_irreg_gate(vars); +} + +void Solver::clean_sampl_and_get_empties( + vector& sampl_vars, vector& empty_vars) +{ + if (!okay()) return; + assert(get_num_bva_vars() == 0); + map_outer_to_inter(sampl_vars); + map_outer_to_inter(empty_vars); + for(const auto& v: empty_vars) sampl_vars.push_back(v); + empty_vars.clear(); + + occsimplifier->clean_sampl_and_get_empties(sampl_vars, empty_vars); + map_inter_to_outer(sampl_vars); + map_inter_to_outer(empty_vars); +} + +bool Solver::remove_and_clean_all() { + return clauseCleaner->remove_and_clean_all(); +} + +void Solver::set_max_confl(uint64_t max_confl) +{ + if (get_stats().conflicts + max_confl < max_confl) { + conf.max_confl = numeric_limits::max(); + } else { + conf.max_confl = get_stats().conflicts + max_confl; + } +} + +lbool Solver::bnn_eval(BNN& bnn) +{ + assert(decisionLevel() == 0); + + for(const auto& p: bnn) assert(value(p) == l_Undef); + if (bnn.set) assert(bnn.out == lit_Undef); + else assert(value(bnn.out) == l_Undef); + + // we are at the cutoff no matter what undef is + if (bnn.cutoff <= 0) { + if (bnn.set) return l_True; + enqueue(bnn.out, decisionLevel()); + return l_True; + } + + // we are under the cutoff no matter what undef is + if ((int)bnn.size() < bnn.cutoff) { + if (bnn.set) { + return l_False; + } + + enqueue(~bnn.out, decisionLevel()); + return l_True; + } + + //it's set and cutoff can ONLY be met by ALL TRUE + if (bnn.set && (int)bnn.size() == bnn.cutoff) { + for(const auto& l: bnn) { + enqueue(l, decisionLevel()); + } + return l_True; + } + + if (bnn.size() == 0) { + if (bnn.cutoff <= 0) { + assert(bnn.set); + } else { + assert(false); + } + //remove + return l_True; + } + + return l_Undef; +} + +#define PICOLIT(x) ((((int)(x).var()+1)) * ((x).sign() ? -1:1)) + +PicoSAT* Solver::build_picosat() +{ + PicoSAT* picosat = picosat_init(); + for(uint32_t i = 0; i < nVars(); i++) picosat_inc_max_var(picosat); + + for(auto const& off: longIrredCls) { + Clause* cl = cl_alloc.ptr(off); + for(auto const& l1: *cl) { + picosat_add(picosat, PICOLIT(l1)); + } + picosat_add(picosat, 0); + } + for(uint32_t i = 0; i < nVars()*2; i++) { + Lit l1 = Lit::toLit(i); + for(auto const& w: watches[l1]) { + if (!w.isBin() || w.red()) continue; + const Lit l2 = w.lit2(); + if (l1 > l2) continue; + + picosat_add(picosat, PICOLIT(l1)); + picosat_add(picosat, PICOLIT(l2)); + picosat_add(picosat, 0); + } + } + return picosat; +} + +inline int orclit(const Lit x) { + return (x.sign() ? ((x.var()+1)*2+1) : (x.var()+1)*2); +} + +inline int Neg(int x) { + return x^1; +} + +inline Lit orc_to_lit(int x) { + uint32_t var = x/2-1; + bool neg = x&1; + return Lit(var, neg); +} + + +inline vector Negate(vector vec) { + for (int& lit : vec) lit = Neg(lit); + return vec; +} + +template +void SwapDel(vector& vec, size_t i) { + assert(i < vec.size()); + std::swap(vec[i], vec.back()); + vec.pop_back(); +} + +vector> Solver::get_irred_cls_for_oracle() const +{ + vector> clauses; + vector tmp; + for (const auto& off: longIrredCls) { + const Clause& cl = *cl_alloc.ptr(off); + tmp.clear(); + for (auto const& l: cl) { + tmp.push_back(orclit(l)); + } + clauses.push_back(tmp); + } + for (uint32_t i = 0; i < nVars()*2; i++) { + Lit l = Lit::toLit(i); + for(auto const& ws: watches[l]) { + if (!ws.isBin() || ws.red()) continue; + if (l < ws.lit2()) { + tmp.clear(); + tmp.push_back(orclit(l)); + tmp.push_back(orclit(ws.lit2())); + clauses.push_back(tmp); + } + } + } + return clauses; +} + +bool Solver::oracle_vivif(bool& finished) +{ + assert(!frat->enabled()); + assert(solver->okay()); + finished = false; + + backbone_simpl(300LL*1000LL, true, finished); + execute_inprocess_strategy(false, "must-renumber"); + if (!okay()) return okay(); + if (nVars() < 10) return okay(); + double myTime = cpuTime(); + + auto clauses = get_irred_cls_for_oracle(); + detach_and_free_all_irred_cls(); + + sspp::oracle::Oracle oracle(nVars(), clauses, {}); + oracle.SetVerbosity(conf.verbosity); + bool sat = false; + for (int i = 0; i < (int)clauses.size(); i++) { + for (int j = 0; j < (int)clauses[i].size(); j++) { + if (oracle.getStats().mems > 1600LL*1000LL*1000LL) goto end; + auto assump = Negate(clauses[i]); + SwapDel(assump, j); + auto ret = oracle.Solve(assump, true, 500LL*1000LL*1000LL); + if (ret.isUnknown()) { + goto end; + } + if (ret.isFalse()) { + sort(assump.begin(), assump.end()); + auto clause = Negate(assump); + oracle.AddClauseIfNeededAndStr(clause, true); + clauses[i] = clause; + j = -1; //start from beginning + if (clause.empty()) { + ok = false; + return false; + } + } else if(!sat) { + sat = true; + } + } + } + finished |= true; + + end: + vector tmp2; + for(const auto& cl: clauses) { + tmp2.clear(); + for(const auto& l: cl) tmp2.push_back(orc_to_lit(l)); + Clause* cl2 = solver->add_clause_int(tmp2); + if (cl2) longIrredCls.push_back(cl_alloc.get_offset(cl2)); + if (!okay()) return false; + } + + if (conf.oracle_get_learnts) { + for (const auto& cl: oracle.GetLearnedClauses()) { + tmp2.clear(); + for(const auto& l: cl) tmp2.push_back(orc_to_lit(l)); + ClauseStats stats; + stats.which_red_array = 2; + stats.ID = clauseID++; + stats.glue = cl.size(); + Clause* cl2 = solver->add_clause_int(tmp2, true, &stats); + if (cl2) longRedCls[2].push_back(cl_alloc.get_offset(cl2)); + if (!okay()) return false; + } + } + + verb_print(1, "[oracle-vivif] finished: " << finished + << " cache-used: " << oracle.getStats().cache_useful + << " cache-added: " << oracle.getStats().cache_added + << " learnt-units: " << oracle.getStats().learned_units + << " finished (vivif or backbone): " << finished + << " T: " << std::setprecision(2) << (cpuTime()-myTime)); + return solver->okay(); +} + +void Solver::dump_cls_oracle(const string fname, const vector& cs) +{ + vector tmp; + std::ofstream fout(fname.c_str()); + fout << nVars() << endl; + for(uint32_t i = 0; i < cs.size(); i++) { + const auto& c = cs[i]; + tmp.clear(); + if (!c.binary) { + Clause& cl = *cl_alloc.ptr(c.off); + for(auto const& l: cl) assert(l.var() < nVars()); + for(auto const& l: cl) tmp.push_back(orclit(l)); + } else { + const OracleBin& b = c.bin; + assert(b.l1.var() < nVars()); + assert(b.l2.var() < nVars()); + tmp.push_back(orclit(b.l1)); + tmp.push_back(orclit(b.l2)); + } + for(auto const& l: tmp) fout << l << " "; + fout << endl; + } +} + +void Solver::print_cs_ordering(const vector& cs) const +{ + for(const auto& c: cs) { + cout << "c.bin:" << c.binary; + if (!c.binary) cout << " offs: " << c.off; + else { + cout << " bincl: " << c.bin.l1 << "," << c.bin.l2; + } + + cout << " c.val: "; + for(const auto& v: c.val) cout << v << " "; + cout << endl; + } +} + +vector> Solver::compute_edge_weights() const +{ + vector> edgew(nVars()); + for (uint32_t i = 0; i < nVars(); i++) edgew[i].resize(nVars(), 0); + for (const auto& off: longIrredCls) { + Clause& cl = *cl_alloc.ptr(off); + for (auto const& l1 : cl) { for (auto const& l2 : cl) { + uint32_t v1 = l1.var(); + uint32_t v2 = l2.var(); + if (v1 < v2) edgew[v1][v2]++; + } } + } + for (uint32_t i = 0; i < nVars()*2; i++) { + Lit l = Lit::toLit(i); + for(auto const& ws: watches[l]) { + if (!ws.isBin() || ws.red()) continue; + uint32_t v1 = l.var(); + uint32_t v2 = ws.lit2().var(); + if (v1 < v2) edgew[v1][v2]++; + } + } + return edgew; +} + +vector Solver::order_clauses_for_oracle() const +{ + vector> edgew; + bool edgew_avail = false; + // Cutoff to limit memory usage. Otherwise it's n**2 memory usage + if (nVars() < 35000) { edgew = compute_edge_weights(); edgew_avail = true; } + vector cs; + array ww; + for (const auto& off: longIrredCls) { + Clause& cl = *cl_alloc.ptr(off); + assert(!cl.red()); + ww = {}; + if (edgew_avail) { + for (auto const& l1 : cl) { for (auto const& l2: cl) { + const uint32_t v1 = l1.var(); + const uint32_t v2 = l2.var(); + if (v1 < v2) { + assert(edgew[v1][v2] >= 1); + if (edgew[v1][v2] <= ww.size()) ww[edgew[v1][v2]-1]--; + } + } } + } else ww[0] = cl.size(); + cs.push_back(OracleDat(ww, off)); + } + + for (uint32_t i = 0; i < nVars()*2; i++) { + Lit l = Lit::toLit(i); + for(auto const& ws: watches[l]) { + if (!ws.isBin() || ws.red()) continue; + const uint32_t v1 = l.var(); + const uint32_t v2 = ws.lit2().var(); + if (v1 < v2) { + ww = {}; + if (edgew_avail) { + assert(edgew[v1][v2] >= 1); + if (edgew[v1][v2] <= ww.size()) ww[edgew[v1][v2]-1]--; + } else ww[0] = 2; + cs.push_back(OracleDat(ww, OracleBin(l, ws.lit2(), ws.get_ID()))); + } + } + } + std::sort(cs.begin(), cs.end()); + /* print_cs_ordering(cs); */ + return cs; +} + +bool Solver::oracle_sparsify() +{ + assert(!frat->enabled()); + execute_inprocess_strategy(false, "sub-impl, occ-backw-sub, must-renumber"); + if (!okay()) return okay(); + if (nVars() < 10) return okay(); + + double myTime = cpuTime(); + uint32_t removed = 0; + uint32_t removed_bin = 0; + auto cs = order_clauses_for_oracle(); + const uint32_t tot_cls = longIrredCls.size() + binTri.irredBins; + assert(cs.size() == tot_cls); + //dump_cls_oracle("debug.xt", cs); + + // The "+tot_cls" is for indicator variables + sspp::oracle::Oracle oracle(nVars()+tot_cls, {}); + oracle.SetVerbosity(conf.verbosity); + vector tmp; + for(uint32_t i = 0; i < cs.size(); i++) { + const auto& c = cs[i]; + tmp.clear(); + if (!c.binary) { + Clause& cl = *cl_alloc.ptr(c.off); + for(auto const& l: cl) assert(l.var() < nVars()); + for(auto const& l: cl) tmp.push_back(orclit(l)); + } else { + const OracleBin& b = c.bin; + assert(b.l1.var() < nVars()); + assert(b.l2.var() < nVars()); + tmp.push_back(orclit(b.l1)); + tmp.push_back(orclit(b.l2)); + } + // Indicator variable + tmp.push_back(orclit(Lit(nVars()+i, false))); + oracle.AddClause(tmp, false); + } + const double build_time = cpuTime() - myTime; + + // Set all assumptions to FALSE, i.e. all clauses are active + for (uint32_t i = 0; i < tot_cls; i++) { + oracle.SetAssumpLit(orclit(Lit(nVars()+i, true)), false); + } + + // Now try to remove clauses one-by-one + uint32_t last_printed = 0; + for (uint32_t i = 0; i < tot_cls; i++) { + if ((10*i)/(tot_cls) != last_printed) { + verb_print(1, "[oracle-sparsify] done with " << ((10*i)/(tot_cls))*10 << " %" + << " oracle mems: " << print_value_kilo_mega(oracle.getStats().mems) + << " T: " << (cpuTime()-myTime)); + last_printed = (10*i)/(tot_cls); + } + + // Try removing this clause, making its indicator TRUE (i.e. removed) + oracle.SetAssumpLit(orclit(Lit(nVars()+i, false)), false); + tmp.clear(); + const auto& c = cs[i]; + if (!c.binary) { + Clause& cl = *cl_alloc.ptr(c.off); + for(auto const& l: cl) tmp.push_back(orclit(~l)); + } else { + tmp.push_back(orclit(~(c.bin.l1))); + tmp.push_back(orclit(~(c.bin.l2))); + } + + auto ret = oracle.Solve(tmp, false, 600LL*1000LL*1000LL); + if (ret.isUnknown()) { /*out of time*/ goto fin; } + + if (ret.isTrue()) { + // We need this clause, can't remove + oracle.SetAssumpLit(orclit(Lit(nVars()+i, true)), true); + } else { + assert(ret.isFalse()); + // We can freeze(!) this clause to be disabled. + oracle.SetAssumpLit(orclit(Lit(nVars()+i, false)), true); + removed++; + if (!c.binary) { + Clause& cl = *cl_alloc.ptr(c.off); + assert(!cl.stats.marked_clause); + cl.stats.marked_clause = 1; + } else { + removed_bin++; + Lit lit1 = c.bin.l1; + Lit lit2 = c.bin.l2; + findWatchedOfBin(watches, lit1, lit2, false, c.bin.ID).mark_bin_cl(); + findWatchedOfBin(watches, lit2, lit1, false, c.bin.ID).mark_bin_cl(); + } + } + + if (oracle.getStats().mems > 900LL*1000LL*1000LL) { + verb_print(1, "[oracle-sparsify] too many mems in oracle, aborting"); + goto fin; + } + } + + fin: + uint32_t bin_red_added = 0; + uint32_t bin_irred_removed = 0; + for(auto& ws: watches) { + uint32_t j = 0; + for(uint32_t i = 0; i < ws.size(); i++) { + if (ws[i].isBNN()) { + ws[j++] = ws[i]; + continue; + } else if (ws[i].isBin()) { + if (!ws[i].bin_cl_marked()) { + ws[j++] = ws[i]; + continue; + } + bin_irred_removed++; + if (conf.oracle_removed_is_learnt) { + ws[i].unmark_bin_cl(); + ws[i].setReallyRed(); + bin_red_added++; + ws[j++] = ws[i]; + } + continue; + } else if (ws[i].isClause()) { + Clause* cl = cl_alloc.ptr(ws[i].get_offset()); + if (conf.oracle_removed_is_learnt || !cl->stats.marked_clause) ws[j++] = ws[i]; + continue; + } + } + ws.shrink(ws.size()-j); + } + binTri.redBins+=bin_red_added/2; + binTri.irredBins-=bin_irred_removed/2; + + uint32_t j = 0; + for(uint32_t i = 0; i < longIrredCls.size(); i++) { + ClOffset off = longIrredCls[i]; + Clause* cl = cl_alloc.ptr(off); + if (!cl->stats.marked_clause) { + longIrredCls[j++] = longIrredCls[i]; + } else { + litStats.irredLits -= cl->size(); + if (conf.oracle_removed_is_learnt) { + cl->stats.marked_clause = false; + litStats.redLits += cl->size(); + longRedCls[2].push_back(off); + cl->stats.which_red_array = 2; + cl->isRed = true; + } else { + cl_alloc.clauseFree(off); + } + } + } + longIrredCls.resize(j); + + //cout << "New cls size: " << clauses.size() << endl; + //Subsume(); + + verb_print(1, "[oracle-sparsify] removed: " << removed + << " of which bin: " << removed_bin + << " tot considered: " << tot_cls + << " cache-used: " << oracle.getStats().cache_useful + << " cache-added: " << oracle.getStats().cache_added + << " learnt-units: " << oracle.getStats().learned_units + << " T: " << (cpuTime()-myTime) << " buildT: " << build_time); + + return solver->okay(); +} + +#ifdef ARJUN_SERIALIZE +string Solver::serialize_solution_reconstruction_data() const +{ + assert(!detached_xor_clauses && "Otherwise we need to extend to detached XORs too"); + + std::ostringstream archive_stream; + boost::archive::text_oarchive ar(archive_stream); + ar << ok; + if (ok) { + uint32_t nvars = nVars(); + ar << nvars; + ar << assigns; + ar << interToOuterMain; + ar << outerToInterMain; + ar << varData; + ar << minNumVars; + CNF::serialize(ar); + occsimplifier->serialize_elimed_cls(ar); + varReplacer->serialize_tables(ar); + } + return archive_stream.str(); +} + +void Solver::create_from_solution_reconstruction_data(const string& data) +{ + std::istringstream ss(data); + boost::archive::text_iarchive ar(ss); + ar >> ok; + if (ok) { + uint32_t nvars; + ar >> nvars; + new_vars(nvars); + ar >> assigns; + ar >> interToOuterMain; + ar >> outerToInterMain; + ar >> varData; + ar >> minNumVars; + CNF::unserialize(ar); + occsimplifier->unserialize_elimed_cls(ar); + varReplacer->unserialize_tables(ar); + } +} +#endif + +pair> Solver::extend_minimized_model(const vector& m) +{ + if (!ok) return make_pair(l_False, vector()); + + verb_print(3, "Size of m: " << m.size()); + verb_print(2, "Size of nVars(): " << nVars()); + + assert (get_num_bva_vars() == 0 && "Otherwise we'd need to map outer to outside. Not impossible, but can't be bothered right now"); + assert(m.size() == nVars()); + + for (uint32_t i = 0; i < nVars(); i++) { + if (m[i] == l_Undef) { + cout << "ERROR: the solution given does NOT contain a value for variable: " << i+1 + << " which was part of the minimized set of variables." + << " This var corresponds to external: " << map_inter_to_outer(Lit(i, false)) + << endl; + exit(-1); + } else { + verb_print(2, "OK, var " << i+1 \ + << " set, which was part of the internal set of variables." \ + << " This var corresponds to external: " << map_outer_to_inter(Lit(i, false))); + } + } + + // set values from model given + for(size_t i = 0; i < m.size(); i++) { + assigns[i] = m[i]; + assert(varData[i].removed == Removed::none); + } + + // checking + for(size_t i = 0; i < assigns.size(); i++) { + if (varData[i].removed == Removed::none) { + assert(assigns[i] != l_Undef); + } else { + assert(assigns[i] == l_Undef); + } + } + model = assigns; + updateArrayRev(model, interToOuterMain); + + SolutionExtender extender(this, occsimplifier); + extender.extend(); + return make_pair(l_True, model); +} + +// returns whether it can be removed +bool Solver::minimize_clause(vector& cl) { + assert(get_num_bva_vars() == 0); + + addClauseHelper(cl); + new_decision_level(); + uint32_t i = 0; + uint32_t j = 0; + PropBy confl; + + for (uint32_t sz = cl.size(); i < sz; i++) { + const Lit lit = cl[i]; + lbool val = value(lit); + if (val == l_Undef) { + enqueue(~lit); + cl[j++] = cl[i]; + confl = solver->propagate(); + if (!confl.isNULL()) break; + } else if (val == l_False) { + } else { + assert(val == l_True); + cl[j++] = cl[i]; + break; + } + } + assert(solver->ok); + cl.resize(j); + cancelUntil(0); + map_inter_to_outer(cl); + + bool can_be_removed = !confl.isNULL(); + return can_be_removed; +} + +void Solver::copy_to_simp(SATSolver* s2) +{ + s2->new_vars(nVars()); + s2->set_verbosity(0); + bool ret = true; + start_getting_small_clauses( + std::numeric_limits::max(), + std::numeric_limits::max(), + false, + false, + true); + vector clause; + while (ret) { + ret = get_next_small_clause(clause); + if (!ret) break; + s2->add_clause(clause); + } + end_getting_small_clauses(); +} + +bool Solver::backbone_simpl(int64_t orig_max_confl, bool cmsgen, bool& finished) +{ + execute_inprocess_strategy(false, "must-renumber"); + if (!okay()) return false; + assert(get_num_bva_vars() == 0); + verb_print(1, "[backbone-simpl] starting backbone simplification..."); + + double myTime = cpuTime(); + Lit l; + uint32_t undefs = 0; + uint32_t falses = 0; + uint32_t tried = 0; + const auto orig_trail_size = trail.size(); + + vector tmp_clause; + vector old_model; + uint32_t num_seen_flipped = 0; + vector seen_flipped(nVars(), 0); + + if (cmsgen) { + //CMSGen-based seen_flipped detection, so we don't need to query so much + SATSolver s2; + copy_to_simp(&s2); + + uint64_t last_num_conflicts = 0; + int64_t remaining_confls = orig_max_confl/10; + s2.set_max_confl(remaining_confls); + uint32_t num_runs = 0; + auto s2_ret = s2.solve(); + remaining_confls -= (s2.get_sum_conflicts() - last_num_conflicts); + if (s2_ret == l_True) { + old_model = s2.get_model(); + s2.set_up_for_sample_counter(100); + for(uint32_t i = 0; i < 30 && remaining_confls > 0; i++) { + last_num_conflicts = s2.get_sum_conflicts(); + s2.set_max_confl(remaining_confls); + s2_ret = s2.solve(); + remaining_confls -= (s2.get_sum_conflicts() - last_num_conflicts); + if (s2_ret == l_Undef) break; + num_runs++; + const auto& this_model = s2.get_model(); + for(uint32_t i2 = 0, max = s2.nVars(); i2 < max; i2++) { + if (value(i2) != l_Undef) continue; + if (varData[i2].removed != Removed::none) continue; + if (seen_flipped[i2]) continue; + if (this_model[i2] != old_model[i2]) { + seen_flipped[i2] = 1; + num_seen_flipped++; + } + } + } + } + verb_print(1, "[backbone-simpl] num seen flipped: " + << num_seen_flipped + << " conflicts used: " << print_value_kilo_mega(s2.get_sum_conflicts()) + << " num runs succeeded: " << num_runs + << " T: " << std::fixed << std::setprecision(2) << (cpuTime() - myTime)); + } + myTime = cpuTime(); + + // random order + vector var_order; + for(uint32_t var = 0; var < nVars(); var++) { + if (seen_flipped[var]) continue; + if (value(var) != l_Undef) continue; + if (varData[var].removed != Removed::none) continue; + var_order.push_back(var); + } + std::shuffle(var_order.begin(), var_order.end(), mtrand); + + int64_t orig_max_props = orig_max_confl*1000LL; + if (orig_max_props < orig_max_confl) orig_max_props = orig_max_confl; + vector old_model2(nVars(), 0); + PicoSAT* picosat = build_picosat(); + picosat_set_propagation_limit(picosat, orig_max_props); + auto ret = picosat_sat(picosat, -1); + if (ret == PICOSAT_UNKNOWN || ret == PICOSAT_UNSATISFIABLE) goto end; + if (ret == PICOSAT_SATISFIABLE) { + for(uint32_t i = 0; i < nVars(); i++) { + old_model2[i] = picosat_deref(picosat, i+1); + } + } + + for(const auto& var: var_order) { + if (seen_flipped[var]) continue; + if (value(var) != l_Undef) continue; + if (varData[var].removed != Removed::none) continue; + + l = Lit(var, old_model2[var]==-1); + auto top_val = picosat_deref_toplevel(picosat, l.var()+1); + if (top_val != 0) { + if (l.sign()) assert(top_val == -1); + else assert(top_val == 1); + goto next; + } + + //There is definitely a solution with "l". Let's see if ~l fails. + picosat_assume(picosat, PICOLIT(~l)); + ret = picosat_sat(picosat, -1); + tried++; + + if (ret == PICOSAT_SATISFIABLE) { + for(uint32_t i2 = 0; i2 < nVars(); i2++) { + auto val = picosat_deref(picosat, i2+1); + if (seen_flipped[i2] || + value(i2) != l_Undef || val == 0 || + varData[i2].removed != Removed::none) continue; + if (val != old_model2[i2]) { + seen_flipped[i2] = 1; + num_seen_flipped++; + } + } + } else if (ret == PICOSAT_UNSATISFIABLE) { + next: + tmp_clause.clear(); + tmp_clause.push_back(l); + Clause* ptr = add_clause_int(tmp_clause); + assert(ptr == 0); + falses++; + if (orig_max_props + 5000 > orig_max_props) orig_max_props += 5000; + picosat_set_propagation_limit(picosat, orig_max_props); + if (!okay()) goto end; + } else { + assert(ret == PICOSAT_UNKNOWN); + undefs++; + } + } + if (undefs==0) finished = true; + assert(okay()); + + end: + const auto used_props = picosat_propagations(picosat); + picosat_reset(picosat); + uint32_t num_set = trail.size() - orig_trail_size; + double time_used = cpuTime() - myTime; + + verb_print(1, + "[backbone-simpl]" + << " finished: " << finished + << " falses: " << falses + << " undefs: " << undefs + << " tried: " << tried + << " set: " << num_set + << " props used: " << print_value_kilo_mega(used_props) + << " T: " << std::setprecision(2) << time_used); + + return okay(); +} + +void Solver::detach_and_free_all_irred_cls() +{ + for(auto& ws: watches) { + uint32_t j = 0; + for(uint32_t i = 0; i < ws.size(); i++) { + if (ws[i].isBin()) { + if (ws[i].red()) ws[j++] = ws[i]; + continue; + } + assert(!ws[i].isBNN()); + assert(ws[i].isClause()); + Clause* cl = cl_alloc.ptr(ws[i].get_offset()); + if (cl->red()) ws[j++] = ws[i]; + continue; + } + ws.resize(j); + } + binTri.irredBins = 0; + for(auto& c: longIrredCls) free_cl(c); + longIrredCls.clear(); + litStats.irredLits = 0; + cl_alloc.consolidate(this, true); +} + +#ifdef STATS_NEEDED +void Solver::dump_clauses_at_finishup_as_last() +{ + if (!sqlStats) + return; + + for(auto& red_cls: longRedCls) { + for(auto& offs: red_cls) { + Clause* cl = cl_alloc.ptr(offs); + if (cl->stats.is_tracked) { + ClauseStatsExtra& stats_extra = solver->red_stats_extra[cl->stats.extra_pos]; + sqlStats->cl_last_in_solver(solver, stats_extra.orig_ID); + } + } + } +} +#endif diff --git a/cryptominisat/cppsrc/src/solver.h b/cryptominisat/cppsrc/src/solver.h new file mode 100644 index 00000000..eda198eb --- /dev/null +++ b/cryptominisat/cppsrc/src/solver.h @@ -0,0 +1,701 @@ +/****************************************** +Copyright (C) 2009-2020 Authors of CryptoMiniSat, see AUTHORS file + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. +***********************************************/ + +#pragma once + +#include "constants.h" +#include +#include +#include +#include +#include +#include +#include + +#include "solvertypes.h" +#include "propengine.h" +#include "searcher.h" +#include "searchstats.h" +#ifdef CMS_TESTING_ENABLED +#include "gtest/gtest_prod.h" +#endif +#ifdef STATS_NEEDED +#include "satzilla_features.h" +#endif +#define ORACLE_DAT_SIZE 4 + +namespace CMSat { + struct SATSolver; +} +using std::vector; +using std::pair; +using std::string; +using std::array; +struct PicoSAT; + +namespace CMSat { + +class VarReplacer; +class ClauseCleaner; +class OccSimplifier; +class SCCFinder; +class DistillerLong; +class DistillerBin; +class DistillerLitRem; +class DistillerLongWithImpl; +class StrImplWImpl; +class CalcDefPolars; +class SolutionExtender; +class CardFinder; +class SubsumeStrengthen; +class SubsumeImplicit; +class DataSync; +class SharedData; +class ReduceDB; +class InTree; +class BreakID; +class GetClauseQuery; + +struct SolveStats +{ + uint32_t num_simplify = 0; + uint32_t num_simplify_this_solve_call = 0; + uint32_t num_solve_calls = 0; +}; + +class Solver : public Searcher +{ + public: + Solver(const SolverConf *_conf = NULL, + std::atomic* _must_interrupt_inter = NULL); + virtual ~Solver() override; + + void add_sql_tag(const string& name, const string& val); + const vector >& get_sql_tags() const; + void new_external_var(); + void new_external_vars(size_t n); + bool add_clause_outside(const vector& lits, bool red = false); + bool add_xor_clause_outside(const vector& vars, bool rhs); + bool add_bnn_clause_outside( + const vector& lits, + const int32_t cutoff, + Lit out); + void set_var_weight(Lit lit, double weight); + + lbool solve_with_assumptions( + const vector* _assumptions = NULL, + bool only_indep_solution = false); + lbool simplify_with_assumptions(const vector* _assumptions = NULL, const string* strategy = NULL); + void set_shared_data(SharedData* shared_data); + vector probe_inter_tmp; + lbool probe_outside(Lit l, uint32_t& min_props); + void set_max_confl(uint64_t max_confl); + + //frat for SAT problems + void add_empty_cl_to_frat(); + + //Querying model + lbool model_value (const Lit p) const; ///& get_model() const; + const vector& get_final_conflict() const; + vector get_vsids_scores() const; + vector implied_by_tmp_lits; + bool implied_by(const std::vector& lits, + std::vector& out_implied + ); + + //get clauses + void start_getting_small_clauses( + uint32_t max_len, uint32_t max_glue, bool red = true, + bool bva_vars = false, bool simplified = false); + bool get_next_small_clause(std::vector& out, bool all_in_one = false); + void end_getting_small_clauses(); + void get_all_irred_clauses(vector& out); + vector translate_sampl_set(const vector& sampl_set); + + //Version + static const char* get_version_tag(); + static const char* get_version_sha1(); + static const char* get_compilation_env(); + + vector get_zero_assigned_lits(const bool backnumber = true, bool only_nvars = false) const; + void print_stats( + const double cpu_time, + const double cpu_time_total, + double wallclock_time_started = 0) const; + void print_stats_time( + const double cpu_time, + const double cpu_time_total, + double wallclock_time_started = 0) const; + void print_clause_stats() const; + size_t get_num_free_vars() const; + size_t get_num_nonfree_vars() const; + const SolverConf& getConf() const; + void setConf(const SolverConf& conf); + const BinTriStats& getBinTriStats() const; + size_t get_num_vars_elimed() const; + uint32_t num_active_vars() const; + void print_mem_stats() const; + uint64_t print_watch_mem_used(uint64_t totalMem) const; + const SolveStats& get_solve_stats() const; + const SearchStats& get_stats() const; + void add_in_partial_solving_stats(); + void check_implicit_stats(const bool onlypairs = false) const; + void check_stats(const bool allowFreed = false) const; + void reset_vsids(); + bool minimize_clause(vector& cl); + + //Checks + void check_implicit_propagated() const; + bool find_with_watchlist_a_or_b(Lit a, Lit b, int64_t* limit) const; + + //Systems that are used to accompilsh the tasks + ClauseCleaner* clauseCleaner = NULL; + VarReplacer* varReplacer = NULL; + SubsumeImplicit* subsumeImplicit = NULL; + DataSync* datasync = NULL; + ReduceDB* reduceDB = NULL; + InTree* intree = NULL; + BreakID* breakid = NULL; + OccSimplifier* occsimplifier = NULL; + DistillerLong* distill_long_cls = NULL; + DistillerBin* distill_bin_cls = NULL; + DistillerLitRem* distill_lit_rem = NULL; + DistillerLongWithImpl* dist_long_with_impl = NULL; + StrImplWImpl* dist_impl_with_impl = NULL; + CardFinder* card_finder = NULL; + GetClauseQuery* get_clause_query = NULL; + + SearchStats sumSearchStats; + PropStats sumPropStats; + + bool prop_at_head() const; + void set_decision_var(const uint32_t var); + bool fully_enqueue_these(const vector& toEnqueue); + bool fully_enqueue_this(const Lit lit_ID); + void update_assumptions_after_varreplace(); + + //State load/unload + string serialize_solution_reconstruction_data() const; + void create_from_solution_reconstruction_data(const string& str); + pair> extend_minimized_model(const vector& m); + + // Clauses + bool add_clause_outer_copylits(const vector& ps); + bool add_xor_clause_inter( + const vector< Lit >& lits + , bool rhs + , bool attach + , bool addDrat = true + , bool red = false + ); + void new_var( + const bool bva = false, + const uint32_t orig_outer = numeric_limits::max(), + const bool insert_varorder = true + ) override; + void new_vars(const size_t n) override; + void bva_changed(); + + //Attaching-detaching clauses + void attachClause( + const Clause& c + #ifdef DEBUG_ATTACH + , const bool checkAttach = true + #else + , const bool checkAttach = false + #endif + ); + void attach_bnn(const uint32_t bnn_idx); + lbool bnn_eval(BNN& bnn); + bool bnn_to_cnf(BNN& bnn); + void attach_bin_clause( + const Lit lit1 + , const Lit lit2 + , const bool red + , const int32_t ID + , [[maybe_unused]] const bool checkUnassignedFirst = true + ); + void detach_bin_clause( + Lit lit1 + , Lit lit2 + , bool red + , const uint64_t ID + , bool allow_empty_watch = false + , bool allow_change_order = false + ) { + if (red) { + binTri.redBins--; + } else { + binTri.irredBins--; + } + + PropEngine::detach_bin_clause(lit1, lit2, red, ID, allow_empty_watch, allow_change_order); + } + void detachClause(const Clause& c, const bool removeDrat = true); + void detachClause(const ClOffset offset, const bool removeDrat = true); + void detach_modified_clause( + const Lit lit1 + , const Lit lit2 + , const uint32_t origSize + , const Clause* address + ); + Clause* add_clause_int( + const vector& lits + , const bool red = false + , const ClauseStats* const stats = NULL + , const bool attach = true + , vector* finalLits = NULL + , bool addDrat = true + , const Lit frat_first = lit_Undef + , const bool sorted = false + , const bool remove_frat = false + ); + void add_bnn_clause_inter( + vector& lits, + int32_t cutoff, + Lit out + ); + + template vector clause_outer_numbered(const T& cl) const; + template vector xor_outer_numbered(const T& cl) const; + size_t mem_used() const; + void dump_memory_stats_to_sql(); + void dump_clauses_at_finishup_as_last(); + void set_sqlite(const string filename); + //Not Private for testing (maybe could be called from outside) + bool renumber_variables(bool must_renumber = true); + + // Gates + vector get_recovered_or_gates(); + vector get_recovered_ite_gates(); + vector > get_all_binary_xors() const; + vector get_recovered_xors(const bool xor_together_xors); + vector remove_definable_by_irreg_gate(const vector& vars); + void clean_sampl_and_get_empties( + vector& sampl_vars, vector& empty_vars); + + bool remove_and_clean_all(); + vector get_toplevel_units_internal(bool outer_numbering) const; + + // Gauss-Jordan + bool init_all_matrices(); + void detach_xor_clauses( + const set& clash_vars_unused + ); + bool fully_undo_xor_detach(); + bool no_irred_nonxor_contains_clash_vars(); + bool assump_contains_xor_clash(); + void extend_model_to_detached_xors(); + void unset_clash_decision_vars(const vector& xors); + void set_clash_decision_vars(); + bool find_and_init_all_matrices(); + + //assumptions + void set_assumptions(); + vector inter_assumptions_tmp; //used by set_assumptions() ONLY + void add_assumption(const Lit assump); + void check_assigns_for_assumptions() const; + bool check_assumptions_contradict_foced_assignment() const; + + //Deleting clauses + void free_cl(Clause* cl, bool also_remove_clid = true); + void free_cl(ClOffset offs, bool also_remove_clid = true); + #ifdef STATS_NEEDED + void stats_del_cl(Clause* cl); + void stats_del_cl(ClOffset offs); + SatZillaFeatures calculate_satzilla_features(); + SatZillaFeatures last_solve_satzilla_feature; + #endif + + //Helper + void renumber_xors_to_outside(const vector& xors, vector& xors_ret); + void testing_set_solver_not_fresh(); + bool full_probe(const bool bin_only); + PicoSAT* build_picosat(); + void copy_to_simp(SATSolver* s2); + bool backbone_simpl(int64_t max_confl, bool cmsgen, bool& finished); + bool removed_var_ext(uint32_t var) const; + + private: + friend class ClauseDumper; + #ifdef CMS_TESTING_ENABLED + FRIEND_TEST(SearcherTest, pickpolar_auto_not_changed_by_simp); + #endif + + //FRAT + void write_final_frat_clauses(); + + struct OracleBin { + OracleBin (const Lit _l1, const Lit _l2, const int32_t _ID): + l1(_l1), l2(_l2), ID(_ID) {} + + OracleBin() {} + + Lit l1; + Lit l2; + int32_t ID; + }; + + struct OracleDat { + OracleDat(array& _val, ClOffset _off) : + val(_val), off(_off) {binary = 0;} + OracleDat(array& _val, OracleBin _bin) : + val(_val), bin(_bin) {binary = 1;} + + array val; + ClOffset off; + OracleBin bin; + int binary; + + bool operator<(const OracleDat& other) const { + return val < other.val; + } + }; + + vector> get_irred_cls_for_oracle() const; + vector> compute_edge_weights() const; + vector order_clauses_for_oracle() const; + void dump_cls_oracle(const string fname, const vector& cs); + bool find_equivs(); + bool oracle_vivif(bool& finished); + bool oracle_sparsify(); + void print_cs_ordering(const vector& cs) const; + template lbool probe_inter(const Lit l, uint32_t& min_props); + void reset_for_solving(); + vector add_clause_int_tmp_cl; + lbool iterate_until_solved(); + uint64_t mem_used_vardata() const; + uint64_t calc_num_confl_to_do_this_iter(const size_t iteration_num) const; + void detach_and_free_all_irred_cls(); + + bool sort_and_clean_clause( + vector& ps + , const vector& origCl + , const bool red + , const bool sorted = false + ); + void sort_and_clean_bnn(BNN& bnn); + void set_up_sql_writer(); + vector > sql_tags; + + void check_and_upd_config_parameters(); + vector tmp_xor_clash_vars; + void check_xor_cut_config_sanity() const; + void handle_found_solution(const lbool status, const bool only_indep_solution); + void add_every_combination_xor(const vector& lits, bool attach, const bool addDrat, const bool red); + void add_xor_clause_inter_cleaned_cut(const vector& lits, bool attach, bool addDrat, const bool red); + unsigned num_bits_set(const size_t x, const unsigned max_size) const; + void check_too_large_variable_number(const vector& lits) const; + + lbool simplify_problem_outside(const string* strategy = NULL); + void move_to_outside_assumps(const vector* assumps); + vector back_number_from_outside_to_outer_tmp; + void back_number_from_outside_to_outer(const vector& lits) + { + back_number_from_outside_to_outer_tmp.clear(); + for (const Lit lit: lits) { + assert(lit.var() < nVarsOutside()); + if (get_num_bva_vars() > 0 || !fresh_solver) { + back_number_from_outside_to_outer_tmp.push_back(map_to_with_bva(lit)); + assert(back_number_from_outside_to_outer_tmp.back().var() < nVarsOuter()); + } else { + back_number_from_outside_to_outer_tmp.push_back(lit); + } + } + } + vector outside_assumptions; + Lit back_number_from_outside_to_outer(const Lit lit) + { + assert(lit.var() < nVarsOutside()); + if (get_num_bva_vars() > 0 || !fresh_solver) { + Lit ret = map_to_with_bva(lit); + assert(ret.var() < nVarsOuter()); + return ret; + } else { + return lit; + } + } + + uint32_t back_number_from_outside_to_outer(const uint32_t var) + { + Lit lit = Lit(var, false); + return back_number_from_outside_to_outer(lit).var(); + } + + + //Stats printing + void print_norm_stats( + const double cpu_time, + const double cpu_time_total, + const double wallclock_time_started=0) const; + void print_full_stats( + const double cpu_time, + const double cpu_time_total, + const double wallclock_time_started=0) const; + + lbool simplify_problem(const bool startup, const string& strategy); + lbool execute_inprocess_strategy(const bool startup, const string& strategy); + SolveStats solveStats; + void check_minimization_effectiveness(lbool status); + void check_recursive_minimization_effectiveness(const lbool status); + void extend_solution(const bool only_indep_solution); + void check_too_many_in_tier0(); + bool adjusted_glue_cutoff_if_too_many = false; + + ///////////////////////////// + // Temporary datastructs -- must be cleared before use + mutable std::vector tmpCl; + mutable std::vector tmpXor; + + ///////////////////////////// + //Renumberer + double calc_renumber_saving(); + void free_unused_watches(); + uint64_t last_full_watch_consolidate = 0; + void save_on_var_memory(uint32_t newNumVars); + void unSaveVarMem(); + size_t calculate_interToOuter_and_outerToInter( + vector& outerToInter + , vector& interToOuter + ); + void renumber_clauses(const vector& outerToInter); + void test_renumbering() const; + bool clean_xor_clauses_from_duplicate_and_set_vars(); + bool update_vars_of_xors(vector& xors); + + ///////////////////////////// + // SAT solution verification + bool verify_model() const; + bool verify_model_implicit_clauses() const; + bool verify_model_long_clauses(const vector& cs) const; + + + ///////////////////// + // Data + size_t zeroLevAssignsByCNF = 0; + struct GivenW { + bool pos = false; + bool neg = false; + }; + vector weights_given; + + ///////////////////// + // Clauses + bool addClauseHelper(vector& ps); + bool add_clause_outer(vector& ps, bool red = false); + + ///////////////// + // Debug + + void print_watch_list(watch_subarray_const ws, const Lit lit) const; + void print_clause_size_distrib(); + void check_model_for_assumptions() const; +}; + +inline void Solver::set_decision_var(const uint32_t var) +{ + insert_var_order_all(var); +} + +inline const SearchStats& Solver::get_stats() const +{ + return sumSearchStats; +} + +inline const SolveStats& Solver::get_solve_stats() const +{ + return solveStats; +} + +inline const SolverConf& Solver::getConf() const +{ + return conf; +} + +inline const vector >& Solver::get_sql_tags() const +{ + return sql_tags; +} + +inline const BinTriStats& Solver::getBinTriStats() const +{ + return binTri; +} + +template +inline vector Solver::clause_outer_numbered(const T& cl) const +{ + tmpCl.clear(); + for(size_t i = 0; i < cl.size(); i++) { + tmpCl.push_back(map_inter_to_outer(cl[i])); + } + + return tmpCl; +} + +template +inline vector Solver::xor_outer_numbered(const T& cl) const +{ + tmpXor.clear(); + for(size_t i = 0; i < cl.size(); i++) { + tmpXor.push_back(map_inter_to_outer(cl[i])); + } + + return tmpXor; +} + +inline void Solver::move_to_outside_assumps(const vector* assumps) +{ + + if (assumps) { + #ifdef SLOW_DEBUG + outside_assumptions.clear(); + for(const Lit lit: *assumps) { + if (lit.var() >= nVarsOutside()) { + std::cerr << "ERROR: Assumption variable " << (lit.var()+1) + << " is too large, you never" + << " inserted that variable into the solver. Exiting." + << endl; + exit(-1); + } + outside_assumptions.push_back(lit); + } + #else + outside_assumptions.resize(assumps->size()); + std::copy(assumps->begin(), assumps->end(), outside_assumptions.begin()); + #endif + } else { + outside_assumptions.clear(); + } +} + +inline lbool Solver::simplify_with_assumptions( + const vector* _assumptions, + const string* strategy +) { + fresh_solver = false; + move_to_outside_assumps(_assumptions); + return simplify_problem_outside(strategy); +} + +inline bool Solver::find_with_watchlist_a_or_b(Lit a, Lit b, int64_t* limit) const +{ + if (watches[a].size() > watches[b].size()) { + std::swap(a,b); + } + + watch_subarray_const ws = watches[a]; + *limit -= ws.size(); + for (const Watched w: ws) { + if (!w.isBin()) + continue; + + if (!w.red() + && w.lit2() == b + ) { + return true; + } + } + + return false; +} + +inline const vector& Solver::get_model() const +{ + return model; +} + +inline const vector& Solver::get_final_conflict() const +{ + return conflict; +} + +inline void Solver::setConf(const SolverConf& _conf) +{ + conf = _conf; +} + +inline bool Solver::prop_at_head() const +{ + return qhead == trail.size(); +} + +inline lbool Solver::model_value (const Lit p) const +{ + if (model[p.var()] == l_Undef) + return l_Undef; + + return model[p.var()] ^ p.sign(); +} + +inline lbool Solver::model_value (const uint32_t p) const +{ + return model[p]; +} + +inline void Solver::testing_set_solver_not_fresh() +{ + fresh_solver = false; +} + +inline void Solver::free_cl( + Clause* cl, + bool + #ifdef STATS_NEEDED + also_remove_clid + #endif +) { + #ifdef STATS_NEEDED + if (also_remove_clid) { + stats_del_cl(cl); + } + #endif + cl_alloc.clauseFree(cl); +} + +inline void Solver::free_cl( + ClOffset offs, + bool + #ifdef STATS_NEEDED + also_remove_clid + #endif +) { + #ifdef STATS_NEEDED + if (also_remove_clid) { + stats_del_cl(offs); + } + #endif + cl_alloc.clauseFree(offs); +} + +inline bool Solver::removed_var_ext(uint32_t var) const +{ + assert(get_num_bva_vars() == 0); + var = map_outer_to_inter(var); + return value(var) != l_Undef || varData[var].removed != Removed::none; +} + +} //end namespace diff --git a/cryptominisat/cppsrc/src/solverconf.cpp b/cryptominisat/cppsrc/src/solverconf.cpp new file mode 100644 index 00000000..2536824b --- /dev/null +++ b/cryptominisat/cppsrc/src/solverconf.cpp @@ -0,0 +1,437 @@ +/****************************************** +Copyright (C) 2009-2020 Authors of CryptoMiniSat, see AUTHORS file + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. +***********************************************/ + +#include "constants.h" +#include "solverconf.h" +#include +#include +#include +using namespace CMSat; +using std::numeric_limits; + +//UPDATEs for DEVEL +//Fixing to: +//1832701 out-9660847.wlm01-4 239 147 92 a54ed65 --simdrat 1 --bva 1 --slsgetphase 1 --slstype ccnr_yalsat --confbtwsimp 70000 --confbtwsimpinc 1.1 --modbranchstr 3 +//sat race 2019 +//2049104 out-9833438.wlm01-7-drat0 220 135 85 c975a55 --simdrat 1 --slseveryn 2 --slstype ccnr --bvalim 150000 --tern 1 --terncreate 1 --ternkeep 6 -m 3 --distillincconf 0.04 --distillminconf 20000 + + +//UPDATEs for MASTER +//1830735 out-9839185.wlm01-8-drat0 243 148 95 2a30cfb +//--simdrat 1 --bva 1 --slstype ccnr --slseveryn 2 --bvalim 250000 --tern 1 --terncreate 1 --ternkeep 6 -m 3 --distillincconf 0.02 --distillminconf 10000 --slsgetphase 1 + +//Fixing to: +//--simdrat 1 --bva 1 --slstype ccnr --slseveryn 2 --bvalim 250000 --tern 1 --terncreate 1 --ternkeep 6 -m 3 --distillincconf 0.02 --distillminconf 10000 --slsgetphase 1 --slstobump 100 --gluehist 60 --diffdeclevelchrono 20 --conftochrono 0 + +//Fixing to: +//1722973 out-9860239.wlm01-1-drat0 254 154 100 a6005cf --simdrat 1 --gluehist 50 --moremoreminim 1 --lev1usewithin 70000 --bva2lit 1 + +//Fixing to: +//1838305 out-9882018.wlm01-1-drat0 241 145 96 16de7b4 --simdrat 1 --substimelimbinratio 0.1 --substimelimlongratio 0.9 --distilltier1ratio 0.03 --sublonggothrough 1.0 --varelimto 750 --bvaeveryn 7 + +//Fixing to: +//1706988 out-9885914.wlm01-6-drat0 253 153 100 def3339 --simdrat 1 --vsidsalternate 1 --vsidsalterval1 0.92 --vsidsalterval2 0.99 --maplealternate 1 --maplealterval1 0.70 --maplealterval2 0.90 + +//NOTE: diffdeclevel 0 is not good +//1813642 out-9896604.wlm01-0-drat0 242 146 96 6d8c7e2 _satcomp2020 --simdrat 1 +//1867880 out-9896604.wlm01-1-drat0 237 139 98 6d8c7e2 _satcomp2020 --simdrat 1 --diffdeclevelchrono 0 + +//XOR is good, even on GAUSS +//1755046 out-9896604.wlm01-8-drat0 250 146 104 edd5be7 _devel --xor 1 --breakid 1 --breakideveryn 5 +//1773691 out-9896604.wlm01-13-drat0 247 144 103 edd5be7 _devel --xor 0 --breakid 1 --breakideveryn 5 + +//Tuning to +//1684592 out-9915739.wlm01-3-drat0 256 149 107 b3b7cfb _devel --printsol 0 --xorfindtout 400 --gaussusefulcutoff 0.2 + +//Tuning to +//1732414 out-9915739.wlm01-7-drat0 254 157 97 b3b7cfb _devel --printsol 0 --simdrat 1 --polarstablen 4 + +//Tuning to +//1713867 out-175744.wlm01-11-drat0 252 154 98 de15a43 _devel --printsol 0 --simdrat 1 --slsbumptype 6 --polarbestinvmult 9 --lucky 20 + +//Predict setup that works for countbitswagner064: +//--predlongchunkmult 0.8 --predlongmult 0.8 --predshortmult 1.4 --predforevertopperc 40 + +//Tuning to +//mybase="--printsol 0 --simdrat 1 --predforeverpow 0.1 --predforevermult 0.40 --predlongmult 0.5 --predshortmult 0.5 --preddontmovetime 1 --predadjustsize 0 --predforeverchunkmult 4" + + +//tuning to +//--base="--printsol 0 --simdrat 1 --predforeverpow 0.1 --predforevermult 0.40 --predlongmult 0.5 --predshortmult 0.5 --preddontmovetime 1 --predadjustsize 0 --predforeverchunkmult 4 --occredmax 50 --branchstr vsidsx_once+maple1+maple2+vsids2+maple1+maple2+vsidsx --ternkeep 5 --distillmaxm 10" + + +DLL_PUBLIC SolverConf::SolverConf() : + // Polarities + polarity_mode(PolarityMode::polarmode_automatic) + + //Clause cleaning + , pred_short_size(5500) + , pred_long_size(18500) + , pred_forever_size(10500) // Used only if pred_forever_cutoff is 0 + , pred_forever_cutoff(0) //this sets a static cutoff + , order_tier2_by(2) //order Tier2 by this tier's sort function. 2 means Tier2, i.e. default + + , pred_forever_size_pow(0.01) // Used only if pred_forever_cutoff is 0 + // + , pred_long_chunk(4700) + , pred_forever_chunk(2000) // Used only if pred_forever_cutoff is 0 + , pred_forever_chunk_mult(0) + // + , move_from_tier0(1) //if 1 = moves it, rather than deletes it + , move_from_tier1(1) //if 1 = moves it, rather than deletes it + // + , pred_long_check_every_n(3) + , pred_forever_check_every_n(12) + , pred_distill_only_smallgue(false) + , pred_dontmove_until_timeinside(1) //always move, don't wait + + , every_lev1_reduce(10000) // kept for a while then moved to lev2 + , every_lev2_reduce(15000) // cleared regularly + , every_pred_reduce(10000) //5000 seems to work better + , must_touch_lev1_within(70000) + + , max_temp_lev2_learnt_clauses(30000) //only used if every_lev2_reduce==0 + , inc_max_temp_lev2_red_cls(1.0) //only used if every_lev2_reduce==0 + , protect_cl_if_improved_glue_below_this_glue_for_one_turn(30) + , glue_put_lev0_if_below_or_eq(3) // never removed + , glue_put_lev1_if_below_or_eq(6) // kept for a while then moved to lev2 + #ifdef FINAL_PREDICTOR + , dump_pred_distrib(0) + #endif + , clause_decay(0.999) + , adjust_glue_if_too_many_tier0(0.7) + , min_num_confl_adjust_glue_cutoff(150ULL*1000ULL) + //NOTE: The "Scavel" system's "usedt" does NOT speed up the solver + //test conducted: out-drat-check-8359337.wlm01-1-drat0 + + //Restarting + , restart_first(100) + , restart_inc(1.1) + , restartType(Restart::automatic) + , do_blocking_restart(1) + , blocking_restart_trail_hist_length(5000) + , blocking_restart_multip(1.4) + , fixed_restart_num_confl(100) + , local_glue_multiplier(0.80) + , shortTermHistorySize (50) + , lower_bound_for_blocking_restart(10000) + , ratio_glue_geom(5) + , doAlwaysFMinim(false) + + //branch strategy + , branch_strategy_setup("vmtf+vsids") + + //Clause minimisation + , doRecursiveMinim (true) + , doMinimRedMore(true) + , doMinimRedMoreMore(2) + , max_glue_more_minim(6) + , max_size_more_minim(30) + , more_red_minim_limit_binary(200) + , max_num_lits_more_more_red_min(1) + + //Verbosity + , verbosity (0) + , xor_detach_verb (0) + , doPrintGateDot (false) + , print_full_restart_stat (false) + , print_all_restarts (false) + , verbStats (1) + , do_print_times(1) + , print_restart_line_every_n_confl(8192) + + //Limits + , maxTime (numeric_limits::max()) + , max_confl (numeric_limits::max()) + + //Glues + , update_glues_on_analyze(true) + , max_glue_cutoff_gluehistltlimited(50) + + //Chono BT + , diff_declev_for_chrono (20) + + //decision-based clause generation. These values have been validated + //see 8099966.wlm01 + , do_decision_based_cl(1) + , decision_based_cl_max_levels(9) + , decision_based_cl_min_learned_size(50) + + //SQL + , dump_individual_restarts_and_clauses(true) + , dump_individual_cldata_ratio(0.01) + , sql_overwrite_file(0) + , lock_for_data_gen_ratio(0.1) + + //Var-elim + , doVarElim (true) + , varelim_cutoff_too_many_clauses(2000) + , do_empty_varelim (true) + , do_full_varelim(true) + , empty_varelim_time_limitM(300LL) + , varelim_time_limitM(750) + , varelim_sub_str_limitM(600) + , varElimRatioPerIter(1.60) + , velim_resolvent_too_large(20) + , var_linkin_limit_MB(1000) + , varelim_gate_find_limit(800) + , picosat_gate_limitK(70) + , varelim_check_resolvent_subs(false) + + //Subs, str limits for simplifier + , subsumption_time_limitM(300) + , weaken_time_limitM(300) + , dummy_str_time_limitM(20) + , subsumption_time_limit_ratio_sub_str_w_bin(0.1) + , subsumption_time_limit_ratio_sub_w_long(0.9) + , strengthening_time_limitM(300) + , occ_based_lit_rem_time_limitM(50) + + + //Ternary resolution + , doTernary(true) + , ternary_res_time_limitM(100) + , ternary_keep_mult(5) + , ternary_max_create(0.3) + , allow_ternary_bin_create(false) + + //Bosphorus + , do_bosphorus(false) + , bosphorus_every_n(1) + + //BreakID + , doBreakid(true) + , breakid_use_assump(true) + , breakid_every_n(5) + , breakid_vars_limit_K(300) + , breakid_cls_limit_K(600) + , breakid_lits_limit_K(3500) + , breakid_time_limit_K(2000) + , breakid_max_constr_per_permut(50) + , breakid_matrix_detect(true) + + //Bounded variable addition + , do_bva(true) + , min_bva_gain(16) + , bva_limit_per_call(250000) + , bva_also_twolit_diff(true) + , bva_extra_lit_and_red_start(0) + , bva_time_limitM(50) + , bva_every_n(7) + + //Probing + , do_full_probe (true) + , doIntreeProbe (true) + , doTransRed (true) + , full_probe_time_limitM(20ULL) + , intree_time_limitM(400ULL) + , intree_scc_varreplace_time_limitM(30ULL) + , do_hyperbin_and_transred(true) + + //XOR + , doFindXors (true) + , maxXorToFind (7) + , maxXorToFindSlow (5) + , maxXORMatrix (400ULL) + , xor_finder_time_limitM(400) + , allow_elim_xor_vars(1) + , xor_var_per_cut(2) + , force_preserve_xors(true) + + //Cardinality + , doFindCard(0) + + //Var-replacer + , doFindAndReplaceEqLits(true) + , max_scc_depth (10000) + + //Iterative Alo Scheduling + , simplify_at_startup(false) + , simplify_at_every_startup(false) + , do_simplify_problem(true) + , full_simplify_at_startup(false) + , never_stop_search(false) + , num_conflicts_of_search(40ULL*1000ULL) + , num_conflicts_of_search_inc(1.4) + , num_conflicts_of_search_inc_max(10) + , max_num_simplify_per_solve_call(25) + , simplify_schedule_startup( + "sub-impl, occ-backw-sub," + "scc-vrepl," + "breakid, " + "occ-bve,occ-xor" + ) + //validated with run 8114195.wlm01 + , simplify_schedule_nonstartup( + //"scc-vrepl," + //"intree-probe," + "scc-vrepl,sub-impl," + "breakid," + //occurrence based + "occ-backw-sub-str,occ-clean-implicit,occ-bve,"//occ-gates," + "occ-bva,occ-ternary-res,occ-xor,card-find," + //consolidate after OCC + "cl-consolidate," + //strengthen again + "scc-vrepl," + //renumber then it's time for SLS + "renumber," + "bosphorus," + "louvain-comms," + ) + + //Occur based simplification + , perform_occur_based_simp(true) + , do_strengthen_with_occur (true) + , maxRedLinkInSize (50) + , maxOccurIrredMB (2500) + , maxOccurRedMB (600) + , maxOccurRedLitLinkedM(50) + , subsume_gothrough_multip(1.0) + + //WalkSAT + , doSLS(true) + , sls_every_n(2) + , yalsat_max_mems(10) + , sls_memoutMB(500) + , walksat_max_runs(50) + , sls_get_phase(1) + , sls_ccnr_asipire(1) + , which_sls("ccnr") + , sls_how_many_to_bump(100) + , sls_bump_var_max_n_times(100) + , sls_bump_type(6) + + //Distillation + , do_distill_clauses(true) + , do_distill_bin_clauses(true) + , distill_long_cls_time_limitM(20ULL) + , watch_based_str_time_limitM(20LL) + , distill_increase_conf_ratio(0.10) + , distill_min_confl(10000) + , distill_red_tier0_ratio(10.0) + , distill_red_tier1_ratio(0.03) + , distill_irred_alsoremove_ratio(1.2) + , distill_irred_noremove_ratio(1.0) //from out-3946531.wlm01-15-drat0 + , distill_rand_shuffle_order_every_n(3) + #ifdef FINAL_PREDICTOR + , distill_sort(3) + #else + , distill_sort(1) + #endif + + //Memory savings + , doRenumberVars (true) + , must_renumber (false) + , doSaveMem (true) + , full_watch_consolidate_every_n_confl (4ULL*1000ULL*1000ULL) //validated in run 8113323.wlm01 + + //Misc optimisations + , doStrSubImplicit (true) + , subsume_implicit_time_limitM(100LL) + , distill_implicit_with_implicit_time_limitM(200LL) + + //Gates + , doGateFind (false) + , gatefinder_time_limitM(200) + + //Gauss + , xor_detach_reattach(false) + , force_use_all_matrixes(false) + + //Sampling + , sampling_vars(NULL) + + //Timeouts + , global_next_multiplier(1.0) + , orig_global_timeout_multiplier(3.0) + , global_timeout_multiplier(1.0) // WILL BE UNSET, NOT RELEVANT + , global_timeout_multiplier_multiplier(1.1) + , global_multiplier_multiplier_max(3) + , var_and_mem_out_mult(1.0) + + //Multi-thread, MPI + , sync_every_confl(7000) //THREAD syncing + , every_n_mpi_sync(3) //every N thread sync, we do an MPI sync + , thread_num(0) + , is_mpi(false) + + // Oracle + , oracle_get_learnts(false) // get oracle learnt clauses + , oracle_removed_is_learnt(false) // clauses removed by Oracle should be learnt + + //misc + , origSeed(0) + , simulate_frat(false) +{ + ratio_keep_clauses[clean_to_int(ClauseClean::glue)] = 0; + ratio_keep_clauses[clean_to_int(ClauseClean::activity)] = 0.44; +} + + +DLL_PUBLIC std::string SolverConf::print_times( + const double time_used + , const bool time_out + , const double time_remain +) const { + if (do_print_times) { + std::stringstream ss; + ss + << " T: " << std::setprecision(2) << std::fixed << time_used + << " T-out: " << (time_out ? "Y" : "N") + << " T-r: " << time_remain*100.0 << "%"; + + return ss.str(); + } + + return std::string(); +} + +DLL_PUBLIC std::string SolverConf::print_times( + const double time_used + , const bool time_out +) const { + if (do_print_times) { + std::stringstream ss; + ss + << " T: " << std::setprecision(2) << std::fixed << time_used + << " T-out: " << (time_out ? "Y" : "N"); + + return ss.str(); + } + + return std::string(); +} + +DLL_PUBLIC std::string SolverConf::print_times( + const double time_used +) const { + if (do_print_times) { + std::stringstream ss; + ss + << " T: " << std::setprecision(2) << std::fixed << time_used; + + return ss.str(); + } + + return std::string(); +} diff --git a/cryptominisat/cppsrc/src/solverconf.h b/cryptominisat/cppsrc/src/solverconf.h new file mode 100644 index 00000000..cd471fca --- /dev/null +++ b/cryptominisat/cppsrc/src/solverconf.h @@ -0,0 +1,526 @@ +/****************************************** +Copyright (C) 2009-2020 Authors of CryptoMiniSat, see AUTHORS file + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. +***********************************************/ + +#pragma once + +#include +#include +#include +#include +#include "constants.h" +#include "solvertypesmini.h" + +using std::string; + +namespace CMSat { + +enum class ClauseClean { + glue = 0 + , activity = 1 +}; + +inline unsigned clean_to_int(ClauseClean t) +{ + switch(t) + { + case ClauseClean::glue: + return 0; + + case ClauseClean::activity: + return 1; + } + + assert(false); + return 255; +} + +enum class Restart { + glue = 0 + , geom = 1 + , luby = 2 + , fixed = 3 + , never = 4 + , automatic = 5 +}; + +inline std::string polarity_mode_to_long_string(PolarityMode polarmode) +{ + switch(polarmode) { + case PolarityMode::polarmode_automatic : + return "auto"; + case PolarityMode::polarmode_stable : + return "stb"; + case PolarityMode::polarmode_best_inv : + return "inv-bst"; + case PolarityMode::polarmode_best : + return "best"; + case PolarityMode::polarmode_neg : + return "neg"; + case PolarityMode::polarmode_pos : + return "pos"; + case PolarityMode::polarmode_saved : + return "saved-polar"; + case PolarityMode::polarmode_weighted : + return "weighted"; + case PolarityMode::polarmode_rnd : + return "rnd"; + } + assert(false); + return "ERR: undefined!"; +} + +inline std::string restart_type_to_short_string(const Restart type) +{ + switch(type) { + case Restart::glue: + return "glue"; + + case Restart::geom: + return "geom"; + + case Restart::luby: + return "luby"; + + case Restart::fixed: + return "fixd"; + + case Restart::never: + return "neve"; + + case Restart::automatic: + release_assert(false); + return ""; + } + + assert(false && "oops, one of the restart types has no string name"); + return "ERR: undefined!"; +} + +inline std::string polarity_mode_to_short_string(PolarityMode polarmode) +{ + switch(polarmode) { + case PolarityMode::polarmode_automatic : + release_assert(false); + return ""; + case PolarityMode::polarmode_stable : + return "stb"; + case PolarityMode::polarmode_best_inv : + return "ibes"; + case PolarityMode::polarmode_best : + return "best"; + case PolarityMode::polarmode_neg : + return "neg"; + case PolarityMode::polarmode_pos : + return "pos"; + case PolarityMode::polarmode_weighted : + return "wght"; + case PolarityMode::polarmode_saved : + return "svd"; + case PolarityMode::polarmode_rnd : + return "rnd"; + } + assert(false); + return "ERR: undefined!"; +} + +inline std::string getNameOfRestartType(Restart rest_type) +{ + switch(rest_type) { + case Restart::glue : + return "glue"; + + case Restart::geom: + return "geometric"; + + case Restart::luby: + return "luby"; + + case Restart::fixed: + return "fixed"; + + case Restart::never: + return "never"; + + default: + assert(false && "Unknown clause cleaning type?"); + } + assert(false); + return "ERR: undefined!"; +} + +inline std::string getNameOfCleanType(ClauseClean clauseCleaningType) +{ + switch(clauseCleaningType) { + case ClauseClean::glue : + return "glue"; + + case ClauseClean::activity: + return "activity"; + + default: + assert(false && "Unknown clause cleaning type?"); + std::exit(-1); + } + assert(false); + return "ERR: undefined!"; +} + +class GaussConf +{ + public: + + GaussConf() : + autodisable(true) + , min_usefulness_cutoff(0.2) + , max_matrix_columns(1000) + , max_matrix_rows(2000) + , min_matrix_rows(3) + , max_num_matrices(5) + { + } + + bool autodisable; + double min_usefulness_cutoff; + uint32_t max_matrix_columns; + uint32_t max_matrix_rows; //The maximum matrix size -- no. of rows + uint32_t min_matrix_rows; //The minimum matrix size -- no. of rows + uint32_t max_num_matrices; //Maximum number of matrices + + //Matrix extraction config + bool doMatrixFind = true; + uint32_t min_gauss_xor_clauses = 2; + uint32_t max_gauss_xor_clauses = 500000; +}; + +class DLL_PUBLIC SolverConf +{ + public: + SolverConf(); + std::string print_times( + const double time_used + , const bool time_out + , const double time_remain + ) const; + std::string print_times( + const double time_used + , const bool time_out + ) const; + std::string print_times( + const double time_used + ) const; + + //Variable polarities + PolarityMode polarity_mode; + + //Clause cleaning + uint32_t pred_short_size; + uint32_t pred_long_size; + uint32_t pred_forever_size; + uint32_t pred_forever_cutoff; + uint32_t order_tier2_by; + double pred_forever_size_pow; + + uint32_t pred_long_chunk; + uint32_t pred_forever_chunk; + int pred_forever_chunk_mult; //true or false + + int move_from_tier0; + int move_from_tier1; + + uint32_t pred_long_check_every_n; + uint32_t pred_forever_check_every_n; + int pred_distill_only_smallgue; + int pred_dontmove_until_timeinside; + + //if non-zero, we reduce at every X conflicts. + //Reduced according to whether it's been used recently + //Otherwise, we *never* reduce + unsigned every_lev1_reduce; + + //if non-zero, we reduce at every X conflicts. + //Otherwise we geometrically keep around max_temp_lev2_learnt_clauses*(inc**N) + unsigned every_lev2_reduce; + unsigned every_pred_reduce; + + uint32_t must_touch_lev1_within; + unsigned max_temp_lev2_learnt_clauses; + double inc_max_temp_lev2_red_cls; + + unsigned protect_cl_if_improved_glue_below_this_glue_for_one_turn; + unsigned glue_put_lev0_if_below_or_eq; + unsigned glue_put_lev1_if_below_or_eq; + int dump_pred_distrib; + double ratio_keep_clauses[2]; ///< Remove this ratio of clauses at every database reduction round + double clause_decay; + + //If too many (in percentage) low glues after min_num_confl_adjust_glue_cutoff, adjust glue lower + double adjust_glue_if_too_many_tier0; + uint64_t min_num_confl_adjust_glue_cutoff; + + //For restarting + unsigned restart_first; ///* sampling_vars; + + //Timeouts + double global_next_multiplier; + double orig_global_timeout_multiplier; + double global_timeout_multiplier; + double global_timeout_multiplier_multiplier; + double global_multiplier_multiplier_max; + double var_and_mem_out_mult; + + //Multi-thread, MPI + unsigned long long sync_every_confl; + uint32_t every_n_mpi_sync; + unsigned thread_num; + uint32_t is_mpi; + + // Oracle + int oracle_get_learnts; // get oracle learnt clauses + int oracle_removed_is_learnt; // clauses removed by Oracle should be learnt + + //Misc + unsigned origSeed; + int simulate_frat; + int conf_needed = true; +}; + +} //end namespace diff --git a/cryptominisat/cppsrc/src/solvertypes.h b/cryptominisat/cppsrc/src/solvertypes.h new file mode 100644 index 00000000..dc75ae60 --- /dev/null +++ b/cryptominisat/cppsrc/src/solvertypes.h @@ -0,0 +1,512 @@ +/****************************************** +Copyright (C) 2009-2020 Authors of CryptoMiniSat, see AUTHORS file + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. +***********************************************/ + + +#ifndef SOLVERTYPES_H +#define SOLVERTYPES_H + +#include "constants.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "solverconf.h" +#include "solvertypesmini.h" + +namespace CMSat { + +using std::vector; +using std::cout; +using std::endl; +using std::string; + +enum class gret {confl, prop, nothing_satisfied, nothing_fnewwatch}; +enum class gauss_res {none, confl, prop}; +enum class branch {vsids=1, rand=2, vmtf=3}; + +inline std::string restart_type_to_string(const Restart type) +{ + switch(type) { + case Restart::glue: + return "glue"; + + case Restart::automatic: + release_assert(false); + return ""; + + case Restart::geom: + return "geometric"; + + case Restart::luby: + return "luby"; + + case Restart::fixed: + return "fixed"; + + case Restart::never: + return "never"; + } + + assert(false && "oops, one of the restart types has no string name"); + + return "Ooops, undefined!"; +} + +inline std::string branch_type_to_string(const branch type) +{ + switch(type) { + case branch::vsids: + return "vsid"; + + case branch::rand: + return "rand"; + + case branch::vmtf: + return "vmtf"; + } + + assert(false && "oops, one of the branch types has no string name"); + + return "Ooops, undefined!"; +} + +//Removed by which algorithm. NONE = not eliminated +enum class Removed : unsigned char { + none + , elimed + , replaced + , clashed +}; + +inline std::string removed_type_to_string(const Removed removed) { + switch(removed) { + case Removed::none: + return "not removed"; + + case Removed::elimed: + return "variable elimination"; + + case Removed::replaced: + return "variable replacement"; + + case Removed::clashed: + return "clashed on XOR and temporarily removed"; + } + + assert(false && "oops, one of the elim types has no string name"); + return "Oops, undefined!"; +} + +class BinaryClause { + public: + BinaryClause( + const Lit _lit1, + const Lit _lit2, + const bool _red, + const uint32_t _ID): + lit1(_lit1), + lit2(_lit2), + red(_red), + ID(_ID) + { + if (lit1 > lit2) std::swap(lit1, lit2); + } + + bool operator<(const BinaryClause& other) const + { + if (lit1 < other.lit1) return true; + if (lit1 > other.lit1) return false; + + if (lit2 < other.lit2) return true; + if (lit2 > other.lit2) return false; + return (red && !other.red); + } + + bool operator==(const BinaryClause& other) const + { + return (lit1 == other.lit1 + && lit2 == other.lit2 + && red == other.red); + } + + const Lit getLit1() const + { + return lit1; + } + + const Lit getLit2() const + { + return lit2; + } + + bool isRed() const + { + return red; + } + + uint32_t getID() const + { + return ID; + } + + private: + Lit lit1; + Lit lit2; + bool red; + int32_t ID; +}; + +inline std::ostream& operator<<(std::ostream& os, const BinaryClause val) +{ + os << val.getLit1() << " , " << val.getLit2() + << " red: " << std::boolalpha << val.isRed() << std::noboolalpha + << " ID: " << val.getID(); + return os; +} + +inline double ratio_for_stat(double a, double b) +{ + if (b == 0) + return 0; + return a/b; +} + +inline double stats_line_percent(double num, double total) +{ + if (total == 0) { + return 0; + } else { + return num/total*100.0; + } +} + +inline string print_value_kilo_mega(const int64_t value, bool setw = true) +{ + std::stringstream ss; + if (value > 20*1000LL*1000LL) { + if (setw) { + ss << std::setw(4); + } + ss << value/(1000LL*1000LL) << "M"; + } else if (value > 20LL*1000LL) { + if (setw) { + ss << std::setw(4); + } + ss << value/1000LL << "K"; + } else { + if (setw) { + ss << std::setw(5); + } + ss << value; + } + + return ss.str(); +} + +template void print_stats_line( + const string& left + , T value + , T2 value2 + , const string& extra +) { + cout + << std::fixed << std::left << std::setw(27) << left + << ": " << std::setw(11) << std::setprecision(2) << value + << " (" << std::left << std::setw(9) << std::setprecision(2) << value2 + << " " << extra << ")" + << std::right + << endl; +} + +inline void print_stats_line( + const string& left + , uint64_t value + , uint64_t value2 + , uint64_t value3 +) { + cout + << std::fixed << std::left << std::setw(27) << left + << ": " << std::setw(11) << std::setprecision(2) << value + << "/" << value2 + << "/" << value3 + << std::right + << endl; +} + +template void print_stats_line( + const string& left + , T value + , const string& extra1 + , T2 value2 + , const string& extra2 +) { + cout + << std::fixed << std::left << std::setw(27) << left + << ": " << std::setw(11) << std::setprecision(2) << value + << " " << extra1 + << " (" << std::left << std::setw(9) << std::setprecision(2) << value2 + << " " << extra2 << ")" + << std::right + << endl; +} + +template void print_stats_line( + const string& left + , T value +) { + cout + << std::fixed << std::left << std::setw(27) << left + << ": " << std::setw(11) << std::setprecision(2) + << value + << " " + << std::right + << endl; +} + +template void print_stats_line( + const string& left + , T value + , const string& extra +) { + cout + << std::fixed << std::left << std::setw(27) << left + << ": " << std::setw(11) << std::setprecision(2) + << value + << " " << extra + << std::right + << endl; +} + +struct VSIDS_largest_first{ + VSIDS_largest_first(const vector& _vsids_act) : + vsids_act(_vsids_act) + { + } + + bool operator()(const Lit& a, const Lit& b) const { + return vsids_act[a.var()] > vsids_act[b.var()]; + } + + const vector& vsids_act; +}; + +struct AssignStats +{ + AssignStats() : + sumAssignPos(0) + , sumAssignNeg(0) + , sumFlippedPolar(0) + , sumFlippedPolarByDecider(0) + {} + + uint64_t sumAssignPos; + uint64_t sumAssignNeg; + uint64_t sumFlippedPolar; + uint64_t sumFlippedPolarByDecider; + +}; + +struct MedianCommonDataRDB { + uint32_t median_props; + uint32_t median_uip1_used; + double median_sum_uip1_per_time; + double median_sum_props_per_time; + float median_act; +}; + +struct AverageCommonDataRDB { + //double avg_glue = 0; CANNOT CALCULATE! ternaries have no glues + double avg_props = 0; + double avg_uip1_used = 0; + double avg_sum_uip1_per_time = 0; + double avg_sum_props_per_time = 0; +}; + +struct PropStats +{ + void clear() + { + PropStats tmp; + *this = tmp; + } + + PropStats& operator+=(const PropStats& other) + { + propagations += other.propagations; + bogoProps += other.bogoProps; + otfHyperTime += other.otfHyperTime; + otfHyperPropCalled += other.otfHyperPropCalled; + #ifdef STATS_NEEDED + varSetPos += other.varSetPos; + varSetNeg += other.varSetNeg; + varFlipped += other.varFlipped; + #endif + + return *this; + } + + PropStats& operator-=(const PropStats& other) + { + propagations -= other.propagations; + bogoProps -= other.bogoProps; + otfHyperTime -= other.otfHyperTime; + otfHyperPropCalled -= other.otfHyperPropCalled; + #ifdef STATS_NEEDED + varSetPos -= other.varSetPos; + varSetNeg -= other.varSetNeg; + varFlipped -= other.varFlipped; + #endif + + return *this; + } + + PropStats operator-(const PropStats& other) const + { + PropStats result = *this; + result -= other; + return result; + } + + PropStats operator+(const PropStats& other) const + { + PropStats result = *this; + result += other; + return result; + } + + void print(const double cpu_time) const + { + cout << "c PROP stats" << endl; + print_stats_line("c Mbogo-props", (double)bogoProps/(1000.0*1000.0) + , ratio_for_stat(bogoProps, cpu_time*1000.0*1000.0) + , "/ sec" + ); + + print_stats_line("c MHyper-props", (double)otfHyperTime/(1000.0*1000.0) + , ratio_for_stat(otfHyperTime, cpu_time*1000.0*1000.0) + , "/ sec" + ); + + print_stats_line("c Mprops", (double)propagations/(1000.0*1000.0) + , ratio_for_stat(propagations, cpu_time*1000.0*1000.0) + , "/ sec" + ); + + #ifdef STATS_NEEDED + print_stats_line("c varSetPos", varSetPos + , stats_line_percent(varSetPos, propagations) + , "% of propagations" + ); + + print_stats_line("c varSetNeg", varSetNeg + , stats_line_percent(varSetNeg, propagations) + , "% of propagations" + ); + + print_stats_line("c flipped", varFlipped + , stats_line_percent(varFlipped, propagations) + , "% of propagations" + ); + #endif + + } + + uint64_t propagations = 0; /// lit3) + std::swap(lit1, lit3); + + if (lit1 > lit2) + std::swap(lit1, lit2); + + if (lit2 > lit3) + std::swap(lit2, lit3); + + //They are now ordered + assert(lit1 < lit2); + assert(lit2 < lit3); +} + +inline vector sortLits(const vector& lits) +{ + vector tmp(lits); + + std::sort(tmp.begin(), tmp.end()); + return tmp; +} + +template +inline vector vars_to_lits(const T& vars) +{ + vector ret; + for(uint32_t var: vars) { + ret.push_back(Lit(var, false)); + } + return ret; +} + +inline double float_div(const double a, const double b) +{ + if (b != 0) + return a/b; + + return 0; +} + +} //end namespace + +namespace std { + + template <> + struct hash + { + std::size_t operator()(const CMSat::Lit& k) const + { + return k.toInt(); + } + }; + +} + + +#endif //SOLVERTYPES_H diff --git a/cryptominisat/cppsrc/src/solvertypesmini.h b/cryptominisat/cppsrc/src/solvertypesmini.h new file mode 100644 index 00000000..b6c03db2 --- /dev/null +++ b/cryptominisat/cppsrc/src/solvertypesmini.h @@ -0,0 +1,394 @@ +/****************************************** +Copyright (C) 2009-2020 Authors of CryptoMiniSat, see AUTHORS file + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. +***********************************************/ + +#ifndef SOLVERTYPESMINI_H +#define SOLVERTYPESMINI_H + +#include +#include +#include +#include +#include +#include + +namespace CMSat { + +constexpr uint32_t var_Undef(0xffffffffU >> 4); + +class TooManyVarsError {}; +class TooLongClauseError {}; + +class Lit +{ + uint32_t x; + constexpr explicit Lit(uint32_t i) : x(i) { } +public: + constexpr Lit() : x(var_Undef<<1) {} // (lit_Undef) + constexpr explicit Lit(uint32_t var, bool is_inverted) : + x(var + var + is_inverted) + {} + + constexpr const uint32_t& toInt() const { // Guarantees small, positive integers suitable for array indexing. + return x; + } + constexpr Lit operator~() const { + return Lit(x ^ 1); + } + constexpr Lit operator^(const bool b) const { + return Lit(x ^ (uint32_t)b); + } + Lit& operator^=(const bool b) { + x ^= (uint32_t)b; + return *this; + } + constexpr bool sign() const { + return x & 1; + } + constexpr uint32_t var() const { + return x >> 1; + } + constexpr Lit unsign() const { + return Lit(x & ~1U); + } + constexpr bool operator==(const Lit& p) const { + return x == p.x; + } + constexpr bool operator!= (const Lit& p) const { + return x != p.x; + } + /** + @brief ONLY to be used for ordering such as: a, b, ~b, etc. + */ + constexpr bool operator < (const Lit& p) const { + return x < p.x; // '<' guarantees that p, ~p are adjacent in the ordering. + } + constexpr bool operator > (const Lit& p) const { + return x > p.x; + } + constexpr bool operator >= (const Lit& p) const { + return x >= p.x; + } + constexpr static Lit toLit(uint32_t data) + { + return Lit(data); + } + template + void serialize(Archive& ar, const unsigned int /*version*/) { + ar & x; + } +}; + +static const Lit lit_Undef(var_Undef, false); // Useful special constants. +static const Lit lit_Error(var_Undef, true ); // + +inline std::ostream& operator<<(std::ostream& os, const Lit lit) +{ + if (lit == lit_Undef) { + os << "lit_Undef"; + } else { + os << (lit.sign() ? "-" : "") << (lit.var() + 1); + } + return os; +} + +inline std::ostream& operator<<(std::ostream& co, const std::vector& lits) +{ + for (uint32_t i = 0; i < lits.size(); i++) { + co << lits[i]; + + if (i != lits.size()-1) + co << " "; + } + + return co; +} + +class lbool { + uint8_t value; + +public: + constexpr explicit lbool(uint8_t v) : value(v) { } + constexpr lbool() : value(0) { } + constexpr explicit lbool(bool x) : value(!x) { } + + constexpr bool operator == (lbool b) const { + return ((b.value & 2) & (value & 2)) | (!(b.value & 2) & (value == b.value)); + } + constexpr bool operator != (lbool b) const { + return !(*this == b); + } + constexpr lbool operator ^ (bool b) const { + return lbool((uint8_t)(value ^ (uint8_t)b)); + } + + lbool operator && (lbool b) const { + uint8_t sel = (value << 1) | (b.value << 3); + uint8_t v = (0xF7F755F4 >> sel) & 3; + return lbool(v); + } + + lbool operator || (lbool b) const { + uint8_t sel = (value << 1) | (b.value << 3); + uint8_t v = (0xFCFCF400 >> sel) & 3; + return lbool(v); + } + + template + void serialize(Archive& ar, const unsigned int /*version*/) { + ar & value; + } + + constexpr uint8_t getValue() const { return value; } + + friend lbool toLbool(uint32_t v); + constexpr friend uint32_t toInt (lbool l); +}; + +constexpr lbool l_True = lbool((uint8_t)0); +constexpr lbool l_False = lbool((uint8_t)1); +constexpr lbool l_Undef = lbool((uint8_t)2); + +inline lbool toLbool(uint32_t v) +{ + lbool l; + l.value = v; + return l; +} + + +constexpr inline uint32_t toInt (lbool l) +{ + return l.value; +} + +inline lbool boolToLBool(const bool b) +{ + if (b) { + return l_True; + } else { + return l_False; + } +} + +inline std::ostream& operator<<(std::ostream& cout, const lbool val) +{ + if (val == l_True) cout << "l_True"; + if (val == l_False) cout << "l_False"; + if (val == l_Undef) cout << "l_Undef"; + return cout; +} + +class OrGate { + public: + OrGate(const Lit& _rhs, const std::vector& _lits, int32_t _ID) : + lits(_lits), rhs(_rhs), ID(_ID) + + { + std::sort(lits.begin(), lits.end()); + } + + bool operator==(const OrGate& other) const + { + return rhs == other.rhs && lits == other.lits; + } + const std::vector& get_lhs() const + { + return lits; + } + + //LHS + std::vector lits; + + //RHS + Lit rhs; + + //ID of long clause + int32_t ID; +}; + +class ITEGate { + public: + ITEGate() {} + ITEGate(const Lit& _rhs, Lit _lit1, Lit _lit2, Lit _lit3) : + rhs(_rhs) + { + lhs[0] = _lit1; + lhs[1] = _lit2; + lhs[2] = _lit3; + std::sort(lhs.begin(), lhs.end()); + } + + std::array get_all() const + { + return std::array{{lhs[0], lhs[1], lhs[2], rhs}}; + } + + //LHS + std::array lhs; + + //RHS + Lit rhs; +}; + +enum class PolarityMode { + polarmode_pos + , polarmode_neg + , polarmode_rnd + , polarmode_automatic + , polarmode_stable + , polarmode_best_inv + , polarmode_best + , polarmode_saved + , polarmode_weighted +}; + +enum class rst_dat_type {norm, var, cl}; + +struct FastBackwData { + std::vector* _assumptions = NULL; + std::vector* indic_to_var = NULL; + uint32_t orig_num_vars = 0; + std::vector* non_indep_vars = NULL; + std::vector* indep_vars = NULL; + bool fast_backw_on = false; + uint32_t* test_var = NULL; + uint32_t* test_indic = NULL; + uint32_t max_confl = 500; + uint32_t cur_max_confl = 0; + uint32_t indep_because_ran_out_of_confl = 0; + uint64_t start_sumConflicts; +}; + +class BNN +{ +public: + typedef Lit* iterator; + typedef const Lit* const_iterator; + + BNN() + {} + + explicit BNN( + const std::vector& _in, + const int32_t _cutoff, + const Lit _out): + cutoff(_cutoff), + out (_out) + { + if (out == lit_Undef) { + set = true; + } + assert(_in.size() > 0); + undefs = _in.size(); + ts = 0; + sz = _in.size(); + for(uint32_t i = 0; i < _in.size(); i++) { + getData()[i] = _in[i]; + } + } + + Lit* getData() + { + return (Lit*)((char*)this + sizeof(BNN)); + } + + const Lit* getData() const + { + return (Lit*)((char*)this + sizeof(BNN)); + } + + const Lit& operator[](const uint32_t at) const + { + return getData()[at]; + } + + Lit& operator[](const uint32_t at) + { + return getData()[at]; + } + + const Lit& get_out() const + { + return out; + } + + const Lit* begin() const + { + return getData(); + } + + Lit* begin() + { + return getData(); + } + + const Lit* end() const + { + return getData()+size(); + } + + Lit* end() + { + return getData()+size(); + } + + bool empty() const + { + return sz == 0; + } + + void resize(uint32_t _sz) { + sz = _sz; + } + + uint32_t size() const { + return sz; + } + + int32_t cutoff; + Lit out = lit_Undef; + bool set = false; + bool isRemoved = false; + int32_t ts = 0; + int32_t undefs = 0; + uint32_t sz; +}; + +inline std::ostream& operator<<(std::ostream& os, const BNN& bnn) +{ + for (uint32_t i = 0; i < bnn.size(); i++) { + os << "lit[" << bnn[i] << "]"; + + if (i+1 < bnn.size()) + os << " + "; + } + os << " >= " << bnn.cutoff; + if (!bnn.set) + os << " <-> " << bnn.out; + os << " [size: " << bnn.size() << "]"; + + return os; +} + +} + +#endif //SOLVERTYPESMINI_H diff --git a/cryptominisat/cppsrc/src/sql_tablestructure.h b/cryptominisat/cppsrc/src/sql_tablestructure.h new file mode 100644 index 00000000..d159b20f --- /dev/null +++ b/cryptominisat/cppsrc/src/sql_tablestructure.h @@ -0,0 +1,27 @@ +/************************************************************* +Copyright (C) 2009-2020 Authors of CryptoMiniSat, see AUTHORS file + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. +***************************************************************/ + +#ifndef __SQL_TABLESTRUCTURE_H__ +#define __SQL_TABLESTRUCTURE_H__ +extern char cmsat_tablestructure_sql[]; +extern unsigned int cmsat_tablestructure_sql_len; +#endif diff --git a/cryptominisat/cppsrc/src/sqlitestats.cpp b/cryptominisat/cppsrc/src/sqlitestats.cpp new file mode 100644 index 00000000..28d21c48 --- /dev/null +++ b/cryptominisat/cppsrc/src/sqlitestats.cpp @@ -0,0 +1,1094 @@ +/****************************************** +Copyright (C) 2009-2020 Authors of CryptoMiniSat, see AUTHORS file + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. +***********************************************/ + +#include "sqlitestats.h" +#include "solvertypes.h" +#include "solver.h" +#include "time_mem.h" +#include +#include "varreplacer.h" +#include "occsimplifier.h" +#include +#include +#include +#include + +#include "constants.h" +#include "reducedb.h" +#include "sql_tablestructure.h" +#include "varreplacer.h" + +using std::make_pair; + +#define bind_null_or_double(stmt,bindat,stucture,func) \ +{ \ + if (stucture.num_data_elements() == 0) {\ + sqlite3_bind_null(stmt, bindat); \ + } else { \ + sqlite3_bind_double(stmt, bindat, stucture.func()); \ + }\ + bindat++; \ +} + +#define bind_null_or_int(stmt,bindat,stucture,func) \ +{ \ + if (stucture.num_data_elements() == 0) {\ + sqlite3_bind_null(stmt, bindat); \ + } else { \ + sqlite3_bind_int(stmt, bindat, stucture.func()); \ + }\ + bindat++; \ +} + +#define bind_null_or_int64(stmt,bindat,stucture,func) \ +{ \ + if (stucture.num_data_elements() == 0) {\ + sqlite3_bind_null(stmt, bindat); \ + } else { \ + sqlite3_bind_int64(stmt, bindat, stucture.func()); \ + }\ + bindat++; \ +} + +using std::cout; +using std::cerr; +using std::endl; +using std::string; +using namespace CMSat; + +const char* rst_dat_type_to_str(rst_dat_type type) { + static const char* const norm ="restart"; + static const char* const var ="restart_dat_for_var"; + static const char* const cl ="restart_dat_for_cl"; + if (type == rst_dat_type::norm) { + return norm; + } else if (type == rst_dat_type::var) { + return var; + } else if (type == rst_dat_type::cl) { + return cl; + } else { + assert(false); + } + assert(false); + exit(-1); +} + +SQLiteStats::SQLiteStats(const std::string& _filename) : + filename(_filename) +{ +} + +vector SQLiteStats::get_columns(const char* tablename) +{ + vector ret; + + std::stringstream q; + q << "pragma table_info(" << tablename << ");"; + + sqlite3_stmt *stmt; + if (sqlite3_prepare_v2(db, q.str().c_str(), -1, &stmt, NULL)) { + cerr << "ERROR: Couln't create table structure for SQLite: " + << sqlite3_errmsg(db) + << endl; + std::exit(-1); + } + + sqlite3_bind_int(stmt, 1, 16); + int rc; + while ( (rc = sqlite3_step(stmt)) == SQLITE_ROW) { + ret.push_back(string((const char*)sqlite3_column_text(stmt, 1))); + } + sqlite3_finalize(stmt); + + return ret; +} + +void SQLiteStats::del_prepared_stmt(sqlite3_stmt* stmt) +{ + if (stmt == NULL) { + return; + } + + int ret = sqlite3_finalize(stmt); + if (ret != SQLITE_OK) { + cout << "Error closing prepared statement" << endl; + std::exit(-1); + } +} + + +SQLiteStats::~SQLiteStats() +{ + if (!setup_ok) + return; + + dump_id_confl_cache(); + + //Free all the prepared statements + del_prepared_stmt(stmtRst); + del_prepared_stmt(stmtVarRst); + del_prepared_stmt(stmtClRst); + del_prepared_stmt(stmtFeat); + del_prepared_stmt(stmtReduceDB); + del_prepared_stmt(stmtReduceDB_common); + del_prepared_stmt(stmtTimePassed); + del_prepared_stmt(stmtMemUsed); + del_prepared_stmt(stmt_clause_stats); + del_prepared_stmt(stmt_delete_cl); + del_prepared_stmt(stmt_update_id); + del_prepared_stmt(stmt_set_id_confl); + del_prepared_stmt(stmt_set_id_confl_1000); + del_prepared_stmt(stmt_var_data_picktime); + del_prepared_stmt(stmt_var_data_fintime); + del_prepared_stmt(stmt_dec_var_clid); + del_prepared_stmt(stmt_var_dist); + + //Close clonnection + sqlite3_close(db); +} + +bool SQLiteStats::setup(const Solver* solver) +{ + setup_ok = connectServer(solver); + if (!setup_ok) { + return false; + } + + //TODO check if data is in any table + if (sqlite3_exec(db, cmsat_tablestructure_sql, NULL, NULL, NULL)) { + cerr << "ERROR: Couln't create table structure for SQLite: " + << sqlite3_errmsg(db) + << endl; + std::exit(-1); + } + + add_solverrun(solver); + addStartupData(); + init("timepassed", &stmtTimePassed); + init("memused", &stmtMemUsed); + init("satzilla_features", &stmtFeat); + init("clause_stats", &stmt_clause_stats); + init("restart", &stmtRst); + init("restart_dat_for_var", &stmtVarRst); + init("restart_dat_for_cl", &stmtClRst); + init("reduceDB", &stmtReduceDB); + init("reduceDB_common", &stmtReduceDB_common); + init("set_id_confl", &stmt_set_id_confl_1000, 1000); + init("set_id_confl", &stmt_set_id_confl); + #ifdef STATS_NEEDED + init("var_data_fintime", &stmt_var_data_fintime); + init("var_data_picktime", &stmt_var_data_picktime); + init("dec_var_clid", &stmt_dec_var_clid); + init("cl_last_in_solver", &stmt_delete_cl); + init("update_id", &stmt_update_id); + init("var_dist", &stmt_var_dist); + #endif + + return true; +} + + +bool file_exists (const std::string& name) { + std::ifstream f(name.c_str()); + return f.good(); +} + + +bool SQLiteStats::connectServer(const Solver* solver) +{ + if (file_exists(filename) && !solver->conf.sql_overwrite_file) { + cout << "ERROR -- the database already exists: " << filename << endl; + cout << "ERROR -- We cannot store more than one run in the same database" + << endl + << "Exiting." << endl; + exit(-1); + } + + int rc = sqlite3_open(filename.c_str(), &db); + if(rc) { + cout << "c Cannot open sqlite database: " << sqlite3_errmsg(db) << endl; + sqlite3_close(db); + return false; + } + + if (sqlite3_exec(db, "PRAGMA synchronous = OFF", NULL, NULL, NULL)) { + cerr << "ERROR: Problem setting pragma synchronous = OFF to SQLite DB" << endl; + cerr << "c " << sqlite3_errmsg(db) << endl; + std::exit(-1); + } + + if (sqlite3_exec(db, "PRAGMA journal_mode = MEMORY", NULL, NULL, NULL)) { + cerr << "ERROR: Problem setting pragma journal_mode = MEMORY to SQLite DB" << endl; + cerr << "c " << sqlite3_errmsg(db) << endl; + std::exit(-1); + } + + + if (solver->conf.verbosity) { + cout << "c writing to SQLite file: " << filename << endl; + } + + return true; +} + +void SQLiteStats::begin_transaction() +{ + if (sqlite3_exec(db, "BEGIN TRANSACTION", NULL, NULL, NULL)) { + cerr << "ERROR: Beginning SQLITE transaction" << endl; + cerr << "c " << sqlite3_errmsg(db) << endl; + std::exit(-1); + } +} + +void SQLiteStats::end_transaction() +{ + if (sqlite3_exec(db, "END TRANSACTION", NULL, NULL, NULL)) { + cerr << "ERROR: Beginning SQLITE transaction" << endl; + cerr << "c " << sqlite3_errmsg(db) << endl; + std::exit(-1); + } +} + +bool SQLiteStats::add_solverrun(const Solver* solver) +{ + std::stringstream ss; + ss + << "INSERT INTO solverRun (`runtime`, `gitrev`) values (" + << time(NULL) + << ", '" << solver->get_version_sha1() << "'" + << ");"; + + //Inserting element into solverruns to get unique ID + const int rc = sqlite3_exec(db, ss.str().c_str(), NULL, NULL, NULL); + if (rc) { + if (solver->getConf().verbosity >= 6) { + cerr << "c ERROR Couldn't insert into table 'solverruns'" << endl; + cerr << "c " << sqlite3_errmsg(db) << endl; + } + + return false; + } + + return true; +} + +void SQLiteStats::add_tag(const std::pair& tag) +{ + std::stringstream ss; + ss + << "INSERT INTO `tags` (`name`, `val`) VALUES(" + << "'" << tag.first << "'" + << ", '" << tag.second << "'" + << ");"; + + //Inserting element into solverruns to get unique ID + if (sqlite3_exec(db, ss.str().c_str(), NULL, NULL, NULL)) { + cerr << "SQLite: ERROR Couldn't insert into table 'tags'" << endl; + assert(false); + std::exit(-1); + } +} + +void SQLiteStats::addStartupData() +{ + std::stringstream ss; + ss + << "INSERT INTO `startup` (`startTime`) VALUES (" + << "datetime('now')" + << ");"; + + if (sqlite3_exec(db, ss.str().c_str(), NULL, NULL, NULL)) { + cerr << "ERROR Couldn't insert into table 'startup' : " + << sqlite3_errmsg(db) << endl; + + std::exit(-1); + } +} + +void SQLiteStats::finishup(const lbool status) +{ + std::stringstream ss; + ss + << "INSERT INTO `finishup` (`endTime`, `status`) VALUES (" + << "datetime('now') , " + << "'" << status << "'" + << ");"; + + if (sqlite3_exec(db, ss.str().c_str(), NULL, NULL, NULL)) { + cerr << "ERROR Couldn't insert into table 'finishup'" << endl; + std::exit(-1); + } +} + +void SQLiteStats::writeQuestionMarks( + size_t num + , std::stringstream& ss +) { + ss << "("; + for(size_t i = 0 + ; i < num + ; i++ + ) { + if (i < num-1) + ss << "?,"; + else + ss << "?"; + } + ss << ")"; +} + +void SQLiteStats::run_sqlite_step( + sqlite3_stmt* stmt, + const char* name, + const uint32_t bindAt) +{ + if (name != NULL) { + assert(query_to_size.find(name) != query_to_size.end()); + //SQLite numbers them from 1, so it's off-by-one + assert(query_to_size[name]+1 == bindAt); + } + + int rc = sqlite3_step(stmt); + if (rc != SQLITE_DONE) { + cout + << "ERROR: while executing '" << name << "' SQLite prepared statement" + << endl; + + cout << "Error from sqlite: " + << sqlite3_errmsg(db) + << endl; + cout << "Error code from sqlite: " << rc << endl; + std::exit(-1); + } + + if (sqlite3_reset(stmt)) { + cerr << "Error calling sqlite3_reset on cl_last_in_solver" << endl; + std::exit(-1); + } + + if (sqlite3_clear_bindings(stmt)) { + cerr << "Error calling sqlite3_clear_bindings on '" + << name << "'" << endl; + std::exit(-1); + } +} + +void SQLiteStats::init(const char* name, sqlite3_stmt** stmt, uint32_t num) +{ + vector cols = get_columns(name); + query_to_size[string(name)] = cols.size(); + const size_t numElems = cols.size(); + + std::stringstream ss; + ss << "insert into `" << name << "` ("; + for(uint32_t i = 0; i < cols.size(); i++) { + if (i > 0) { + ss << ", "; + } + ss << "`" << cols[i] << "`"; + } + ss << ") values "; + for(uint32_t i = 0; i < num; i++) { + writeQuestionMarks(numElems, ss); + if (i+1 < num) ss << ","; + } + ss << ";"; + + //Prepare the statement + if (sqlite3_prepare(db, ss.str().c_str(), -1, stmt, NULL)) { + cerr << "ERROR in sqlite_stmt_prepare(), INSERT failed" + << endl + << sqlite3_errmsg(db) + << endl + << "Query was: " << ss.str() + << endl; + std::exit(-1); + } +} + +void SQLiteStats::mem_used( + const Solver* solver + , const string& name + , double given_time + , uint64_t mem_used_mb +) { + int bindAt = 1; + //Position + sqlite3_bind_int64(stmtMemUsed, bindAt++, solver->get_solve_stats().num_simplify); + sqlite3_bind_int64(stmtMemUsed, bindAt++, solver->sumConflicts); + sqlite3_bind_double(stmtMemUsed, bindAt++, given_time); + //memory stats + sqlite3_bind_text(stmtMemUsed, bindAt++, name.c_str(), -1, NULL); + sqlite3_bind_int(stmtMemUsed, bindAt++, mem_used_mb); + + run_sqlite_step(stmtMemUsed, "memused", bindAt); +} + +void SQLiteStats::time_passed( + const Solver* solver + , const string& name + , double time_passed + , bool time_out + , double percent_time_remain +) { + + int bindAt = 1; + sqlite3_bind_int64(stmtTimePassed, bindAt++, solver->get_solve_stats().num_simplify); + sqlite3_bind_int64(stmtTimePassed, bindAt++, solver->sumConflicts); + sqlite3_bind_double(stmtTimePassed, bindAt++, cpuTime()); + sqlite3_bind_text(stmtTimePassed, bindAt++, name.c_str(), -1, NULL); + sqlite3_bind_double(stmtTimePassed, bindAt++, time_passed); + sqlite3_bind_int(stmtTimePassed, bindAt++, time_out); + sqlite3_bind_double(stmtTimePassed, bindAt++, percent_time_remain); + + run_sqlite_step(stmtTimePassed, "timepassed", bindAt); +} + +void SQLiteStats::time_passed_min( + const Solver* solver + , const string& name + , double time_passed +) { + int bindAt = 1; + sqlite3_bind_int64(stmtTimePassed, bindAt++, solver->get_solve_stats().num_simplify); + sqlite3_bind_int64(stmtTimePassed, bindAt++, solver->sumConflicts); + sqlite3_bind_double(stmtTimePassed, bindAt++, cpuTime()); + sqlite3_bind_text(stmtTimePassed, bindAt++, name.c_str(), -1, NULL); + sqlite3_bind_double(stmtTimePassed, bindAt++, time_passed); + sqlite3_bind_null(stmtTimePassed, bindAt++); + sqlite3_bind_null(stmtTimePassed, bindAt++); + + run_sqlite_step(stmtTimePassed, "timepassed", bindAt); +} + +void SQLiteStats::dump_id_confl_cache() +{ + if (id_conf_cache.size() == 1000) { + int bindAt = 1; + for(auto const& elem: id_conf_cache) { + sqlite3_bind_int64(stmt_set_id_confl_1000, bindAt++, elem.first); + sqlite3_bind_int64(stmt_set_id_confl_1000, bindAt++, elem.second); + } + run_sqlite_step(stmt_set_id_confl_1000, NULL, 0); + } else { + for(auto const& elem: id_conf_cache) { + int bindAt = 1; + sqlite3_bind_int64(stmt_set_id_confl, bindAt++, elem.first); + sqlite3_bind_int64(stmt_set_id_confl, bindAt++, elem.second); + run_sqlite_step(stmt_set_id_confl, "set_id_confl", bindAt); + } + } + id_conf_cache.clear(); +} + +void SQLiteStats::set_id_confl( + const int32_t id + , const uint64_t sumConflicts) +{ + assert(id != 0); + id_conf_cache.push_back(make_pair(id, sumConflicts)); + if (id_conf_cache.size() < 1000) return; + else dump_id_confl_cache(); +} + +#ifdef STATS_NEEDED +void SQLiteStats::satzilla_features( + const Solver* solver + , const Searcher* search + , const SatZillaFeatures& satzilla_feat +) { + int bindAt = 1; + sqlite3_bind_int64(stmtFeat, bindAt++, solver->get_solve_stats().num_simplify); + sqlite3_bind_int64(stmtFeat, bindAt++, search->sumRestarts()); + sqlite3_bind_int64(stmtFeat, bindAt++, solver->sumConflicts); + sqlite3_bind_int(stmtFeat, bindAt++, solver->latest_satzilla_feature_calc); + + sqlite3_bind_int64(stmtFeat, bindAt++, (uint64_t)satzilla_feat.numVars); + sqlite3_bind_int64(stmtFeat, bindAt++, (uint64_t)satzilla_feat.numClauses); + sqlite3_bind_double(stmtFeat, bindAt++, satzilla_feat.var_cl_ratio); + + //Clause distribution + sqlite3_bind_double(stmtFeat, bindAt++, satzilla_feat.binary); + sqlite3_bind_double(stmtFeat, bindAt++, satzilla_feat.horn); + sqlite3_bind_double(stmtFeat, bindAt++, satzilla_feat.horn_mean); + sqlite3_bind_double(stmtFeat, bindAt++, satzilla_feat.horn_std); + sqlite3_bind_double(stmtFeat, bindAt++, satzilla_feat.horn_min); + sqlite3_bind_double(stmtFeat, bindAt++, satzilla_feat.horn_max); + sqlite3_bind_double(stmtFeat, bindAt++, satzilla_feat.horn_spread); + + sqlite3_bind_double(stmtFeat, bindAt++, satzilla_feat.vcg_var_mean); + sqlite3_bind_double(stmtFeat, bindAt++, satzilla_feat.vcg_var_std); + sqlite3_bind_double(stmtFeat, bindAt++, satzilla_feat.vcg_var_min); + sqlite3_bind_double(stmtFeat, bindAt++, satzilla_feat.vcg_var_max); + sqlite3_bind_double(stmtFeat, bindAt++, satzilla_feat.vcg_var_spread); + + sqlite3_bind_double(stmtFeat, bindAt++, satzilla_feat.vcg_cls_mean); + sqlite3_bind_double(stmtFeat, bindAt++, satzilla_feat.vcg_cls_std); + sqlite3_bind_double(stmtFeat, bindAt++, satzilla_feat.vcg_cls_min); + sqlite3_bind_double(stmtFeat, bindAt++, satzilla_feat.vcg_cls_max); + sqlite3_bind_double(stmtFeat, bindAt++, satzilla_feat.vcg_cls_spread); + + sqlite3_bind_double(stmtFeat, bindAt++, satzilla_feat.pnr_var_mean); + sqlite3_bind_double(stmtFeat, bindAt++, satzilla_feat.pnr_var_std); + sqlite3_bind_double(stmtFeat, bindAt++, satzilla_feat.pnr_var_min); + sqlite3_bind_double(stmtFeat, bindAt++, satzilla_feat.pnr_var_max); + sqlite3_bind_double(stmtFeat, bindAt++, satzilla_feat.pnr_var_spread); + + sqlite3_bind_double(stmtFeat, bindAt++, satzilla_feat.pnr_cls_mean); + sqlite3_bind_double(stmtFeat, bindAt++, satzilla_feat.pnr_cls_std); + sqlite3_bind_double(stmtFeat, bindAt++, satzilla_feat.pnr_cls_min); + sqlite3_bind_double(stmtFeat, bindAt++, satzilla_feat.pnr_cls_max); + sqlite3_bind_double(stmtFeat, bindAt++, satzilla_feat.pnr_cls_spread); + + //Conflict clauses + sqlite3_bind_double(stmtFeat, bindAt++, satzilla_feat.avg_confl_size); + sqlite3_bind_double(stmtFeat, bindAt++, satzilla_feat.confl_size_min); + sqlite3_bind_double(stmtFeat, bindAt++, satzilla_feat.confl_size_max); + sqlite3_bind_double(stmtFeat, bindAt++, satzilla_feat.avg_confl_glue); + sqlite3_bind_double(stmtFeat, bindAt++, satzilla_feat.confl_glue_min); + sqlite3_bind_double(stmtFeat, bindAt++, satzilla_feat.confl_glue_max); + sqlite3_bind_double(stmtFeat, bindAt++, satzilla_feat.avg_num_resolutions); + sqlite3_bind_double(stmtFeat, bindAt++, satzilla_feat.num_resolutions_min); + sqlite3_bind_double(stmtFeat, bindAt++, satzilla_feat.num_resolutions_max); + sqlite3_bind_double(stmtFeat, bindAt++, satzilla_feat.learnt_bins_per_confl); + + //Search + sqlite3_bind_double(stmtFeat, bindAt++, satzilla_feat.avg_branch_depth); + sqlite3_bind_double(stmtFeat, bindAt++, satzilla_feat.branch_depth_min); + sqlite3_bind_double(stmtFeat, bindAt++, satzilla_feat.branch_depth_max); + sqlite3_bind_double(stmtFeat, bindAt++, satzilla_feat.avg_trail_depth_delta); + sqlite3_bind_double(stmtFeat, bindAt++, satzilla_feat.trail_depth_delta_min); + sqlite3_bind_double(stmtFeat, bindAt++, satzilla_feat.trail_depth_delta_max); + sqlite3_bind_double(stmtFeat, bindAt++, satzilla_feat.avg_branch_depth_delta); + sqlite3_bind_double(stmtFeat, bindAt++, satzilla_feat.props_per_confl); + sqlite3_bind_double(stmtFeat, bindAt++, satzilla_feat.confl_per_restart); + sqlite3_bind_double(stmtFeat, bindAt++, satzilla_feat.decisions_per_conflict); + + //red stats + sqlite3_bind_double(stmtFeat, bindAt++, satzilla_feat.red_cl_distrib.glue_distr_mean); + sqlite3_bind_double(stmtFeat, bindAt++, satzilla_feat.red_cl_distrib.glue_distr_var); + sqlite3_bind_double(stmtFeat, bindAt++, satzilla_feat.red_cl_distrib.size_distr_mean); + sqlite3_bind_double(stmtFeat, bindAt++, satzilla_feat.red_cl_distrib.size_distr_var); + sqlite3_bind_double(stmtFeat, bindAt++, satzilla_feat.red_cl_distrib.activity_distr_mean); + sqlite3_bind_double(stmtFeat, bindAt++, satzilla_feat.red_cl_distrib.activity_distr_var); + + //irred stats + sqlite3_bind_double(stmtFeat, bindAt++, satzilla_feat.irred_cl_distrib.glue_distr_mean); + sqlite3_bind_double(stmtFeat, bindAt++, satzilla_feat.irred_cl_distrib.glue_distr_var); + sqlite3_bind_double(stmtFeat, bindAt++, satzilla_feat.irred_cl_distrib.size_distr_mean); + sqlite3_bind_double(stmtFeat, bindAt++, satzilla_feat.irred_cl_distrib.size_distr_var); + sqlite3_bind_double(stmtFeat, bindAt++, satzilla_feat.irred_cl_distrib.activity_distr_mean); + sqlite3_bind_double(stmtFeat, bindAt++, satzilla_feat.irred_cl_distrib.activity_distr_var); + + run_sqlite_step(stmtFeat, "satzilla_features", bindAt); +} + +void SQLiteStats::restart( + const uint32_t restartID + , const Restart rest_type + , const PropStats& thisPropStats + , const SearchStats& thisStats + , const Solver* solver + , const Searcher* search + , const rst_dat_type type + , const int64_t clauseID +) { + sqlite3_stmt* stmt; + if (type == rst_dat_type::norm) { + stmt = stmtRst; + } else if (type == rst_dat_type::var) { + stmt = stmtVarRst; + } else if (type == rst_dat_type::cl) { + stmt = stmtClRst; + } else { + assert(false); + } + + const SearchHist& searchHist = search->getHistory(); + const BinTriStats& binTri = solver->getBinTriStats(); + + int bindAt = 1; + sqlite3_bind_int64(stmt, bindAt++, restartID); + if (clauseID == -1) { + sqlite3_bind_null(stmt, bindAt++); + } else { + sqlite3_bind_int64(stmt, bindAt++, clauseID); + } + sqlite3_bind_int64(stmt, bindAt++, solver->get_solve_stats().num_simplify); + sqlite3_bind_int64(stmt, bindAt++, search->sumRestarts()); + sqlite3_bind_int64(stmt, bindAt++, solver->sumConflicts); + sqlite3_bind_int (stmt, bindAt++, searchHist.num_conflicts_this_restart); + sqlite3_bind_int (stmt, bindAt++, solver->latest_satzilla_feature_calc); + sqlite3_bind_double(stmt, bindAt++, cpuTime()); + + + sqlite3_bind_int64(stmt, bindAt++, binTri.irredBins); + sqlite3_bind_int64(stmt, bindAt++, solver->get_num_long_irred_cls()); + sqlite3_bind_int64(stmt, bindAt++, binTri.redBins); + sqlite3_bind_int64(stmt, bindAt++, solver->get_num_long_red_cls()); + + sqlite3_bind_int64(stmt, bindAt++, solver->litStats.irredLits); + sqlite3_bind_int64(stmt, bindAt++, solver->litStats.redLits); + + //Conflict stats + bind_null_or_double(stmt, bindAt, searchHist.glueHist.getLongtTerm(),avg) + sqlite3_bind_double(stmt, bindAt++, std:: sqrt(searchHist.glueHist.getLongtTerm().var())); + bind_null_or_double(stmt, bindAt, searchHist.glueHist.getLongtTerm(),getMin) + bind_null_or_double(stmt, bindAt, searchHist.glueHist.getLongtTerm(),getMax) + + bind_null_or_double(stmt, bindAt, searchHist.conflSizeHist, avg) + sqlite3_bind_double(stmt, bindAt++, std:: sqrt(searchHist.conflSizeHist.var())); + bind_null_or_double(stmt, bindAt, searchHist.conflSizeHist,getMin) + bind_null_or_double(stmt, bindAt, searchHist.conflSizeHist,getMax) + + bind_null_or_double(stmt, bindAt, searchHist.numResolutionsHist, avg) + sqlite3_bind_double(stmt, bindAt++, std:: sqrt(searchHist.numResolutionsHist.var())); + bind_null_or_double(stmt, bindAt, searchHist.numResolutionsHist,getMin) + bind_null_or_double(stmt, bindAt, searchHist.numResolutionsHist,getMax) + + //Search stats + bind_null_or_double(stmt, bindAt, searchHist.branchDepthHist,avg) + sqlite3_bind_double(stmt, bindAt++, std:: sqrt(searchHist.branchDepthHist.var())); + bind_null_or_double(stmt, bindAt, searchHist.branchDepthHist,getMin) + bind_null_or_double(stmt, bindAt, searchHist.branchDepthHist,getMax) + + bind_null_or_double(stmt, bindAt, searchHist.branchDepthDeltaHist,avg) + sqlite3_bind_double(stmt, bindAt++, std:: sqrt(searchHist.branchDepthDeltaHist.var())); + bind_null_or_double(stmt, bindAt, searchHist.branchDepthDeltaHist,getMin) + bind_null_or_double(stmt, bindAt, searchHist.branchDepthDeltaHist,getMax) + + bind_null_or_double(stmt, bindAt, searchHist.trailDepthHist.getLongtTerm(),avg) + sqlite3_bind_double(stmt, bindAt++, std:: sqrt(searchHist.trailDepthHist.getLongtTerm().var())); + bind_null_or_double(stmt, bindAt, searchHist.trailDepthHist.getLongtTerm(),getMin) + bind_null_or_double(stmt, bindAt, searchHist.trailDepthHist.getLongtTerm(),getMax) + + bind_null_or_double(stmt, bindAt, searchHist.trailDepthDeltaHist,avg) + sqlite3_bind_double(stmt, bindAt++, std:: sqrt(searchHist.trailDepthDeltaHist.var())); + bind_null_or_double(stmt, bindAt, searchHist.trailDepthDeltaHist,getMin) + bind_null_or_double(stmt, bindAt, searchHist.trailDepthDeltaHist,getMax) + + //Red + sqlite3_bind_int64(stmt, bindAt++, thisStats.learntUnits); + sqlite3_bind_int64(stmt, bindAt++, thisStats.learntBins); + sqlite3_bind_int64(stmt, bindAt++, thisStats.learntLongs); + + //Resolv stats + sqlite3_bind_int64(stmt, bindAt++, thisStats.resolvs.binIrred); + sqlite3_bind_int64(stmt, bindAt++, thisStats.resolvs.binRed); + sqlite3_bind_int64(stmt, bindAt++, thisStats.resolvs.longIrred); + sqlite3_bind_int64(stmt, bindAt++, thisStats.resolvs.longRed); + + + //Var stats + sqlite3_bind_int64(stmt, bindAt++, thisPropStats.propagations); + sqlite3_bind_int64(stmt, bindAt++, thisStats.decisions); + + sqlite3_bind_int64(stmt, bindAt++, thisPropStats.varFlipped); + sqlite3_bind_int64(stmt, bindAt++, thisPropStats.varSetPos); + sqlite3_bind_int64(stmt, bindAt++, thisPropStats.varSetNeg); + sqlite3_bind_int64(stmt, bindAt++, solver->get_num_free_vars()); + sqlite3_bind_int64(stmt, bindAt++, solver->varReplacer->get_num_replaced_vars()); + sqlite3_bind_int64(stmt, bindAt++, solver->get_num_vars_elimed()); + sqlite3_bind_int64(stmt, bindAt++, search->getTrailSize()); + + //strategy + sqlite3_bind_int(stmt, bindAt++, (int)solver->branch_strategy); + sqlite3_bind_int(stmt, bindAt++, (int)rest_type); + + run_sqlite_step(stmt, rst_dat_type_to_str(type), bindAt); +} + + +void SQLiteStats::reduceDB_common( + const Solver* solver, + const uint32_t reduceDB_called, + const uint32_t tot_cls_in_db, + const uint32_t cur_rst_type, + const MedianCommonDataRDB& median_data, + const AverageCommonDataRDB& avg_data) +{ + int bindAt = 1; + + sqlite3_bind_int(stmtReduceDB_common, bindAt++, reduceDB_called); + + sqlite3_bind_int64 (stmtReduceDB_common, bindAt++, solver->get_solve_stats().num_simplify); + sqlite3_bind_int64 (stmtReduceDB_common, bindAt++, solver->sumRestarts()); + sqlite3_bind_int64 (stmtReduceDB_common, bindAt++, solver->sumConflicts); + sqlite3_bind_int64 (stmtReduceDB_common, bindAt++, solver->latest_satzilla_feature_calc); + sqlite3_bind_int (stmtReduceDB_common, bindAt++, cur_rst_type); + sqlite3_bind_double(stmtReduceDB_common, bindAt++, cpuTime()); + sqlite3_bind_int (stmtReduceDB_common, bindAt++, tot_cls_in_db); + + sqlite3_bind_double(stmtReduceDB_common, bindAt++, (double)median_data.median_act); + sqlite3_bind_int (stmtReduceDB_common, bindAt++, median_data.median_uip1_used); + sqlite3_bind_int (stmtReduceDB_common, bindAt++, median_data.median_props); + sqlite3_bind_double(stmtReduceDB_common, bindAt++, median_data.median_sum_uip1_per_time); + sqlite3_bind_double(stmtReduceDB_common, bindAt++, median_data.median_sum_props_per_time); + + //sqlite3_bind_double(stmtReduceDB_common, bindAt++, avg_data.avg_glue); + sqlite3_bind_double(stmtReduceDB_common, bindAt++, avg_data.avg_props); + sqlite3_bind_double(stmtReduceDB_common, bindAt++, avg_data.avg_uip1_used); + sqlite3_bind_double(stmtReduceDB_common, bindAt++, avg_data.avg_sum_uip1_per_time); + sqlite3_bind_double(stmtReduceDB_common, bindAt++, avg_data.avg_sum_props_per_time); + + + sqlite3_bind_int (stmtReduceDB_common, bindAt++, solver->nVars()); + sqlite3_bind_int (stmtReduceDB_common, bindAt++, solver->longIrredCls.size()); + sqlite3_bind_int (stmtReduceDB_common, bindAt++, solver->litStats.irredLits); + uint32_t total_long_red_cls = 0; + for(const auto& cls: solver->longRedCls) { + total_long_red_cls += cls.size(); + } + sqlite3_bind_int(stmtReduceDB_common, bindAt++, total_long_red_cls); + sqlite3_bind_int(stmtReduceDB_common, bindAt++, solver->litStats.redLits); + sqlite3_bind_int(stmtReduceDB_common, bindAt++, solver->binTri.irredBins); + sqlite3_bind_int(stmtReduceDB_common, bindAt++, solver->binTri.redBins); + + sqlite3_bind_double(stmtReduceDB_common, bindAt++, solver->hist.trailDepthHistLT.avg()); + sqlite3_bind_double(stmtReduceDB_common, bindAt++, solver->hist.backtrackLevelHistLT.avg()); + sqlite3_bind_double(stmtReduceDB_common, bindAt++, solver->hist.conflSizeHistLT.avg()); + sqlite3_bind_double(stmtReduceDB_common, bindAt++, solver->hist.numResolutionsHistLT.avg()); + sqlite3_bind_double(stmtReduceDB_common, bindAt++, solver->hist.glueHistLT.avg()); + sqlite3_bind_double(stmtReduceDB_common, bindAt++, solver->hist.antec_data_sum_sizeHistLT.avg()); + sqlite3_bind_double(stmtReduceDB_common, bindAt++, solver->hist.overlapHistLT.avg()); + + run_sqlite_step(stmtReduceDB_common, "reduceDB_common", bindAt); +} + +void SQLiteStats::reduceDB( + const Solver* solver + , const bool locked + , const Clause* cl + , const uint32_t reduceDB_called +) { + const ClauseStatsExtra& stats_extra = solver->red_stats_extra[cl->stats.extra_pos]; + assert(stats_extra.dump_no != numeric_limits::max()); + + int bindAt = 1; + + //Global data ("conflicts" is needed because otherwise + // code is complicated in data sampler), even though this data + // is available in reduceDB_common + sqlite3_bind_int(stmtReduceDB, bindAt++, reduceDB_called); + sqlite3_bind_int64(stmtReduceDB, bindAt++, solver->sumConflicts); + sqlite3_bind_int64(stmtReduceDB, bindAt++, stats_extra.introduced_at_conflict); + sqlite3_bind_int(stmtReduceDB, bindAt++, cl->stats.which_red_array); + + //data + sqlite3_bind_int64(stmtReduceDB, bindAt++, stats_extra.orig_ID); + sqlite3_bind_int64(stmtReduceDB, bindAt++, stats_extra.dump_no); + sqlite3_bind_int64(stmtReduceDB, bindAt++, stats_extra.conflicts_made); + sqlite3_bind_int64(stmtReduceDB, bindAt++, cl->stats.props_made); + sqlite3_bind_int64(stmtReduceDB, bindAt++, stats_extra.sum_props_made); + sqlite3_bind_int64(stmtReduceDB, bindAt++, cl->stats.uip1_used); + sqlite3_bind_int64(stmtReduceDB, bindAt++, stats_extra.sum_uip1_used); + + assert(cl->stats.last_touched_any <= solver->sumConflicts); + int64_t last_touched_any_diff = solver->sumConflicts - cl->stats.last_touched_any; + sqlite3_bind_int64(stmtReduceDB, bindAt++, last_touched_any_diff); + sqlite3_bind_double(stmtReduceDB, bindAt++, (double)cl->stats.activity/(double)solver->get_cla_inc()); + sqlite3_bind_int(stmtReduceDB, bindAt++, locked); + sqlite3_bind_int(stmtReduceDB, bindAt++, cl->used_in_xor()); + if (cl->stats.is_ternary_resolvent) { + sqlite3_bind_null(stmtReduceDB, bindAt++); + } else { + sqlite3_bind_int(stmtReduceDB, bindAt++, cl->stats.glue); + } + sqlite3_bind_int(stmtReduceDB, bindAt++, cl->size()); + sqlite3_bind_int(stmtReduceDB, bindAt++, stats_extra.ttl_stats); + sqlite3_bind_int(stmtReduceDB, bindAt++, cl->stats.is_ternary_resolvent); + sqlite3_bind_int(stmtReduceDB, bindAt++, cl->stats.is_decision); + sqlite3_bind_int(stmtReduceDB, bindAt++, cl->distilled); + sqlite3_bind_int(stmtReduceDB, bindAt++, stats_extra.connects_num_communities); + + //Ranking + sqlite3_bind_int(stmtReduceDB, bindAt++, stats_extra.act_ranking); + sqlite3_bind_int(stmtReduceDB, bindAt++, stats_extra.prop_ranking); + sqlite3_bind_int(stmtReduceDB, bindAt++, stats_extra.uip1_ranking); + sqlite3_bind_int(stmtReduceDB, bindAt++, stats_extra.sum_uip1_per_time_ranking); + sqlite3_bind_int(stmtReduceDB, bindAt++, stats_extra.sum_props_per_time_ranking); + + //Discounted + sqlite3_bind_double(stmtReduceDB, bindAt++, (double)stats_extra.discounted_uip1_used); + sqlite3_bind_double(stmtReduceDB, bindAt++, (double)stats_extra.discounted_props_made); + sqlite3_bind_double(stmtReduceDB, bindAt++, (double)stats_extra.discounted_uip1_used2); + sqlite3_bind_double(stmtReduceDB, bindAt++, (double)stats_extra.discounted_props_made2); + sqlite3_bind_double(stmtReduceDB, bindAt++, (double)stats_extra.discounted_uip1_used3); + sqlite3_bind_double(stmtReduceDB, bindAt++, (double)stats_extra.discounted_props_made3); + + run_sqlite_step(stmtReduceDB, "reduceDB", bindAt); +} + +void SQLiteStats::clause_stats( + const Solver* solver + , uint64_t clid + , const uint64_t restartID + , uint32_t glue + , uint32_t glue_before_minim + , uint32_t size + , uint32_t size_before_minim + , uint32_t backtrack_level + , AtecedentData antec_data + , size_t decision_level + , size_t trail_depth + , uint64_t conflicts_this_restart + , const uint32_t restart_type + , const SearchHist& hist + , const bool is_decision + , const uint32_t orig_connects_num_communities +) { + uint32_t num_overlap_literals = antec_data.sum_size()-(antec_data.num()-1)-size; + + int bindAt = 1; + sqlite3_bind_int64(stmt_clause_stats, bindAt++, solver->get_solve_stats().num_simplify); + sqlite3_bind_int64(stmt_clause_stats, bindAt++, solver->sumRestarts()); + if (solver->sumRestarts() == 0) { + sqlite3_bind_int64(stmt_clause_stats, bindAt++, 0); + } else { + sqlite3_bind_int64(stmt_clause_stats, bindAt++, solver->sumRestarts()-1); + } + sqlite3_bind_int64 (stmt_clause_stats, bindAt++, solver->sumConflicts); + sqlite3_bind_int (stmt_clause_stats, bindAt++, solver->latest_satzilla_feature_calc); + sqlite3_bind_int64 (stmt_clause_stats, bindAt++, clid); + sqlite3_bind_int (stmt_clause_stats, bindAt++, restartID); + + sqlite3_bind_int (stmt_clause_stats, bindAt++, glue); + sqlite3_bind_int (stmt_clause_stats, bindAt++, glue_before_minim); + sqlite3_bind_int (stmt_clause_stats, bindAt++, size); + sqlite3_bind_int (stmt_clause_stats, bindAt++, size_before_minim); + sqlite3_bind_int64 (stmt_clause_stats, bindAt++, conflicts_this_restart); + sqlite3_bind_int (stmt_clause_stats, bindAt++, num_overlap_literals); + sqlite3_bind_int (stmt_clause_stats, bindAt++, antec_data.num()); + sqlite3_bind_int (stmt_clause_stats, bindAt++, antec_data.sum_size()); + sqlite3_bind_int (stmt_clause_stats, bindAt++, is_decision); + + sqlite3_bind_int (stmt_clause_stats, bindAt++, backtrack_level); + sqlite3_bind_int64 (stmt_clause_stats, bindAt++, decision_level); + sqlite3_bind_int64 (stmt_clause_stats, bindAt++, hist.branchDepthHistQueue.prev(1)); + sqlite3_bind_int64 (stmt_clause_stats, bindAt++, hist.branchDepthHistQueue.prev(2)); + sqlite3_bind_int64 (stmt_clause_stats, bindAt++, trail_depth); + sqlite3_bind_int (stmt_clause_stats, bindAt++, restart_type); + + sqlite3_bind_int (stmt_clause_stats, bindAt++, antec_data.binIrred); + sqlite3_bind_int (stmt_clause_stats, bindAt++, antec_data.binRed); + sqlite3_bind_int (stmt_clause_stats, bindAt++, antec_data.longIrred); + sqlite3_bind_int (stmt_clause_stats, bindAt++, antec_data.longRed); + + bind_null_or_double(stmt_clause_stats, bindAt, hist.decisionLevelHistLT,avg) + bind_null_or_double(stmt_clause_stats, bindAt, hist.backtrackLevelHistLT,avg) + bind_null_or_double(stmt_clause_stats, bindAt, hist.trailDepthHistLT,avg) + bind_null_or_double(stmt_clause_stats, bindAt, hist.conflSizeHistLT,avg) + bind_null_or_double(stmt_clause_stats, bindAt, hist.glueHistLT,avg) + bind_null_or_double(stmt_clause_stats, bindAt, hist.connects_num_communities_histLT,avg) + bind_null_or_double(stmt_clause_stats, bindAt, hist.numResolutionsHistLT,avg) + + bind_null_or_double(stmt_clause_stats, bindAt, hist.antec_data_sum_sizeHistLT,avg) + bind_null_or_double(stmt_clause_stats, bindAt, hist.overlapHistLT,avg) + + bind_null_or_double(stmt_clause_stats, bindAt, hist.branchDepthHistQueue,avg_nocheck) + bind_null_or_double(stmt_clause_stats, bindAt, hist.trailDepthHist,avg_nocheck) + bind_null_or_double(stmt_clause_stats, bindAt, hist.trailDepthHistLonger,avg_nocheck) + bind_null_or_double(stmt_clause_stats, bindAt, hist.numResolutionsHist,avg) + bind_null_or_double(stmt_clause_stats, bindAt, hist.conflSizeHist,avg) + bind_null_or_double(stmt_clause_stats, bindAt, hist.trailDepthDeltaHist,avg) + bind_null_or_double(stmt_clause_stats, bindAt, hist.backtrackLevelHist,avg_nocheck) + bind_null_or_double(stmt_clause_stats, bindAt, hist.glueHist,avg_nocheck) + bind_null_or_double(stmt_clause_stats, bindAt, hist.glueHist.getLongtTerm(),avg) + sqlite3_bind_int (stmt_clause_stats, bindAt++, orig_connects_num_communities); + + run_sqlite_step(stmt_clause_stats, "clause_stats", bindAt); +} + +#ifdef STATS_NEEDED_BRANCH +void SQLiteStats::var_data_fintime( + const Solver* solver + , const uint32_t var + , const VarData& vardata + , const double rel_activity +) { + int bindAt = 1; + sqlite3_bind_int (stmt_var_data_fintime, bindAt++, var); + sqlite3_bind_int64 (stmt_var_data_fintime, bindAt++, vardata.sumConflicts_at_picktime); + + sqlite3_bind_double (stmt_var_data_fintime, bindAt++, rel_activity); + + sqlite3_bind_int64 (stmt_var_data_fintime, bindAt++, vardata.inside_conflict_clause); + sqlite3_bind_int64 (stmt_var_data_fintime, bindAt++, vardata.inside_conflict_clause_antecedents); + sqlite3_bind_int64 (stmt_var_data_fintime, bindAt++, vardata.inside_conflict_clause_glue); + + sqlite3_bind_int64 (stmt_var_data_fintime, bindAt++, solver->sumDecisions); + sqlite3_bind_int64 (stmt_var_data_fintime, bindAt++, solver->sumConflicts); + sqlite3_bind_int64 (stmt_var_data_fintime, bindAt++, solver->sumPropagations); + sqlite3_bind_int64 (stmt_var_data_fintime, bindAt++, solver->sumAntecedents); + sqlite3_bind_int64 (stmt_var_data_fintime, bindAt++, solver->sumAntecedentsLits); + sqlite3_bind_int64 (stmt_var_data_fintime, bindAt++, solver->sumConflictClauseLits); + sqlite3_bind_int64 (stmt_var_data_fintime, bindAt++, solver->sumDecisionBasedCl); + sqlite3_bind_int64 (stmt_var_data_fintime, bindAt++, solver->sumClLBD); + sqlite3_bind_int64 (stmt_var_data_fintime, bindAt++, solver->sumClSize); + + run_sqlite_step(stmt_var_data_fintime, "var_data_fintime"); +} + +void SQLiteStats::var_data_picktime( + const Solver* solver + , const uint32_t var + , const VarData& vardata + , const double rel_activity +) { + int bindAt = 1; + sqlite3_bind_int (stmt_var_data_picktime, bindAt++, var); + sqlite3_bind_int64 (stmt_var_data_picktime, bindAt++, vardata.level); + sqlite3_bind_double(stmt_var_data_picktime, bindAt++, rel_activity); + sqlite3_bind_int64 (stmt_var_data_picktime, bindAt++, solver->latest_vardist_feature_calc); + + sqlite3_bind_int64 (stmt_var_data_picktime, bindAt++, vardata.inside_conflict_clause); + sqlite3_bind_int64 (stmt_var_data_picktime, bindAt++, vardata.inside_conflict_clause_antecedents); + sqlite3_bind_int64 (stmt_var_data_picktime, bindAt++, vardata.inside_conflict_clause_glue); + + sqlite3_bind_int64 (stmt_var_data_picktime, bindAt++, vardata.inside_conflict_clause_during); + sqlite3_bind_int64 (stmt_var_data_picktime, bindAt++, vardata.inside_conflict_clause_antecedents_during); + sqlite3_bind_int64 (stmt_var_data_picktime, bindAt++, vardata.inside_conflict_clause_glue_during); + + + sqlite3_bind_int64 (stmt_var_data_picktime, bindAt++, vardata.num_decided); + sqlite3_bind_int64 (stmt_var_data_picktime, bindAt++, vardata.num_decided_pos); + sqlite3_bind_int64 (stmt_var_data_picktime, bindAt++, vardata.num_propagated); + sqlite3_bind_int64 (stmt_var_data_picktime, bindAt++, vardata.num_propagated_pos); + + sqlite3_bind_int64 (stmt_var_data_picktime, bindAt++, solver->sumConflicts-vardata.last_seen_in_1uip); + sqlite3_bind_int64 (stmt_var_data_picktime, bindAt++, solver->sumConflicts-vardata.last_decided_on); + sqlite3_bind_int64 (stmt_var_data_picktime, bindAt++, solver->sumConflicts-vardata.last_propagated); + sqlite3_bind_int64 (stmt_var_data_picktime, bindAt++, solver->sumConflicts-vardata.last_canceled); + + + sqlite3_bind_int64 (stmt_var_data_picktime, bindAt++, solver->sumDecisions); + sqlite3_bind_int64 (stmt_var_data_picktime, bindAt++, solver->sumConflicts); + sqlite3_bind_int64 (stmt_var_data_picktime, bindAt++, solver->sumPropagations); + sqlite3_bind_int64 (stmt_var_data_picktime, bindAt++, solver->sumAntecedents); + sqlite3_bind_int64 (stmt_var_data_picktime, bindAt++, solver->sumAntecedentsLits); + sqlite3_bind_int64 (stmt_var_data_picktime, bindAt++, solver->sumConflictClauseLits); + sqlite3_bind_int64 (stmt_var_data_picktime, bindAt++, solver->sumDecisionBasedCl); + sqlite3_bind_int64 (stmt_var_data_picktime, bindAt++, solver->sumClLBD); + sqlite3_bind_int64 (stmt_var_data_picktime, bindAt++, solver->sumClSize); + + sqlite3_bind_int64 (stmt_var_data_picktime, bindAt++, vardata.sumConflicts_below_during); + sqlite3_bind_int64 (stmt_var_data_picktime, bindAt++, vardata.sumDecisions_below_during); + sqlite3_bind_int64 (stmt_var_data_picktime, bindAt++, vardata.sumPropagations_below_during); + sqlite3_bind_int64 (stmt_var_data_picktime, bindAt++, vardata.sumAntecedents_below_during); + sqlite3_bind_int64 (stmt_var_data_picktime, bindAt++, vardata.sumAntecedentsLits_below_during); + sqlite3_bind_int64 (stmt_var_data_picktime, bindAt++, vardata.sumConflictClauseLits_below_during); + sqlite3_bind_int64 (stmt_var_data_picktime, bindAt++, vardata.sumDecisionBasedCl_below_during); + sqlite3_bind_int64 (stmt_var_data_picktime, bindAt++, vardata.sumClLBD_below_during); + sqlite3_bind_int64 (stmt_var_data_picktime, bindAt++, vardata.sumClSize_below_during); + + sqlite3_bind_int64 (stmt_var_data_picktime, bindAt++, solver->sumConflicts-vardata.last_flipped); + + run_sqlite_step(stmt_var_data_picktime, "var_data_picktime"); +} + +void SQLiteStats::var_dist( + const uint32_t var + , const VarData2& data + , const Solver* solver +) { + int bindAt = 1; + sqlite3_bind_int(stmt_var_dist, bindAt++, var); + sqlite3_bind_int64(stmt_var_dist, bindAt++, solver->latest_vardist_feature_calc); + sqlite3_bind_int64(stmt_var_dist, bindAt++, solver->sumConflicts); + + sqlite3_bind_int64(stmt_var_dist, bindAt++, solver->longIrredCls.size()); + uint32_t num = 0; + for(auto& x: solver->longRedCls) { + num+=x.size(); + } + sqlite3_bind_int64(stmt_var_dist, bindAt++, num); + sqlite3_bind_int64(stmt_var_dist, bindAt++, solver->binTri.irredBins); + sqlite3_bind_int64(stmt_var_dist, bindAt++, solver->binTri.redBins); + + + sqlite3_bind_int64(stmt_var_dist, bindAt++, data.red.num_times_in_bin_clause); + sqlite3_bind_int64(stmt_var_dist, bindAt++, data.red.num_times_in_long_clause); + sqlite3_bind_int64(stmt_var_dist, bindAt++, data.red.satisfies_cl); + sqlite3_bind_int64(stmt_var_dist, bindAt++, data.red.falsifies_cl); + sqlite3_bind_int64(stmt_var_dist, bindAt++, data.red.tot_num_lit_of_bin_it_appears_in); + sqlite3_bind_int64(stmt_var_dist, bindAt++, data.red.tot_num_lit_of_long_cls_it_appears_in); + sqlite3_bind_double(stmt_var_dist, bindAt++, data.red.sum_var_act_of_cls); + + sqlite3_bind_int64(stmt_var_dist, bindAt++, data.irred.num_times_in_bin_clause); + sqlite3_bind_int64(stmt_var_dist, bindAt++, data.irred.num_times_in_long_clause); + sqlite3_bind_int64(stmt_var_dist, bindAt++, data.irred.satisfies_cl); + sqlite3_bind_int64(stmt_var_dist, bindAt++, data.irred.falsifies_cl); + sqlite3_bind_int64(stmt_var_dist, bindAt++, data.irred.tot_num_lit_of_bin_it_appears_in); + sqlite3_bind_int64(stmt_var_dist, bindAt++, data.irred.tot_num_lit_of_long_cls_it_appears_in); + sqlite3_bind_double(stmt_var_dist, bindAt++, data.irred.sum_var_act_of_cls); + + sqlite3_bind_double(stmt_var_dist, bindAt++, data.tot_act_long_red_cls); + + run_sqlite_step(stmt_var_dist, "var_dist"); +} + +void SQLiteStats::dec_var_clid( + const uint32_t var + , const uint64_t sumConflicts_at_picktime + , const uint64_t clid +) { + assert(clid != 0); + + int bindAt = 1; + sqlite3_bind_int(stmt_dec_var_clid, bindAt++, var); + sqlite3_bind_int64(stmt_dec_var_clid, bindAt++, sumConflicts_at_picktime); + sqlite3_bind_int64(stmt_dec_var_clid, bindAt++, clid); + + run_sqlite_step(stmt_dec_var_clid, "dec_var_clid"); +} +#endif + +void SQLiteStats::cl_last_in_solver( + const Solver* solver + , const uint64_t clid) +{ + assert(clid != 0); + + int bindAt = 1; + sqlite3_bind_int64(stmt_delete_cl, bindAt++, solver->sumConflicts); + sqlite3_bind_int64(stmt_delete_cl, bindAt++, clid); + + run_sqlite_step(stmt_delete_cl, "cl_last_in_solver", bindAt); +} + +void SQLiteStats::update_id( + const uint32_t old_id, + const uint32_t new_id) +{ + assert(old_id != 0); + assert(new_id != 0); + assert((new_id == old_id || new_id > old_id) && "not neccessary, but I think we have this always"); + + int bindAt = 1; + sqlite3_bind_int64(stmt_update_id, bindAt++, old_id); + sqlite3_bind_int64(stmt_update_id, bindAt++, new_id); + + run_sqlite_step(stmt_update_id, "update_id", bindAt); +} + + +#endif diff --git a/cryptominisat/cppsrc/src/sqlitestats.h b/cryptominisat/cppsrc/src/sqlitestats.h new file mode 100644 index 00000000..c48656de --- /dev/null +++ b/cryptominisat/cppsrc/src/sqlitestats.h @@ -0,0 +1,224 @@ +/****************************************** +Copyright (C) 2009-2020 Authors of CryptoMiniSat, see AUTHORS file + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. +***********************************************/ + +#ifndef SQLITESTATS_H__ +#define SQLITESTATS_H__ + +#include "sqlstats.h" +#include +#include +#include + +using std::pair; + +#ifdef STATS_NEEDED +#include "satzilla_features.h" +#endif + +namespace CMSat { + +class SQLiteStats: public SQLStats +{ +public: + virtual ~SQLiteStats() override; + explicit SQLiteStats(const std::string& _filename); + + void end_transaction() override; + void begin_transaction() override; + + void time_passed( + const Solver* solver + , const string& name + , double time_passed + , bool time_out + , double percent_time_remain + ) override; + + void time_passed_min( + const Solver* solver + , const string& name + , double time_passed + ) override; + + void mem_used( + const Solver* solver + , const string& name + , double given_time + , uint64_t mem_used_mb + ) override; + + vector> id_conf_cache; + void dump_id_confl_cache(); + virtual void set_id_confl( + const int32_t id + , const uint64_t sumConflicts + ) override; + + #ifdef STATS_NEEDED + void satzilla_features( + const Solver* solver + , const Searcher* search + , const SatZillaFeatures& satzilla_feat + ) override; + + virtual void restart( + const uint32_t restartID + , const Restart rest_type + , const PropStats& thisPropStats + , const SearchStats& thisStats + , const Solver* solver + , const Searcher* searcher + , const rst_dat_type type + , const int64_t clauseID + ) override; + + virtual void reduceDB_common( + const Solver* solver, + const uint32_t reduceDB_called, + const uint32_t tot_cls_in_db, + const uint32_t cur_rst_type, + const MedianCommonDataRDB& median_data, + const AverageCommonDataRDB& avg_data + ) override; + + virtual void reduceDB( + const Solver* solver + , const bool locked + , const Clause* cl + , const uint32_t reduceDB_called + ) override; + + virtual void cl_last_in_solver( + const Solver* solver + , const uint64_t clid + ) override; + + virtual void update_id( + const uint32_t old_id + , const uint32_t new_id + ) override; + + void clause_stats( + const Solver* solver + , uint64_t clid + , const uint64_t restartID + , uint32_t glue + , uint32_t glue_before_minim + , uint32_t size + , uint32_t size_before_minim + , const uint32_t backtrack_level + , AtecedentData resoltypes + , size_t decision_level + , size_t trail_depth + , uint64_t conflicts_this_restart + , const uint32_t rest_type + , const SearchHist& hist + , const bool is_decision + , const uint32_t orig_connects_num_communities + ) override; + + #ifdef STATS_NEEDED_BRANCH + void var_data_picktime( + const Solver* solver + , const uint32_t var + , const VarData& vardata + , const double rel_activity + ) override; + + void var_data_fintime( + const Solver* solver + , const uint32_t var + , const VarData& vardata + , const double rel_activity + ) override; + + void dec_var_clid( + const uint32_t var + , const uint64_t sumConflicts_at_picktime + , const uint64_t clid + ) override; + + void var_dist( + const uint32_t var + , const VarData2& data + , const Solver* solver + ) override; + #endif + #endif + + bool setup(const Solver* solver) override; + void finishup(lbool status) override; + void add_tag(const std::pair& tag) override; + +private: + + bool connectServer(const Solver* solver); + bool add_solverrun(const Solver* solver); + void init(const char* name, sqlite3_stmt** stmt, uint32_t num = 1); + vector get_columns(const char* tablename); + + void addStartupData(); + void del_prepared_stmt(sqlite3_stmt* stmt); + void initRestartSTMT(const char* tablename, sqlite3_stmt** stmt); + void initTimePassedSTMT(); + void init_cl_last_in_solver_STMT(); + void initMemUsedSTMT(); + void init_clause_stats_STMT(); + void init_var_data_picktime_STMT(); + void init_var_data_fintime_STMT(); + void init_dec_var_clid_STMT(); + void run_sqlite_step( + sqlite3_stmt* stmt, + const char* name, + const uint32_t bindAt); + + void writeQuestionMarks(size_t num, std::stringstream& ss); + void initReduceDBSTMT(); + + sqlite3_stmt *stmtTimePassed = NULL; + sqlite3_stmt *stmtMemUsed = NULL; + sqlite3_stmt *stmtReduceDB = NULL; + sqlite3_stmt *stmtReduceDB_common = NULL; + sqlite3_stmt *stmtRst = NULL; + sqlite3_stmt *stmtVarRst = NULL; + sqlite3_stmt *stmtClRst = NULL; + sqlite3_stmt *stmtFeat = NULL; + sqlite3_stmt *stmt_clause_stats = NULL; + sqlite3_stmt *stmt_delete_cl = NULL; + sqlite3_stmt *stmt_update_id = NULL; + sqlite3_stmt *stmt_set_id_confl = NULL; + sqlite3_stmt *stmt_set_id_confl_1000 = NULL; + sqlite3_stmt *stmt_var_data_fintime = NULL; + sqlite3_stmt *stmt_var_data_picktime = NULL; + sqlite3_stmt *stmt_dec_var_clid = NULL; + sqlite3_stmt *stmt_var_dist = NULL; + + std::map query_to_size; + + sqlite3 *db = NULL; + bool setup_ok = false; + const string filename; +}; + +} + +#endif diff --git a/cryptominisat/cppsrc/src/sqlstats.cpp b/cryptominisat/cppsrc/src/sqlstats.cpp new file mode 100644 index 00000000..4f9cdab2 --- /dev/null +++ b/cryptominisat/cppsrc/src/sqlstats.cpp @@ -0,0 +1,28 @@ +/****************************************** +Copyright (C) 2009-2020 Authors of CryptoMiniSat, see AUTHORS file + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. +***********************************************/ + +#include "sqlstats.h" + +using namespace CMSat; + +SQLStats::~SQLStats() +{} diff --git a/cryptominisat/cppsrc/src/sqlstats.h b/cryptominisat/cppsrc/src/sqlstats.h new file mode 100644 index 00000000..f243a254 --- /dev/null +++ b/cryptominisat/cppsrc/src/sqlstats.h @@ -0,0 +1,174 @@ +/****************************************** +Copyright (C) 2009-2020 Authors of CryptoMiniSat, see AUTHORS file + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. +***********************************************/ + +#ifndef __SQLSTATS_H__ +#define __SQLSTATS_H__ + +#include "searchstats.h" +#include "vardata.h" +#include "searchhist.h" + +#ifdef STATS_NEEDED +#include "satzilla_features.h" +#endif + +namespace CMSat { + +class Solver; +class Searcher; +class Clause; + +class SQLStats +{ +public: + + virtual ~SQLStats(); + + virtual void end_transaction() = 0; + virtual void begin_transaction() = 0; + + virtual void time_passed( + const Solver* solver + , const string& name + , double time_passed + , bool time_out + , double percent_time_remain + ) = 0; + + virtual void time_passed_min( + const Solver* solver + , const string& name + , double time_passed + ) = 0; + + virtual void mem_used( + const Solver* solver + , const string& name + , const double given_time + , uint64_t mem_used_mb + ) = 0; + + virtual void set_id_confl( + const int32_t id + , const uint64_t sumConflicts + ) = 0; + + #ifdef STATS_NEEDED + virtual void satzilla_features( + const Solver* solver + , const Searcher* search + , const SatZillaFeatures& satzilla_feat + ) = 0; + + virtual void restart( + const uint32_t restartID + , const Restart rest_type + , const PropStats& thisPropStats + , const SearchStats& thisStats + , const Solver* solver + , const Searcher* searcher + , const rst_dat_type type + , const int64_t clauseID = -1 + ) = 0; + + virtual void reduceDB( + const Solver* solver + , const bool locked + , const Clause* cl + , const uint32_t reduceDB_called + ) = 0; + + virtual void reduceDB_common( + const Solver* solver, + const uint32_t reduceDB_called, + const uint32_t tot_cls_in_db, + const uint32_t cur_rst_type, + const MedianCommonDataRDB& median_data, + const AverageCommonDataRDB& avg_data + ) = 0; + + #ifdef STATS_NEEDED_BRANCH + virtual void var_data_picktime( + const Solver* solver + , const uint32_t var + , const VarData& vardata + , const double rel_activity + ) = 0; + + virtual void var_data_fintime( + const Solver* solver + , const uint32_t var + , const VarData& vardata + , const double rel_activity + ) = 0; + + virtual void dec_var_clid( + const uint32_t var + , const uint64_t sumConflicts_at_picktime + , const uint64_t clid + ) = 0; + + virtual void var_dist( + const uint32_t var + , const VarData2& data + , const Solver* solver + ) = 0; + #endif + + virtual void cl_last_in_solver( + const Solver* solver + , const uint64_t clid + ) = 0; + + virtual void update_id( + const uint32_t old_id + , const uint32_t new_id + ) = 0; + + virtual void clause_stats( + const Solver* solver + , uint64_t clid + , uint64_t restartID + , uint32_t glue + , uint32_t glue_before_minim + , uint32_t size + , uint32_t size_before_minim + , uint32_t backtrack_level + , AtecedentData resoltypes + , size_t decision_level + , size_t trail_depth + , uint64_t conflicts_this_restart + , const uint32_t restart_type + , const SearchHist& hist + , const bool is_decision + , const uint32_t orig_connects_num_communities + ) = 0; + #endif + + virtual bool setup(const Solver* solver) = 0; + virtual void finishup(lbool status) = 0; + virtual void add_tag(const std::pair& tag) = 0; +}; + +} //end namespace + +#endif //__SQLSTATS_H__ diff --git a/cryptominisat/cppsrc/src/str_impl_w_impl.cpp b/cryptominisat/cppsrc/src/str_impl_w_impl.cpp new file mode 100644 index 00000000..eadc4241 --- /dev/null +++ b/cryptominisat/cppsrc/src/str_impl_w_impl.cpp @@ -0,0 +1,212 @@ +/****************************************** +Copyright (C) 2009-2020 Authors of CryptoMiniSat, see AUTHORS file + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. +***********************************************/ + +#include "str_impl_w_impl.h" +#include "clausecleaner.h" +#include "time_mem.h" +#include "solver.h" +#include "watchalgos.h" +#include "clauseallocator.h" +#include "sqlstats.h" + +using namespace CMSat; + +bool StrImplWImpl::str_impl_w_impl() +{ + #ifdef DEBUG_IMPLICIT_STATS + solver->check_stats(); + #endif + + str_impl_data.clear(); + + const size_t origTrailSize = solver->trail_size(); + timeAvailable = + solver->conf.distill_implicit_with_implicit_time_limitM*1000LL*1000LL + *solver->conf.global_timeout_multiplier; + const int64_t orig_time = timeAvailable; + double myTime = cpuTime(); + + //Cannot handle empty + if (solver->watches.size() == 0) + return solver->okay(); + + //Randomize starting point + size_t upI = rnd_uint(solver->mtrand, solver->watches.size()-1); + size_t numDone = 0; + for (; numDone < solver->watches.size() && timeAvailable > 0 + ; upI = (upI +1) % solver->watches.size(), numDone++ + + ) { + str_impl_data.numWatchesLooked++; + const Lit lit = Lit::toLit(upI); + distill_implicit_with_implicit_lit(lit); + } + + //Enqueue delayed values + if (!solver->fully_enqueue_these(str_impl_data.toEnqueue)) + goto end; + + //Add delayed binary clauses + for(const BinaryClause& bin: str_impl_data.binsToAdd) { + lits.clear(); + lits.push_back(bin.getLit1()); + lits.push_back(bin.getLit2()); + timeAvailable -= 5; + solver->add_clause_int(lits, bin.isRed()); + if (!solver->okay()) + goto end; + } + +end: + + if (solver->conf.verbosity) { + str_impl_data.print( + solver->trail_size() - origTrailSize + , cpuTime() - myTime + , timeAvailable + , orig_time + , solver + ); + } + #ifdef DEBUG_IMPLICIT_STATS + solver->check_stats(); + #endif + + return solver->okay(); +} + +void StrImplWImpl::distill_implicit_with_implicit_lit(const Lit lit) +{ + watch_subarray ws = solver->watches[lit]; + + Watched* i = ws.begin(); + Watched* j = i; + for (const Watched* end = ws.end() + ; i != end + ; i++ + ) { + timeAvailable -= 2; + if (timeAvailable < 0) { + *j++ = *i; + continue; + } + + switch(i->getType()) { + case WatchType::watch_clause_t: + case WatchType::watch_bnn_t: + *j++ = *i; + break; + + case WatchType::watch_binary_t: + timeAvailable -= 20; + strengthen_bin_with_bin(lit, i, j, end); + break; + + default: + assert(false); + break; + } + } + ws.shrink(i-j); +} + +void StrImplWImpl::strengthen_bin_with_bin( + const Lit lit + , Watched* i + , Watched*& j + , const Watched* end +) { + lits.clear(); + lits.push_back(lit); + lits.push_back(i->lit2()); + + //If inverted, then the inverse will never be found, because + //watches are sorted + if (i->lit2().sign()) { + *j++ = *i; + return; + } + + //Try to look for a binary in this same watchlist + //that has ~i->lit2() inside. Everything is sorted, so we are + //lucky, this is speedy + bool rem = false; + const Watched* i2 = i; + while(i2 != end + && i2->isBin() + && i->lit2().var() == i2->lit2().var() + ) { + timeAvailable -= 2; + //Yay, we have found what we needed! + if (i2->lit2() == ~i->lit2()) { + rem = true; + break; + } + + i2++; + } + + //Enqeue literal + if (rem) { + str_impl_data.remLitFromBin++; + str_impl_data.toEnqueue.push_back(lit); + } + *j++ = *i; +} + +void StrImplWImpl::StrImplicitData::print( + const size_t trail_diff + , const double time_used + , const int64_t timeAvailable + , const int64_t orig_time + , Solver* _solver +) const { + bool time_out = timeAvailable <= 0; + const double time_remain = float_div(timeAvailable, orig_time); + + cout + << "c [impl-str]" + << " lit bin: " << remLitFromBin + << " set-var: " << trail_diff + << _solver->conf.print_times(time_used, time_out, time_remain) + << " w-visit: " << numWatchesLooked + << endl; + + if (_solver->sqlStats) { + _solver->sqlStats->time_passed( + _solver + , "implicit str" + , time_used + , time_out + , time_remain + ); + } +} + +double StrImplWImpl::mem_used() const +{ + double mem = sizeof(StrImplWImpl); + mem += lits.size()*sizeof(Lit); + + return mem; + +} diff --git a/cryptominisat/cppsrc/src/str_impl_w_impl.h b/cryptominisat/cppsrc/src/str_impl_w_impl.h new file mode 100644 index 00000000..430e621a --- /dev/null +++ b/cryptominisat/cppsrc/src/str_impl_w_impl.h @@ -0,0 +1,91 @@ +/****************************************** +Copyright (C) 2009-2020 Authors of CryptoMiniSat, see AUTHORS file + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. +***********************************************/ + +#ifndef __DISTILLER_IMPL_WITH_IMP__ +#define __DISTILLER_IMPL_WITH_IMP__ + +#include +#include "clause.h" +#include "constants.h" +#include "solvertypes.h" +#include "cloffset.h" +#include "watcharray.h" +using std::vector; + +namespace CMSat { + +class Solver; +class Clause; + +class StrImplWImpl { +public: + explicit StrImplWImpl(Solver* _solver) : + solver(_solver) + {} + + bool str_impl_w_impl(); + double mem_used() const; + +private: + Solver* solver; + void distill_implicit_with_implicit_lit(const Lit lit); + + void strengthen_bin_with_bin( + const Lit lit + , Watched* i + , Watched*& j + , const Watched* end + ); + + //Vars for strengthen implicit + struct StrImplicitData + { + uint64_t remLitFromBin = 0; + uint64_t numWatchesLooked = 0; + + //For delayed enqueue and binary adding + //Used for strengthening + vector toEnqueue; + vector binsToAdd; + + void clear() + { + StrImplicitData tmp; + *this = tmp; + } + + void print( + const size_t trail_diff + , const double time_used + , const int64_t timeAvailable + , const int64_t orig_time + , Solver* solver + ) const; + }; + StrImplicitData str_impl_data; + int64_t timeAvailable; + vector lits; +}; + +} + +#endif // __DISTILLER_IMPL_WITH_IMP__ diff --git a/cryptominisat/cppsrc/src/streambuffer.h b/cryptominisat/cppsrc/src/streambuffer.h new file mode 100644 index 00000000..a2e50ecb --- /dev/null +++ b/cryptominisat/cppsrc/src/streambuffer.h @@ -0,0 +1,236 @@ +/******************************************************************************* +MiniSat -- Copyright (c) 2003-2006, Niklas Een, Niklas Sorensson + +Permission is hereby granted, free of charge, to any person obtaining a copy of this software and +associated documentation files (the "Software"), to deal in the Software without restriction, +including without limitation the rights to use, copy, modify, merge, publish, distribute, +sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all copies or +substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT +NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, +DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT +OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +*******************************************************************************/ + +#pragma once + +#include +#include +#include +#include +#include +#include +#include + +using std::numeric_limits; + +#ifdef USE_ZLIB +#include +namespace CMSat { +struct GZ { + static inline int read(void* buf, size_t num, size_t count, gzFile f) + { + return gzread(f, buf, num*count); + } +}; +} +#endif + +namespace CMSat { +static const unsigned chunk_limit = 148576; + +struct FN { + static inline int read(void* buf, size_t num, size_t count, FILE* f) + { + return fread(buf, num, count, f); + } +}; + +struct CH { + static inline int read(void* buf, size_t num, size_t count, const char*& f) + { + int toread = num*count; + char* mybuf = (char*)buf; + + int read = 0; + while(*f != 0 && read < toread) { + *mybuf = *f; + mybuf++; + f++; + read++; + } + return read; + } +}; + +template +class StreamBuffer +{ + A in; + void assureLookahead() { + if (pos >= size) { + pos = 0; + size = B::read(buf.get(), 1, chunk_limit, in); + } + } + int pos; + int size; + std::unique_ptr buf; + + void advance() + { + operator++(); + } + int value() + { + return operator*(); + } + +public: + StreamBuffer(A i) : + in(i) + , pos(0) + , size(0) + , buf(new char[chunk_limit]()) + { + assureLookahead(); + } + + int operator * () { + return (pos >= size) ? EOF : buf[pos]; + } + void operator ++ () { + pos++; + assureLookahead(); + } + + void skipWhitespace() + { + char c = value(); + while (c == '\t' || c == '\r' || c == ' ') { + advance(); + c = value(); + } + } + + void skipLine() + { + for (;;) { + if (value() == EOF || value() == '\0') return; + if (value() == '\n') { + advance(); + return; + } + advance(); + } + } + + bool skipEOL(const size_t lineNum) + { + for (;;) { + if (value() == EOF || value() == '\0') return true; + if (value() == '\n') { + advance(); + return true; + } + if (value() != '\r') { + std::cerr + << "PARSE ERROR! Unexpected char (hex: " << std::hex + << std::setw(2) + << std::setfill('0') + << "0x" << value() + << std::setfill(' ') + << std::dec + << ")" + << " At line " << lineNum+1 + << " we expected an end of line character (\\n or \\r + \\n)" + << std::endl; + return false; + } + advance(); + } + exit(-1); + } + + inline bool parseDouble(double& ret, size_t lineNum) + { + int32_t head; + bool rc = parseInt(head, lineNum); + if (!rc) { + return false; + } + if (value() == '.') { + advance(); + int64_t tail; + rc = parseInt(tail, lineNum); + if (!rc) { + return false; + } + uint32_t num_10s = std::floor(std::log10(tail)); + ret = head + tail/std::pow(10, num_10s+1); + } else { + ret = head; + } + return true; + } + + template + inline bool parseInt(T& ret, size_t lineNum, bool allow_eol = false) + { + T val = 0; + T mult = 1; + skipWhitespace(); + if (value() == '-') { + mult = -1; + advance(); + } else if (value() == '+') { + advance(); + } + + char c = value(); + if (allow_eol && c == '\n') { + ret = numeric_limits::max(); + return true; + } + if (c < '0' || c > '9') { + std::cerr + << "PARSE ERROR! Unexpected char (dec: '" << c << ")" + << " At line " << lineNum + << " we expected a number" + << std::endl; + return false; + } + + while (c >= '0' && c <= '9') { + T val2 = val*10 + (c - '0'); + if (val2 < val) { + std::cerr << "PARSE ERROR! At line " << lineNum + << " the variable number is to high" + << std::endl; + return false; + } + val = val2; + advance(); + c = value(); + } + ret = mult*val; + return true; + } + + void parseString(std::string& str) + { + str.clear(); + skipWhitespace(); + while (value() != ' ' && value() != '\n' && value() != EOF) { + str.push_back(value()); + advance(); + } + } +}; + +} diff --git a/cryptominisat/cppsrc/src/subsumeimplicit.cpp b/cryptominisat/cppsrc/src/subsumeimplicit.cpp new file mode 100644 index 00000000..fa0ef19f --- /dev/null +++ b/cryptominisat/cppsrc/src/subsumeimplicit.cpp @@ -0,0 +1,231 @@ +/****************************************** +Copyright (C) 2009-2020 Authors of CryptoMiniSat, see AUTHORS file + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. +***********************************************/ + +#include "subsumeimplicit.h" +#include "clausecleaner.h" +#include "time_mem.h" +#include "solver.h" +#include "watchalgos.h" +#include "clauseallocator.h" +#include "sqlstats.h" + +#include +#include +using std::cout; +using std::endl; +using namespace CMSat; + +SubsumeImplicit::SubsumeImplicit(Solver* _solver) : + solver(_solver) +{ +} + +void SubsumeImplicit::try_subsume_bin( + const Lit lit + , Watched* i + , Watched*& j + , int64_t *timeAvail + , TouchList* touched +) { + //Subsume bin with bin + if (i->lit2() == lastLit2) { + //The sorting algorithm prefers irred to red, so it is + //impossible to have red before irred + assert(!(i->red() == false && lastRed == true)); + + runStats.remBins++; + assert(i->lit2().var() != lit.var()); + *timeAvail -= 30; + *timeAvail -= solver->watches[i->lit2()].size(); + removeWBin(solver->watches, i->lit2(), lit, i->red(), i->get_ID()); + if (touched) { + touched->touch(i->lit2()); + } + if (i->red()) { + solver->binTri.redBins--; + } else { + solver->binTri.irredBins--; + } + (*solver->frat) << del << i->get_ID() << lit << i->lit2() << fin; + + return; + } else { + lastBin = j; + lastLit2 = i->lit2(); + lastRed = i->red(); + *j++ = *i; + } +} + +uint32_t SubsumeImplicit::subsume_at_watch(const uint32_t at, + int64_t* timeAvail, + TouchList* touched) +{ + runStats.numWatchesLooked++; + const Lit lit = Lit::toLit(at); + watch_subarray ws = solver->watches[lit]; + + if (ws.size() > 1) { + *timeAvail -= (int64_t)(ws.size()*std::ceil(std::log((double)ws.size())) + 20); + std::sort(ws.begin(), ws.end(), WatchSorterBinTriLong()); + } + /*cout << "---> Before" << endl; + print_watch_list(ws, lit);*/ + + Watched* i = ws.begin(); + Watched* j = i; + clear(); + + for (Watched* end = ws.end(); i != end; i++) { + if (*timeAvail < 0) { + *j++ = *i; + continue; + } + + switch(i->getType()) { + case WatchType::watch_clause_t: + case WatchType::watch_bnn_t: + *j++ = *i; + break; + + case WatchType::watch_binary_t: + try_subsume_bin(lit, i, j, timeAvail, touched); + break; + + default: + assert(false); + break; + } + } + ws.shrink(i-j); + return i-j; +} + +void SubsumeImplicit::subsume_implicit(const bool check_stats, std::string caller) +{ + assert(solver->okay()); + const double myTime = cpuTime(); + const uint64_t orig_timeAvailable = + 1000LL*1000LL*solver->conf.subsume_implicit_time_limitM + *solver->conf.global_timeout_multiplier; + timeAvailable = orig_timeAvailable; + runStats.clear(); + *solver->frat << __PRETTY_FUNCTION__ << " start\n"; + + //For randomization, we must have at least 1 + if (solver->watches.size() == 0) { + return; + } + + //Randomize starting point + const size_t rnd_start = rnd_uint(solver->mtrand, solver->watches.size()-1); + size_t numDone = 0; + for (;numDone < solver->watches.size() && timeAvailable > 0 && !solver->must_interrupt_asap() + ;numDone++ + ) { + const size_t at = (rnd_start + numDone) % solver->watches.size(); + subsume_at_watch(at, &timeAvailable); + } + + const double time_used = cpuTime() - myTime; + const bool time_out = (timeAvailable <= 0); + const double time_remain = float_div(timeAvailable, orig_timeAvailable); + runStats.numCalled++; + runStats.time_used += time_used; + runStats.time_out += time_out; + if (solver->conf.verbosity) { + runStats.print_short(solver, caller.c_str()); + } + if (solver->sqlStats) { + solver->sqlStats->time_passed( + solver + , std::string("subsume implicit")+caller + , time_used + , time_out + , time_remain + ); + } + *solver->frat << __PRETTY_FUNCTION__ << " end\n"; + + if (check_stats) { + #ifdef DEBUG_IMPLICIT_STATS + solver->check_stats(); + #endif + } + + globalStats += runStats; +} + +SubsumeImplicit::Stats SubsumeImplicit::Stats::operator+=(const SubsumeImplicit::Stats& other) +{ + numCalled+= other.numCalled; + time_out += other.time_out; + time_used += other.time_used; + remBins += other.remBins; + numWatchesLooked += other.numWatchesLooked; + + return *this; +} + +void SubsumeImplicit::Stats::print_short(const Solver* _solver, const char* caller) const +{ + cout + << "c [impl-sub" << caller << "]" + << " bin: " << remBins + << _solver->conf.print_times(time_used, time_out) + << " w-visit: " << numWatchesLooked + << endl; +} + +void SubsumeImplicit::Stats::print(const char* caller) const +{ + cout << "c -------- IMPLICIT SUB " << caller << " STATS --------" << endl; + print_stats_line("c time" + , time_used + , float_div(time_used, numCalled) + , "per call" + ); + + print_stats_line("c timed out" + , time_out + , stats_line_percent(time_out, numCalled) + , "% of calls" + ); + + print_stats_line("c rem bins" + , remBins + ); + cout << "c -------- IMPLICIT SUB STATS END --------" << endl; +} + +SubsumeImplicit::Stats SubsumeImplicit::get_stats() const +{ + return globalStats; +} + +double SubsumeImplicit::mem_used() const +{ + double mem = sizeof(SubsumeImplicit); + mem += tmplits.size()*sizeof(Lit); + + return mem; +} diff --git a/cryptominisat/cppsrc/src/subsumeimplicit.h b/cryptominisat/cppsrc/src/subsumeimplicit.h new file mode 100644 index 00000000..4885b915 --- /dev/null +++ b/cryptominisat/cppsrc/src/subsumeimplicit.h @@ -0,0 +1,98 @@ +/****************************************** +Copyright (C) 2009-2020 Authors of CryptoMiniSat, see AUTHORS file + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. +***********************************************/ + +#ifndef SUBSUMEIMPLICIT_H +#define SUBSUMEIMPLICIT_H + +#include +#include "clause.h" +#include "constants.h" +#include "solvertypes.h" +#include "cloffset.h" +#include "watcharray.h" +#include "touchlist.h" + +namespace CMSat { + +using std::vector; + +class Solver; +class Clause; + +class SubsumeImplicit +{ +public: + explicit SubsumeImplicit(Solver* solver); + void subsume_implicit(bool check_stats = true, std::string caller = std::string()); + uint32_t subsume_at_watch(const uint32_t at, + int64_t *timeAvail, + TouchList* touched = NULL); + + struct Stats { + void clear() + { + *this = Stats(); + } + Stats operator+=(const Stats& other); + void print_short(const Solver* solver, const char* caller) const; + void print(const char* caller) const; + + double time_used = 0.0; + uint64_t numCalled = 0; + uint64_t time_out = 0; + uint64_t remBins = 0; + uint64_t numWatchesLooked = 0; + }; + Stats get_stats() const; + double mem_used() const; + +private: + Solver* solver; + int64_t timeAvailable; + + Lit lastLit2; + Watched* lastBin; + bool lastRed; + vector tmplits; + Stats runStats; + Stats globalStats; + + void clear() + { + lastLit2 = lit_Undef; + lastBin = NULL; + lastRed = false; + } + + //ImplSubsumeData impl_subs_dat; + void try_subsume_bin( + const Lit lit + , Watched* i + , Watched*& j + , int64_t* timeAvail + , TouchList* touched = NULL + ); +}; + +} //end namespace + +#endif //SUBSUMEIMPLICIT_H diff --git a/cryptominisat/cppsrc/src/subsumestrengthen.cpp b/cryptominisat/cppsrc/src/subsumestrengthen.cpp new file mode 100644 index 00000000..e2a2d64c --- /dev/null +++ b/cryptominisat/cppsrc/src/subsumestrengthen.cpp @@ -0,0 +1,1088 @@ +/****************************************** +Copyright (C) 2009-2020 Authors of CryptoMiniSat, see AUTHORS file + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. +***********************************************/ + +#include "subsumestrengthen.h" +#include "occsimplifier.h" +#include "solver.h" +#include "watchalgos.h" +#include "clauseallocator.h" +#include "sqlstats.h" +#include "solver.h" +#include "solvertypes.h" +#include "subsumeimplicit.h" +#include +#include + +//#define VERBOSE_DEBUG + +using namespace CMSat; + +SubsumeStrengthen::SubsumeStrengthen( + OccSimplifier* _simplifier + , Solver* _solver +) : + simplifier(_simplifier) + , solver(_solver) +{ +} + +Sub0Ret SubsumeStrengthen::backw_sub_with_long(const ClOffset offset) +{ + Clause& cl = *solver->cl_alloc.ptr(offset); + assert(!cl.getRemoved()); + assert(!cl.freed()); + + #ifdef VERBOSE_DEBUG + cout << "subsume-ing with clause: " << cl << endl; + #endif + + Sub0Ret ret = subsume_and_unlink( + offset + , cl + , cl.abst + ); + + //If irred is subsumed by redundant, make the redundant into irred + if (cl.red() && ret.subsumedIrred) { + STATS_DO(solver->stats_del_cl(&cl)); + cl.makeIrred(); + solver->litStats.redLits -= cl.size(); + solver->litStats.irredLits += cl.size(); + if (!cl.getOccurLinked()) { + simplifier->link_in_clause(cl); + } else { + for(const Lit l: cl) { + simplifier->n_occurs[l.toInt()]++; + simplifier->elim_calc_need_update.touch(l); + simplifier->added_cl_to_var.touch(l); + } + } + } + + //Update stats + cl.stats = ClauseStats::combineStats(cl.stats, ret.stats); + #if defined(STATS_NEEDED) || defined (FINAL_PREDICTOR) + if (cl.red()) { + auto& extra_stats = solver->red_stats_extra[cl.stats.extra_pos]; + extra_stats = ClauseStatsExtra::combineStats(extra_stats, ret.stats_extra); + } + #endif + + return ret; +} +template Sub0Ret SubsumeStrengthen::subsume_and_unlink( + const ClOffset offset + , const vector& ps + , const cl_abst_type abs +); + +/** +@brief Backward-subsumption using given clause +*/ +template +Sub0Ret SubsumeStrengthen::subsume_and_unlink( + const ClOffset offset + , const T& ps + , const cl_abst_type abs +) { + Sub0Ret ret; + + subs.clear(); + find_subsumed(offset, ps, abs, subs); + + //Go through each clause that can be subsumed + for (const auto& occ_cl: subs) { + if (!occ_cl.ws.isClause()) { + continue; + } + ClOffset off = occ_cl.ws.get_offset(); + Clause *tmpcl = solver->cl_alloc.ptr(off); + + //-> ID kept will be 1st parameter + //Stats will be merged together here then merged into the + //subsuming clause's stats + ret.stats = ClauseStats::combineStats(tmpcl->stats, ret.stats); + #if defined(STATS_NEEDED) || defined(FINAL_PREDICTOR) + if (tmpcl->red()) { + ret.stats_extra = ClauseStatsExtra::combineStats( + solver->red_stats_extra[tmpcl->stats.extra_pos], + ret.stats_extra); + } + #endif + VERBOSE_PRINT("-> subsume removing:" << *tmpcl); + + ret.subsumedIrred |= !tmpcl->red(); + simplifier->unlink_clause(off, true, false, true); + ret.numSubsumed++; + + //If we are waaay over time, just exit + if (*simplifier->limit_to_decrease < -20LL*1000LL*1000LL) + break; + } + + return ret; +} + +bool SubsumeStrengthen::backw_sub_str_with_long( + const ClOffset offset, + Sub1Ret& ret_sub_str) +{ + subs.clear(); + subsLits.clear(); + Clause& cl = *solver->cl_alloc.ptr(offset); + assert(!cl.getRemoved()); + assert(!cl.freed()); + + if (solver->conf.verbosity >= 6) + cout << "backw_sub_str_with_long-ing with clause:" << cl + << " offset: " << offset << endl; + + find_subsumed_and_strengthened( + offset + , cl + , cl.abst + , subs + , subsLits + ); + + for (size_t j = 0 + ; j < subs.size() && solver->okay() && *simplifier->limit_to_decrease > -20LL*1000LL*1000LL + ; j++ + ) { + assert(subs[j].ws.isClause()); + ClOffset offset2 = subs[j].ws.get_offset(); + Clause& cl2 = *solver->cl_alloc.ptr(offset2); + if (cl2.used_in_xor() && + solver->conf.force_preserve_xors) + { + continue; + } + + if (subsLits[j] == lit_Undef) { //Subsume + VERBOSE_PRINT("subsumed clause " << cl2); + + //If subsumes a irred, and is redundant, make it irred + if (cl.red() + && !cl2.red() + ) { + STATS_DO(solver->stats_del_cl(&cl)); + cl.makeIrred(); + solver->litStats.redLits -= cl.size(); + solver->litStats.irredLits += cl.size(); + if (!cl.getOccurLinked()) { + simplifier->link_in_clause(cl); + } else { + for(const Lit l: cl) { + simplifier->n_occurs[l.toInt()]++; + } + } + } + + //Update stats + cl.stats = ClauseStats::combineStats(cl.stats, cl2.stats); + #if defined(STATS_NEEDED) || defined (FINAL_PREDICTOR) + if (cl.red() && cl2.red()) { + auto& extra_stats = solver->red_stats_extra[cl.stats.extra_pos]; + auto& extra_stats2 = solver->red_stats_extra[cl2.stats.extra_pos]; + extra_stats = ClauseStatsExtra::combineStats(extra_stats, extra_stats2); + } + #endif + + //this will handle touching all vars for elim re-calc + simplifier->unlink_clause(offset2, true, false, true); + ret_sub_str.sub++; + } else { //Strengthen + VERBOSE_PRINT("strenghtened clause " << cl2); + if (cl2.used_in_xor() && + solver->conf.force_preserve_xors) + { + continue; + } + if (!simplifier->remove_literal(offset2, subsLits[j], true)) { + return false; + } + ret_sub_str.str++; + } + } + + return solver->okay(); +} + +void SubsumeStrengthen::backw_sub_long_with_long() +{ + //If clauses are empty, the system below segfaults + if (simplifier->clauses.empty()) + return; + + double myTime = cpuTime(); + size_t wenThrough = 0; + Sub0Ret sub0ret; + const int64_t orig_limit = simplifier->subsumption_time_limit; + std::shuffle(simplifier->clauses.begin(), simplifier->clauses.end(), solver->mtrand); + const size_t max_go_through = + solver->conf.subsume_gothrough_multip*(double)simplifier->clauses.size(); + + while (*simplifier->limit_to_decrease > 0 + && wenThrough < max_go_through + ) { + *simplifier->limit_to_decrease -= 3; + wenThrough++; + + //Print status + if (solver->conf.verbosity >= 5 + && wenThrough % 10000 == 0 + ) { + cout << "toDecrease: " << *simplifier->limit_to_decrease << endl; + } + + const size_t at = wenThrough % simplifier->clauses.size(); + const ClOffset offset = simplifier->clauses[at]; + Clause* cl = solver->cl_alloc.ptr(offset); + + //Has already been removed + if (cl->freed() || cl->getRemoved()) + continue; + + + *simplifier->limit_to_decrease -= 10; + sub0ret += backw_sub_with_long(offset); + } + + const double time_used = cpuTime() - myTime; + const bool time_out = (*simplifier->limit_to_decrease <= 0); + const double time_remain = float_div(*simplifier->limit_to_decrease, orig_limit); + if (solver->conf.verbosity) { + cout + << "c [occ-backw-sub-long-w-long] rem cl: " << sub0ret.numSubsumed + << " tried: " << wenThrough << "/" << simplifier->clauses.size() + << " (" << std::setprecision(1) << std::fixed + << stats_line_percent(wenThrough, simplifier->clauses.size()) + << "%)" + << solver->conf.print_times(time_used, time_out, time_remain) + << endl; + } + if (solver->sqlStats) { + solver->sqlStats->time_passed( + solver + , "occ-backw-sub-long-w-long" + , time_used + , time_out + , time_remain + ); + } + + //Update time used + runStats.sub0 += sub0ret; + runStats.subsumeTime += cpuTime() - myTime; +} + +bool SubsumeStrengthen::backw_str_long_with_long() +{ + assert(solver->ok); + + double myTime = cpuTime(); + size_t wenThrough = 0; + const int64_t orig_limit = *simplifier->limit_to_decrease; + Sub1Ret ret; + + std::shuffle(simplifier->clauses.begin(), simplifier->clauses.end(), solver->mtrand); + while(*simplifier->limit_to_decrease > 0 + && wenThrough < 1.5*(double)2*simplifier->clauses.size() + && solver->okay() + ) { + *simplifier->limit_to_decrease -= 10; + wenThrough++; + + //Print status + if (solver->conf.verbosity >= 5 + && wenThrough % 10000 == 0 + ) { + cout << "toDecrease: " << *simplifier->limit_to_decrease << endl; + } + + const size_t at = wenThrough % simplifier->clauses.size(); + ClOffset offset = simplifier->clauses[at]; + Clause* cl = solver->cl_alloc.ptr(offset); + + //Has already been removed + if (cl->freed() || cl->getRemoved()) + continue; + + if (!backw_sub_str_with_long(offset, ret)) { + return false; + } + + } + + const double time_used = cpuTime() - myTime; + const bool time_out = *simplifier->limit_to_decrease <= 0; + const double time_remain = float_div(*simplifier->limit_to_decrease, orig_limit); + + if (solver->conf.verbosity) { + cout + << "c [occ-backw-sub-str-long-w-long]" + << " sub: " << ret.sub + << " str: " << ret.str + << " tried: " << wenThrough << "/" << simplifier->clauses.size() + << " (" + << stats_line_percent(wenThrough, simplifier->clauses.size()) + << ") " + << solver->conf.print_times(time_used, time_out, time_remain) + << endl; + } + if (solver->sqlStats) { + solver->sqlStats->time_passed( + solver + , "occ-backw-sub-str-long-w-long" + , time_used + , time_out + , time_remain + ); + } + + //Update time used + runStats.sub1 += ret; + runStats.strengthenTime += cpuTime() - myTime; + + return solver->okay(); +} + +/** +@brief Helper function for find_subsumed_and_strengthened + +Used to avoid duplication of code +*/ +template +void inline SubsumeStrengthen::fill_sub_str( + const ClOffset offset + , const T& cl + , const cl_abst_type abs + , vector& out_subsumed + , vector& out_lits + , const Lit lit // this variable is in the "cl", but may be inverted + , bool inverted // whether "lit" is inverted +) { + Lit litSub; + uint32_t num_bin_found = 0; + watch_subarray_const cs = solver->watches[lit]; + + //Do subsume only for the moment + //TODO strengthening + Lit bin_other_lit = lit_Undef; + if (cl.size() == 2) { + if (lit == (cl[0]^inverted)) { + bin_other_lit = cl[1]; + } else if (lit == (cl[1]^inverted)) { + bin_other_lit = cl[0]; + } + } + + *simplifier->limit_to_decrease -= (long)cs.size()*2+ 40; + for (const auto& w: cs) { + if (w.isBin()) { + if (cl.size() > 2) { + continue; + } + + if (w.red()) { + //let's ignore + continue; + } + + if (w.lit2() != bin_other_lit) { + continue; + } + + if (inverted) { + out_subsumed.push_back(OccurClause(lit, w)); + out_lits.push_back(bin_other_lit); + } else { + //Don't delete ourselves + num_bin_found++; + if (num_bin_found <= 1) { + continue; + } + out_subsumed.push_back(OccurClause(lit, w)); + out_lits.push_back(lit_Undef); + } + continue; + } + + assert(w.isClause()); + if (w.get_offset() == offset + || !subsetAbst(abs, w.getAbst()) + ) { + continue; + } + + ClOffset offset2 = w.get_offset(); + const Clause& cl2 = *solver->cl_alloc.ptr(offset2); + if (cl2.getRemoved() + || cl.size() > cl2.size()) + { + continue; + } + + *simplifier->limit_to_decrease -= (long)((cl.size() + cl2.size())/4); + litSub = subset1(cl, cl2); + if (litSub != lit_Error) { + out_subsumed.push_back(OccurClause(lit, w)); + out_lits.push_back(litSub); + + #ifdef VERBOSE_DEBUG + if (litSub == lit_Undef) cout << "subsume-d: "; + else cout << "backw_sub_str_with_long-ed (lit: " + << litSub + << ") clause offset: " + << w.get_offset() + << endl; + #endif + } + } +} + +/** +@brief Checks if clauses are subsumed or could be strenghtened with given clause + +Checks if: +* any clause is subsumed with given clause +* the given clause could perform self-subsuming resolution on any other clause + +@param[in] ps The clause to perform the above listed algos with +@param[in] abs The abstraction of clause ps +@param[out] out_subsumed The clauses that could be modified by ps +@param[out] out_lits Defines HOW these clauses could be modified. By removing +literal, or by subsumption (in this case, there is lit_Undef here) +*/ +template +void SubsumeStrengthen::find_subsumed_and_strengthened( + ClOffset offset + , const T& cl + , const cl_abst_type abs + , vector& out_subsumed + , vector& out_lits +) +{ + #ifdef VERBOSE_DEBUG + cout << "find_subsumed_and_strengthened: " << cl << endl; + #endif + + Lit minLit = lit_Undef; + uint32_t bestSize = numeric_limits::max(); + for (uint32_t i = 0; i < cl.size(); i++){ + uint32_t newSize = + solver->watches[cl[i]].size() + + solver->watches[~cl[i]].size(); + + if (newSize < bestSize) { + minLit = cl[i]; + bestSize = newSize; + } + } + assert(minLit != lit_Undef); + *simplifier->limit_to_decrease -= (long)cl.size(); + + fill_sub_str(offset, cl, abs, out_subsumed, out_lits, minLit, false); + fill_sub_str(offset, cl, abs, out_subsumed, out_lits, ~minLit, true); +} + +//must be called from deal_with_added_long_and_bin +bool SubsumeStrengthen::handle_added_long_cl(const bool verbose) +{ + assert(solver->prop_at_head()); + + int64_t orig_limit = *simplifier->limit_to_decrease; + size_t origTrailSize = solver->trail_size(); + const double start_time = cpuTime(); + Sub1Ret stat; + + //NOTE added_long_cl CAN CHANGE while the below is running! + uint32_t i = 0; + for(; i < simplifier->added_long_cl.size() + && *simplifier->limit_to_decrease >= 0 + ; i++ + ) { + const ClOffset offs = simplifier->added_long_cl[i]; + Clause* cl = solver->cl_alloc.ptr(offs); + if (cl->freed() || cl->getRemoved()) continue; + cl->stats.marked_clause = 0; + if (!backw_sub_str_with_long(offs, stat)) goto end; + if ((i&0xfff) == 0xfff && solver->must_interrupt_asap()) goto end; + } + + end: + //we still have to clear the marks + for(; i < simplifier->added_long_cl.size(); i ++) { + ClOffset off = simplifier->added_long_cl[i]; + Clause* cl = solver->cl_alloc.ptr(off); + if (cl->freed() || cl->getRemoved()) continue; + cl->stats.marked_clause = 0; + } + simplifier->added_long_cl.clear(); + + if (verbose) { + const bool time_out = *simplifier->limit_to_decrease <= 0; + const double time_used = cpuTime() - start_time; + const double time_remain = float_div(*simplifier->limit_to_decrease, orig_limit); + if (solver->conf.verbosity) { + cout + << "c [occ-backw-sub-str-w-added-long] " + << " sub: " << stat.sub + << " str: " << stat.str + << " 0-depth ass: " << solver->trail_size() - origTrailSize + << solver->conf.print_times(time_used, time_out, time_remain) + << endl; + } + if (solver->sqlStats) { + solver->sqlStats->time_passed( + solver + , "occ-backw-sub-str-w-added-long" + , time_used + , time_out + , time_remain + ); + } + } + + return solver->okay(); +} + +//A subsumes B (A <= B) +template +bool SubsumeStrengthen::subset(const T1& A, const T2& B) +{ + #ifdef MORE_DEUBUG + cout << "A:" << A << endl; + for(size_t i = 1; i < A.size(); i++) { + assert(A[i-1] < A[i]); + } + + cout << "B:" << B << endl; + for(size_t i = 1; i < B.size(); i++) { + assert(B[i-1] < B[i]); + } + #endif + + bool ret; + uint32_t i = 0; + uint32_t i2; + Lit lastB = lit_Undef; + for (i2 = 0; i2 < B.size(); i2++) { + if (lastB != lit_Undef) + assert(lastB < B[i2]); + + lastB = B[i2]; + //Literals are ordered + if (A[i] < B[i2]) { + ret = false; + goto end; + } + else if (A[i] == B[i2]) { + i++; + + //went through the whole of A now, so A subsumes B + if (i == A.size()) { + ret = true; + goto end; + } + } + } + ret = false; + + end: + *simplifier->limit_to_decrease -= (long)i2*4 + (long)i*4; + return ret; +} + +/** +@brief Decides if A subsumes B, or if not, if A could strenghten B + +@note: Assumes 'seen' is cleared (will leave it cleared) + +Helper function for strengthening. Does two things in one go: +1) decides if clause A could subsume clause B +2) decides if clause A could be used to perform self-subsuming resoltuion on +clause B + +@return lit_Error, if neither (1) or (2) is true. Returns lit_Undef (1) is true, +and returns the literal to remove if (2) is true +*/ +template +Lit SubsumeStrengthen::subset1(const T1& A, const T2& B) +{ + Lit retLit = lit_Undef; + + uint32_t i = 0; + uint32_t i2; + for (i2 = 0; i2 < B.size(); i2++) { + if (A[i] == ~B[i2] && retLit == lit_Undef) { + retLit = B[i2]; + i++; + if (i == A.size()) + goto end; + + continue; + } + + //Literals are ordered + if (A[i] < B[i2]) { + retLit = lit_Error; + goto end; + } + + if (A[i] == B[i2]) { + i++; + + if (i == A.size()) + goto end; + } + } + retLit = lit_Error; + + end: + *simplifier->limit_to_decrease -= (long)i2*4 + (long)i*4; + return retLit; +} + +template +uint32_t SubsumeStrengthen::find_smallest_watchlist_for_clause(const T& ps) const +{ + uint32_t min_i = 0; + size_t min_num = solver->watches[ps[min_i]].size(); + for (uint32_t i = 1; i < ps.size(); i++){ + const size_t this_num = solver->watches[ps[i]].size(); + if (this_num < min_num) { + min_i = i; + min_num = this_num; + } + } + *simplifier->limit_to_decrease -= (long)ps.size(); + + return min_i; +} + +/** +@brief Finds clauses that are backward-subsumed by given clause + +Only handles backward-subsumption. Uses occurrence lists +@param[out] out_subsumed The set of clauses subsumed by the given +*/ +template void SubsumeStrengthen::find_subsumed( + const ClOffset offset //Will not match with index of the name value + , const T& ps //Literals in clause + , const cl_abst_type abs //Abstraction of literals in clause + , vector& out_subsumed //List of clauses + , bool only_irred +) { + #ifdef VERBOSE_DEBUG + cout << "find_subsumed: "; + for (const Lit lit: ps) { + cout << lit << " , "; + } + cout << endl; + #endif + + const uint32_t smallest = find_smallest_watchlist_for_clause(ps); + const Lit lit = ps[smallest]; + + //Go through the occur list of the literal that has the smallest occur list + watch_subarray occ = solver->watches[lit]; + *simplifier->limit_to_decrease -= (long)occ.size()*8 + 40; + + //cout << "find_subsumed going through: " << solver->watches_to_string(lit, occ) << endl; + for (const auto& w: occ) { + if (w.isBin() + && ps.size() == 2 + && ps[!smallest] == w.lit2() + && !w.red() + ) { + out_subsumed.push_back(OccurClause(lit, w)); + } + + if (!w.isClause()) { + continue; + } + + *simplifier->limit_to_decrease -= 15; + + if (w.get_offset() == offset + || !subsetAbst(abs, w.getAbst()) + ) { + continue; + } + + const ClOffset offset2 = w.get_offset(); + Clause& cl2 = *solver->cl_alloc.ptr(offset2); + + if (ps.size() > cl2.size() || + cl2.getRemoved() || + (only_irred && cl2.red())) + { + continue; + } + + *simplifier->limit_to_decrease -= 50; + if (subset(ps, cl2)) { + out_subsumed.push_back(OccurClause(lit, w)); + #ifdef VERBOSE_DEBUG + cout << "subsumed cl offset: " << offset2 << endl; + #endif + } + } +} +template void SubsumeStrengthen::find_subsumed( + const ClOffset offset + , const std::array& ps + , const cl_abst_type abs //Abstraction of literals in clause + , vector& out_subsumed //List of clause indexes subsumed + , bool only_irred +); +template void SubsumeStrengthen::find_subsumed( + const ClOffset offset + , const vector& ps + , const cl_abst_type abs //Abstraction of literals in clause + , vector& out_subsumed //List of clause indexes subsumed + , bool only_irred +); + +size_t SubsumeStrengthen::mem_used() const +{ + size_t b = 0; + b += subs.capacity()*sizeof(ClOffset); + b += subsLits.capacity()*sizeof(Lit); + + return b; +} + +void SubsumeStrengthen::remove_binary_cl(const OccurClause& cl) +{ + solver->detach_bin_clause( + cl.lit, cl.ws.lit2(), cl.ws.red(), cl.ws.get_ID()); + (*solver->frat) << del << cl.ws.get_ID() << cl.lit << cl.ws.lit2() << fin; + if (!cl.ws.red()) { + simplifier->n_occurs[cl.lit.toInt()]--; + simplifier->n_occurs[cl.ws.lit2().toInt()]--; + simplifier->elim_calc_need_update.touch(cl.lit); + simplifier->elim_calc_need_update.touch(cl.ws.lit2()); + simplifier->removed_cl_with_var.touch(cl.lit); + simplifier->removed_cl_with_var.touch(cl.ws.lit2()); + } +} + +//Implicit input here is ALWAY irred +bool SubsumeStrengthen::backw_sub_str_with_impl( + const vector& lits, + Sub1Ret& ret_sub_str +) { + subs.clear(); + subsLits.clear(); + + find_subsumed_and_strengthened( + CL_OFFSET_MAX + , lits + , calcAbstraction(lits) + , subs + , subsLits + ); + + for (size_t j = 0 + ; j < subs.size() && solver->okay() + ; j++ + ) { + if (subs[j].ws.isBin()) { + if (subsLits[j] == lit_Undef) { //subsume + remove_binary_cl(subs[j]); + } else { //strengthen + lbool val = solver->value(subsLits[j]); + const int32_t ID = ++solver->clauseID; + if (val == l_False) { + (*solver->frat) << add << ID << subsLits[j] << fin; + (*solver->frat) << add << ++solver->clauseID << fin; + assert(solver->unsat_cl_ID == 0); + solver->unsat_cl_ID = solver->clauseID; + solver->ok = false; + return false; + } else if (val == l_Undef) { + solver->enqueue(subsLits[j]); + solver->ok = solver->propagate_occur(simplifier->limit_to_decrease); + if (!solver->okay()) { + return false; + } + } + //this binary is definitely satisfied + solver->detach_bin_clause( + subs[j].lit, subs[j].ws.lit2(), subs[j].ws.red(), subs[j].ws.get_ID()); + (*solver->frat) << del << subs[j].ws.get_ID() << subs[j].lit << subs[j].ws.lit2() << fin; + if (!subs[j].ws.red()) { + simplifier->n_occurs[subs[j].lit.toInt()]--; + simplifier->n_occurs[subs[j].ws.lit2().toInt()]--; + simplifier->elim_calc_need_update.touch(subs[j].lit); + simplifier->elim_calc_need_update.touch(subs[j].ws.lit2()); + simplifier->removed_cl_with_var.touch(subs[j].lit); + simplifier->removed_cl_with_var.touch(subs[j].ws.lit2()); + } + } + continue; + } + + assert(subs[j].ws.isClause()); + ClOffset offset2 = subs[j].ws.get_offset(); + Clause& cl2 = *solver->cl_alloc.ptr(offset2); + if (subsLits[j] == lit_Undef) { //Subsume + #ifdef VERBOSE_DEBUG + if (solver->conf.verbosity >= 6) + cout << "subsumed clause " << cl2 << endl; + #endif + if (cl2.used_in_xor() && + solver->conf.force_preserve_xors) + { + continue; + } + + if (!cl2.red()) { + ret_sub_str.subsumedIrred = true; + } + + simplifier->unlink_clause(offset2, true, false, true); + ret_sub_str.sub++; + } else { //Strengthen + #ifdef VERBOSE_DEBUG + if (solver->conf.verbosity >= 6) { + cout << "strenghtened clause " << cl2 << endl; + } + #endif + if (cl2.used_in_xor() && + solver->conf.force_preserve_xors) + { + //cout << "str-ing used in XOR with bin" << endl; + continue; + } + if (!simplifier->remove_literal(offset2, subsLits[j], true)) { + return false; + } + ret_sub_str.str++; + + //If we are waaay over time, just exit + if (*simplifier->limit_to_decrease < -20LL*1000LL*1000LL) + break; + } + } + runStats.sub1 += ret_sub_str; + return true; +} + +//Implicit input here is ALWAYS irred +void SubsumeStrengthen::backw_sub_with_impl( + const vector& lits, + Sub1Ret& ret_sub_str +) { + subs.clear(); + + find_subsumed( + CL_OFFSET_MAX + , lits + , calcAbstraction(lits) + , subs + , true + ); + + for (size_t j = 0 + ; j < subs.size() && solver->okay() + ; j++ + ) { + if (subs[j].ws.isBin()) { + remove_binary_cl(subs[j]); + continue; + } + + assert(subs[j].ws.isClause()); + ClOffset offset2 = subs[j].ws.get_offset(); + Clause& cl2 = *solver->cl_alloc.ptr(offset2); + if (subsLits[j] == lit_Undef) { //Subsume + if (cl2.used_in_xor() && solver->conf.force_preserve_xors) + continue; + + if (!cl2.red()) ret_sub_str.subsumedIrred = true; + simplifier->unlink_clause(offset2, true, false, true); + ret_sub_str.sub++; + } + } + runStats.sub1 += ret_sub_str; +} + +bool SubsumeStrengthen::backw_sub_str_long_with_bins_watch( + const Lit lit, + bool both_bins +) { + //NOTE this can modify itself, + // by removing a binary from tmp by backw_sub_str_with_impl + solver->watches[lit].copyTo(tmp); + for (size_t i = 0 + ; i < tmp.size() && *simplifier->limit_to_decrease > 0 + ; i++ + ) { + //Each BIN only once + if (tmp[i].isBin() && + (both_bins || lit < tmp[i].lit2())) + { + const bool red = tmp[i].red(); + tried_bin_tri++; + tmpLits.resize(2); + tmpLits[0] = lit; + tmpLits[1] = tmp[i].lit2(); + std::sort(tmpLits.begin(), tmpLits.end()); + + Sub1Ret ret; + if (!backw_sub_str_with_impl(tmpLits, ret)) { + return false; + } + subsumedBin += ret.sub; + strBin += ret.str; + + if (red + && ret.subsumedIrred + ) { + solver->binTri.redBins--; + solver->binTri.irredBins++; + simplifier->n_occurs[tmpLits[0].toInt()]++; + simplifier->n_occurs[tmpLits[1].toInt()]++; + simplifier->elim_calc_need_update.touch(tmpLits[0]); + simplifier->elim_calc_need_update.touch(tmpLits[1]); + simplifier->added_cl_to_var.touch(tmpLits[0]); + simplifier->added_cl_to_var.touch(tmpLits[1]); + findWatchedOfBin( + solver->watches, tmpLits[1], tmpLits[0], true, tmp[i].get_ID()).setRed(false); + findWatchedOfBin( + solver->watches, tmpLits[0], tmpLits[1], true, tmp[i].get_ID()).setRed(false); + } + continue; + } + + //Must be a longer clause, break + //assert(ws[i].isClause()); + //break; + } + + return true; +} + +bool SubsumeStrengthen::backw_sub_str_long_with_bins() +{ + //Stats + int64_t orig_time_limit = *simplifier->limit_to_decrease; + const size_t origTrailSize = solver->trail_size(); + double myTime = cpuTime(); + subsumedBin = 0; + strBin = 0; + + //Randomize start in the watchlist + size_t upI; + upI = rnd_uint(solver->mtrand, solver->watches.size()-1); + + size_t numDone = 0; + for (; numDone < solver->watches.size() && *simplifier->limit_to_decrease > 0 + ; upI = (upI +1) % solver->watches.size(), numDone++ + + ) { + Lit lit = Lit::toLit(upI); + if (!backw_sub_str_long_with_bins_watch(lit)) { + break; + } + } + + const double time_used = cpuTime() - myTime; + const bool time_out = *simplifier->limit_to_decrease <= 0; + const double time_remain = float_div(*simplifier->limit_to_decrease, orig_time_limit); + if (solver->conf.verbosity) { + cout + << "c [occ-backw-sub-str-long-w-bins]" + << " subs: " << subsumedBin + << " str: " << strBin + << " tried: " << tried_bin_tri + << " 0-depth ass: " << solver->trail_size() - origTrailSize + << solver->conf.print_times(time_used, time_out, time_remain) + << endl; + } + + if (solver->sqlStats) { + solver->sqlStats->time_passed( + solver + , "occ-backw-sub-str-long-w-bins" + , time_used + , time_out + , time_remain + ); + } + + //runStats.zeroDepthAssigns = solver->trail_size() - origTrailSize; + + return solver->okay(); +} + + +void SubsumeStrengthen::finishedRun() +{ + globalstats += runStats; +} + +void SubsumeStrengthen::Stats::print_short(const Solver* solver) const +{ + cout << "c [occ-substr] long" + << " subBySub: " << sub0.numSubsumed + << " subByStr: " << sub1.sub + << " lits-rem-str: " << sub1.str + << solver->conf.print_times(subsumeTime+strengthenTime) + << endl; +} + +void SubsumeStrengthen::Stats::print() const +{ + cout << "c -------- SubsumeStrengthen STATS ----------" << endl; + print_stats_line("c cl-subs" + , sub0.numSubsumed + sub1.sub + , " Clauses" + ); + print_stats_line("c cl-str rem lit" + , sub1.str + , " Lits" + ); + print_stats_line("c cl-sub T" + , subsumeTime + , " s" + ); + print_stats_line("c cl-str T" + , strengthenTime + , " s" + ); + cout << "c -------- SubsumeStrengthen STATS END ----------" << endl; +} + +SubsumeStrengthen::Stats& SubsumeStrengthen::Stats::operator+=(const Stats& other) +{ + sub1 += other.sub1; + sub0 += other.sub0; + + subsumeTime += other.subsumeTime; + strengthenTime += other.strengthenTime; + + return *this; +} diff --git a/cryptominisat/cppsrc/src/subsumestrengthen.h b/cryptominisat/cppsrc/src/subsumestrengthen.h new file mode 100644 index 00000000..b5f08d07 --- /dev/null +++ b/cryptominisat/cppsrc/src/subsumestrengthen.h @@ -0,0 +1,158 @@ +/****************************************** +Copyright (C) 2009-2020 Authors of CryptoMiniSat, see AUTHORS file + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. +***********************************************/ + +#ifndef __SUBSUMESTRENGTHEN_H__ +#define __SUBSUMESTRENGTHEN_H__ + +#include "cloffset.h" +#include "solvertypesmini.h" +#include "clabstraction.h" +#include "clause.h" +#include "Vec.h" +#include +using std::vector; + +namespace CMSat { + +class OccSimplifier; +class GateFinder; +class Solver; + +class SubsumeStrengthen +{ +public: + SubsumeStrengthen(OccSimplifier* simplifier, Solver* solver); + size_t mem_used() const; + + void backw_sub_long_with_long(); + bool backw_str_long_with_long(); + bool backw_sub_str_long_with_bins(); + bool backw_sub_str_long_with_bins_watch(const Lit lit, bool both_bins = false); + bool handle_added_long_cl(const bool main_run); + void remove_binary_cl(const OccurClause& cl); + + + Sub0Ret backw_sub_with_long(const ClOffset offset); + + void backw_sub_with_impl( + const vector& lits, + Sub1Ret& ret_sub_str + ); + bool backw_sub_str_with_impl( + const vector& lits, + Sub1Ret& ret_sub_str); + bool backw_sub_str_with_long( + ClOffset offset, + Sub1Ret& ret_sub_str); + + struct Stats + { + Stats& operator+=(const Stats& other); + void print_short(const Solver* solver) const; + void print() const; + + Sub0Ret sub0; + Sub1Ret sub1; + + double subsumeTime = 0.0; + double strengthenTime = 0.0; + }; + + void finishedRun(); + const Stats& get_stats() const; + const Stats& getRunStats() const; + + template + void find_subsumed( + const ClOffset offset + , const T& ps + , const cl_abst_type abs + , vector& out_subsumed + , const bool only_irred = false + ); + +private: + Stats globalstats; + Stats runStats; + + OccSimplifier* simplifier; + Solver* solver; + + //Called from simplifier at resolvent-adding of var-elim + template + Sub0Ret subsume_and_unlink( + const ClOffset offset + , const T& ps + , const cl_abst_type abs + ); + + template + uint32_t find_smallest_watchlist_for_clause(const T& ps) const; + + template + void find_subsumed_and_strengthened( + const ClOffset offset + , const T& ps + , const cl_abst_type abs + , vector& out_subsumed + , vector& out_lits + ); + + template + void fill_sub_str( + const ClOffset offset + , const T& ps + , cl_abst_type abs + , vector& out_subsumed + , vector& out_lits + , const Lit lit + , const bool inverted + ); + + template + bool subset(const T1& A, const T2& B); + + template + Lit subset1(const T1& A, const T2& B); + + vector subs; + vec tmp; + vector subsLits; + vector tmpLits; + size_t tried_bin_tri = 0; + uint64_t subsumedBin = 0; + uint64_t strBin = 0; +}; + +inline const SubsumeStrengthen::Stats& SubsumeStrengthen::getRunStats() const +{ + return runStats; +} + +inline const SubsumeStrengthen::Stats& SubsumeStrengthen::get_stats() const +{ + return globalstats; +} + +} //end namespace + +#endif //__SUBSUMESTRENGTHEN_H__ diff --git a/cryptominisat/cppsrc/src/time_mem.h b/cryptominisat/cppsrc/src/time_mem.h new file mode 100644 index 00000000..022190be --- /dev/null +++ b/cryptominisat/cppsrc/src/time_mem.h @@ -0,0 +1,211 @@ +/********************************************************* +MiniSat -- Copyright (c) 2003-2006, Niklas Een, Niklas Sorensson +CryptoMiniSat -- Copyright (C) 2009-2020 Authors of CryptoMiniSat, see AUTHORS file + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. +***********************************************************/ + +#ifndef TIME_MEM_H +#define TIME_MEM_H +#include "constants.h" +#include +#include + +#include +#include +#include +#include +#include + +// note: MinGW64 defines both __MINGW32__ and __MINGW64__ +#if defined (_MSC_VER) || defined (__MINGW32__) || defined(_WIN32) || defined(EMSCRIPTEN) +#include +static inline double cpuTime(void) +{ + return (double)clock() / CLOCKS_PER_SEC; +} +static inline double cpuTimeTotal(void) +{ + return (double)clock() / CLOCKS_PER_SEC; +} +static inline double realTimeSec() { + return 0; +} + +static inline double real_time_sec() { + return 0; +} + + +#else //Linux or POSIX +#include +#include +#include + +static inline long realTimeMicros() { + struct timeval tv; + gettimeofday(&tv, NULL); + return 1000000 * tv.tv_sec + tv.tv_usec; +} + +static inline double real_time_sec() { + return (double) realTimeMicros() / 1000000; +} + +static inline double cpuTime(void) +{ + struct rusage ru; + #ifdef RUSAGE_THREAD + int ret = getrusage(RUSAGE_THREAD, &ru); + #else + int ret = getrusage(RUSAGE_SELF, &ru); + #endif + assert(ret == 0); + + return (double)ru.ru_utime.tv_sec + ((double)ru.ru_utime.tv_usec / 1000000.0); +} + +static inline double cpuTimeTotal(void) +{ + struct rusage ru; + int ret = getrusage(RUSAGE_SELF, &ru); + assert(ret == 0); + + return (double)ru.ru_utime.tv_sec + ((double)ru.ru_utime.tv_usec / 1000000.0); +} + +#endif + +#if defined(__linux__) +// process_mem_usage(double &, double &) - takes two doubles by reference, +// attempts to read the system-dependent data for a process' virtual memory +// size and resident set size, and return the results in KB. +// +// On failure, returns 0.0, 0.0 +static inline uint64_t memUsedTotal(double& vm_usage, std::string* max_mem_usage = NULL) +{ + //double& vm_usage + using std::ios_base; + using std::ifstream; + using std::string; + + vm_usage = 0.0; + + // 'file' stat seems to give the most reliable results + // + ifstream stat_stream("/proc/self/stat",ios_base::in); + + // dummy vars for leading entries in stat that we don't care about + // + string pid; // The process ID. + string comm; //The filename of the executable, in parentheses. + string state; //One of the following characters, indicating process (see man stat(2)) + string ppid; //The PID of the parent of this process. + string pgrp; //The process group ID of the process. + string session; //The session ID of the process. + + //The controlling terminal of the process. (The minor device number is contained in the combina‐ + //tion of bits 31 to 20 and 7 to 0; the major device number is in bits 15 to 8.) + string tty_nr; + + //The ID of the foreground process group of the controlling terminal of the process. + string tpgid; + + + string flags; + string minflt; + string cminflt; + string majflt; + string cmajflt; + string utime; + string stime; + string cutime; + string cstime; + string priority; + string nice; + + //Number of threads in this process (since Linux 2.6). Before kernel 2.6, this field was hard + //coded to 0 as a placeholder for an earlier removed field. + string num_threads; + + string itrealvalue; + string starttime; + + /**** the two fields we want *****/ + unsigned long vsize; //Virtual memory size in bytes. + + //Resident Set Size: number of pages the process has in real memory. This is just the pages which + //count toward text, data, or stack space. This does not include pages which have not been demand- + //loaded in, or which are swapped out. + long rss; + /**** the two fields we want *****/ + + stat_stream >> pid >> comm >> state >> ppid >> pgrp >> session >> tty_nr + >> tpgid >> flags >> minflt >> cminflt >> majflt >> cmajflt + >> utime >> stime >> cutime >> cstime >> priority >> nice + >> num_threads >> itrealvalue >> starttime >> vsize >> rss; // don't care about the rest + + stat_stream.close(); + + long page_size_kb = sysconf(_SC_PAGE_SIZE); // in case x86-64 is configured to use 2MB pages + vm_usage = vsize; + double resident_set = (double)rss * (double)page_size_kb; + + if (max_mem_usage != NULL) { + //NOTE: we could query the MAXIMUM resident size using + // /proc/self/status + // as it contains: * VmHWM: Peak resident set size ("high water mark"). + // but we'd need to parse it, etc. + // see man(5) proc for details + // This note is related to issue #629 in CryptoMiniSat + ifstream stat_stream2("/proc/self/status",ios_base::in); + string tp; + while(getline(stat_stream2, tp)){ + if (tp.size() > 7 && tp.find("VmHWM:") != std::string::npos) { + tp.erase(0, 7); + tp.erase(tp.begin(), + std::find_if(tp.begin(), tp.end(), std::bind1st(std::not_equal_to(), '\t'))); + tp.erase(tp.begin(), + std::find_if(tp.begin(), tp.end(), std::bind1st(std::not_equal_to(), ' '))); + *max_mem_usage = tp; + } + } + } + + return resident_set; +} +#elif defined(__FreeBSD__) +#include +inline uint64_t memUsedTotal(double& vm_usage, std::string* max_mem_usage = NULL) +{ + vm_usage = 0; + + struct rusage ru; + getrusage(RUSAGE_SELF, &ru); + return ru.ru_maxrss*1024; +} +#else //Windows +static inline size_t memUsedTotal(double& vm_usage, std::string* max_mem_usage = NULL) +{ + vm_usage = 0; + return 0; +} +#endif + +#endif //TIME_MEM_H diff --git a/cryptominisat/cppsrc/src/touchlist.h b/cryptominisat/cppsrc/src/touchlist.h new file mode 100644 index 00000000..a77fecc2 --- /dev/null +++ b/cryptominisat/cppsrc/src/touchlist.h @@ -0,0 +1,183 @@ +/****************************************** +Copyright (C) 2009-2020 Authors of CryptoMiniSat, see AUTHORS file + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. +***********************************************/ + +#ifndef __TOUCHLIST_H__ +#define __TOUCHLIST_H__ + +#include +#include "solvertypes.h" + +namespace CMSat { + +class TouchList +{ +public: + void touch(const Lit lit) + { + touch(lit.var()); + } + + template + void touch(T value, Targs... Fargs) // recursive variadic function + { + touch(value); + touch(Fargs...); + } + + void touch(const vector& lits) + { + for(const Lit lit: lits) + touch(lit.var()); + } + + void touch(const uint32_t var) + { + if (touchedBitset.size() <= var) + touchedBitset.resize(var+1, 0); + + if (touchedBitset[var] == 0) { + touched.push_back(var); + touchedBitset[var] = 1; + } + } + + const vector& getTouchedList() const + { + return touched; + } + + void clear() + { + //Clear touchedBitset + for(vector::const_iterator + it = touched.begin(), end = touched.end() + ; it != end + ; ++it + ) { + touchedBitset[*it] = 0; + } + + //Clear touched + touched.clear(); + } + + size_t mem_used() const + { + uint64_t mem = 0; + mem += touched.capacity()*sizeof(uint32_t); + mem += touchedBitset.capacity()*sizeof(char); + + return mem; + } + + void shrink_to_fit() + { + touched.clear(); + touched.shrink_to_fit(); + touchedBitset.clear(); + touchedBitset.shrink_to_fit(); + } + +private: + vector touched; + vector touchedBitset; +}; + + +class TouchListLit +{ +public: + void touch(const Lit lit) + { + touch(lit.toInt()); + } + + template + void touch(T value, Targs... Fargs) // recursive variadic function + { + touch(value); + touch(Fargs...); + } + + void touch(const vector& lits) + { + for(const Lit lit: lits) + touch(lit); + } + + void touch(const uint32_t var) + { + if (touchedBitset.size() <= var) + touchedBitset.resize(var+1, 0); + + if (touchedBitset[var] == 0) { + touched.push_back(var); + touchedBitset[var] = 1; + } + } + + const vector& getTouchedList() const + { + return touched; + } + + void clear() + { + //Clear touchedBitset + for(vector::const_iterator + it = touched.begin(), end = touched.end() + ; it != end + ; ++it + ) { + touchedBitset[*it] = 0; + } + + //Clear touched + touched.clear(); + } + + size_t mem_used() const + { + uint64_t mem = 0; + mem += touched.capacity()*sizeof(uint32_t); + mem += touchedBitset.capacity()*sizeof(char); + + return mem; + } + + void shrink_to_fit() + { + touched.clear(); + touched.shrink_to_fit(); + touchedBitset.clear(); + touchedBitset.shrink_to_fit(); + } + +private: + vector touched; + vector touchedBitset; +}; + + +} //end namespace + +#endif //__TOUCHLIST_H__ diff --git a/cryptominisat/cppsrc/src/trim.h b/cryptominisat/cppsrc/src/trim.h new file mode 100644 index 00000000..7a8405dd --- /dev/null +++ b/cryptominisat/cppsrc/src/trim.h @@ -0,0 +1,44 @@ +/****************************************** +Copyright (C) 2009-2020 Authors of CryptoMiniSat, see AUTHORS file + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. +***********************************************/ + +#ifndef TRIM_H +#define TRIM_H + +#include + +static inline std::string trim(const std::string& str) +{ + std::string ret; + for(const char c: str) + { + if (c != ' ' + && c != '\n' + && c != '\r' + ) { + ret += c; + } + } + + return ret; +} + +#endif //TRIM_H diff --git a/cryptominisat/cppsrc/src/vardata.h b/cryptominisat/cppsrc/src/vardata.h new file mode 100644 index 00000000..e2730b39 --- /dev/null +++ b/cryptominisat/cppsrc/src/vardata.h @@ -0,0 +1,194 @@ +/****************************************** +Copyright (C) 2009-2020 Authors of CryptoMiniSat, see AUTHORS file + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. +***********************************************/ + +#ifndef __VARDATA_H__ +#define __VARDATA_H__ + +#include +#ifdef ARJUN_SERIALIZE +#include +#endif + +#include "constants.h" +#include "propby.h" +#include "avgcalc.h" + +using std::numeric_limits; + +namespace CMSat +{ + +struct VarData +{ + VarData() + { + is_bva = 0; + occ_simp_tried = 0; + saved_polarity = false; + stable_polarity = false; + best_polarity = false; + inv_polarity = false; + } + + ///contains the decision level at which the assignment was made. + uint32_t level = numeric_limits::max(); + uint32_t sublevel = numeric_limits::max(); + + #ifdef WEIGHTED_SAMPLING + double weight = 0.5; + #endif + + //Reason this got propagated. NULL means decision/toplevel + PropBy reason = PropBy(); + + lbool assumption = l_Undef; + + ///Whether var has been eliminated (var-elim, different component, etc.) + Removed removed = Removed::none; + + ///The preferred polarity of each variable. + uint8_t stable_polarity:1; + uint8_t saved_polarity:1; + uint8_t best_polarity:1; + uint8_t inv_polarity:1; + uint8_t is_bva:1; + uint8_t occ_simp_tried:1; + bool propagated = false; + + #if defined(STATS_NEEDED) + uint32_t community_num = numeric_limits::max(); + #endif + + template + void save(Archive& ar, const unsigned int /*version*/) const { + ar << level; + ar << sublevel; + #ifdef WEIGHTED_SAMPLING + ar << weight; + #endif + ar << reason; + ar << assumption; + ar << removed; + + //bitfield + const bool my_stable_polarity = stable_polarity; + const bool my_saved_polarity = saved_polarity; + const bool my_best_polarity = best_polarity; + const bool my_inv_polarity = inv_polarity; + const bool my_is_bva = is_bva; + const bool my_occ_simp_tried = occ_simp_tried; + ar << my_stable_polarity; + ar << my_saved_polarity; + ar << my_best_polarity; + ar << my_inv_polarity; + ar << my_is_bva; + ar << my_occ_simp_tried; + + #if defined(STATS_NEEDED) + ar << community_num; + #endif + ar << propagated; + } + + template + void load(Archive& ar, const unsigned int /*version*/) { + ar >> level; + ar >> sublevel; + #ifdef WEIGHTED_SAMPLING + ar >> weight; + #endif + ar >> reason; + ar >> assumption; + ar >> removed; + + //bitfield + bool bit; + ar >> bit; stable_polarity = bit; + ar >> bit; saved_polarity = bit; + ar >> bit; best_polarity = bit; + ar >> bit; inv_polarity = bit; + ar >> bit; is_bva = bit; + ar >> bit; occ_simp_tried = bit; + + #if defined(STATS_NEEDED) + ar >> community_num; + #endif + ar >> propagated; + } +#ifdef ARJUN_SERIALIZE + BOOST_SERIALIZATION_SPLIT_MEMBER() +#endif + + #if defined(STATS_NEEDED_BRANCH) || defined(FINAL_PREDICTOR_BRANCH) + uint32_t set = 0; + uint64_t num_propagated = 0; + uint64_t num_propagated_pos = 0; + uint64_t num_decided = 0; + uint64_t num_decided_pos = 0; + bool last_time_set_was_dec; + uint32_t last_seen_in_1uip = 0; + uint32_t last_decided_on = 0; + uint32_t last_propagated = 0; + uint32_t last_canceled = 0; + + //these are per-solver data + uint64_t sumDecisions_at_picktime = 0; + uint64_t sumConflicts_at_picktime = 0; + uint64_t sumPropagations_at_picktime = 0; + uint64_t sumAntecedents_at_picktime = 0; + uint64_t sumAntecedentsLits_at_picktime = 0; + uint64_t sumConflictClauseLits_at_picktime = 0; + uint64_t sumDecisionBasedCl_at_picktime = 0; + uint64_t sumClLBD_at_picktime = 0; + uint64_t sumClSize_at_picktime = 0; + + uint64_t sumDecisions_below_during = 0; + uint64_t sumConflicts_below_during = 0; + uint64_t sumPropagations_below_during = 0; + uint64_t sumAntecedents_below_during = 0; + uint64_t sumAntecedentsLits_below_during = 0; + uint64_t sumConflictClauseLits_below_during = 0; + uint64_t sumDecisionBasedCl_below_during = 0; + uint64_t sumClLBD_below_during = 0; + uint64_t sumClSize_below_during = 0; + + //these are per-variable data + uint64_t inside_conflict_clause = 0; + uint64_t inside_conflict_clause_glue = 0; + uint64_t inside_conflict_clause_antecedents = 0; + + uint64_t inside_conflict_clause_at_picktime = 0; + uint64_t inside_conflict_clause_glue_at_picktime = 0; + uint64_t inside_conflict_clause_antecedents_at_picktime = 0; + + uint64_t inside_conflict_clause_during = 0; + uint64_t inside_conflict_clause_glue_during = 0; + uint64_t inside_conflict_clause_antecedents_during = 0; + + uint64_t last_flipped = 0; + bool dump; + #endif +}; + +} + +#endif //__VARDATA_H__ diff --git a/cryptominisat/cppsrc/src/vardistgen.cpp b/cryptominisat/cppsrc/src/vardistgen.cpp new file mode 100644 index 00000000..e28d6a72 --- /dev/null +++ b/cryptominisat/cppsrc/src/vardistgen.cpp @@ -0,0 +1,141 @@ +/****************************************** +Copyright (C) 2009-2020 Authors of CryptoMiniSat, see AUTHORS file + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. +***********************************************/ + + +#include "vardistgen.h" +#include "solver.h" +#include "sqlstats.h" + +using namespace CMSat; + +VarDistGen::VarDistGen(Solver* _solver) : + solver(_solver) +{} + +double VarDistGen::compute_tot_act_vsids(Clause* cl) const +{ + double tot_var_acts = 0.0; + for(Lit l: *cl) { + tot_var_acts += solver->var_act_vsids[l.var()]; + } + tot_var_acts += 10e-300; + //NOTE Kuldeep wants to re-visit + tot_var_acts = std::log2(tot_var_acts)/std::log2(solver->max_vsids_act+10e-300); + return tot_var_acts; +} + +void VarDistGen::calc() +{ + double myTime = cpuTime(); + data.clear(); + data.resize(solver->nVars()); + + for(auto& off: solver->longIrredCls) { + Clause* cl = solver->cl_alloc.ptr(off); + double tot_var_acts = compute_tot_act_vsids(cl); + + for(Lit l: *cl) { + data[l.var()].irred.num_times_in_long_clause++; + data[l.var()].irred.tot_num_lit_of_long_cls_it_appears_in+=cl->size(); + if (solver->varData[l.var()].stable_polarity ^ !l.sign()) { + data[l.var()].irred.satisfies_cl++; + } else { + data[l.var()].irred.falsifies_cl++; + } + data[l.var()].irred.sum_var_act_of_cls += tot_var_acts; + } + } + + for(auto& x: solver->longRedCls) { + for(auto& off: x) { + Clause* cl = solver->cl_alloc.ptr(off); + double tot_var_acts = compute_tot_act_vsids(cl); + for(Lit l: *cl) { + data[l.var()].red.num_times_in_long_clause++; + data[l.var()].red.tot_num_lit_of_long_cls_it_appears_in+=cl->size(); + if (std::log2(solver->max_cl_act+10e-300) != 0) { + data[l.var()].tot_act_long_red_cls += + std::log2((double)cl->stats.activity+10e-300) + /std::log2(solver->max_cl_act+10e-300); + } + + if (solver->varData[l.var()].stable_polarity ^ !l.sign()) { + data[l.var()].red.satisfies_cl++; + } else { + data[l.var()].red.falsifies_cl++; + } + data[l.var()].red.sum_var_act_of_cls += tot_var_acts; + } + } + } + + for(uint32_t i = 0; i < solver->nVars()*2; i++) { + Lit l = Lit::toLit(i); + for(Watched& w: solver->watches[l]) { + if (w.isBin() && l < w.lit2()) { + if (w.red()) { + data[l.var()].red.num_times_in_bin_clause++; + data[l.var()].red.tot_num_lit_of_bin_it_appears_in+=2; + if (solver->varData[l.var()].stable_polarity ^ !l.sign()) { + data[l.var()].red.satisfies_cl++; + } else { + data[l.var()].red.falsifies_cl++; + } + } else { + data[l.var()].irred.num_times_in_bin_clause++; + data[l.var()].irred.tot_num_lit_of_bin_it_appears_in+=2; + if (solver->varData[l.var()].stable_polarity ^ !l.sign()) { + data[l.var()].irred.satisfies_cl++; + } else { + data[l.var()].irred.falsifies_cl++; + } + } + } + } + } + + double time_used = cpuTime() - myTime; + if (solver->conf.verbosity) { + cout << "c [vardistgen] generated var distribution data " + << solver->conf.print_times(time_used) + << endl; + } + + if (solver->sqlStats) { + solver->sqlStats->time_passed_min( + solver + , "var-dist-gen" + , time_used + ); + } +} + +#ifdef STATS_NEEDED_BRANCH +void VarDistGen::dump() +{ + for(uint32_t i = 0; i < solver->nVars(); i++) { + uint32_t outer_var = solver->map_inter_to_outer(i); + solver->sqlStats->var_dist( + outer_var, data[i], solver); + } +} +#endif diff --git a/cryptominisat/cppsrc/src/vardistgen.h b/cryptominisat/cppsrc/src/vardistgen.h new file mode 100644 index 00000000..c74f359e --- /dev/null +++ b/cryptominisat/cppsrc/src/vardistgen.h @@ -0,0 +1,70 @@ +/****************************************** +Copyright (C) 2009-2020 Authors of CryptoMiniSat, see AUTHORS file + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. +***********************************************/ + +#include +#include + +#ifndef VARDISTGEN_H +#define VARDISTGEN_H + +using std::vector; + +namespace CMSat { + +class Solver; +class Clause; + +struct VarData2 +{ + struct Dat { + uint32_t num_times_in_bin_clause = 0; + uint32_t num_times_in_long_clause = 0; + uint32_t satisfies_cl = 0; + uint32_t falsifies_cl = 0; + uint32_t tot_num_lit_of_bin_it_appears_in =0; + uint32_t tot_num_lit_of_long_cls_it_appears_in = 0; + double sum_var_act_of_cls; + }; + Dat irred; + Dat red; + double tot_act_long_red_cls; +}; + +class VarDistGen { +public: + VarDistGen(Solver* solver); + void calc(); + #ifdef STATS_NEEDED_BRANCH + void dump(); + #endif + +private: + double compute_tot_act_vsids(Clause* cl) const; + + Solver* solver; + vector data; + +}; + +} + +#endif diff --git a/cryptominisat/cppsrc/src/varreplacer.cpp b/cryptominisat/cppsrc/src/varreplacer.cpp new file mode 100644 index 00000000..2a4da392 --- /dev/null +++ b/cryptominisat/cppsrc/src/varreplacer.cpp @@ -0,0 +1,1352 @@ +/****************************************** +Copyright (C) 2009-2020 Authors of CryptoMiniSat, see AUTHORS file + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. +***********************************************/ + +#include "varreplacer.h" +#include "varupdatehelper.h" +#include "solver.h" +#include "clausecleaner.h" +#include "time_mem.h" +#include "clauseallocator.h" +#include "sqlstats.h" +#include "sccfinder.h" +#ifdef USE_BREAKID +#include "cms_breakid.h" +#endif + +#include +#include +#include +using std::cout; +using std::endl; +using std::make_pair; + +#ifdef VERBOSE_DEBUG +#define REPLACE_STATISTICS +#define VERBOSE_DEBUG_BIN_REPLACER +#endif + +using namespace CMSat; + +//#define VERBOSE_DEBUG +//#define REPLACE_STATISTICS +//#define DEBUG_BIN_REPLACER +//#define VERBOSE_DEBUG_BIN_REPLACER + +VarReplacer::VarReplacer(Solver* _solver) : + solver(_solver) +{ + scc_finder = new SCCFinder(_solver); + ps_tmp.resize(2); +} + +VarReplacer::~VarReplacer() +{ + delete scc_finder; +} + +void VarReplacer::new_var(const uint32_t orig_outer) +{ + if (orig_outer == numeric_limits::max()) { + table.push_back(Lit(table.size(), false)); + } +} + +void VarReplacer::check_no_replaced_var_set() const +{ + for(uint32_t var = 0; var < solver->nVarsOuter(); var++) { + if (solver->value(var) != l_Undef) { + if (solver->varData[var].removed != Removed::none) + { + cout << "ERROR: var " << var + 1 << " has removed: " + << removed_type_to_string(solver->varData[var].removed) + << " but is set to " << solver->value(var) << endl; + assert(solver->varData[var].removed == Removed::none); + exit(-1); + } + } + } +} + +void VarReplacer::new_vars(const size_t n) +{ + size_t oldsize = table.size(); + table.insert(table.end(), n, lit_Undef); + for(size_t i = oldsize; i < table.size(); i++) { + table[i] = Lit(i, false); + } +} + +void VarReplacer::save_on_var_memory() +{ +} + +void VarReplacer::updateVars( + const std::vector< uint32_t >& /*outerToInter*/ + , const std::vector< uint32_t >& /*interToOuter*/ +) { + //Nothing to do, we keep OUTER in all these data structures + //hence, it needs no update +} + +void VarReplacer::printReplaceStats() const +{ + uint32_t i = 0; + for (vector::const_iterator + it = table.begin(); it != table.end() + ; ++it, i++ + ) { + if (it->var() == i) continue; + cout << "Replacing var " << i+1 << " with Lit " << *it << endl; + } +} + +void VarReplacer::update_vardata( + const Lit orig + , const Lit replaced_with +) { + uint32_t orig_var = orig.var(); + uint32_t replaced_with_var = replaced_with.var(); + + //Not replaced_with, or not replaceable, so skip + if (orig_var == replaced_with_var + || solver->varData[replaced_with_var].removed == Removed::elimed + ) { + return; + } + + //Has already been handled previously, just skip + if (solver->varData[orig_var].removed == Removed::replaced) { + return; + } + + //Okay, so unset decision, and set the other one decision + assert(orig_var != replaced_with_var); + solver->varData[orig_var].removed = Removed::replaced; + assert(solver->varData[replaced_with_var].removed == Removed::none); + assert(solver->value(replaced_with_var) == l_Undef); + assert(orig_var <= solver->nVars() && replaced_with_var <= solver->nVars()); +} + +bool VarReplacer::enqueueDelayedEnqueue() +{ + for(auto& l: delayedEnqueue) { + l.first = get_lit_replaced_with(l.first); + + if (!solver->ok) { + //if we are UNSAT, just delete them + *solver->frat << del << l.second << l.first << fin; + continue; + } + + if (solver->value(l.first) == l_Undef) { + solver->enqueue(l.first); + *solver->frat << del << l.second << l.first << fin; // double unit delete + } else if (solver->value(l.first) == l_False) { + *solver->frat + << add << ++solver->clauseID << fin + << del << l.second << l.first << fin; + assert(solver->unsat_cl_ID == 0); + solver->unsat_cl_ID = solver->clauseID; + solver->ok = false; + } else { + //it's already set, delete + *solver->frat << del << l.second << l.first << fin; + } + } + delayedEnqueue.clear(); + + if (!solver->ok) return false; + + solver->ok = solver->propagate().isNULL(); + return solver->okay(); +} + +void VarReplacer::attach_delayed_attach() +{ + for(Clause* c: delayed_attach_or_free) { + if (c->size() <= 2) { + solver->free_cl(c); + } else { + c->unset_removed(); + solver->attachClause(*c); + } + } + delayed_attach_or_free.clear(); +} + +void VarReplacer::update_all_vardata() +{ + uint32_t var = 0; + for (vector::const_iterator + it = table.begin(); it != table.end() + ; ++it, var++ + ) { + const uint32_t orig = solver->map_outer_to_inter(var); + const Lit orig_lit = Lit(orig, false); + + const uint32_t repl = solver->map_outer_to_inter(it->var()); + const Lit repl_lit = Lit(repl, it->sign()); + + update_vardata(orig_lit, repl_lit); + } +} + +bool VarReplacer::perform_replace() +{ + assert(solver->ok); + checkUnsetSanity(); + *solver->frat << __PRETTY_FUNCTION__ << " start\n"; + + //Set up stats + runStats.clear(); + runStats.numCalls = 1; + const double myTime = cpuTime(); + const size_t origTrailSize = solver->trail_size(); + + if (!solver->clauseCleaner->remove_and_clean_all()) { + return false; + } + #ifdef DEBUG_ATTACH_MORE + solver->test_all_clause_attached(); + #endif + + //Printing stats + if (solver->conf.verbosity >= 5) + printReplaceStats(); + + update_all_vardata(); + check_no_replaced_var_set(); + + runStats.actuallyReplacedVars = replacedVars -lastReplacedVars; + lastReplacedVars = replacedVars; + + #ifdef DEBUG_ATTACH_MORE + solver->test_all_clause_attached(); + #endif + assert(solver->prop_at_head()); + + #ifdef DEBUG_IMPLICIT_STATS + solver->check_implicit_stats(); + #endif + build_fast_inter_replace_lookup(); + + //Replace implicits + if (!replaceImplicit()) { + goto end; + } + + //Replace longs + assert(solver->watches.get_smudged_list().empty()); + assert(delayed_attach_or_free.empty()); + if (!replace_set(solver->longIrredCls)) { + goto end; + } + for(auto& lredcls: solver->longRedCls) { + if (!replace_set(lredcls)) { + goto end; + } + } + replace_bnns(); + + solver->clean_occur_from_removed_clauses_only_smudged(); + attach_delayed_attach(); + + //Replace XORs + if (!replace_xor_clauses(solver->xorclauses)) goto end; + if (!replace_xor_clauses(solver->xorclauses_orig)) goto end; + if (!replace_xor_clauses(solver->xorclauses_unused)) goto end; + + assert(solver->gmatrices.empty() && "Cannot replace vars inside GJ elim"); + + for(auto& v: solver->removed_xorclauses_clash_vars) { + v = get_var_replaced_with_fast(v); + } + + //While replacing the clauses + //we cannot(for implicits) and/or shouldn't (for implicit & long cls) enqueue + //* We cannot because we are going through a struct and we might change it + //* We shouldn't because then non-dominators would end up in the 'trail' + if (!enqueueDelayedEnqueue()) { + goto end; + } + + solver->update_assumptions_after_varreplace(); +#ifdef USE_BREAKID + if (solver->breakid) { + solver->breakid->update_var_after_varreplace(); + } +#endif + +end: + delayed_attach_or_free.clear(); + destroy_fast_inter_replace_lookup(); + assert(solver->prop_at_head() || !solver->ok); + + //Update stats + const double time_used = cpuTime() - myTime; + runStats.zeroDepthAssigns += solver->trail_size() - origTrailSize; + runStats.cpu_time = time_used; + globalStats += runStats; + if (solver->conf.verbosity) { + if (solver->conf.verbosity >= 3) + runStats.print(solver->nVarsOuter()); + else + runStats.print_short(solver); + } + if (solver->sqlStats) { + solver->sqlStats->time_passed_min( + solver + , "vrep" + , time_used + ); + } + *solver->frat << __PRETTY_FUNCTION__ << " end\n"; + + if (solver->okay()) { + #ifdef DEBUG_ATTACH_MORE + solver->test_all_clause_attached(); + #endif + solver->check_wrong_attach(); + #ifdef DEBUG_IMPLICIT_STATS + solver->check_stats(); + #endif + checkUnsetSanity(); + } + delete_frat_cls(); + + return solver->okay(); +} + +void VarReplacer::delete_frat_cls() +{ + for(const auto& f: bins_for_frat) { + *solver->frat << del << std::get<0>(f) << std::get<1>(f) << std::get<2>(f) << fin; + } + bins_for_frat.clear(); +} + +bool VarReplacer::replace_one_xor_clause(Xor& x) +{ + uint32_t j = 0; + for(uint32_t i = 0; i < x.clash_vars.size(); i++) { + uint32_t v = x.clash_vars[i]; + uint32_t upd = get_var_replaced_with_fast(v); + if (!solver->seen[upd]) { + solver->seen[upd] = 1; + x.clash_vars[j++] = upd; + } + } + x.clash_vars.resize(j); + for(auto& v: x.clash_vars) solver->seen[v] = 0; + + for(uint32_t& v: x) { + assert(v < solver->nVars()); + + Lit l = Lit(v, false); + if (get_lit_replaced_with_fast(l) != l) { + const Lit l2 = get_lit_replaced_with_fast(l); + #ifdef USE_TBUDDY + if (solver->frat->enabled()) { + solver->frat->flush(); + ilist bin = ilist_new(2); + ilist_resize(bin, 2); + bin[0] = v+1; + bin[1] = l2.var()+1; + tbdd::xor_constraint* bdd2 = new tbdd::xor_constraint(bin, l2.sign()); + tbdd::xor_set xs; + xs.add(*x.bdd); + xs.add(*bdd2); + const auto new_bdd = xs.sum(); + delete bdd2; + delete x.bdd; + x.bdd = new_bdd; + } + #endif + x.rhs ^= l2.sign(); + v = l2.var(); + runStats.replacedLits++; + } + } + + solver->clean_xor_vars_no_prop(x.get_vars(), x.rhs); + switch (x.size()) { + case 0: + if (x.rhs == true) solver->ok = false; + return false; + break; + case 1: { + Lit l(x[0], !x.rhs); + *solver->frat << add << ++solver->clauseID << l << fin; + delayedEnqueue.push_back(make_pair(l, solver->clauseID)); + return false; + break; + } + default: + return true; + break; + } +} + +bool VarReplacer::replace_xor_clauses(vector& xors) +{ + uint32_t j = 0; + + for(uint32_t i = 0; i < xors.size(); i++) { + Xor& x = xors[i]; + if (replace_one_xor_clause(x)) { + std::swap(xors[j], xors[i]); + j++; + } else { + TBUDDY_DO(delete x.bdd); + TBUDDY_DO(x.bdd = NULL); + } + } + xors.resize(j); + + return solver->okay(); +} + +inline void VarReplacer::updateBin( + Watched* i + , Watched*& j + , const Lit origLit1 + , const Lit origLit2 + , Lit lit1 + , Lit lit2 +) { + bool remove = false; + + //Two lits are the same in BIN + if (lit1 == lit2) { + int32_t ID = ++solver->clauseID; + (*solver->frat) << add << ID << lit2 << fin; + delayedEnqueue.push_back(make_pair(lit2, ID)); + remove = true; + } + + //Tautology + if (lit1 == ~lit2) remove = true; + if (remove) { + impl_tmp_stats.remove(*i); + + //Drat -- Delete only once + if (origLit1 < origLit2) { + (*solver->frat) << del << i->get_ID() << origLit1 << origLit2 << fin; + } + + return; + } + + //Drat + if (//Changed + (lit1 != origLit1 || lit2 != origLit2) + //Delete&attach only once + && (origLit1 < origLit2) + ) { + //WARNING TODO beware, this make post-FRAT parsing for ML fail. + //we need a better mechanism than reloc, or we need to teach the tool reloc + //solver->clauseID+1 is used and then unused immediately + (*solver->frat) + << reloc << i->get_ID() << solver->clauseID+1 << fin + << add << i->get_ID() << lit1 << lit2 << fin + << del << solver->clauseID+1 << origLit1 << origLit2 << fin; + } + + if (lit1 != origLit1) { + solver->watches[lit1].push(*i); + } else { + *j++ = *i; + } +} + +void VarReplacer::updateStatsFromImplStats() +{ + assert(impl_tmp_stats.removedRedBin % 2 == 0); + solver->binTri.redBins -= impl_tmp_stats.removedRedBin/2; + + assert(impl_tmp_stats.removedIrredBin % 2 == 0); + solver->binTri.irredBins -= impl_tmp_stats.removedIrredBin/2; + + #ifdef DEBUG_IMPLICIT_STATS + solver->check_implicit_stats(); + #endif + + runStats.removedBinClauses += impl_tmp_stats.removedRedBin/2 + impl_tmp_stats.removedIrredBin/2; + + impl_tmp_stats.clear(); +} + +bool VarReplacer::replaceImplicit() +{ + impl_tmp_stats.clear(); + delayedEnqueue.clear(); + delayed_attach_bin.clear(); + assert(solver->watches.get_smudged_list().empty()); + + for(size_t i = 0; i < solver->nVars()*2; i++) { + const Lit lit = Lit::toLit(i); + if (get_lit_replaced_with_fast(lit) != lit) { + solver->watches.smudge(lit); + } + } + + for(size_t at = 0; at < solver->watches.get_smudged_list().size(); at++) { + const Lit origLit1 = solver->watches.get_smudged_list()[at]; + watch_subarray ws = solver->watches[origLit1]; + + Watched* i = ws.begin(); + Watched* j = i; + for (Watched *end2 = ws.end(); i != end2; i++) { + //Don't bother non-bin + if (!i->isBin()) { + *j++ = *i; + continue; + } + runStats.bogoprops += 1; + + const Lit origLit2 = i->lit2(); + assert(solver->value(origLit1) == l_Undef); + assert(solver->value(origLit2) == l_Undef); + assert(origLit1.var() != origLit2.var()); + + //Update main lit + Lit lit1 = origLit1; + if (get_lit_replaced_with_fast(lit1) != lit1) { + lit1 = get_lit_replaced_with_fast(lit1); + runStats.replacedLits++; + solver->watches.smudge(origLit2); + } + + //Update lit2 + Lit lit2 = origLit2; + if (get_lit_replaced_with_fast(lit2) != lit2) { + lit2 = get_lit_replaced_with_fast(lit2); + i->setLit2(lit2); + runStats.replacedLits++; + } + + assert(i->isBin()); + updateBin(i, j, origLit1, origLit2, lit1, lit2); + } + ws.shrink_(i-j); + } + + for(const BinaryClause& bincl : delayed_attach_bin) { + solver->attach_bin_clause( + bincl.getLit1(), bincl.getLit2(), bincl.isRed(), bincl.getID()); + } + delayed_attach_bin.clear(); + + #ifdef VERBOSE_DEBUG_BIN_REPLACER + cout << "c debug bin replacer start" << endl; + cout << "c debug bin replacer end" << endl; + #endif + + updateStatsFromImplStats(); + solver->watches.clear_smudged(); + + return solver->okay(); +} + + +void VarReplacer::replace_bnn_lit(Lit& l, uint32_t idx, bool& changed) +{ + removeWBNN(solver->watches, l, idx); + removeWBNN(solver->watches, ~l, idx); + changed = true; + l = get_lit_replaced_with_fast(l); + runStats.replacedLits++; +} + +bool VarReplacer::replace_bnns() +{ + assert(!solver->frat->something_delayed()); + for (uint32_t idx = 0; idx < solver->bnns.size(); idx++) { + BNN* bnn = solver->bnns[idx]; + if (bnn == NULL) { + continue; + } + assert(!bnn->isRemoved); + runStats.bogoprops += 3; + + bool changed = false; + + for (Lit& l: *bnn) { + if (isReplaced_fast(l)) { + replace_bnn_lit(l, idx, changed); + solver->watches[l].push(Watched(idx, WatchType::watch_bnn_t, bnn_pos_t)); + solver->watches[~l].push(Watched(idx, WatchType::watch_bnn_t, bnn_neg_t)); + } + } + if (!bnn->set) { + if (isReplaced_fast(bnn->out)) { + replace_bnn_lit(bnn->out, idx, changed); + solver->watches[bnn->out].push( + Watched(idx, WatchType::watch_bnn_t, bnn_out_t)); + solver->watches[~bnn->out].push( + Watched(idx, WatchType::watch_bnn_t, bnn_out_t)); + } + } + + if (changed) { + // TODO fix up BNN: p + ~p + } + + } + + assert(solver->okay() && "Beware, we don't check return value of this function"); + return solver->okay(); +} + +/** +@brief Replaces variables in long clauses +*/ +bool VarReplacer::replace_set(vector& cs) +{ + assert(!solver->frat->something_delayed()); + vector::iterator i = cs.begin(); + vector::iterator j = i; + for (vector::iterator end = cs.end(); i != end; ++i) { + runStats.bogoprops += 3; + assert(!solver->frat->something_delayed()); + + //Finish up if UNSAT + if (!solver->ok) { + *j++ = *i; + continue; + } + + Clause& c = *solver->cl_alloc.ptr(*i); + assert(!c.getRemoved()); + assert(c.size() > 2); + + bool changed = false; + (*solver->frat) << deldelay << c << fin; + + const Lit origLit1 = c[0]; + const Lit origLit2 = c[1]; + + for (Lit& l: c) { + if (isReplaced_fast(l)) { + changed = true; + l = get_lit_replaced_with_fast(l); + runStats.replacedLits++; + } + } + + if (changed && handleUpdatedClause(c, origLit1, origLit2)) { + runStats.removedLongClauses++; + if (!solver->ok) { + //if it became UNSAT, then don't delete. + *j++ = *i; + } + } else { + *j++ = *i; + solver->frat->forget_delay(); + } + + } + cs.resize(cs.size() - (i-j)); + assert(!solver->frat->something_delayed()); + + return solver->okay(); +} + +Lit* my_lit_find(Clause& cl, const Lit lit) +{ + for(Lit* a = cl.begin(); a != cl.end(); a++) { + if (*a == lit) + return a; + } + return NULL; +} + +/** +@returns TRUE if needs removal +*/ +bool VarReplacer::handleUpdatedClause( + Clause& c + , const Lit origLit1 + , const Lit origLit2 +) { + assert(!c.getRemoved()); + bool satisfied = false; + std::sort(c.begin(), c.end()); + Lit p; + uint32_t i, j; + const uint32_t origSize = c.size(); + for (i = j = 0, p = lit_Undef; i != origSize; i++) { + assert(solver->varData[c[i].var()].removed == Removed::none); + if (solver->value(c[i]) == l_True || c[i] == ~p) { + satisfied = true; + break; + } + else if (solver->value(c[i]) != l_False && c[i] != p) { + c[j++] = p = c[i]; + } + } + c.shrink(i - j); + c.setStrenghtened(); + + runStats.bogoprops += 10; + if (c.red()) { + solver->litStats.redLits -= origSize; + } else { + solver->litStats.irredLits -= origSize; + } + delayed_attach_or_free.push_back(&c); + VERBOSE_PRINT("clause after var-replacement: " << c); + + if (satisfied) { + (*solver->frat) << findelay; + c.shrink(c.size()); //needed to make clause cleaner happy + solver->watches.smudge(origLit1); + solver->watches.smudge(origLit2); + c.setRemoved(); + return true; + } + + INC_ID(c); + (*solver->frat) << add << c << fin << findelay; + + runStats.bogoprops += 3; + switch(c.size()) { + case 0: + assert(solver->unsat_cl_ID == 0); + solver->unsat_cl_ID = c.stats.ID; + solver->ok = false; + return true; + case 1 : + c.setRemoved(); + solver->watches.smudge(origLit1); + solver->watches.smudge(origLit2); + + delayedEnqueue.push_back(make_pair(c[0], c.stats.ID)); + runStats.removedLongLits += origSize; + return true; + case 2: + c.setRemoved(); + solver->watches.smudge(origLit1); + solver->watches.smudge(origLit2); + + solver->attach_bin_clause(c[0], c[1], c.red(), c.stats.ID); + runStats.removedLongLits += origSize; + return true; + + default: + Lit* at = my_lit_find(c, origLit1); + if (at != NULL) { + std::swap(c[0], *at); + } + Lit* at2 = my_lit_find(c, origLit2); + if (at2 != NULL) { + std::swap(c[1], *at2); + } + if (at != NULL && at2 != NULL) { + delayed_attach_or_free.pop_back(); + if (c.red()) { + solver->litStats.redLits += c.size(); + } else { + solver->litStats.irredLits += c.size(); + } + } else { + c.setRemoved(); + solver->watches.smudge(origLit1); + solver->watches.smudge(origLit2); + } + + runStats.removedLongLits += origSize - c.size(); + return false; + } + + release_assert(false); +} + +void VarReplacer::set_sub_var_during_solution_extension(uint32_t var, const uint32_t sub_var) +{ + assert(table.size() > sub_var); + assert(solver->model.size() > var); + const lbool to_set = solver->model[var] ^ table[sub_var].sign(); + const uint32_t sub_var_inter = solver->map_outer_to_inter(sub_var); + assert(solver->varData[sub_var_inter].removed == Removed::replaced); + #ifdef VERBOSE_DEBUG + if (solver->model_value(sub_var) != l_Undef) { + cout << "ERROR: var " << sub_var +1 << " is set but it's replaced!" << endl; + } + #endif + assert(solver->model_value(sub_var) == l_Undef); + + if (solver->conf.verbosity > 10) { + cout << "Varreplace-extend: setting outer " << sub_var+1 + << " to " << to_set << " because of " << var+1 << endl; + } + solver->model[sub_var] = to_set; +} + +//NOTE: 'var' is OUTER +void VarReplacer::extend_model(const uint32_t var) +{ + assert(solver->model[var] != l_Undef); + auto it = reverseTable.find(var); + if (it == reverseTable.end()) return; + + assert(it->first == var); + for(const uint32_t sub_var: it->second) + set_sub_var_during_solution_extension(var, sub_var); +} + +void VarReplacer::extend_pop_queue(vector& pop) +{ + vector extra; + for (Lit p: pop) { + const auto& repl = reverseTable[p.var()]; + for(uint32_t x: repl) { + extra.push_back(Lit(x, table[x].sign() ^ p.sign())); + } + } + + for(Lit x: extra) { + pop.push_back(x); + } +} + +void VarReplacer::extend_model_already_set() +{ + assert(solver->model.size() == solver->nVarsOuter()); + for (auto it = reverseTable.begin() , end = reverseTable.end() + ; it != end + ; ++it + ) { + if (solver->model_value(it->first) == l_Undef) { + continue; + } + + for(const uint32_t sub_var: it->second) + { + set_sub_var_during_solution_extension(it->first, sub_var); + } + } +} + +void VarReplacer::extend_model_set_undef() +{ + assert(solver->model.size() == solver->nVarsOuter()); + for (auto it = reverseTable.begin() , end = reverseTable.end() + ; it != end + ; ++it + ) { + if (solver->model_value(it->first) == l_Undef) { + solver->model[it->first] = l_False; + for(const uint32_t sub_var: it->second) + { + set_sub_var_during_solution_extension(it->first, sub_var); + } + } + } +} + +void VarReplacer::replaceChecks(const uint32_t var1, const uint32_t var2) const +{ + + assert(solver->ok); + assert(solver->decisionLevel() == 0); + assert(solver->value(var1) == l_Undef); + assert(solver->value(var2) == l_Undef); + + assert(solver->varData[var1].removed == Removed::none); + assert(solver->varData[var2].removed == Removed::none); +} + +bool VarReplacer::handleAlreadyReplaced(const Lit lit1, const Lit lit2) +{ + //OOps, already inside, but with inverse polarity, UNSAT + if (lit1.sign() != lit2.sign()) { + (*solver->frat) + << add << ++solver->clauseID << ~lit1 << lit2 << fin + << add << ++solver->clauseID << lit1 << ~lit2 << fin + << add << ++solver->clauseID << lit1 << fin + << add << ++solver->clauseID << ~lit1 << fin + << add << ++solver->clauseID << fin + << del << solver->clauseID-1 << ~lit1 << fin + << del << solver->clauseID-2 << lit1 << fin + << del << solver->clauseID-3 << lit1 << ~lit2 << fin + << del << solver->clauseID-4 << ~lit1 << lit2 << fin; + // the UNSAT one, i.e. solver->clauseID-1 does not need to be deleted, + // it's automatically deleted + assert(solver->unsat_cl_ID == 0); + solver->unsat_cl_ID = solver->clauseID; + solver->ok = false; + return false; + } + + //Already inside in the correct way, return + return true; +} + +bool VarReplacer::replace_vars_already_set( + const Lit lit1 + , const lbool val1 + , const Lit /*lit2*/ + , const lbool val2 +) { + if (val1 != val2) { + + (*solver->frat) + << add << ++solver->clauseID << ~lit1 << fin + << add << ++solver->clauseID << lit1 << fin + << add << ++solver->clauseID << fin + << del << solver->clauseID-1 << lit1 << fin + << del << solver->clauseID-2 << ~lit1 << fin; + assert(solver->unsat_cl_ID == 0); + solver->unsat_cl_ID = solver->clauseID; + solver->ok = false; + } + + //Already set, return with correct code + return solver->okay(); +} + +bool VarReplacer::handleOneSet( + const Lit lit1 + , const lbool val1 + , const Lit lit2 + , const lbool val2 +) { + if (solver->ok) { + Lit toEnqueue; + if (val1 != l_Undef) { + toEnqueue = lit2 ^ (val1 == l_False); + } else { + toEnqueue = lit1 ^ (val2 == l_False); + } + solver->enqueue(toEnqueue); + solver->ok = (solver->propagate().isNULL()); + } + return solver->okay(); +} + +/** +@brief Replaces two two lits with one another +*/ +bool VarReplacer::replace( + uint32_t var1 + , uint32_t var2 + , const bool xor_is_true +) +{ + #ifdef VERBOSE_DEBUG + cout + << "replace() called with var " << Lit(var1, false) + << " and var " << Lit(var2, false) + << " with xor_is_true " << xor_is_true << endl; + #endif + + replaceChecks(var1, var2); + + //Move forward + const Lit lit1 = get_lit_replaced_with(Lit(var1, false)); + const Lit lit2 = get_lit_replaced_with(Lit(var2, false)) ^ xor_is_true; + + //Already inside? + if (lit1.var() == lit2.var()) { + return handleAlreadyReplaced(lit1, lit2); + } + + int32_t ID = ++solver->clauseID; + int32_t ID2 = ++solver->clauseID; + (*solver->frat) + << add << ID << ~lit1 << lit2 << fin + << add << ID2 << lit1 << ~lit2 << fin; + bins_for_frat.push_back(std::tuple{ID, ~lit1, lit2}); + bins_for_frat.push_back(std::tuple{ID2, lit1, ~lit2}); + + //None should be removed, only maybe queued for replacement + assert(solver->varData[lit1.var()].removed == Removed::none); + assert(solver->varData[lit2.var()].removed == Removed::none); + + const lbool val1 = solver->value(lit1); + const lbool val2 = solver->value(lit2); + + //Both are set + if (val1 != l_Undef && val2 != l_Undef) { + return replace_vars_already_set(lit1, val1, lit2, val2); + } + + //exactly one set + if ((val1 != l_Undef && val2 == l_Undef) + || (val2 != l_Undef && val1 == l_Undef) + ) { + return handleOneSet(lit1, val1, lit2, val2); + } + + assert(val1 == l_Undef && val2 == l_Undef); + + const Lit lit1_outer = solver->map_inter_to_outer(lit1); + const Lit lit2_outer = solver->map_inter_to_outer(lit2); + return update_table_and_reversetable(lit1_outer, lit2_outer); +} + +bool VarReplacer::update_table_and_reversetable(const Lit lit1, const Lit lit2) +{ + if (reverseTable.find(lit1.var()) == reverseTable.end()) { + reverseTable[lit2.var()].push_back(lit1.var()); + table[lit1.var()] = lit2 ^ lit1.sign(); + replacedVars++; + return true; + } + + if (reverseTable.find(lit2.var()) == reverseTable.end()) { + reverseTable[lit1.var()].push_back(lit2.var()); + table[lit2.var()] = lit1 ^ lit2.sign(); + replacedVars++; + return true; + } + + //both have children + setAllThatPointsHereTo(lit1.var(), lit2 ^ lit1.sign()); + replacedVars++; + return true; +} + +/** +@brief Changes internal graph to set everything that pointed to var to point to lit +*/ +void VarReplacer::setAllThatPointsHereTo(const uint32_t var, const Lit lit) +{ + map >::iterator it = reverseTable.find(var); + if (it != reverseTable.end()) { + for(const uint32_t var2: it->second) { + assert(table[var2].var() == var); + if (lit.var() != var2) { + table[var2] = lit ^ table[var2].sign(); + reverseTable[lit.var()].push_back(var2); + } + } + reverseTable.erase(it); + } + table[var] = lit; + reverseTable[lit.var()].push_back(var); +} + +void VarReplacer::checkUnsetSanity() +{ + for(size_t i = 0; i < solver->nVarsOuter(); i++) { + const Lit repLit = get_lit_replaced_with(Lit(i, false)); + const uint32_t repVar = get_var_replaced_with(i); + + if (solver->varData[i].removed == Removed::none + && solver->varData[repVar].removed == Removed::none + && solver->value(i) != solver->value(repLit) + ) { + cout + << "Variable " << (i+1) + << " has been set to " << solver->value(i) + << " but it has been replaced with lit " + << get_lit_replaced_with(Lit(i, false)) + << " and that has been set to " + << solver->value(get_lit_replaced_with(Lit(i, false))) + << endl; + + assert(solver->value(i) == solver->value(repLit)); + std::exit(-1); + } + } + + #ifdef SLOW_DEBUG + check_no_replaced_var_set(); + #endif +} + +bool VarReplacer::add_xor_as_bins(const BinaryXor& bin_xor) +{ + ps_tmp[0] = Lit(bin_xor.vars[0], false); + ps_tmp[1] = Lit(bin_xor.vars[1], true ^ bin_xor.rhs); + solver->add_clause_int(ps_tmp); + if (!solver->ok) return false; + + ps_tmp[0] = Lit(bin_xor.vars[0], true); + ps_tmp[1] = Lit(bin_xor.vars[1], false ^ bin_xor.rhs); + solver->add_clause_int(ps_tmp); + if (!solver->ok) return false; + + return true; +} + +bool VarReplacer::replace_if_enough_is_found(const size_t limit, uint64_t* bogoprops_given, bool *replaced) +{ + if (replaced) + *replaced = false; + + scc_finder->performSCC(bogoprops_given); + if (scc_finder->get_num_binxors_found() < limit) { + scc_finder->clear_binxors(); + return solver->okay(); + } + + assert(solver->gmatrices.empty()); + assert(solver->gqueuedata.empty()); + + if (replaced) + *replaced = true; + + const set& xors_found = scc_finder->get_binxors(); + for(BinaryXor bin_xor: xors_found) { + if (!add_xor_as_bins(bin_xor)) return false; + + if (solver->value(bin_xor.vars[0]) == l_Undef + && solver->value(bin_xor.vars[1]) == l_Undef + ) { + replace(bin_xor.vars[0], bin_xor.vars[1], bin_xor.rhs); + if (!solver->okay()) { + return false; + } + } + } + + const bool ret = perform_replace(); + if (bogoprops_given) { + *bogoprops_given += runStats.bogoprops; + } + scc_finder->clear_binxors(); + + return ret; +} + +size_t VarReplacer::mem_used() const +{ + size_t b = 0; + b += scc_finder->mem_used(); + b += delayedEnqueue.capacity()*sizeof(Lit); + b += table.capacity()*sizeof(Lit); + for(map >::const_iterator + it = reverseTable.begin(), end = reverseTable.end() + ; it != end + ; ++it + ) { + b += it->second.capacity()*sizeof(Lit); + } + //TODO under-counting + b += reverseTable.size()*(sizeof(uint32_t) + sizeof(vector)); + + return b; +} + +uint32_t VarReplacer::print_equivalent_literals(bool outer_numbering, std::ostream *os) const +{ + uint32_t num = 0; + vector tmpCl; + for (uint32_t var = 0; var < table.size(); var++) { + const Lit lit = table[var]; + if (lit.var() == var) + continue; + + //They have been renumbered in a way that cannot be dumped + Lit lit1; + Lit lit2; + if (outer_numbering) { + lit1 = lit; + lit2 = Lit(var, false); + } else { + lit1 = solver->map_outer_to_inter(lit); + lit2 = solver->map_outer_to_inter(Lit(var, false)); + + if (lit1.var() >= solver->nVars() || + lit2.var() >= solver->nVars() + ) { + continue; + } + } + + if (os) { + tmpCl.clear(); + tmpCl.push_back(~lit1); + tmpCl.push_back(lit2); + std::sort(tmpCl.begin(), tmpCl.end()); + + *os + << tmpCl[0] << " " + << tmpCl[1] + << " 0\n"; + + tmpCl[0] ^= true; + tmpCl[1] ^= true; + + *os + << tmpCl[0] << " " + << tmpCl[1] + << " 0\n"; + } + num++; + } + return num; +} + +void VarReplacer::print_some_stats(const double global_cpu_time) const +{ + print_stats_line("c vrep replace time" + , globalStats.cpu_time + , stats_line_percent(globalStats.cpu_time, global_cpu_time) + , "% time" + ); + + print_stats_line("c vrep tree roots" + , getNumTrees() + ); + + print_stats_line("c vrep trees' crown" + , get_num_replaced_vars() + , float_div(get_num_replaced_vars(), getNumTrees()) + , "leafs/tree" + ); +} + +void VarReplacer::Stats::print(const size_t nVars) const +{ + cout << "c --------- VAR REPLACE STATS ----------" << endl; + print_stats_line("c time" + , cpu_time + , float_div(cpu_time, numCalls) + , "per call" + ); + + print_stats_line("c trees' crown" + , actuallyReplacedVars + , stats_line_percent(actuallyReplacedVars, nVars) + , "% of vars" + ); + + print_stats_line("c 0-depth assigns" + , zeroDepthAssigns + , stats_line_percent(zeroDepthAssigns, nVars) + , "% vars" + ); + + print_stats_line("c lits replaced" + , replacedLits + ); + + print_stats_line("c bin cls removed" + , removedBinClauses + ); + + print_stats_line("c long cls removed" + , removedLongClauses + ); + + print_stats_line("c long lits removed" + , removedLongLits + ); + + print_stats_line("c bogoprops" + , bogoprops + ); + cout << "c --------- VAR REPLACE STATS END ----------" << endl; +} + +void VarReplacer::Stats::print_short(const Solver* solver) const +{ + cout + << "c [vrep]" + << " vars " << actuallyReplacedVars + << " lits " << replacedLits + << " rem-bin-cls " << removedBinClauses + << " rem-long-cls " << removedLongClauses + << " BP " << bogoprops/(1000*1000) << "M" + << solver->conf.print_times(cpu_time) + << endl; +} + +VarReplacer::Stats& VarReplacer::Stats::operator+=(const Stats& other) +{ + numCalls += other.numCalls; + cpu_time += other.cpu_time; + replacedLits += other.replacedLits; + zeroDepthAssigns += other.zeroDepthAssigns; + actuallyReplacedVars += other.actuallyReplacedVars; + removedBinClauses += other.removedBinClauses; + removedLongClauses += other.removedLongClauses; + removedLongLits += other.removedLongLits; + bogoprops += other.bogoprops; + + return *this; +} + +void VarReplacer::build_fast_inter_replace_lookup() +{ + fast_inter_replace_lookup.clear(); + fast_inter_replace_lookup.reserve(solver->nVars()); + for(uint32_t var = 0; var < solver->nVars(); var++) { + fast_inter_replace_lookup.push_back(get_lit_replaced_with(Lit(var, false))); + } +} + +void VarReplacer::destroy_fast_inter_replace_lookup() +{ + vector tmp; + fast_inter_replace_lookup.swap(tmp); +} + +Lit VarReplacer::get_lit_replaced_with(Lit lit) const +{ + lit = solver->map_inter_to_outer(lit); + Lit lit2 = get_lit_replaced_with_outer(lit); + return solver->map_outer_to_inter(lit2); +} + +// Takes inter, outputs inter +uint32_t VarReplacer::get_var_replaced_with(uint32_t var) const +{ + var = solver->map_inter_to_outer(var); + uint32_t var2 = table[var].var(); + return solver->map_outer_to_inter(var2); +} + +vector VarReplacer::get_vars_replacing(uint32_t var) const +{ + vector ret; + var = solver->map_inter_to_outer(var); + map >::const_iterator it = reverseTable.find(var); + if (it != reverseTable.end()) { + for(uint32_t v: it->second) { + ret.push_back(solver->map_outer_to_inter(v)); + } + } + + return ret; +} + +vector > VarReplacer::get_all_binary_xors_outer() const +{ + vector > ret; + for(size_t i = 0; i < table.size(); i++) { + if (table[i] != Lit(i, false)) { + ret.push_back(make_pair(Lit(i, false), table[i])); + } + } + + return ret; +} + +bool VarReplacer::get_scc_depth_warning_triggered() const +{ + return scc_finder->depth_warning_triggered(); +} diff --git a/cryptominisat/cppsrc/src/varreplacer.h b/cryptominisat/cppsrc/src/varreplacer.h new file mode 100644 index 00000000..e78fc82e --- /dev/null +++ b/cryptominisat/cppsrc/src/varreplacer.h @@ -0,0 +1,347 @@ +/****************************************** +Copyright (C) 2009-2020 Authors of CryptoMiniSat, see AUTHORS file + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. +***********************************************/ + +#pragma once + +#include +#include +#include +#include +#ifdef ARJUN_SERIALIZE +#include +#include +#endif + +#include "constants.h" +#include "solvertypes.h" +#include "clause.h" +#include "xor.h" +#include "watcharray.h" +#include "simplefile.h" + +namespace CMSat { + +//#define VERBOSE_DEBUG + +using std::map; +using std::vector; +using std::tuple; +class Solver; +class SCCFinder; + +/** +@brief Replaces variables with their anti/equivalents +*/ +class VarReplacer +{ + public: + explicit VarReplacer(Solver* solver); + ~VarReplacer(); + void new_var(const uint32_t orig_outer); + void new_vars(const size_t n); + void save_on_var_memory(); + bool replace_if_enough_is_found(const size_t limit = 0, uint64_t* bogoprops = NULL, bool* replaced = NULL); + uint32_t print_equivalent_literals(bool outer_numbering, std::ostream *os = NULL) const; + void print_some_stats(const double global_cpu_time) const; + const SCCFinder* get_scc_finder() const; + + void extend_model_already_set(); + void extend_model_set_undef(); + void extend_model(const uint32_t var); + void extend_pop_queue(vector& pop); + + uint32_t get_var_replaced_with(const uint32_t var) const; + uint32_t get_var_replaced_with(const Lit lit) const; + Lit get_lit_replaced_with(Lit lit) const; + Lit get_lit_replaced_with_outer(Lit lit) const; + uint32_t get_var_replaced_with_outer(uint32_t var) const; + bool var_is_replacing(const uint32_t var); + +#ifdef ARJUN_SERIALIZE + template void unserialize_tables(T& ar); + template void serialize_tables (T& ar) const; +#endif + + vector get_vars_replacing(uint32_t var) const; + void updateVars( + const vector& outerToInter + , const vector& interToOuter + ); + + //Stats + size_t get_num_replaced_vars() const; + struct Stats + { + void clear() + { + Stats tmp; + *this = tmp; + } + + Stats& operator+=(const Stats& other); + void print(const size_t nVars) const; + void print_short(const Solver* solver) const; + + uint64_t numCalls = 0; + double cpu_time = 0; + uint64_t replacedLits = 0; + uint64_t zeroDepthAssigns = 0; + uint64_t actuallyReplacedVars = 0; + uint64_t removedBinClauses = 0; + uint64_t removedLongClauses = 0; + uint64_t removedLongLits = 0; + uint64_t bogoprops = 0; + }; + const Stats& get_stats() const; + size_t mem_used() const; + vector > get_all_binary_xors_outer() const; + vector get_vars_replacing_others() const; + bool get_scc_depth_warning_triggered() const; + void delete_frat_cls(); + + private: + Solver* solver; + SCCFinder* scc_finder; + vector delayed_attach_or_free; + + void replace_bnn_lit(Lit& l, uint32_t idx, bool& changed); + bool replace_bnns(); + + void check_no_replaced_var_set() const; + vector fast_inter_replace_lookup; + void build_fast_inter_replace_lookup(); + void destroy_fast_inter_replace_lookup(); + Lit get_lit_replaced_with_fast(const Lit lit) const { + return fast_inter_replace_lookup[lit.var()] ^ lit.sign(); + } + uint32_t get_var_replaced_with_fast(const uint32_t var) const { + return fast_inter_replace_lookup[var].var(); + } + bool replace_xor_clauses(vector& xors); + bool replace_one_xor_clause(Xor& x); + + vector ps_tmp; + bool perform_replace(); + bool add_xor_as_bins(const BinaryXor& bin_xor); + bool replace( + uint32_t lit1 + , uint32_t lit2 + , bool xor_is_true + ); + + bool isReplaced(const uint32_t var) const; + bool isReplaced(const Lit lit) const; + bool isReplaced_fast(const uint32_t var) const; + bool isReplaced_fast(const Lit lit) const; + + size_t getNumTrees() const; + void set_sub_var_during_solution_extension(uint32_t var, uint32_t sub_var); + void checkUnsetSanity(); + + bool replace_set(vector& cs); + void attach_delayed_attach(); + void update_all_vardata(); + void update_vardata( + const Lit orig + , const Lit replaced + ); + bool enqueueDelayedEnqueue(); + + //Helpers for replace() + void replaceChecks(const uint32_t var1, const uint32_t var2) const; + bool handleAlreadyReplaced(const Lit lit1, const Lit lit2); + bool replace_vars_already_set( + const Lit lit1 + , const lbool val1 + , const Lit lit2 + , const lbool val2 + ); + bool handleOneSet( + const Lit lit1 + , const lbool val1 + , const Lit lit2 + , const lbool val2 + ); + + //Temporary used in replaceImplicit + vector delayed_attach_bin; + bool replaceImplicit(); + struct ImplicitTmpStats + { + ImplicitTmpStats() : + removedRedBin(0) + , removedIrredBin(0) + { + } + + void remove(const Watched& ws) + { + if (ws.isBin()) { + if (ws.red()) { + removedRedBin++; + } else { + removedIrredBin++; + } + } else { + assert(false); + } + } + + void clear() + { + *this = ImplicitTmpStats(); + } + + size_t removedRedBin; + size_t removedIrredBin; + }; + ImplicitTmpStats impl_tmp_stats; + void updateBin( + Watched* i + , Watched*& j + , const Lit origLit1 + , const Lit origLit2 + , Lit lit1 + , Lit lit2 + ); + void updateStatsFromImplStats(); + + bool handleUpdatedClause(Clause& c, const Lit origLit1, const Lit origLit2); + + //While replacing the implicit clauses we cannot enqeue + vector> delayedEnqueue; + bool update_table_and_reversetable(const Lit lit1, const Lit lit2); + void setAllThatPointsHereTo(const uint32_t var, const Lit lit); + + /////////////////// + //Mapping tables + /////////////////// + + ///Stores which variables have been replaced by which literals. + //Everything is OUTER here. + //Index by: table[VAR] -> tells us what literal + // Lit(VAR, false) has been replaced with. + vector table; + + ///mapping of variable to set of variables it replaces + //Everything is OUTER here. + map > reverseTable; + + //FRAT + vector> bins_for_frat; + + //Stats + void printReplaceStats() const; + uint64_t replacedVars = 0; /// VarReplacer::get_vars_replacing_others() const +{ + vector replacingVars; + for(const auto& it: reverseTable) { + replacingVars.push_back(it.first); + } + return replacingVars; +} + +inline bool VarReplacer::var_is_replacing(const uint32_t var) +{ + auto it = reverseTable.find(var); + return it != reverseTable.end(); +} + +inline const VarReplacer::Stats& VarReplacer::get_stats() const +{ + return globalStats; +} + +inline const SCCFinder* VarReplacer::get_scc_finder() const +{ + return scc_finder; +} + +inline Lit VarReplacer::get_lit_replaced_with_outer(Lit lit) const +{ + Lit lit2 = table[lit.var()] ^ lit.sign(); + return lit2; +} + +inline uint32_t VarReplacer::get_var_replaced_with_outer(uint32_t var) const +{ + return table[var].var(); +} + +#ifdef ARJUN_SERIALIZE +template +void VarReplacer::serialize_tables(T& ar) const +{ + ar << table; + ar << reverseTable; +} + +template +void VarReplacer::unserialize_tables(T& ar) +{ + ar >> table; + ar >> reverseTable; +} +#endif + +} //end namespace diff --git a/cryptominisat/cppsrc/src/varupdatehelper.h b/cryptominisat/cppsrc/src/varupdatehelper.h new file mode 100644 index 00000000..7761d8ab --- /dev/null +++ b/cryptominisat/cppsrc/src/varupdatehelper.h @@ -0,0 +1,142 @@ +/****************************************** +Copyright (C) 2009-2020 Authors of CryptoMiniSat, see AUTHORS file + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. +***********************************************/ + +#ifndef __VARUPDATE_HELPER_H__ +#define __VARUPDATE_HELPER_H__ + +#include "solvertypes.h" +#include +#include + +namespace CMSat { + +uint32_t getUpdatedVar(uint32_t toUpdate, const vector< uint32_t >& mapper); +Lit getUpdatedLit(Lit toUpdate, const vector< uint32_t >& mapper); + +template +void updateArray(T& toUpdate, const vector< uint32_t >& mapper) +{ + T backup = toUpdate; + for(size_t i = 0; i < toUpdate.size(); i++) { + toUpdate.at(i) = backup.at(mapper.at(i)); + } +} + +template +void updateArrayRev(T& toUpdate, const vector< uint32_t >& mapper) +{ + assert(toUpdate.size() >= mapper.size()); + T backup = toUpdate; + for(size_t i = 0; i < mapper.size(); i++) { + toUpdate[mapper[i]] = backup[i]; + } +} + +template +void updateArrayMapCopy(T& toUpdate, const vector< uint32_t >& mapper) +{ + //assert(toUpdate.size() == mapper.size()); + T backup = toUpdate; + for(size_t i = 0; i < toUpdate.size(); i++) { + if (backup[i] < mapper.size()) { + toUpdate[i] = mapper[backup[i]]; + } + } +} + +template +void updateLitsMap(T& toUpdate, const vector< uint32_t >& mapper) +{ + for(size_t i = 0; i < toUpdate.size(); i++) { + if (toUpdate[i].var() < mapper.size()) { + toUpdate[i] = getUpdatedLit(toUpdate[i], mapper); + } + } +} + +template +void updateVarsMap(T& toUpdate, const vector< uint32_t >& mapper) +{ + for(size_t i = 0; i < toUpdate.size(); i++) { + if (toUpdate[i] < mapper.size()) { + toUpdate[i] = getUpdatedVar(toUpdate[i], mapper); + } + } +} + +inline Lit getUpdatedLit(Lit toUpdate, const vector< uint32_t >& mapper) +{ + return Lit(getUpdatedVar(toUpdate.var(), mapper), toUpdate.sign()); +} + +inline uint32_t getUpdatedVar(uint32_t toUpdate, const vector< uint32_t >& mapper) +{ + return mapper.at(toUpdate); +} + +inline uint32_t getUpdatedVarMaxToMax(uint32_t toUpdate, const vector< uint32_t >& mapper) +{ + if (toUpdate == numeric_limits::max()) { + return numeric_limits::max(); + } + return mapper.at(toUpdate); +} + +template +inline void updateBySwap(T& toUpdate, T2& seen, const vector< uint32_t >& mapper) +{ + for(size_t i = 0; i < toUpdate.size(); i++) { + if (seen.at(i)) { + //Already updated, skip + continue; + } + + //Swap circularly until we reach full circle + uint32_t var = i; + const uint32_t origStart = var; + while(true) { + uint32_t swapwith = mapper.at(var); + assert(seen.at(swapwith) == 0); + //std::cout << "Swapping " << var << " with " << swapwith << std::endl; + using std::swap; + swap(toUpdate.at(var), toUpdate.at(swapwith)); + seen.at(swapwith) = 1; + var = swapwith; + + //Full circle + if (mapper.at(var) == origStart) { + seen.at(mapper.at(var)) = 1; + break; + } + } + } + + //clear seen + for(size_t i = 0; i < toUpdate.size(); i++) { + assert(seen.at(i) == 1); + seen.at(i) = 0; + } +} + +} //end namespace + +#endif //__VARUPDATE_HELPER_H__ diff --git a/cryptominisat/cppsrc/src/vmtf.h b/cryptominisat/cppsrc/src/vmtf.h new file mode 100644 index 00000000..90ec1e8b --- /dev/null +++ b/cryptominisat/cppsrc/src/vmtf.h @@ -0,0 +1,96 @@ +/****************************************** +Copyright (c) 2019, Armin Biere + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. +***********************************************/ + +#pragma once + +#include +#include +#include +#include +#include "constants.h" +using std::vector; +using std::numeric_limits; + +namespace CMSat { + +// variable indices +struct Link { + uint32_t prev = numeric_limits::max(); ///< VARIABLE NUMBER + uint32_t next = numeric_limits::max(); ///< VARIABLE NUMBER +}; + +struct Queue { + + // We use integers instead of variable pointers. This is more compact and + // also avoids issues due to moving the variable table during 'resize'. + + uint32_t first; ///< VARIABLE NUMBER. anchor (head/tail) for doubly linked list. + uint32_t last; ///< VARIABLE NUMBER. anchor (head/tail) for doubly linked list. + uint32_t unassigned; ///< VARIABLE NUMBER. All variables after this one are assigned + uint64_t vmtf_bumped; ///< Last unassigned variable's btab value + + Queue () : + first (numeric_limits::max()), + last (numeric_limits::max()), + unassigned (numeric_limits::max()), + vmtf_bumped (0) + {} + + // We explicitly provide the mapping of integer indices to vmtf_links to the + // following two (inlined) functions. They are just ordinary doubly + // linked list 'dequeue' and 'enqueue' operations. + + // Removes from the list + void dequeue (vector& vmtf_links, const uint32_t var) { + auto& l = vmtf_links[var]; + + if (l.prev != numeric_limits::max()) { + // Not the first one in the list + vmtf_links[l.prev].next = l.next; + } else { + first = l.next; + } + + if (l.next != numeric_limits::max()) { + // No the last one in the list + vmtf_links[l.next].prev = l.prev; + } else { + last = l.prev; + } + } + + // Puts varible at the head of the list + void enqueue (vector& vmtf_links, const uint32_t var) { + auto& l = vmtf_links[var]; + l.prev = last; + if (l.prev != numeric_limits::max()) { + // Not the first one in the list + vmtf_links[last].next = var; + } else { + first = var; + } + last = var; + l.next = numeric_limits::max(); + } +}; + +} //namespace diff --git a/cryptominisat/cppsrc/src/watchalgos.h b/cryptominisat/cppsrc/src/watchalgos.h new file mode 100644 index 00000000..85a83560 --- /dev/null +++ b/cryptominisat/cppsrc/src/watchalgos.h @@ -0,0 +1,198 @@ +/****************************************** +Copyright (C) 2009-2020 Authors of CryptoMiniSat, see AUTHORS file + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. +***********************************************/ + +#ifndef __WATCHALGOS_H__ +#define __WATCHALGOS_H__ + +#include "watched.h" +#include "watcharray.h" +#include "clauseallocator.h" + +namespace CMSat { + +////////////////// +// NORMAL Clause +////////////////// +static inline bool findWCl(watch_subarray_const ws, const ClOffset c) +{ + const Watched* i = ws.begin(), *end = ws.end(); + for (; i != end && (!i->isClause() || i->get_offset() != c); i++); + return i != end; +} + +static inline void removeWCl(watch_subarray ws, const ClOffset c) +{ + Watched* i = ws.begin(), *end = ws.end(); + for (; i != end && (!i->isClause() || i->get_offset() != c); i++); + assert(i != end); + Watched* j = i; + i++; + for (; i != end; j++, i++) *j = *i; + ws.shrink_(1); +} + +////////////////// +// BINARY Clause +////////////////// + +inline void removeWBin( + watch_array &wsFull + , const Lit lit1 + , const Lit lit2 + , const bool red + , const int32_t ID +) { + watch_subarray ws = wsFull[lit1]; + Watched *i = ws.begin(), *end = ws.end(); + for (; i != end && ( + !i->isBin() + || i->lit2() != lit2 + || i->red() != red + || i->get_ID() != ID + ); i++); + + assert(i != end); + Watched *j = i; + i++; + for (; i != end; j++, i++) *j = *i; + ws.shrink_(1); +} + +inline void removeWBin_change_order( + watch_array &wsFull + , const Lit lit1 + , const Lit lit2 + , const bool red + , const int32_t ID +) { + watch_subarray ws = wsFull[lit1]; + Watched *i = ws.begin(), *end = ws.end(); + for (; i != end && ( + !i->isBin() + || i->lit2() != lit2 + || i->red() != red + || i->get_ID() != ID + ); i++); + + assert(i != end); + *i = ws[ws.size()-1]; + ws.shrink_(1); +} + +inline bool removeWBin_except_marked( + watch_array &wsFull + , const Lit lit1 + , const Lit lit2 + , const bool red + , const int32_t ID +) { + watch_subarray ws = wsFull[lit1]; + Watched *i = ws.begin(), *end = ws.end(); + for (; i != end && ( + !i->isBin() + || i->lit2() != lit2 + || i->red() != red + || i->get_ID() != ID + ); i++); + assert(i != end); + + if (i->bin_cl_marked()) { + return false; + } + + Watched *j = i; + i++; + for (; i != end; j++, i++) *j = *i; + ws.shrink_(1); + + return true; +} + +inline const Watched& findWatchedOfBin( + const watch_array& wsFull + , const Lit lit1 + , const Lit lit2 + , const bool red + , const int32_t ID +) { + watch_subarray_const ws = wsFull[lit1]; + for (const Watched *i = ws.begin(), *end = ws.end(); i != end; i++) { + if (i->isBin() && i->lit2() == lit2 && i->red() == red && i->get_ID() == ID) + return *i; + } + + assert(false); + return *ws.begin(); +} + +inline Watched& findWatchedOfBin( + watch_array& wsFull + , const Lit lit1 + , const Lit lit2 + , const bool red + , const int32_t ID +) { + watch_subarray ws = wsFull[lit1]; + for (Watched *i = ws.begin(), *end = ws.end(); i != end; i++) { + if (i->isBin() && i->lit2() == lit2 && i->red() == red && i->get_ID() == ID) + return *i; + } + + assert(false); + return *ws.begin(); +} + +static inline void removeWXCl(watch_array& wsFull + , const Lit lit + , const ClOffset offs +) { + watch_subarray ws = wsFull[lit]; + Watched *i = ws.begin(), *end = ws.end(); + for (; i != end && (!i->isClause() || i->get_offset() != offs); i++); + assert(i != end); + Watched *j = i; + i++; + for (; i != end; j++, i++) *j = *i; + ws.shrink_(1); +} + + +// Removes BNN *once* +static inline void removeWBNN(watch_array& wsFull + , const Lit lit + , const uint32_t bnnIdx +) { + watch_subarray ws = wsFull[lit]; + Watched *i = ws.begin(), *end = ws.end(); + for (; i != end && (!i->isBNN() || i->get_bnn() != bnnIdx); i++); + assert(i != end); + Watched *j = i; + i++; + for (; i != end; j++, i++) *j = *i; + ws.shrink_(1); +} + + +} //end namespace + + +#endif //__WATCHALGOS_H__ diff --git a/cryptominisat/cppsrc/src/watcharray.h b/cryptominisat/cppsrc/src/watcharray.h new file mode 100644 index 00000000..ebb3a9be --- /dev/null +++ b/cryptominisat/cppsrc/src/watcharray.h @@ -0,0 +1,195 @@ +/************************************************************* +MiniSat --- Copyright (c) 2003-2006, Niklas Een, Niklas Sorensson +CryptoMiniSat --- Copyright (C) 2009-2020 Authors of CryptoMiniSat, see AUTHORS file + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. +***************************************************************/ + +#ifndef __WATCHARRAY_H__ +#define __WATCHARRAY_H__ + +#include "watched.h" +#include "Vec.h" +#include +#include + +namespace CMSat { +using std::vector; + +typedef vec& watch_subarray; +typedef const vec& watch_subarray_const; + +class watch_array +{ +public: + vec > watches; + vector smudged_list; + vector smudged; + + void smudge(const Lit lit) { + if (!smudged[lit.toInt()]) { + smudged_list.push_back(lit); + smudged[lit.toInt()] = true; + } + } + + const vector& get_smudged_list() const { + return smudged_list; + } + + void clear_smudged() + { + for(const Lit lit: smudged_list) { + assert(smudged[lit.toInt()]); + smudged[lit.toInt()] = false; + } + smudged_list.clear(); + } + + watch_subarray operator[](Lit pos) + { + return watches[pos.toInt()]; + } + + watch_subarray at(size_t pos) + { + assert(watches.size() > pos); + return watches[pos]; + } + + watch_subarray_const operator[](Lit at) const + { + return watches[at.toInt()]; + } + + watch_subarray_const at(size_t pos) const + { + assert(watches.size() > pos); + return watches[pos]; + } + + void resize(const size_t new_size) + { + assert(smudged_list.empty()); + if (watches.size() < new_size) { + watches.growTo(new_size); + } else { + watches.shrink(watches.size()-new_size); + } + smudged.resize(new_size, false); + } + + void insert(uint32_t num) + { + smudged.insert(smudged.end(), num, false); + watches.insert(num); + } + + size_t mem_used() const + { + double mem = watches.capacity()*sizeof(vec); + for(size_t i = 0; i < watches.size(); i++) { + //1.2 is overhead + mem += (double)watches[i].capacity()*(double)sizeof(Watched)*1.2; + } + mem += smudged.capacity()*sizeof(char); + mem += smudged_list.capacity()*sizeof(Lit); + return mem; + } + + size_t size() const + { + return watches.size(); + } + + void prefetch(const size_t at) const + { + cmsat_prefetch(watches[at].data); + } + typedef vec* iterator; + typedef const vec* const_iterator; + + iterator begin() + { + return watches.begin(); + } + + iterator end() + { + return watches.end(); + } + + const_iterator begin() const + { + return watches.begin(); + } + + const_iterator end() const + { + return watches.end(); + } + + void consolidate() + { + /*for(auto& ws: watches) { + ws.shrink_to_fit(); + }*/ + watches.shrink_to_fit(); + } + + void full_consolidate() + { + for(auto& ws: watches) { + ws.shrink_to_fit(); + } + watches.shrink_to_fit(); + } + + void print_stat() + { + } + + size_t mem_used_alloc() const + { + size_t mem = 0; + for(auto& ws: watches) { + mem += ws.capacity()*sizeof(Watched); + } + + return mem; + } + + size_t mem_used_array() const + { + size_t mem = 0; + mem += watches.capacity()*sizeof(vector); + mem += sizeof(watch_array); + return mem; + } +}; + +inline void swap(watch_subarray a, watch_subarray b) +{ + a.swap(b); +} + + +} //End of namespace + +#endif //__WATCHARRAY_H__ diff --git a/cryptominisat/cppsrc/src/watcharray_handrolled.cpp b/cryptominisat/cppsrc/src/watcharray_handrolled.cpp new file mode 100644 index 00000000..2f2e8cd0 --- /dev/null +++ b/cryptominisat/cppsrc/src/watcharray_handrolled.cpp @@ -0,0 +1,122 @@ +/****************************************** +Copyright (C) 2009-2020 Authors of CryptoMiniSat, see AUTHORS file + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. +***********************************************/ + +#include "watcharray.h" +#include +using namespace CMSat; + +void watch_array::consolidate() +{ + size_t total_needed = total_needed_during_consolidate(); + + vector newmems; + size_t at_watches = 0; + //size_t last_needed = 0; + while(total_needed > 0) { + Mem newmem; + size_t needed = std::min(total_needed, WATCH_MAX_SIZE_ONE_ALLOC); + assert(needed > 0); + + //If last one was larger than this, let's take the last one + //needed = std::max(needed, last_needed/2); + //last_needed = needed; + total_needed -= needed; + + newmem.alloc = needed; + newmem.base_ptr = (Watched*)malloc(newmem.alloc*sizeof(Watched)); + for(; at_watches < watches.size(); at_watches++) { + //Not used + if (watches[at_watches].size == 0) { + watches[at_watches] = Elem(); + continue; + } + + Elem& ws = watches[at_watches]; + + //Allow for some space to breathe + size_t toalloc = extra_space_during_consolidate(ws.size); + + //Does not fit into this 'newmem' + if (newmem.next_space_offset + toalloc > newmem.alloc) { + break; + } + + ws.alloc = toalloc; + Watched* orig_ptr = mems[ws.num].base_ptr + ws.offset; + Watched* new_ptr = newmem.base_ptr + newmem.next_space_offset; + memmove(new_ptr, orig_ptr, ws.size * sizeof(Watched)); + ws.num = newmems.size(); + ws.offset = newmem.next_space_offset; + //ws.accessed = 0; + newmem.next_space_offset += ws.alloc; + } + newmems.push_back(newmem); + } + assert(at_watches == watches.size()); + assert(total_needed == 0); + + for(size_t i = 0; i < mems.size(); i++) { + free(mems[i].base_ptr); + } + + mems = newmems; + for(auto& mem: free_mem) { + mem.clear(); + } + free_mem_used = 0; + free_mem_not_used = 0; +} + +void watch_array::print_stat(bool detailed) const +{ + cout + << "c [watch] mems.size(): " << mems.size() + << " free mem used/unused:" + << free_mem_used << "/" << free_mem_not_used + << " (" + << std::fixed << std::setprecision(2) + << stats_line_percent(free_mem_used, free_mem_not_used+free_mem_used) + << "%)" + << endl; + + if (detailed) { + for(size_t i = 0; i < mems.size(); i++) { + const Mem& mem = mems[i]; + cout + << " c [watch] mem " << i + << " alloc: " << mem.alloc + << " next_space_offset: " << mem.next_space_offset + << " base_ptr: " << mem.base_ptr + << endl; + } + + cout << "c [watch] free stats:" << endl; + for(size_t i = 0; i < free_mem.size(); i++) + { + cout << "c [watch] ->free_mem[" << i << "]: " << free_mem[i].size() << endl; + } + } + + /*for(size_t i = 0; i < watches.size(); i++) { + cout << "ws[" << i << "] accessed: " << watches[i].accessed << " size: " << watches[i].size << endl; + }*/ +} diff --git a/cryptominisat/cppsrc/src/watcharray_handrolled.h b/cryptominisat/cppsrc/src/watcharray_handrolled.h new file mode 100644 index 00000000..0cd18838 --- /dev/null +++ b/cryptominisat/cppsrc/src/watcharray_handrolled.h @@ -0,0 +1,552 @@ +/****************************************** +Copyright (C) 2009-2020 Authors of CryptoMiniSat, see AUTHORS file + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. +***********************************************/ + +#ifndef __WATCHARRAY_H__ +#define __WATCHARRAY_H__ + +#include +#include +#include "watched.h" +#include + +namespace CMSat { +using std::vector; + +struct watch_array; + +struct Elem +{ + Elem() : + num(0) + , offset(0) + {} + + uint32_t num:8; + uint32_t offset:24; + uint32_t size = 0; + uint32_t alloc = 0; + //uint32_t accessed = 0; + + void print_stat() const + { + cout + << "c elem." + << " num: " << num + << " offset:" << offset + << " size" << size + << " alloc" << alloc + << endl; + } +}; + +struct Mem +{ + uint32_t alloc = 0; + Watched* base_ptr = NULL; + uint32_t next_space_offset = 0; +}; + +struct OffsAndNum +{ + OffsAndNum() : + offset(0) + , num(0) + {} + + OffsAndNum(uint32_t _offset, uint32_t _num) : + offset(_offset) + , num(_num) + {} + + uint32_t offset; + uint32_t num; +}; + +struct watch_subarray +{ + vector::iterator base_at; + watch_array* base; + explicit watch_subarray(vector::iterator _base_at, watch_array* _base) : + base_at(_base_at) + , base(_base) + {} + + Watched& operator[](const uint32_t at); + void clear(); + uint32_t size() const; + bool empty() const; + Watched* begin(); + Watched* end(); + const Watched* begin() const; + const Watched* end() const; + void shrink(const uint32_t num); + void shrink_(const uint32_t num); + void push(const Watched& watched); + void get_space_for_push(); + + typedef Watched* iterator; + typedef const Watched* const_iterator; +}; + +struct watch_subarray_const +{ + vector::const_iterator base_at; + const watch_array* base; + explicit watch_subarray_const(vector::const_iterator _base_at, const watch_array* _base) : + base_at(_base_at) + , base(_base) + {} + + watch_subarray_const(const watch_subarray& other) : + base_at(other.base_at) + , base(other.base) + {} + + void print_stat() const; + const Watched& operator[](const uint32_t at) const; + uint32_t size() const; + bool empty() const; + const Watched* begin() const; + const Watched* end() const; + typedef const Watched* const_iterator; +}; + +struct watch_array +{ + const static size_t WATCH_MIN_SIZE_ONE_ALLOC_FIRST = 1ULL*1000ULL*1000ULL; + const static size_t WATCH_MIN_SIZE_ONE_ALLOC_LATER = 50ULL*1000ULL*1000ULL; + const static size_t WATCH_MAX_SIZE_ONE_ALLOC = (1ULL<<24)-1; + + vector watches; + vector mems; + size_t free_mem_used = 0; + size_t free_mem_not_used = 0; + + //at least 2**N elements in there + vector > free_mem; + + watch_array() + { + //We need at least 1 + Mem new_mem; + size_t elems = WATCH_MIN_SIZE_ONE_ALLOC_FIRST; + new_mem.base_ptr = (Watched*)malloc(elems*sizeof(Watched)); + new_mem.alloc = elems; + mems.push_back(new_mem); + + free_mem.resize(20); + } + + ~watch_array() + { + for(size_t i = 0; i < mems.size(); i++) { + free(mems[i].base_ptr); + } + } + + uint32_t get_suitable_base(uint32_t elems) + { + //print_stat(); + + assert(mems.size() > 0); + size_t last_alloc = mems[0].alloc; + for(size_t i = 0; i < mems.size(); i++) { + if (mems[i].next_space_offset + elems < mems[i].alloc) { + return i; + } + last_alloc = mems[i].alloc; + } + assert(mems.size() < 255); + + Mem new_mem; + new_mem.alloc = std::max(3*last_alloc, WATCH_MIN_SIZE_ONE_ALLOC_LATER); + new_mem.alloc = std::min(3*last_alloc, WATCH_MAX_SIZE_ONE_ALLOC); + new_mem.base_ptr = (Watched*)malloc(new_mem.alloc*sizeof(Watched)); + assert(new_mem.base_ptr != NULL); + mems.push_back(new_mem); + return mems.size()-1; + } + + bool find_free_space(OffsAndNum& toret, uint32_t size) + { + size_t bucket = get_bucket(size); + if (free_mem.size() <= bucket + || free_mem[bucket].empty() + ) { + free_mem_not_used++; + return false; + } + + toret = free_mem[bucket].back(); + free_mem[bucket].pop_back(); + free_mem_used++; + return true; + } + + OffsAndNum get_space(uint32_t elems) + { + OffsAndNum toret; + if (find_free_space(toret, elems)) + return toret; + + uint32_t num = get_suitable_base(elems); + Mem& mem = mems[num]; + assert(mem.next_space_offset + elems < mem.alloc); + + uint32_t off_to_ret = mem.next_space_offset; + mem.next_space_offset += elems; + + toret = OffsAndNum(off_to_ret, num); + return toret; + } + + size_t extra_space_during_consolidate(size_t orig_size) + { + if (orig_size == 1) + return 2; + + unsigned bucket = get_bucket(orig_size); + if (2U<(total_needed, WATCH_MIN_SIZE_ONE_ALLOC_FIRST); + + return total_needed; + } + + void consolidate(); + void print_stat(bool detailed = false) const; + + unsigned get_bucket(unsigned size) + { + //assert(size >= 2); + int at = ((int)((sizeof(unsigned)*8))-__builtin_clz(size))-2; + //assert(at >= 0); + return at; + } + + void delete_offset(uint32_t num, uint32_t offs, uint32_t size) + { + size_t bucket = get_bucket(size); + //assert(size == 2U<= free_mem.size()) { + return; + } + + free_mem[bucket].push_back(OffsAndNum(offs, num)); + } + + size_t mem_used_alloc() const + { + size_t total = 0; + for(size_t i = 0; i < mems.size(); i++) { + total += mems[i].alloc*sizeof(Watched); + } + return total; + } + + size_t mem_used_array() const + { + size_t total = 0; + total += watches.capacity() * sizeof(Elem); + total += mems.capacity() * sizeof(Mem); + return total; + } + + watch_subarray operator[](size_t at) + { + assert(watches.size() > at); + return watch_subarray(watches.begin() + at, this); + } + + watch_subarray_const operator[](size_t at) const + { + assert(watches.size() > at); + return watch_subarray_const(watches.begin() + at, this); + } + + void resize(const size_t new_size) + { + watches.resize(new_size); + } + + uint32_t size() const + { + return watches.size(); + } + + void shrink_to_fit() + { + watches.shrink_to_fit(); + } + + void prefetch(const size_t at) const + { + cmsat_prefetch(mems[watches[at].num].base_ptr + watches[at].offset); + } + + struct iterator + { + vector::iterator it; + watch_array* base; + explicit iterator(vector::iterator _it, watch_array* _base) : + it(_it) + , base(_base) + {} + + iterator operator++() + { + ++it; + return *this; + } + + watch_subarray operator*() + { + return watch_subarray(it, base); + } + + bool operator==(const iterator& it2) const + { + return it == it2.it; + } + + bool operator!=(const iterator& it2) const + { + return it != it2.it; + } + + friend size_t operator-(const iterator& lhs, const iterator& rhs); + }; + + struct const_iterator + { + vector::const_iterator it; + const watch_array* base; + explicit const_iterator(vector::const_iterator _it, const watch_array* _base) : + it(_it) + , base(_base) + {} + + const_iterator(const iterator& other) : + it(other.it) + , base(other.base) + {} + + const_iterator operator++() + { + ++it; + return *this; + } + + const watch_subarray_const operator*() const + { + return watch_subarray_const(it, base); + } + + bool operator==(const const_iterator& it2) const + { + return it == it2.it; + } + + bool operator!=(const const_iterator& it2) const + { + return it != it2.it; + } + + friend size_t operator-(const const_iterator& lhs, const const_iterator& rhs); + }; + + iterator begin() + { + return iterator(watches.begin(), this); + } + + iterator end() + { + return iterator(watches.end(), this); + } + + const_iterator begin() const + { + return const_iterator(watches.begin(), this); + } + + const_iterator end() const + { + return const_iterator(watches.end(), this); + } + + void fitToSize() + { + //TODO shirnk + } +}; + +inline size_t operator-(const watch_array::iterator& lhs, const watch_array::iterator& rhs) +{ + return lhs.it-rhs.it; +} + +inline size_t operator-(const watch_array::const_iterator& lhs, const watch_array::const_iterator& rhs) +{ + return lhs.it-rhs.it; +} + +inline Watched& watch_subarray::operator[](const uint32_t at) +{ + //base_at->accessed++; + return *(begin() + at); +} + +inline void watch_subarray::clear() +{ + base_at->size = 0; +} + +inline uint32_t watch_subarray::size() const +{ + return base_at->size; +} + +inline bool watch_subarray::empty() const +{ + return size() == 0; +} + +inline Watched* watch_subarray::begin() +{ + return base->mems[base_at->num].base_ptr + base_at->offset; +} + +inline Watched* watch_subarray::end() +{ + return begin() + size(); +} + +inline const Watched* watch_subarray::begin() const +{ + return base->mems[base_at->num].base_ptr + base_at->offset; +} + +inline const Watched* watch_subarray::end() const +{ + return begin() + size(); +} + +inline void watch_subarray::shrink(const uint32_t num) +{ + base_at->size -= num; +} + +inline void watch_subarray::shrink_(const uint32_t num) +{ + shrink(num); +} + +inline void watch_subarray::get_space_for_push() +{ + uint32_t new_alloc = std::max(base_at->alloc*2, 2U); + OffsAndNum off_and_num = base->get_space(new_alloc); + + //Copy + if (base_at->size > 0) { + Watched* newptr = base->mems[off_and_num.num].base_ptr + off_and_num.offset; + Watched* oldptr = begin(); + memmove(newptr, oldptr, size() * sizeof(Watched)); + base->delete_offset(base_at->num, base_at->offset, base_at->alloc); + } + + //Update + base_at->num = off_and_num.num; + base_at->offset = off_and_num.offset; + base_at->alloc = new_alloc; +} + +inline void watch_subarray::push(const Watched& watched) +{ + //Make space + if (base_at->alloc <= base_at->size) { + get_space_for_push(); + } + + //There is enough space + //assert(base_at->alloc > base_at->size); + + //Append to the end + operator[](size()) = watched; + base_at->size++; +} + +inline const Watched& watch_subarray_const::operator[](const uint32_t at) const +{ + return *(begin() + at); +} +inline uint32_t watch_subarray_const::size() const +{ + return base_at->size; +} + +inline bool watch_subarray_const::empty() const +{ + return size() == 0; +} +inline const Watched* watch_subarray_const::begin() const +{ + return base->mems[base_at->num].base_ptr + base_at->offset; +} + +inline const Watched* watch_subarray_const::end() const +{ + return begin() + size(); +} + +inline void watch_subarray_const::print_stat() const +{ + base->print_stat(); + base_at->print_stat(); +} + +inline void swap(watch_subarray a, watch_subarray b) +{ + Elem tmp; + tmp = *(a.base_at); + *(a.base_at) = *(b.base_at); + *(b.base_at) = tmp; +} + + +} //End of namespace + +#endif //__WATCHARRAY_H__ diff --git a/cryptominisat/cppsrc/src/watched.h b/cryptominisat/cppsrc/src/watched.h new file mode 100644 index 00000000..f68b7e01 --- /dev/null +++ b/cryptominisat/cppsrc/src/watched.h @@ -0,0 +1,355 @@ +/****************************************** +Copyright (C) 2009-2020 Authors of CryptoMiniSat, see AUTHORS file + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. +***********************************************/ + +#pragma once + +//#define DEBUG_WATCHED + +#include +#include +#include + +#include "clabstraction.h" +#include "constants.h" +#include "cloffset.h" +#include "solvertypes.h" + +using std::numeric_limits; + +namespace CMSat { + +enum class WatchType { + watch_clause_t = 0 + , watch_binary_t = 1 + , watch_bnn_t = 2 + , watch_idx_t = 3 +}; + +enum BNNPropType { + bnn_pos_t = 0 + , bnn_neg_t = 1 + , bnn_out_t = 2 +}; + +class Watched { + public: + Watched(Watched const&) = default; + + /** + @brief Constructor for a long (>2) clause + */ + Watched(const ClOffset offset, Lit blockedLit) : + data1(blockedLit.toInt()) + , type(static_cast(WatchType::watch_clause_t)) + , data2(offset) + { + } + + /** + @brief Constructor for a long (>2) clause + */ + Watched(const ClOffset offset, cl_abst_type abst) : + data1(abst) + , type(static_cast(WatchType::watch_clause_t)) + , data2(offset) + { + } + + Watched(const uint32_t idx, WatchType t): + data1(idx) + , type(static_cast(t)) + { + assert(t == WatchType::watch_idx_t); + } + + Watched(const uint32_t idx, WatchType t, BNNPropType bnn_p_t): + data1(idx) + , type(static_cast(t)) + , data2(bnn_p_t) + { + DEBUG_WATCHED_DO(assert(t == watch_bnn_t)); + } + + Watched() : + data1 (numeric_limits::max()) + , type(static_cast(WatchType::watch_clause_t)) // initialize type with most generic type of clause + , data2(numeric_limits::max() >> 2) + {} + + /** + @brief Constructor for a binary clause + */ + Watched(const Lit lit, const bool red, int32_t ID) : + data1(lit.toInt()) + , type(static_cast(WatchType::watch_binary_t)) + , data2((int32_t)red | ID<<2) //marking is 2nd bit + { + assert(ID < 1LL<< (EFFECTIVELY_USEABLE_BITS-2) && "Please compile with -DLARGEMEM"); + } + + /** + @brief To update the blocked literal of a >3-long normal clause + */ + void setElimedLit(const Lit blockedLit) + { + DEBUG_WATCHED_DO(assert(type == watch_clause_t)); + data1 = blockedLit.toInt(); + } + + WatchType getType() const + { + // we rely that WatchType enum is in [0-3] range and fits into type field two bits + return static_cast(type); + } + + bool isBin() const + { + return (type == static_cast(WatchType::watch_binary_t)); + } + + bool isClause() const + { + return (type == static_cast(WatchType::watch_clause_t)); + } + + bool isIdx() const + { + return (type == static_cast(WatchType::watch_idx_t)); + } + + bool isBNN() const + { + return (type == static_cast(WatchType::watch_bnn_t)); + } + + uint32_t get_idx() const + { + DEBUG_WATCHED_DO(assert(type == static_cast(WatchType::watch_idx_t))); + return data1; + } + + uint32_t get_bnn() const + { + DEBUG_WATCHED_DO(assert(type == static_cast(WatchType::watch_bnn_t))); + return data1; + } + + BNNPropType get_bnn_prop_t() const + { + DEBUG_WATCHED_DO(assert(type == static_cast(WatchType::watch_bnn_t))); + return (BNNPropType)data2; + } + + /** + @brief Get the sole other lit of the binary clause, or get lit2 of the tertiary clause + */ + Lit lit2() const + { + DEBUG_WATCHED_DO(assert(isBin())); + return Lit::toLit(data1); + } + + /** + @brief Set the sole other lit of the binary clause + */ + void setLit2(const Lit lit) + { + DEBUG_WATCHED_DO(assert(isBin())); + data1 = lit.toInt(); + } + + bool red() const + { + DEBUG_WATCHED_DO(assert(isBin())); + return data2 & 1; + } + + int32_t get_ID() const + { + DEBUG_WATCHED_DO(assert(isBin())); + return data2 >> 2; + } + + void setRed(const bool toSet) + { + DEBUG_WATCHED_DO(assert(isBin())); + DEBUG_WATCHED_DO(assert(red())); + assert(toSet == false); + data2 &= (~(1U)); + } + + void setReallyRed() + { + DEBUG_WATCHED_DO(assert(isBin())); + DEBUG_WATCHED_DO(assert(!red())); + data2 |= 1U; + assert(red()); + } + + void mark_bin_cl() + { + DEBUG_WATCHED_DO(assert(isBin())); + data2 |= 2; + } + + void unmark_bin_cl() + { + DEBUG_WATCHED_DO(assert(isBin())); + data2 &= (~(2ULL)); + } + + bool bin_cl_marked() const + { + DEBUG_WATCHED_DO(assert(isBin())); + return data2&2; + } + + /** + @brief Get example literal (blocked lit) of a normal long clause + */ + Lit getBlockedLit() const + { + DEBUG_WATCHED_DO(assert(isClause())); + return Lit::toLit(data1); + } + + cl_abst_type getAbst() const + { + DEBUG_WATCHED_DO(assert(isClause())); + return data1; + } + + /** + @brief Get offset of a >3-long normal clause or of an xor clause (which may be 3-long) + */ + ClOffset get_offset() const + { + DEBUG_WATCHED_DO(assert(isClause())); + return data2; + } + + bool operator==(const Watched& other) const + { + return data1 == other.data1 && data2 == other.data2 && type == other.type; + } + + bool operator!=(const Watched& other) const + { + return !(*this == other); + } + + private: + uint32_t data1; + ClOffset type:2; + ClOffset data2:EFFECTIVELY_USEABLE_BITS; +}; + +inline std::ostream& operator<<(std::ostream& os, const Watched& ws) +{ + + if (ws.isClause()) { + os << "Clause offset " << ws.get_offset(); + } + + if (ws.isBin()) { + os << "Bin lit " << ws.lit2() << " (red: " << ws.red() << " )"; + } + + return os; +} + +struct OccurClause { + OccurClause(const Lit& _lit, const Watched& _ws) : + lit(_lit) + , ws(_ws) + {} + + OccurClause() : + lit(lit_Undef) + {} + + Lit lit; + Watched ws; + + // will be equal even if one is removing a literal, and the other is subsuming the whole clause + bool operator==(const OccurClause& other) const { + if (ws.getType() != other.ws.getType()) return false; + if (ws.isBin()) return ws.get_ID() == other.ws.get_ID(); + if (ws.isBNN()) return ws.get_bnn() == other.ws.get_bnn(); + if (ws.isClause()) return ws.get_offset() == other.ws.get_offset(); + release_assert(false); + return false; + } + + bool operator<(const OccurClause& other) const { + if (ws.isBin() && !other.ws.isBin()) { + return true; + } + if (!ws.isBin() && other.ws.isBin()) { + return false; + } + + if (ws.isBin()) { + assert(other.ws.isBin()); + return ws.get_ID() < other.ws.get_ID(); + } + + assert(!ws.isBNN()); // no idea how this would work + assert(!other.ws.isBNN()); // no idea how this would work + return ws.get_offset() < other.ws.get_offset(); + } +}; + +struct WatchSorterBinTriLong { + bool operator()(const Watched& a, const Watched& b) + { + assert(!a.isIdx()); + assert(!b.isIdx()); + + //Anything but clause! + if (a.isClause() || a.isBNN()) { + //A is definitely not better than B + return false; + } + if (b.isClause() || b.isBNN()) { + //B is clause, A is NOT a clause. So A is better than B. + return true; + } + + //Both are BIN + assert(a.isBin()); + assert(b.isBin()); + + if (a.lit2() != b.lit2()) { + return a.lit2() < b.lit2(); + } + + if (a.red() != b.red()) { + return !a.red(); + } + + return (a.get_ID() < b.get_ID()); + } + }; + + +} //end namespace diff --git a/cryptominisat/cppsrc/src/xor.h b/cryptominisat/cppsrc/src/xor.h new file mode 100644 index 00000000..a7f25dda --- /dev/null +++ b/cryptominisat/cppsrc/src/xor.h @@ -0,0 +1,221 @@ +/****************************************** +Copyright (C) 2009-2020 Authors of CryptoMiniSat, see AUTHORS file + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. +***********************************************/ + +#ifndef _XOR_H_ +#define _XOR_H_ + +#include "solvertypes.h" + +#include +#include +#include +#include +#include +#ifdef USE_TBUDDY +#include +namespace tbdd = trustbdd; +#endif + +using std::vector; +using std::set; + + +namespace CMSat { + +class Xor +{ +public: + Xor() + {} + + explicit Xor(const vector& cl, const bool _rhs, const vector& _clash_vars): + rhs(_rhs) + , clash_vars(_clash_vars) + { + for (uint32_t i = 0; i < cl.size(); i++) vars.push_back(cl[i]); + } + +#ifdef USE_TBUDDY + tbdd::xor_constraint* create_bdd_xor() + { + if (bdd == NULL) { + ilist l = ilist_new(vars.size()); + ilist_resize(l, vars.size()); + for (uint32_t i = 0; i < vars.size(); i++) l[i] = vars[i]+1; + bdd = new tbdd::xor_constraint(l, rhs); + } + return bdd; + } +#endif + + template + explicit Xor(const T& cl, const bool _rhs, const vector& _clash_vars): + rhs(_rhs) + , clash_vars(_clash_vars) + { + for (uint32_t i = 0; i < cl.size(); i++) { + vars.push_back(cl[i].var()); + } + } + + explicit Xor(const vector& cl, const bool _rhs, const uint32_t clash_var): + rhs(_rhs) + { + clash_vars.push_back(clash_var); + for (uint32_t i = 0; i < cl.size(); i++) { + vars.push_back(cl[i]); + } + } + + ~Xor() + { + } + + vector::const_iterator begin() const + { + return vars.begin(); + } + + vector::const_iterator end() const + { + return vars.end(); + } + + vector::iterator begin() + { + return vars.begin(); + } + + vector::iterator end() + { + return vars.end(); + } + + bool operator<(const Xor& other) const + { + uint64_t i = 0; + while(i < other.size() && i < size()) { + if (other[i] != vars[i]) { + return (vars[i] < other[i]); + } + i++; + } + + if (other.size() != size()) { + return size() < other.size(); + } + return false; + } + + const uint32_t& operator[](const uint32_t at) const + { + return vars[at]; + } + + uint32_t& operator[](const uint32_t at) + { + return vars[at]; + } + + void resize(const uint32_t newsize) + { + vars.resize(newsize); + } + + vector& get_vars() + { + return vars; + } + + const vector& get_vars() const + { + return vars; + } + + size_t size() const + { + return vars.size(); + } + + bool empty() const + { + if (!vars.empty()) + return false; + + if (!clash_vars.empty()) + return false; + + if (rhs != false) { + return false; + } + + return true; + } + + void merge_clash(const Xor& other, vector& seen) { + for(const auto& v: clash_vars) { + seen[v] = 1; + } + + for(const auto& v: other.clash_vars) { + if (!seen[v]) { + seen[v] = 1; + clash_vars.push_back(v); + } + } + + for(const auto& v: clash_vars) { + seen[v] = 0; + } + } + + + bool rhs = false; + vector clash_vars; + bool detached = false; + vector vars; + #ifdef USE_TBUDDY + tbdd::xor_constraint* bdd = NULL; + #endif +}; + +inline std::ostream& operator<<(std::ostream& os, const Xor& thisXor) +{ + for (uint32_t i = 0; i < thisXor.size(); i++) { + os << Lit(thisXor[i], false); + + if (i+1 < thisXor.size()) + os << " + "; + } + os << " = " << std::boolalpha << thisXor.rhs << std::noboolalpha; + + os << " -- clash: "; + for(const auto& c: thisXor.clash_vars) { + os << c+1 << ", "; + } + + return os; +} + +} + +#endif //_XOR_H_ diff --git a/cryptominisat/cppsrc/src/xorfinder.cpp b/cryptominisat/cppsrc/src/xorfinder.cpp new file mode 100644 index 00000000..bcdd6402 --- /dev/null +++ b/cryptominisat/cppsrc/src/xorfinder.cpp @@ -0,0 +1,913 @@ +/****************************************** +Copyright (C) 2009-2020 Authors of CryptoMiniSat, see AUTHORS file + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. +***********************************************/ + +#include "xorfinder.h" +#include "time_mem.h" +#include "solver.h" +#include "occsimplifier.h" +#include "clauseallocator.h" +#include "sqlstats.h" +#include "varreplacer.h" + +#include +#include +#ifdef USE_TBUDDY +#include +#endif +//#define XOR_DEBUG + +using namespace CMSat; +using std::cout; +using std::endl; + +XorFinder::XorFinder(OccSimplifier* _occsimplifier, Solver* _solver) : + occsimplifier(_occsimplifier) + , solver(_solver) + , toClear(_solver->toClear) + , seen(_solver->seen) + , seen2(_solver->seen2) +{ + tmp_vars_xor_two.reserve(2000); +} + +void XorFinder::find_xors_based_on_long_clauses() +{ + #ifdef DEBUG_MARKED_CLAUSE + assert(solver->no_marked_clauses()); + #endif + + vector lits; + for (const auto & offset: occsimplifier->clauses) { + if (xor_find_time_limit <= 0) break; + + Clause* cl = solver->cl_alloc.ptr(offset); + xor_find_time_limit -= 1; + + //Already freed + if (cl->freed() || cl->getRemoved() || cl->red()) { + continue; + } + + //Too large -> too expensive + if (cl->size() > solver->conf.maxXorToFind) { + continue; + } + + //If not tried already, find an XOR with it + if (!cl->stats.marked_clause ) { + cl->stats.marked_clause = 1; + assert(!cl->getRemoved()); + + size_t needed_per_ws = 1ULL << (cl->size()-2); + //let's allow shortened clauses + needed_per_ws >>= 1; + + for(const Lit lit: *cl) { + if (solver->watches[lit].size() < needed_per_ws) { + goto next; + } + if (solver->watches[~lit].size() < needed_per_ws) { + goto next; + } + } + + lits.resize(cl->size()); + std::copy(cl->begin(), cl->end(), lits.begin()); + findXor(lits, offset, cl->abst); + next:; + } + } +} + +void XorFinder::clean_equivalent_xors(vector& txors) +{ + if (!txors.empty()) { + size_t orig_size = txors.size(); + for(Xor& x: txors) { + std::sort(x.begin(), x.end()); + } + std::sort(txors.begin(), txors.end()); + + size_t sz = 1; + vector::iterator i = txors.begin(); + vector::iterator j = i; + ++i; + for(vector::iterator end = txors.end(); i != end; ++i) { + if (j->vars == i->vars && j->rhs == i->rhs) { + j->merge_clash(*i, seen); + j->detached |= i->detached; + if (solver->frat->enabled()) { + verb_print(5, "Cleaning equivalent XOR at: " << (i - txors.begin()) << " xor: " << *i); + TBUDDY_DO(solver->frat->flush()); + TBUDDY_DO(delete i->bdd); + } + } else { + j++; + *j = *i; + sz++; + } + } + txors.resize(sz); + + if (solver->conf.verbosity) { + cout << "c [xor-clean-equiv] removed equivalent xors: " + << (orig_size-txors.size()) << " left with: " << txors.size() + << endl; + } + } +} + +void XorFinder::find_xors() +{ + runStats.clear(); + runStats.numCalls = 1; + grab_mem(); + if ((solver->conf.xor_var_per_cut + 2) > solver->conf.maxXorToFind) { + if (solver->conf.verbosity) { + cout << "c WARNING updating max XOR to find to " + << (solver->conf.xor_var_per_cut + 2) + << " as the current number was lower than the cutting number" << endl; + } + solver->conf.maxXorToFind = solver->conf.xor_var_per_cut + 2; + } + + //Clear flags. This is super-important. + for(auto& offs: occsimplifier->clauses) { + Clause* cl = solver->cl_alloc.ptr(offs); + if (cl->getRemoved() || cl->freed()) { + continue; + } + + cl->set_used_in_xor(false); + cl->set_used_in_xor_full(false); + } + + if (solver->frat->enabled()) { + solver->frat->flush(); + TBUDDY_DO(for (auto const& x: solver->xorclauses) delete x.bdd); + TBUDDY_DO(for (auto const& x: solver->xorclauses_unused) delete x.bdd); + TBUDDY_DO(for (auto const& x: solver->xorclauses_orig) delete x.bdd); + } + solver->xorclauses.clear(); + solver->xorclauses_orig.clear(); + solver->xorclauses_unused.clear(); + + double myTime = cpuTime(); + const int64_t orig_xor_find_time_limit = + 1000LL*1000LL*solver->conf.xor_finder_time_limitM + *solver->conf.global_timeout_multiplier; + + xor_find_time_limit = orig_xor_find_time_limit; + + occsimplifier->sort_occurs_and_set_abst(); + if (solver->conf.verbosity) { + cout << "c [occ-xor] sort occur list T: " << (cpuTime()-myTime) << endl; + } + + #ifdef DEBUG_MARKED_CLAUSE + assert(solver->no_marked_clauses()); + #endif + + find_xors_based_on_long_clauses(); + assert(runStats.foundXors == solver->xorclauses.size()); + + //clean them of equivalent XORs + clean_equivalent_xors(solver->xorclauses); + solver->xorclauses_orig = solver->xorclauses; + + // Need to do this due to XORs encoding new info + // see NOTE in cnf.h + TBUDDY_DO(solver->frat->flush()); + TBUDDY_DO(for(auto& x: solver->xorclauses) if (solver->frat->enabled()) x.create_bdd_xor()); + TBUDDY_DO(for(auto& x: solver->xorclauses_orig) if (solver->frat->enabled()) x.create_bdd_xor()); + + //Cleanup + for(ClOffset offset: occsimplifier->clauses) { + Clause* cl = solver->cl_alloc.ptr(offset); + cl->stats.marked_clause = 0; + } + + //Print stats + const bool time_out = (xor_find_time_limit < 0); + const double time_remain = float_div(xor_find_time_limit, orig_xor_find_time_limit); + runStats.findTime = cpuTime() - myTime; + runStats.time_outs += time_out; + solver->sumSearchStats.num_xors_found_last = solver->xorclauses.size(); + print_found_xors(); + + if (solver->conf.verbosity) runStats.print_short(solver, time_remain); + globalStats += runStats; + + if (solver->sqlStats) { + solver->sqlStats->time_passed( + solver + , "xor-find" + , cpuTime() - myTime + , time_out + , time_remain + ); + } + solver->xor_clauses_updated = true; + + #ifdef SLOW_DEBUG + for(const Xor& x: solver->xorclauses) + for(uint32_t v: x) + assert(solver->varData[v].removed == Removed::none); + #endif +} + +void XorFinder::print_found_xors() +{ + if (solver->conf.verbosity >= 5) { + cout << "c Found XORs: " << endl; + for(auto const& x: solver->xorclauses) cout << "c " << x << endl; + cout << "c -> Total: " << solver->xorclauses.size() << " xors" << endl; + } +} + +void XorFinder::findXor(vector& lits, const ClOffset offset, cl_abst_type abst) +{ + //Set this clause as the base for the XOR, fill 'seen' + xor_find_time_limit -= lits.size()/4+1; + poss_xor.setup(lits, offset, abst, occcnt); + + //Run findXorMatch for the 2 smallest watchlists + Lit slit = lit_Undef; + Lit slit2 = lit_Undef; + uint32_t smallest = numeric_limits::max(); + uint32_t smallest2 = numeric_limits::max(); + for (size_t i = 0, end = lits.size(); i < end; i++) { + const Lit lit = lits[i]; + uint32_t num = solver->watches[lit].size(); + num += solver->watches[~lit].size(); + if (num < smallest) { + slit2 = slit; + smallest2 = smallest; + + slit = lit; + smallest = num; + } else if (num < smallest2) { + slit2 = lit; + smallest2 = num; + } + } + findXorMatch(solver->watches[slit], slit); + findXorMatch(solver->watches[~slit], ~slit); + + if (lits.size() <= solver->conf.maxXorToFindSlow) { + findXorMatch(solver->watches[slit2], slit2); + findXorMatch(solver->watches[~slit2], ~slit2); + } + + if (poss_xor.foundAll()) { + std::sort(lits.begin(), lits.end()); + Xor found_xor(lits, poss_xor.getRHS(), vector()); + SLOW_DEBUG_DO(for(Lit lit: lits) assert(solver->varData[lit.var()].removed == Removed::none)); + + add_found_xor(found_xor); + assert(poss_xor.get_fully_used().size() == poss_xor.get_offsets().size()); + for(uint32_t i = 0; i < poss_xor.get_offsets().size() ; i++) { + ClOffset offs = poss_xor.get_offsets()[i]; + bool fully_used = poss_xor.get_fully_used()[i]; + + Clause* cl = solver->cl_alloc.ptr(offs); + assert(!cl->getRemoved()); + cl->set_used_in_xor(true); + cl->set_used_in_xor_full(fully_used); + } + } + poss_xor.clear_seen(occcnt); +} + +void XorFinder::add_found_xor(const Xor& found_xor) +{ + solver->xorclauses.push_back(found_xor); + runStats.foundXors++; + runStats.sumSizeXors += found_xor.size(); + runStats.maxsize = std::max(runStats.maxsize, found_xor.size()); + runStats.minsize = std::min(runStats.minsize, found_xor.size()); +} + +void XorFinder::findXorMatch(watch_subarray_const occ, const Lit wlit) +{ + xor_find_time_limit -= (int64_t)occ.size()/8+1; + for (const Watched& w: occ) { + if (w.isIdx()) { + continue; + } + assert(poss_xor.getSize() > 2); + + if (w.isBin()) { + SLOW_DEBUG_DO(assert(occcnt[wlit.var()])); + if (w.red()) continue; + if (!occcnt[w.lit2().var()]) goto end; + + binvec.clear(); + binvec.resize(2); + binvec[0] = w.lit2(); + binvec[1] = wlit; + if (binvec[0] > binvec[1]) { + std::swap(binvec[0], binvec[1]); + } + + xor_find_time_limit -= 1; + poss_xor.add(binvec, numeric_limits::max(), varsMissing); + if (poss_xor.foundAll()) + break; + } else { + if (w.getBlockedLit().toInt() == lit_Undef.toInt()) + //Clauses are ordered, lit_Undef means it's larger than maxXorToFind + break; + + if (w.getBlockedLit().toInt() == lit_Error.toInt()) + //lit_Error means it's freed or removed, and it's ordered so no more + break; + + if ((w.getBlockedLit().toInt() | poss_xor.getAbst()) != poss_xor.getAbst()) + continue; + + xor_find_time_limit -= 3; + const ClOffset offset = w.get_offset(); + Clause& cl = *solver->cl_alloc.ptr(offset); + if (cl.freed() || cl.getRemoved() || cl.red()) { + //Clauses are ordered!! + break; + } + + //Allow the clause to be smaller or equal in size + if (cl.size() > poss_xor.getSize()) { + //clauses are ordered!! + break; + } + + //For longer clauses, don't the the fancy algo that can + //deal with incomplete XORs + if (cl.size() != poss_xor.getSize() + && poss_xor.getSize() > solver->conf.maxXorToFindSlow + ) { + break; + } + + //Doesn't contain variables not in the original clause + SLOW_DEBUG_DO(assert(cl.abst == calcAbstraction(cl))); + if ((cl.abst | poss_xor.getAbst()) != poss_xor.getAbst()) + continue; + + //Check RHS, vars inside + bool rhs = true; + for (const Lit cl_lit :cl) { + //early-abort, contains literals not in original clause + if (!occcnt[cl_lit.var()]) + goto end; + + rhs ^= cl_lit.sign(); + } + //either the invertedness has to match, or the size must be smaller + if (rhs != poss_xor.getRHS() && cl.size() == poss_xor.getSize()) + continue; + + //If the size of this clause is the same of the base clause, then + //there is no point in using this clause as a base for another XOR + //because exactly the same things will be found. + if (cl.size() == poss_xor.getSize()) { + cl.stats.marked_clause = 1; + } + + xor_find_time_limit -= cl.size()/4+1; + poss_xor.add(cl, offset, varsMissing); + if (poss_xor.foundAll()) + break; + } + end:; + } +} + +void XorFinder::move_xors_without_connecting_vars_to_unused() +{ + if (solver->xorclauses.empty()) return; + + double myTime = cpuTime(); + vector cleaned; + assert(toClear.empty()); + + //Fill "seen" with vars used + uint32_t non_empty = 0; + for(const Xor& x: solver->xorclauses) { + if (x.size() != 0) { + non_empty++; + } + + for(uint32_t v: x) { + if (solver->seen[v] == 0) { + toClear.push_back(Lit(v, false)); + } + + if (solver->seen[v] < 2) { + solver->seen[v]++; + } + } + } + + //has at least 1 var with occur of 2 + for(const Xor& x: solver->xorclauses) { + if (xor_has_interesting_var(x) || x.detached) { + #ifdef VERBOSE_DEBUG + cout << "XOR has connecting var: " << x << endl; + #endif + cleaned.push_back(x); + } else { + #ifdef VERBOSE_DEBUG + cout << "XOR has no connecting var: " << x << endl; + #endif + solver->xorclauses_unused.push_back(x); + } + } + + //clear "seen" + for(Lit l: toClear) solver->seen[l.var()] = 0; + toClear.clear(); + + solver->xorclauses = cleaned; + + double time_used = cpuTime() - myTime; + if (solver->conf.verbosity) { + cout << "c [xor-rem-unconnected] left with " << solver->xorclauses.size() + << " xors from " << non_empty << " non-empty xors" + << solver->conf.print_times(time_used) + << endl; + } + if (solver->sqlStats) { + solver->sqlStats->time_passed_min( + solver + , "xor-rem-no-connecting-vars" + , time_used + ); + } +} + +bool XorFinder::xor_together_xors(vector& this_xors) +{ + if (occcnt.size() != solver->nVars()) + grab_mem(); + + if (this_xors.empty()) + return solver->okay(); + + #ifdef SLOW_DEBUG + for(auto x: occcnt) { + assert(x == 0); + } + #endif + + if (solver->conf.verbosity >= 5) { + cout << "c XOR-ing together XORs. Starting with: " << endl; + for(const auto& x: this_xors) { + cout << "c XOR before xor-ing together: " << x << endl; + } + } + + assert(solver->okay()); + assert(solver->decisionLevel() == 0); + assert(solver->watches.get_smudged_list().empty()); + const size_t origsize = this_xors.size(); + + uint32_t xored = 0; + const double myTime = cpuTime(); + assert(toClear.empty()); + + //Link in xors into watchlist + for(size_t i = 0; i < this_xors.size(); i++) { + const Xor& x = this_xors[i]; + for(uint32_t v: x) { + if (occcnt[v] == 0) { + toClear.push_back(Lit(v, false)); + } + occcnt[v]++; + + Lit l(v, false); + assert(solver->watches.size() > l.toInt()); + solver->watches[l].push(Watched(i, WatchType::watch_idx_t)); + solver->watches.smudge(l); + } + } + + //Don't XOR together over the sampling vars + //or variables that are in regular clauses + vector to_clear_2; + if (solver->conf.sampling_vars) { + for(uint32_t outside_var: *solver->conf.sampling_vars) { + uint32_t outer_var = solver->map_to_with_bva(outside_var); + outer_var = solver->varReplacer->get_var_replaced_with_outer(outer_var); + uint32_t int_var = solver->map_outer_to_inter(outer_var); + if (int_var < solver->nVars()) { + if (!seen2[int_var]) { + seen2[int_var] = 1; + to_clear_2.push_back(int_var); + //cout << "sampling var: " << int_var+1 << endl; + } + } + } + } + + for(const auto& ws: solver->watches) { + for(const auto& w: ws) { + if (w.isBin() && !w.red()) { + uint32_t v = w.lit2().var(); + if (!seen2[v]) { + seen2[v] = 1; + to_clear_2.push_back(v); + } + } + } + } + + for(const auto& offs: solver->longIrredCls) { + Clause* cl = solver->cl_alloc.ptr(offs); + if (cl->red() || cl->used_in_xor()) { + continue; + } + for(Lit l: *cl) { + if (!seen2[l.var()]) { + seen2[l.var()] = 1; + to_clear_2.push_back(l.var()); + //cout << "Not XORing together over var: " << l.var()+1 << endl; + } + } + } + + //until fixedpoint + bool changed = true; + while(changed) { + changed = false; + interesting.clear(); + for(const Lit l: toClear) { + if (occcnt[l.var()] == 2 && !seen2[l.var()]) { + interesting.push_back(l.var()); + } + } + + while(!interesting.empty()) { + #ifdef SLOW_DEBUG + { + vector check; + check.resize(solver->nVars(), 0); + for(size_t i = 0; i < this_xors.size(); i++) { + const Xor& x = this_xors[i]; + for(uint32_t v: x) { + check[v]++; + } + } + for(size_t i = 0; i < solver->nVars(); i++) { + assert(check[i] == occcnt[i]); + } + } + #endif + + //Pop and check if it can be XOR-ed together + const uint32_t v = interesting.back(); + interesting.resize(interesting.size()-1); + if (occcnt[v] != 2) + continue; + + size_t idxes[2]; + unsigned at = 0; + size_t i2 = 0; + assert(solver->watches.size() > Lit(v, false).toInt()); + watch_subarray ws = solver->watches[Lit(v, false)]; + + //Remove the 2 indexes from the watchlist + for(size_t i = 0; i < ws.size(); i++) { + const Watched& w = ws[i]; + if (!w.isIdx()) { + ws[i2++] = ws[i]; + } else if (!this_xors[w.get_idx()].empty()) { + assert(at < 2); + idxes[at] = w.get_idx(); + at++; + } + } + assert(at == 2); + ws.resize(i2); + + Xor& x0 = this_xors[idxes[0]]; + Xor& x1 = this_xors[idxes[1]]; + uint32_t clash_var; + uint32_t clash_num = xor_two(&x0, &x1, clash_var); + + //If they are equivalent + if (x0.size() == x1.size() + && x0.rhs == x1.rhs + && clash_num == x0.size() + ) { + VERBOSE_PRINT("x1: " << x0 << " -- at idx: " << idxes[0]); + VERBOSE_PRINT("x2: " << x1 << " -- at idx: " << idxes[1]); + VERBOSE_PRINT("equivalent. "); + + //Update clash values & detached values + x1.merge_clash(x0, seen); + x1.detached |= x0.detached; + + VERBOSE_PRINT("after merge: " << x1 << " -- at idx: " << idxes[1]); + + //Equivalent, so delete one + if (solver->frat->enabled()) { + TBUDDY_DO(solver->frat->flush()); + TBUDDY_DO(delete x0.bdd); + } + x0 = Xor(); + + //Re-attach the other, remove the occur of the one we deleted + solver->watches[Lit(v, false)].push(Watched(idxes[1], WatchType::watch_idx_t)); + + for(uint32_t v2: x1) { + Lit l(v2, false); + assert(occcnt[l.var()] >= 2); + occcnt[l.var()]--; + if (occcnt[l.var()] == 2 && !seen2[l.var()]) { + interesting.push_back(l.var()); + } + } + } else if (clash_num > 1 || x0.detached || x1.detached) { + //add back to ws, can't do much + ws.push(Watched(idxes[0], WatchType::watch_idx_t)); + ws.push(Watched(idxes[1], WatchType::watch_idx_t)); + continue; + } else { + occcnt[v] -= 2; + assert(occcnt[v] == 0); + + Xor x_new(tmp_vars_xor_two, x0.rhs ^ x1.rhs, clash_var); + x_new.merge_clash(x0, seen); + x_new.merge_clash(x1, seen); + #ifdef USE_TBUDDY + if (solver->frat->enabled()) { + solver->frat->flush(); + tbdd::xor_set xs; + xs.add(*x0.create_bdd_xor()); + xs.add(*x1.create_bdd_xor()); + x_new.bdd = xs.sum(); + } + #endif + + VERBOSE_PRINT("x1: " << x0 << " -- at idx: " << idxes[0]); + VERBOSE_PRINT("x2: " << x1 << " -- at idx: " << idxes[1]); + VERBOSE_PRINT("clashed on var: " << clash_var+1); + VERBOSE_PRINT("final: " << x_new << " -- at idx: " << this_xors.size()); + + changed = true; + this_xors.push_back(x_new); + for(uint32_t v2: x_new) { + Lit l(v2, false); + solver->watches[l].push(Watched(this_xors.size()-1, WatchType::watch_idx_t)); + assert(occcnt[l.var()] >= 1); + if (occcnt[l.var()] == 2 && !seen2[l.var()]) { + interesting.push_back(l.var()); + } + } + if (solver->frat->enabled()) { + TBUDDY_DO(solver->frat->flush()); + TBUDDY_DO(delete this_xors[idxes[0]].bdd); + TBUDDY_DO(delete this_xors[idxes[1]].bdd); + } + this_xors[idxes[0]] = Xor(); + this_xors[idxes[1]] = Xor(); + xored++; + } + } + } + + if (solver->conf.verbosity >= 5) { + cout << "c Finished XOR-ing together XORs. " << endl; + size_t at = 0; + for(const auto& x: this_xors) { + cout << "c XOR after xor-ing together: " << x << " -- at idx: " << at << endl; + at++; + } + } + + //Clear + for(const Lit l: toClear) occcnt[l.var()] = 0; + toClear.clear(); + for(const auto& x: to_clear_2) seen2[x] = 0; + + solver->clean_occur_from_idx_types_only_smudged(); + clean_xors_from_empty(this_xors); + double recur_time = cpuTime() - myTime; + if (solver->conf.verbosity) { + cout + << "c [xor-together] xored together: " << xored + << " orig xors: " << origsize + << " new xors: " << this_xors.size() + << solver->conf.print_times(recur_time) + << endl; + } + + + if (solver->sqlStats) { + solver->sqlStats->time_passed_min( + solver + , "xor-xor-together" + , recur_time + ); + } + + #if defined(SLOW_DEBUG) || defined(XOR_DEBUG) + //Make sure none is 2. + assert(toClear.empty()); + for(const Xor& x: this_xors) { + for(uint32_t v: x) { + if (occcnt[v] == 0) { + toClear.push_back(Lit(v, false)); + } + + //Don't roll around + occcnt[v]++; + } + } + + for(const Lit c: toClear) { + /*This is now possible because we don't XOR them together + in case they clash on more than 1 variable */ + //assert(occcnt[c.var()] != 2); + + occcnt[c.var()] = 0; + } + toClear.clear(); + #endif + + return solver->okay(); +} + +void XorFinder::clean_xors_from_empty(vector& thisxors) +{ + size_t j = 0; + for(size_t i = 0;i < thisxors.size(); i++) { + Xor& x = thisxors[i]; + if (x.size() == 0 && x.rhs == false) { + if (!x.clash_vars.empty()) { + solver->xorclauses_unused.push_back(x); + } else { + TBUDDY_DO(solver->frat->flush()); + TBUDDY_DO(delete x.bdd); + } + } else { + verb_print(4, "xor after clean: " << thisxors[i]); + thisxors[j++] = thisxors[i]; + } + } + thisxors.resize(j); +} + +uint32_t XorFinder::xor_two(Xor const* x1_p, Xor const* x2_p, uint32_t& clash_var) +{ + tmp_vars_xor_two.clear(); + if (x1_p->size() > x2_p->size()) { + std::swap(x1_p, x2_p); + } + const Xor& x1 = *x1_p; + const Xor& x2 = *x2_p; + + uint32_t clash_num = 0; + for(uint32_t v: x1) { + assert(seen[v] == 0); + seen[v] = 1; + } + + uint32_t i_x2; + bool early_abort = false; + for(i_x2 = 0; i_x2 < x2.size(); i_x2++) { + uint32_t v = x2[i_x2]; + assert(seen[v] != 2); + if (seen[v] == 0) { + tmp_vars_xor_two.push_back(v); + } else { + clash_var = v; + if (clash_num > 0 && + clash_num != i_x2 //not equivalent by chance + ) { + //early abort, it's never gonna be good + clash_num++; + early_abort = true; + break; + } + clash_num++; + } + seen[v] = 2; + } + + if (!early_abort) { + #ifdef SLOW_DEBUG + uint32_t other_clash = 0; + #endif + for(uint32_t v: x1) { + if (seen[v] != 2) { + tmp_vars_xor_two.push_back(v); + } else { + #ifdef SLOW_DEBUG + other_clash++; + #endif + } + seen[v] = 0; + } + #ifdef SLOW_DEBUG + assert(other_clash == clash_num); + #endif + } else { + for(uint32_t v: x1) { + seen[v] = 0; + } + } + + for(uint32_t i = 0; i < i_x2; i++) { + seen[x2[i]] = 0; + } + + #ifdef SLOW_DEBUG + for(uint32_t v: x1) { + assert(seen[v] == 0); + } + #endif + + return clash_num; +} + +bool XorFinder::xor_has_interesting_var(const Xor& x) +{ + for(uint32_t v: x) { + if (solver->seen[v] > 1) { + return true; + } + } + return false; +} + +size_t XorFinder::mem_used() const +{ + size_t mem = 0; + mem += solver->xorclauses.capacity()*sizeof(Xor); + + //Temporary + mem += tmpClause.capacity()*sizeof(Lit); + mem += varsMissing.capacity()*sizeof(uint32_t); + + return mem; +} + +void XorFinder::grab_mem() +{ + occcnt.clear(); + occcnt.resize(solver->nVars(), 0); +} + +void XorFinder::Stats::print_short(const Solver* solver, double time_remain) const +{ + cout + << "c [occ-xor] found " << std::setw(6) << foundXors + ; + if (foundXors > 0) { + cout + << " avg sz " << std::setw(3) << std::fixed << std::setprecision(1) + << float_div(sumSizeXors, foundXors) + << " min sz " << std::setw(2) << std::fixed << std::setprecision(1) + << minsize + << " max sz " << std::setw(2) << std::fixed << std::setprecision(1) + << maxsize; + } + cout + << solver->conf.print_times(findTime, time_outs, time_remain) + << endl; +} + +XorFinder::Stats& XorFinder::Stats::operator+=(const XorFinder::Stats& other) +{ + //Time + findTime += other.findTime; + + //XOR + foundXors += other.foundXors; + sumSizeXors += other.sumSizeXors; + + //Usefulness + time_outs += other.time_outs; + + return *this; +} diff --git a/cryptominisat/cppsrc/src/xorfinder.h b/cryptominisat/cppsrc/src/xorfinder.h new file mode 100644 index 00000000..05ebcc8a --- /dev/null +++ b/cryptominisat/cppsrc/src/xorfinder.h @@ -0,0 +1,376 @@ +/****************************************** +Copyright (C) 2009-2020 Authors of CryptoMiniSat, see AUTHORS file + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. +***********************************************/ + +#ifndef _XORFINDER_H_ +#define _XORFINDER_H_ + +#include +#include +#include +#include +#include +#include +#include +#include "constants.h" +#include "xor.h" +#include "cset.h" +#include "watcharray.h" + +using std::vector; +using std::set; + +namespace CMSat { + +//#define VERBOSE_DEBUG_XOR_FINDER + +class Solver; +class OccSimplifier; + +class PossibleXor +{ + public: + PossibleXor() + { + } + + void setup( + const vector& cl + , const ClOffset offset + , cl_abst_type _abst + , vector& seen + ) { + abst = _abst; + size = cl.size(); + offsets.clear(); + fully_used.clear(); + #ifdef VERBOSE_DEBUG_XOR_FINDER + cout << "Trying to create XOR from clause: " << cl << endl; + #endif + + assert(cl.size() <= sizeof(origCl)/sizeof(Lit) + && "The XOR being recovered is larger than MAX_XOR_RECOVER_SIZE"); + for(size_t i = 0; i < size; i++) { + origCl[i] = cl[i]; + if (i > 0) + assert(cl[i-1] < cl[i]); + } + setup_seen_rhs_foundcomb(seen); + if (offset != numeric_limits::max()) { + //this is the XOR that starts it all + //so it's fully used + offsets.push_back(offset); + fully_used.push_back(true); + } + } + + void clear_seen(vector& seen) + { + for (uint32_t i = 0; i < size; i++) { + seen[origCl[i].var()] = 0; + } + } + + //GET-type functions + cl_abst_type getAbst() const; + uint32_t getSize() const; + bool getRHS() const; + bool foundAll() const; + + //Add + template + void add(const T& cl, const ClOffset offset, vector& varsMissing); + + const vector& get_offsets() const + { + return offsets; + } + + const vector& get_fully_used() const + { + return fully_used; + } + + private: + void setup_seen_rhs_foundcomb(vector& seen) + { + //Calculate parameters of base clause. + //Also set 'seen' for easy check in 'findXorMatch()' + rhs = true; + uint32_t whichOne = 0; + for (uint32_t i = 0; i < size; i++) { + rhs ^= origCl[i].sign(); + whichOne += ((uint32_t)origCl[i].sign()) << i; + seen[origCl[i].var()] = 1; + } + + foundComb.clear(); + foundComb.resize(1ULL< foundComb; + Lit origCl[MAX_XOR_RECOVER_SIZE]; + cl_abst_type abst; + uint32_t size; + bool rhs; + vector offsets; + vector fully_used; +}; + +class XorFinder +{ +public: + XorFinder(OccSimplifier* occsimplifier, Solver* solver); + void find_xors(); + + struct Stats + { + void clear() + { + Stats tmp; + *this = tmp; + } + + Stats& operator+=(const Stats& other); + void print_short(const Solver* solver, const double time_remain) const; + + //Time + uint32_t numCalls = 0; + double findTime = 0.0; + uint32_t time_outs = 0; + + //XOR stats + uint64_t foundXors = 0; + uint64_t sumSizeXors = 0; + uint32_t minsize = numeric_limits::max(); + uint32_t maxsize = numeric_limits::min(); + }; + + const Stats& get_stats() const; + size_t mem_used() const; + void grab_mem(); + void move_xors_without_connecting_vars_to_unused(); + bool xor_together_xors(vector& xors); + void clean_equivalent_xors(vector& txors); + +private: + PossibleXor poss_xor; + void add_found_xor(const Xor& found_xor); + void find_xors_based_on_long_clauses(); + void print_found_xors(); + bool xor_has_interesting_var(const Xor& x); + void clean_xors_from_empty(vector& thisxors); + + ///xor two -- don't re-allocate memory all the time + ///use tmp_vars_xor_two instead + uint32_t xor_two(Xor const* x1, Xor const* x2, uint32_t& clash_var); + vector tmp_vars_xor_two; + + int64_t xor_find_time_limit; + + //Find XORs + void findXor(vector& lits, const ClOffset offset, cl_abst_type abst); + + ///Normal finding of matching clause for XOR + void findXorMatch(watch_subarray_const occ, const Lit wlit); + + OccSimplifier* occsimplifier; + Solver *solver; + + //Stats + Stats runStats; + Stats globalStats; + + //Temporary + vector tmpClause; + vector varsMissing; + vector binvec; + + //Other temporaries + vector occcnt; + vector& toClear; + vector& seen; + vector& seen2; + vector interesting; +}; + + +inline cl_abst_type PossibleXor::getAbst() const +{ + return abst; +} + +inline uint32_t PossibleXor::getSize() const +{ + return size; +} + +inline bool PossibleXor::getRHS() const +{ + return rhs; +} + +template void PossibleXor::add( + const T& cl + , const ClOffset offset + , vector& varsMissing +) { + #ifdef VERBOSE_DEBUG_XOR_FINDER + cout << "Adding to XOR: " << cl << endl; + + cout << "FoundComb before:" << endl; + for(size_t i = 0; i < foundComb.size(); i++) { + cout << "foundComb[" << i << "]: " << (int)foundComb[i] << endl; + } + cout << "----" << endl; + #endif + + //It's the base clause, skip. + if (!offsets.empty() && offset == offsets[0]) + return; + + assert(cl.size() <= size); + + //If clause covers more than one combination, this is used to calculate which ones + varsMissing.clear(); + + //Position of literal in the ORIGINAL clause. + //This may be larger than the position in the current clause (as some literals could be missing) + uint32_t origI = 0; + + //Position in current clause + uint32_t i = 0; + + //Used to calculate this clause covers which combination(s) + uint32_t whichOne = 0; + + bool thisRhs = true; + + for (typename T::const_iterator + l = cl.begin(), end = cl.end() + ; l != end + ; ++l, i++, origI++ + ) { + thisRhs ^= l->sign(); + + //some variables might be missing in the middle + while(cl[i].var() != origCl[origI].var()) { + varsMissing.push_back(origI); + origI++; + assert(origI < size && "cl must be sorted"); + } + if (i > 0) { + assert(cl[i-1] < cl[i] && "Must be sorted"); + } + whichOne |= ((uint32_t)l->sign()) << origI; + } + + //if vars are missing from the end + while(origI < size) { + varsMissing.push_back(origI); + origI++; + } + + assert(cl.size() < size || rhs == thisRhs); + + //set to true every combination for the missing variables + for (uint32_t j = 0; j < 1UL<<(varsMissing.size()); j++) { + uint32_t thisWhichOne = whichOne; + for (uint32_t i2 = 0; i2 < varsMissing.size(); i2++) { + if (bit(j, i2)) thisWhichOne+= 1<<(varsMissing[i2]); + } + foundComb[thisWhichOne] = true; + } + if (offset != numeric_limits::max()) { + offsets.push_back(offset); + fully_used.push_back(varsMissing.empty()); + } + + #ifdef VERBOSE_DEBUG_XOR_FINDER + cout << "whichOne was:" << whichOne << endl; + cout << "FoundComb after:" << endl; + for(size_t i = 0; i < foundComb.size(); i++) { + cout << "foundComb[" << i << "]: " << foundComb[i] << endl; + } + cout << "----" << endl; + #endif +} + +inline bool PossibleXor::foundAll() const +{ + bool OK = true; + for (uint32_t i = 0; i < foundComb.size(); i++) { + //Only count combinations with the correct RHS + if ((NumberOfSetBits(i)%2) == (uint32_t)rhs) { + continue; + } + + //If this combination hasn't been found yet, then the XOR is not complete + if (!foundComb[i]) { + OK = false; + break; + } + } + + #ifdef VERBOSE_DEBUG_XOR_FINDER + if (OK) { + cout << "Found all for this clause" << endl; + } + #endif + + return OK; +} + +inline uint32_t PossibleXor::NumberOfSetBits(uint32_t i) const +{ + //Magic is coming! (copied from some book.... never trust code like this!) + i = i - ((i >> 1) & 0x55555555); + i = (i & 0x33333333) + ((i >> 2) & 0x33333333); + return (((i + (i >> 4)) & 0xF0F0F0F) * 0x1010101) >> 24; +} + +inline bool PossibleXor::bit(const uint32_t a, const uint32_t b) const +{ + return (((a)>>(b))&1); +} + +inline const XorFinder::Stats& XorFinder::get_stats() const +{ + return globalStats; +} + +} //end namespace + +#endif //_XORFINDER_H_ diff --git a/cryptominisat/cppsrc/tests/CMakeLists.txt b/cryptominisat/cppsrc/tests/CMakeLists.txt new file mode 100644 index 00000000..c47f8e5b --- /dev/null +++ b/cryptominisat/cppsrc/tests/CMakeLists.txt @@ -0,0 +1,227 @@ +# Copyright (C) 2009-2020 Authors of CryptoMiniSat, see AUTHORS file +# +# Permission is hereby granted, free of charge, to any person obtaining a copy +# of this software and associated documentation files (the "Software"), to deal +# in the Software without restriction, including without limitation the rights +# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +# copies of the Software, and to permit persons to whom the Software is +# furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in +# all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +# THE SOFTWARE. + +if (NOT WIN32) + add_cxx_flag_if_supported("-Wno-sign-compare") +endif() + +set (LIT_TOOL "${Python3_EXECUTABLE} -m lit.main") +execute_process( + COMMAND "${Python3_EXECUTABLE}" "-m" "lit.main" "--version" + OUTPUT_VARIABLE LIT_VER_OUT + ERROR_VARIABLE LIT_VER_ERR + RESULT_VARIABLE RES +) + +if(NOT("${RES}" STREQUAL "0")) + message(STATUS "Output of LIT stdout: '${LIT_VER_OUT}'") + message(STATUS "Output of LIT stderr: '${LIT_VER_ERR}'") + message(STATUS "LIT result val is: '${RES}'") + message(FATAL_ERROR "Could not find 'lit' tool for Python executable ${Python3_EXECUTABLE}. You need to install it for this Python version by running '${Python3_EXECUTABLE} -m pip install lit'. If it's already installed, set LIT_TOOL to the full path for lit") +endif() + +set(LIT_ARGS -v CACHE STRING "Arguments to pass to lit") + +# ----------------------------------------------------------------------------- +# Find GTest library which will be used to drive tests +# ----------------------------------------------------------------------------- +# GoogleTest devs don't recommend using a pre-built GTest library +# ( https://code.google.com/p/googletest/wiki/FAQ#Why_is_it_not_recommended_to_install_a_pre-compiled_copy_of_Goog ). +# Because of this, distros like Ubuntu don't provide a pre-built GTest library +# so ``find_package(GTest REQUIRED)`` fails. +# +# Instead it is recommended that projects build their own copy of GTest. Detecting +# the location of GTest source code is probably error prone so using a copy in the +# repository seems like the easiest thing to do. This also has the added benefit that +# everyone uses the same version of GTest. +set(GTEST_PREFIX ${PROJECT_SOURCE_DIR}/utils/gtest) +message(STATUS "NOTE: if adding the 'gtest' subdirectory fails, you need to issue 'git submodule init' and 'git submodule update'") +add_subdirectory(${GTEST_PREFIX} gtest) +set(GTEST_BOTH_LIBRARIES gtest gtest_main) + +include_directories(${GTEST_PREFIX}/include) +include_directories( ${TBUDDY_INCLUDE_DIRS} ) +add_definitions( -DCMS_TESTING_ENABLED ) + +# Add handy macros/functions +include(AddSTPGTest) +include(AddGTestSuite) + +# ----------------------------------------------------------------------------- +# ----------------------------------------------------------------------------- + +if(NOT ONLY_SIMPLE) + # Tests that drive cryptominisat by using cnf files (e.g. smt2, smt and cvc files) + add_subdirectory(${PROJECT_SOURCE_DIR}/tests/cnf-files) + + # Needed for fuzz-testing + add_subdirectory(${PROJECT_SOURCE_DIR}/utils/cnf-utils cnf-utils) + add_subdirectory(${PROJECT_SOURCE_DIR}/utils/sha1-sat sha1-sat) + add_subdirectory(${PROJECT_SOURCE_DIR}/utils/minisat minisat) +endif() + +add_sanitize_flags() +# below is expensive tests, let's not run it +# if (Python3_EXECUTABLE AND ZLIB_FOUND AND NOT STATS_NEEDED AND NOT ONLY_SIMPLE) +# add_subdirectory(${PROJECT_SOURCE_DIR}/utils/minisat_only_elim_and_subsume minisat_only_elim_and_subsume) +# add_subdirectory(simp-checks) +# endif() + + +include_directories( ${PROJECT_SOURCE_DIR} ) +include_directories( + #${PROJECT_BINARY_DIR}/cmsat5-src + ${PROJECT_BINARY_DIR}/include +) + +set(cryptoms_lib_link_libs cryptominisat5) +if (tbuddy_FOUND) + set(cryptoms_lib_link_libs ${cryptoms_lib_link_libs} tbuddy) +endif() + +# README test +add_executable(readme_test + readme_test.cpp +) +target_link_libraries(readme_test + ${cryptoms_lib_link_libs} +) +add_test ( + NAME readme_test + COMMAND readme_test + WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR} +) + +# C bindings test +if (NOT SANITIZE) + add_executable(c_test + c_test.c + ) + target_link_libraries(c_test + ${cryptoms_lib_link_libs} + ) + add_test ( + NAME c_test + COMMAND c_test + WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR} + ) +endif() + +# Multisol test +add_executable(multisol_test + multisol_test.cpp +) +target_link_libraries(multisol_test + ${cryptoms_lib_link_libs} +) +add_test ( + NAME multisol_test + COMMAND multisol_test + WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR} +) + + +if (IPASIR) + add_executable(ipasir_test + ipasir_test.cpp + ) + target_link_libraries(ipasir_test + ${GTEST_BOTH_LIBRARIES} + ipasircryptominisat5 + ) + add_test ( + NAME ipasir_test + COMMAND ipasir_test + WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR} + ) + + add_executable(ipasir_example + ipasir_example.c + ) + target_link_libraries(ipasir_example + ipasircryptominisat5 + ) + add_test ( + NAME ipasir_example + COMMAND ipasir_example + WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR} + ) +endif() + +# unit tests +set (MY_TESTS +# clause_alloc_test + basic_test + assump_test + heap_test + clause_test + stp_test + scc_test + vrepl_test + clause_cleaner_test + distiller_test + distill_long_with_implicit_test + subsume_impl_test + intree_test + xorfinder_test + searcher_test + solver_test + cardfinder_test + ternary_resolve_test + implied_by_test + lucky_test + definability_test + gatefinder_test + matrixfinder_test + # gauss_test +# undefine_test +) + +foreach(F ${MY_TESTS}) + add_executable(${F} + ${F}.cpp + ) + target_link_libraries(${F} + ${cryptoms_lib_link_libs} + ${GTEST_BOTH_LIBRARIES} + ) + add_test ( + NAME ${F} + COMMAND ${F} + WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR} + ) +endforeach() + +# if (FINAL_PREDICTOR) +# add_executable(ml_perf_test +# ml_perf_test.cpp +# ${PROJECT_SOURCE_DIR}/src/cl_predictors.cpp +# ) +# +# target_link_libraries(ml_perf_test +# LINK_PUBLIC xgboost dmlc rabit rt +# ) +# +# add_test ( +# NAME ml_perf_test +# COMMAND ml_perf_test +# WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR} +# ) +# endif() diff --git a/cryptominisat/cppsrc/tests/assump_test.cpp b/cryptominisat/cppsrc/tests/assump_test.cpp new file mode 100644 index 00000000..75ed044a --- /dev/null +++ b/cryptominisat/cppsrc/tests/assump_test.cpp @@ -0,0 +1,215 @@ +/****************************************** +Copyright (C) 2009-2020 Authors of CryptoMiniSat, see AUTHORS file + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. +***********************************************/ + +#include "gtest/gtest.h" + +#include "cryptominisat5/cryptominisat.h" +#include "src/solverconf.h" +#include +#include +using std::vector; +using namespace CMSat; + +struct assump_interf : public ::testing::Test { + assump_interf() + { + SolverConf conf; + s = new SATSolver(&conf); + } + ~assump_interf() + { + delete s; + } + SATSolver* s = NULL; + vector assumps; +}; + +TEST_F(assump_interf, empty) +{ + s->new_var(); + s->add_clause(vector{Lit(0, false)}); + lbool ret = s->solve(&assumps); + EXPECT_EQ( ret, l_True); + EXPECT_EQ( s->okay(), true); +} + +TEST_F(assump_interf, single_true) +{ + s->new_var(); + s->add_clause(vector{Lit(0, false)}); + assumps.push_back(Lit(0, false)); + lbool ret = s->solve(&assumps); + EXPECT_EQ( ret, l_True); + EXPECT_EQ( s->okay(), true); +} + +TEST_F(assump_interf, single_false) +{ + s->new_var(); + s->add_clause(vector{Lit(0, false)}); + assumps.push_back(Lit(0, true)); + lbool ret = s->solve(&assumps); + EXPECT_EQ( ret, l_False); + EXPECT_EQ( s->get_conflict().size(), 1u); + EXPECT_EQ( s->get_conflict()[0], Lit(0, false)); +} + + +TEST_F(assump_interf, single_false_then_true) +{ + s->new_var(); + s->add_clause(vector{Lit(0, false)}); + assumps.push_back(Lit(0, true)); + lbool ret = s->solve(&assumps); + EXPECT_EQ( ret, l_False); + EXPECT_EQ( s->okay(), true); + + ret = s->solve(); + EXPECT_EQ( ret, l_True); + EXPECT_EQ( s->okay(), true); + +} + +TEST_F(assump_interf, binclause_true) +{ + s->new_var(); + s->new_var(); + s->add_clause(vector{Lit(0, false), Lit(1, false)}); + assumps.push_back(Lit(0, true)); + lbool ret = s->solve(&assumps); + EXPECT_EQ( ret, l_True ); + EXPECT_EQ( s->get_model()[0], l_False ); + EXPECT_EQ( s->get_model()[1], l_True ); +} + +TEST_F(assump_interf, binclause_false) +{ + s->new_var(); + s->new_var(); + s->add_clause(vector{Lit(0, false), Lit(1, false)}); + assumps.push_back(Lit(0, true)); + assumps.push_back(Lit(1, true)); + lbool ret = s->solve(&assumps); + EXPECT_EQ( ret, l_False); + EXPECT_EQ( s->get_conflict().size(), 2u); + + vector tmp = s->get_conflict(); + std::sort(tmp.begin(), tmp.end()); + EXPECT_EQ( tmp[0], Lit(0, false) ); + EXPECT_EQ( tmp[1], Lit(1, false) ); +} + +TEST_F(assump_interf, replace_true) +{ + s->new_var(); + s->new_var(); + s->add_clause(vector{Lit(0, false), Lit(1, true)}); + s->add_clause(vector{Lit(0, true), Lit(1, false)}); + assumps.push_back(Lit(0, true)); + assumps.push_back(Lit(1, true)); + lbool ret = s->solve(&assumps); + EXPECT_EQ( ret, l_True); + EXPECT_EQ( s->get_model()[0], l_False ); + EXPECT_EQ( s->get_model()[1], l_False ); + + assumps.clear(); + assumps.push_back(Lit(0, true)); + assumps.push_back(Lit(1, false)); + ret = s->solve(&assumps); + EXPECT_EQ( ret, l_False); +} + +TEST_F(assump_interf, replace_false) +{ + s->new_var(); + s->new_var(); + s->add_clause(vector{Lit(0, false), Lit(1, true)}); //a V -b + s->add_clause(vector{Lit(0, true), Lit(1, false)}); //-a V b + //a == b + + assumps.push_back(Lit(0, false)); + assumps.push_back(Lit(1, true)); + //a = 1, b = 0 + + lbool ret = s->solve(&assumps); + EXPECT_EQ( ret, l_False); + EXPECT_EQ( s->okay(), true); + + EXPECT_EQ( s->get_conflict().size(), 2u); + + vector tmp = s->get_conflict(); + std::sort(tmp.begin(), tmp.end()); + EXPECT_EQ( tmp[0], Lit(0, true) ); + EXPECT_EQ( tmp[1], Lit(1, false) ); +} + +TEST_F(assump_interf, set_var_by_prop) +{ + s->new_var(); + s->new_var(); + s->add_clause(vector{Lit(0, false)}); //a = 1 + s->add_clause(vector{Lit(0, true), Lit(1, false)}); //-a V b + //-> b = 1 + + assumps.push_back(Lit(1, true)); + //b = 0 + + lbool ret = s->solve(&assumps); + EXPECT_EQ( ret, l_False); + EXPECT_EQ( s->okay(), true); + + EXPECT_EQ( s->get_conflict().size(), 1u); + + vector tmp = s->get_conflict(); + EXPECT_EQ( tmp[0], Lit(1, false) ); +} + +TEST_F(assump_interf, only_assump) +{ + s->new_var(); + s->new_var(); + + assumps.push_back(Lit(1, true)); + assumps.push_back(Lit(1, false)); + + lbool ret = s->solve(&assumps); + EXPECT_EQ( ret, l_False); + EXPECT_EQ( s->okay(), true); + EXPECT_EQ( s->get_conflict().size(), 2u); + + vector tmp = s->get_conflict(); + std::sort(tmp.begin(), tmp.end()); + EXPECT_EQ( tmp[0] , Lit(1, false) ); + EXPECT_EQ( tmp[1], Lit(1, true) ); + + ret = s->solve(NULL); + EXPECT_EQ( ret, l_True ); + + ret = s->solve(&assumps); + EXPECT_EQ( ret, l_False); +} + + +int main(int argc, char **argv) { + ::testing::InitGoogleTest(&argc, argv); + return RUN_ALL_TESTS(); +} diff --git a/cryptominisat/cppsrc/tests/basic_test.cpp b/cryptominisat/cppsrc/tests/basic_test.cpp new file mode 100644 index 00000000..5f56b267 --- /dev/null +++ b/cryptominisat/cppsrc/tests/basic_test.cpp @@ -0,0 +1,1399 @@ +/****************************************** +Copyright (C) 2009-2020 Authors of CryptoMiniSat, see AUTHORS file + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. +***********************************************/ + +#include "gtest/gtest.h" + +#include + +#include "cryptominisat5/cryptominisat.h" +#include "src/solverconf.h" +#include "test_helper.h" +#include + +using namespace CMSat; +using std::vector; + + +TEST(normal_interface, start) +{ + SATSolver s; + lbool ret = s.solve(); + EXPECT_EQ( ret, l_True); + EXPECT_EQ( s.okay(), true); +} + +TEST(normal_interface, onelit) +{ + SATSolver s; + s.new_var(); + s.add_clause(str_to_cl("1")); + lbool ret = s.solve(); + EXPECT_EQ( ret, l_True); + EXPECT_EQ( s.okay(), true); +} + +TEST(normal_interface, twolit) +{ + SATSolver s; + s.new_var(); + s.add_clause(str_to_cl("1")); + s.add_clause(str_to_cl("-1")); + lbool ret = s.solve(); + EXPECT_EQ( ret, l_False); + EXPECT_EQ( s.okay(), false); +} + +TEST(normal_interface, multi_solve_unsat) +{ + SATSolver s; + s.new_var(); + s.add_clause(str_to_cl("1")); + s.add_clause(str_to_cl("-1")); + lbool ret = s.solve(); + EXPECT_EQ( ret, l_False); + EXPECT_EQ( s.okay(), false); + for(size_t i = 0;i < 10; i++) { + ret = s.solve(); + EXPECT_EQ( ret, l_False); + EXPECT_EQ( s.okay(), false); + } +} + +TEST(normal_interface, multi_solve_unsat_multi_thread) +{ + SATSolver s; + s.set_num_threads(2); + s.new_var(); + s.add_clause(str_to_cl("1")); + s.add_clause(str_to_cl("-1")); + lbool ret = s.solve(); + EXPECT_EQ( ret, l_False); + EXPECT_EQ( s.okay(), false); + for(size_t i = 0;i < 10; i++) { + ret = s.solve(); + EXPECT_EQ( ret, l_False); + EXPECT_EQ( s.okay(), false); + } +} + +TEST(normal_interface, solve_multi_thread) +{ + SATSolver s; + s.set_num_threads(2); + s.new_vars(2); + s.add_clause(str_to_cl("1, 2")); + lbool ret = s.solve(); + EXPECT_EQ( ret, l_True); + + s.add_clause(str_to_cl("-1")); + ret = s.solve(); + EXPECT_EQ( ret, l_True); + EXPECT_EQ(s.get_model()[0], l_False); + EXPECT_EQ(s.get_model()[1], l_True); +} + +TEST(normal_interface, logfile) +{ + SATSolver* s = new SATSolver(); + s->log_to_file("testfile"); + s->new_vars(2); + s->add_clause(str_to_cl("1, 2")); + lbool ret = s->solve(); + EXPECT_EQ( ret, l_True); + delete s; + + std::ifstream infile("testfile"); + std::string line; + std::getline(infile, line); + EXPECT_EQ(line, "c Solver::new_vars( 2 )"); + std::getline(infile, line); + EXPECT_EQ(line, "1 2 0"); + std::getline(infile, line); + EXPECT_EQ(line, "c Solver::solve( )"); +} + +TEST(normal_interface, logfile2) +{ + SATSolver* s = new SATSolver(); + s->log_to_file("testfile"); + s->new_vars(2); + s->add_clause(str_to_cl("1")); + s->add_clause(str_to_cl("1, 2")); + lbool ret = s->solve(); + s->add_clause(vector{Lit(1, false)}); + ret = s->solve(); + delete s; + + std::ifstream infile("testfile"); + std::string line; + std::getline(infile, line); + EXPECT_EQ(line, "c Solver::new_vars( 2 )"); + std::getline(infile, line); + EXPECT_EQ(line, "1 0"); + std::getline(infile, line); + EXPECT_EQ(line, "1 2 0"); + std::getline(infile, line); + EXPECT_EQ(line, "c Solver::solve( )"); + std::getline(infile, line); + EXPECT_EQ(line, "2 0"); + std::getline(infile, line); + EXPECT_EQ(line, "c Solver::solve( )"); +} + +TEST(normal_interface, logfile2_assumps) +{ + SATSolver* s = new SATSolver(); + s->log_to_file("testfile"); + s->new_vars(2); + s->add_clause(str_to_cl("1")); + s->add_clause(str_to_cl("1, 2")); + std::vector assumps {Lit(0, false), Lit(1, true)}; + lbool ret = s->solve(&assumps); + s->add_clause(vector{Lit(1, false)}); + assumps.clear(); + assumps.push_back(Lit(1, true)); + ret = s->solve(&assumps); + delete s; + + std::ifstream infile("testfile"); + std::string line; + std::getline(infile, line); + EXPECT_EQ(line, "c Solver::new_vars( 2 )"); + std::getline(infile, line); + EXPECT_EQ(line, "1 0"); + std::getline(infile, line); + EXPECT_EQ(line, "1 2 0"); + std::getline(infile, line); + EXPECT_EQ(line, "c Solver::solve( 1 -2 )"); + std::getline(infile, line); + EXPECT_EQ(line, "2 0"); + std::getline(infile, line); + EXPECT_EQ(line, "c Solver::solve( -2 )"); +} + +TEST(normal_interface, max_time) +{ + SATSolver* s = new SATSolver(); + s->new_vars(200); + s->add_clause(str_to_cl("1")); + s->add_clause(str_to_cl("1, 2")); + s->set_max_time(3); + lbool ret = s->solve(); + s->add_clause(vector{Lit(1, false)}); + ret = s->solve(); + delete s; + EXPECT_EQ(ret, l_True); +} + +bool is_critical(const std::range_error&) { return true; } + +TEST(xor_interface, xor_check_sat_solution) +{ + SATSolver s; + s.new_var(); + s.add_xor_clause(vector{0U}, false); + s.add_xor_clause(vector{0U}, true); + lbool ret = s.solve(); + EXPECT_EQ( ret, l_False); + for(size_t i = 0;i < 10; i++) { + ret = s.solve(); + EXPECT_EQ( ret, l_False); + } + EXPECT_EQ( s.nVars(), 1u); +} + +TEST(xor_interface, xor_check_unsat_solution) +{ + SATSolver s; + s.new_var(); + s.add_xor_clause(vector{0U}, true); + s.add_xor_clause(vector{0U}, true); + lbool ret = s.solve(); + EXPECT_EQ( ret, l_True); + for(size_t i = 0;i < 10; i++) { + ret = s.solve(); + EXPECT_EQ( ret, l_True); + EXPECT_EQ( s.okay(), true); + } + EXPECT_EQ( s.nVars(), 1u); +} + +TEST(xor_interface, xor_check_solution_values) +{ + SATSolver s; + s.new_var(); + s.add_xor_clause(vector{0U}, true); + s.add_xor_clause(vector{0U}, true); + lbool ret = s.solve(); + EXPECT_EQ( ret, l_True); + for(size_t i = 0;i < 10; i++) { + ret = s.solve(); + EXPECT_EQ( ret, l_True); + EXPECT_EQ( s.okay(), true); + } + EXPECT_EQ( s.nVars(), 1u); +} + +TEST(xor_interface, xor_check_solution_values2) +{ + SATSolver s; + s.new_var(); + s.new_var(); + s.add_xor_clause(vector{0U}, true); + s.add_xor_clause(vector{1U}, true); + lbool ret = s.solve(); + EXPECT_EQ( ret, l_True); + for(size_t i = 0;i < 10; i++) { + ret = s.solve(); + EXPECT_EQ( ret, l_True); + EXPECT_EQ(s.get_model()[0], l_True); + EXPECT_EQ(s.get_model()[1], l_True); + } + EXPECT_EQ( s.nVars(), 2u); +} + +TEST(xor_interface, xor_check_solution_values3) +{ + SATSolver s; + s.new_var(); + s.new_var(); + s.add_xor_clause(vector{0U, 0U}, true); + lbool ret = s.solve(); + EXPECT_EQ( ret, l_False); +} + +TEST(xor_interface, xor_check_solution_values4) +{ + SATSolver s; + s.new_var(); + s.new_var(); + s.add_xor_clause(vector{0U, 0U}, false); + lbool ret = s.solve(); + EXPECT_EQ( ret, l_True); + EXPECT_EQ( s.nVars(), 2u); +} + + +TEST(xor_interface, xor_check_solution_values5) +{ + SATSolver s; + s.new_var(); + s.new_var(); + s.add_xor_clause(vector{0U, 1U}, true); + vector assump = {Lit(0, false)}; + lbool ret = s.solve(&assump); + EXPECT_EQ( ret, l_True); + EXPECT_EQ( s.okay(), true); + EXPECT_EQ(s.get_model()[0], l_True); + EXPECT_EQ(s.get_model()[1], l_False); + EXPECT_EQ( s.nVars(), 2u); +} + +TEST(xor_interface, xor_check_solution_values6) +{ + SATSolver s; + s.new_var(); + s.new_var(); + s.add_xor_clause(vector{0U, 1U}, false); + vector assump = {Lit(0, true)}; + lbool ret = s.solve(&assump); + EXPECT_EQ( ret, l_True); + EXPECT_EQ(s.get_model()[0], l_False); + EXPECT_EQ(s.get_model()[1], l_False); + EXPECT_EQ( s.nVars(), 2u); +} + +TEST(xor_interface, xor_check_solution_values7) +{ + SATSolver s; + s.new_var(); + s.new_var(); + s.new_var(); + s.add_xor_clause(vector{0U, 1U, 2U}, false); + vector assump = {Lit(0, false), Lit(1, false)}; + lbool ret = s.solve(&assump); + EXPECT_EQ( ret, l_True); + EXPECT_EQ(s.get_model()[0], l_True); + EXPECT_EQ(s.get_model()[1], l_True); + EXPECT_EQ(s.get_model()[2], l_False); + EXPECT_EQ( s.nVars(), 3u); +} + +TEST(xor_interface, xor_3_long) +{ + SATSolver s; + s.new_var(); + s.new_var(); + s.new_var(); + s.add_xor_clause(vector{0U, 1U, 2U}, true); + s.add_xor_clause(vector{0}, true); + s.add_xor_clause(vector{1}, true); + lbool ret = s.solve(); + EXPECT_EQ( ret, l_True); + EXPECT_EQ(s.get_model()[0], l_True); + EXPECT_EQ(s.get_model()[1], l_True); + EXPECT_EQ(s.get_model()[2], l_True); + EXPECT_EQ( s.nVars(), 3u); +} + +TEST(xor_interface, xor_3_long2) +{ + SATSolver s; + s.new_var(); + s.new_var(); + s.new_var(); + s.add_xor_clause(vector{0U, 1U, 2U}, false); + s.add_xor_clause(vector{0U}, true); + s.add_xor_clause(vector{1U}, true); + lbool ret = s.solve(); + EXPECT_EQ( ret, l_True); + EXPECT_EQ(s.get_model()[0], l_True); + EXPECT_EQ(s.get_model()[1], l_True); + EXPECT_EQ(s.get_model()[2], l_False); + EXPECT_EQ( s.nVars(), 3u); +} + +TEST(xor_interface, xor_4_long) +{ + SATSolver s; + s.new_var(); + s.new_var(); + s.new_var(); + s.new_var(); + s.add_xor_clause(vector{0U, 1U, 2U, 3U}, false); + s.add_xor_clause(vector{0U}, false); + s.add_xor_clause(vector{1U}, false); + s.add_xor_clause(vector{2U}, false); + lbool ret = s.solve(); + EXPECT_EQ( ret, l_True); + EXPECT_EQ(s.get_model()[0], l_False); + EXPECT_EQ(s.get_model()[1], l_False); + EXPECT_EQ(s.get_model()[2], l_False); + EXPECT_EQ(s.get_model()[3], l_False); + EXPECT_EQ( s.nVars(), 4u); +} + +TEST(xor_interface, xor_4_long2) +{ + SATSolver s; + s.new_var(); + s.new_var(); + s.new_var(); + s.new_var(); + s.add_xor_clause(vector{0U, 1U, 2U, 3U}, true); + s.add_xor_clause(vector{0U}, false); + s.add_xor_clause(vector{1U}, false); + s.add_xor_clause(vector{2U}, true); + lbool ret = s.solve(); + EXPECT_EQ( ret, l_True); + EXPECT_EQ(s.get_model()[0], l_False); + EXPECT_EQ(s.get_model()[1], l_False); + EXPECT_EQ(s.get_model()[2], l_True); + EXPECT_EQ(s.get_model()[3], l_False); + EXPECT_EQ( s.nVars(), 4u); +} + +TEST(xor_interface, xor_very_long) +{ + SATSolver s; + vector vars; + for(unsigned i = 0; i < 30; i++) { + s.new_var(); + vars.push_back(i); + } + s.add_xor_clause(vars, false); + for(unsigned i = 0; i < 29; i++) { + s.add_xor_clause(vector{i}, false); + } + lbool ret = s.solve(); + EXPECT_EQ( ret, l_True); + for(unsigned i = 0; i < 30; i++) { + EXPECT_EQ(s.get_model()[i], l_False); + } + EXPECT_EQ( s.nVars(), 30u); +} + +TEST(xor_interface, xor_very_long2) +{ + for(size_t num = 3; num < 30; num++) { + SATSolver s; + vector vars; + for(unsigned i = 0; i < num; i++) { + s.new_var(); + vars.push_back(i); + } + s.add_xor_clause(vars, true); + for(unsigned i = 0; i < num-1; i++) { + s.add_xor_clause(vector{i}, false); + } + lbool ret = s.solve(); + EXPECT_EQ( ret, l_True); + for(unsigned i = 0; i < num-1; i++) { + EXPECT_EQ(s.get_model()[i], l_False); + } + EXPECT_EQ(s.get_model()[num-1], l_True); + EXPECT_EQ( s.nVars(), num); + } +} + +TEST(xor_interface, xor_check_unsat) +{ + SATSolver s; + s.new_vars(3); + s.add_xor_clause(vector{0U, 1U, 2U}, false); + s.add_xor_clause(vector{0U, 1U, 2U}, true); + lbool ret = s.solve(); + EXPECT_EQ( ret, l_False); + EXPECT_EQ( s.nVars(), 3u); +} + +TEST(xor_interface, xor_check_unsat_multi_thread) +{ + SATSolver s; + s.set_num_threads(3); + s.new_vars(3); + s.add_xor_clause(vector{0U, 1U, 2U}, false); + s.add_xor_clause(vector{0U, 1U, 2U}, true); + lbool ret = s.solve(); + EXPECT_EQ( ret, l_False); + EXPECT_EQ( s.okay(), false); + EXPECT_EQ( s.nVars(), 3u); +} + +TEST(xor_interface, xor_check_unsat_multi_solve_multi_thread) +{ + SATSolver s; + s.set_num_threads(3); + s.new_vars(3); + s.add_xor_clause(vector{0U, 1U}, false); + s.add_xor_clause(vector{0U, 1U, 2U}, true); + lbool ret = s.solve(); + EXPECT_EQ( ret, l_True); + EXPECT_EQ( s.nVars(), 3u); + + s.add_xor_clause(vector{0U}, false); + ret = s.solve(); + EXPECT_EQ( ret, l_True); + EXPECT_EQ( s.get_model()[0], l_False); + EXPECT_EQ( s.get_model()[1], l_False); + EXPECT_EQ( s.get_model()[2], l_True); + EXPECT_EQ( s.nVars(), 3u); + + s.add_xor_clause(vector{1U}, true); + ret = s.solve(); + EXPECT_EQ( ret, l_False); + EXPECT_EQ( s.nVars(), 3u); +} + +TEST(xor_interface, xor_norm_mix_unsat_multi_thread) +{ + SATSolver s; + //s.set_num_threads(3); + s.new_vars(3); + s.add_clause(str_to_cl("1")); + s.add_xor_clause(vector{0U, 1U, 2U}, false); + s.add_clause(vector{Lit(1, false)}); + s.add_clause(vector{Lit(2, false)}); + lbool ret = s.solve(); + EXPECT_EQ( ret, l_False); + EXPECT_EQ( s.nVars(), 3u); +} + +TEST(xor_interface, unit) +{ + SATSolver s; + s.new_vars(3); + s.add_clause(str_to_cl("1")); + lbool ret = s.solve(); + EXPECT_EQ( ret, l_True); + + vector units = s.get_zero_assigned_lits(); + EXPECT_EQ( units.size(), 1u); + EXPECT_EQ( units[0], Lit(0, false)); +} + +TEST(xor_interface, unit2) +{ + SATSolver s; + s.new_vars(3); + s.add_clause(str_to_cl("1")); + lbool ret = s.solve(); + EXPECT_EQ( ret, l_True); + + vector units = s.get_zero_assigned_lits(); + EXPECT_EQ( units.size(), 1u); + EXPECT_EQ( units[0], Lit(0, false)); + + s.add_clause(vector{Lit(1, true)}); + ret = s.solve(); + EXPECT_EQ( ret, l_True); + + units = s.get_zero_assigned_lits(); + EXPECT_EQ( units.size(), 2u); + EXPECT_EQ( units[0], Lit(0, false)); + EXPECT_EQ( units[1], Lit(1, true)); +} + +TEST(xor_interface, unit3) +{ + SATSolver s; + s.new_vars(3); + s.add_clause(str_to_cl("1")); + s.add_clause(str_to_cl("-1, -2")); + lbool ret = s.solve(); + EXPECT_EQ( ret, l_True); + + vector units = s.get_zero_assigned_lits(); + EXPECT_EQ( units.size(), 2u); + EXPECT_EQ( units[0], Lit(0, false)); + EXPECT_EQ( units[1], Lit(1, true)); +} + +TEST(xor_interface, xor1) +{ + SolverConf conf; + conf.simplify_at_startup = true; + conf.full_simplify_at_startup = true; + SATSolver s(&conf); + + s.new_vars(3); + s.add_xor_clause(vector{0, 1}, false); + lbool ret = s.solve(); + EXPECT_EQ( ret, l_True); + + vector > pairs = s.get_all_binary_xors(); + EXPECT_EQ( pairs.size(), 1u); +} + +TEST(xor_interface, xor2) +{ + SolverConf conf; + conf.simplify_at_startup = true; + conf.full_simplify_at_startup = true; + SATSolver s(&conf); + + s.new_vars(3); + s.add_xor_clause(vector{0, 1}, false); + s.add_xor_clause(vector{1, 2}, false); + lbool ret = s.solve(); + EXPECT_EQ( ret, l_True); + + vector > pairs = s.get_all_binary_xors(); + EXPECT_EQ( pairs.size(), 2u); +} + +TEST(xor_interface, abort_early) +{ + SATSolver s; + s.set_no_simplify(); + s.set_no_equivalent_lit_replacement(); + + s.set_num_threads(2); + s.set_max_confl(0); + s.new_vars(2); + + s.add_clause(str_to_cl("1, 2")); + s.add_clause(str_to_cl("1, -2")); + s.add_clause(str_to_cl("-1, 2")); + s.add_clause(str_to_cl("-1, -2")); + + lbool ret = s.solve(); + EXPECT_EQ( ret, l_Undef); +} + +TEST(xor_interface, abort_once_continue_next) +{ + SATSolver s; + s.set_no_simplify(); + s.set_no_equivalent_lit_replacement(); + + s.set_num_threads(2); + s.set_max_confl(0); + s.new_vars(2); + + s.add_clause(str_to_cl("1, 2")); + s.add_clause(str_to_cl("1, -2")); + s.add_clause(str_to_cl("-1, 2")); + s.add_clause(str_to_cl("-1, -2")); + + lbool ret = s.solve(); + EXPECT_EQ( ret, l_Undef); + lbool ret2 = s.solve(); + EXPECT_EQ( ret2, l_False); +} + +TEST(xor_interface, xor3) +{ + SolverConf conf; + conf.simplify_at_startup = true; + conf.simplify_at_every_startup = true; + conf.full_simplify_at_startup = true; + SATSolver s(&conf); + + s.new_vars(3); + s.add_xor_clause(vector{0, 1}, false); + lbool ret = s.solve(); + EXPECT_EQ( ret, l_True); + + vector > pairs = s.get_all_binary_xors(); + EXPECT_EQ( pairs.size(), 1u); + + s.add_xor_clause(vector{1, 2}, false); + ret = s.solve(); + EXPECT_EQ( ret, l_True); + pairs = s.get_all_binary_xors(); + EXPECT_EQ( pairs.size(), 2u); +} + +TEST(error_throw, multithread_newvar) +{ + SATSolver s; + + s.new_vars(3); + EXPECT_THROW({ + s.set_num_threads(3);} + , std::runtime_error); +} + +TEST(error_throw, multithread_0) +{ + SATSolver s; + + EXPECT_THROW({ + s.set_num_threads(0);} + , std::runtime_error); +} + +TEST(error_throw, multithread_drat) +{ + SATSolver s; + FILE* os = NULL; + s.set_frat(os); + + EXPECT_THROW({ + s.set_num_threads(3);} + , std::runtime_error); +} + +TEST(error_throw, toomany_vars) +{ + SATSolver s; + + EXPECT_THROW({ + s.new_vars(1ULL << 28);} + , CMSat::TooManyVarsError); +} + +TEST(error_throw, toomany_vars2) +{ + SATSolver s; + s.new_vars(1ULL << 27); + + EXPECT_THROW({ + s.new_vars(1ULL << 27);} + , CMSat::TooManyVarsError); +} + +TEST(error_throw, toomany_vars_single) +{ + SATSolver s; + s.new_vars((1ULL << 28) -1); + + EXPECT_THROW({ + s.new_var();} + , CMSat::TooManyVarsError); +} + +TEST(no_error_throw, long_clause) +{ + SATSolver s; + s.new_vars(1ULL << 20); + + vector cl; + for(size_t i = 0; i < 1ULL << 20; i++) { + cl.push_back(Lit(i, false)); + } + s.add_clause(cl); + lbool ret = s.solve(); + EXPECT_EQ(ret, l_True); +} + +TEST(statistics, zero) +{ + SATSolver s; + s.set_no_simplify(); + s.new_vars(10); + + lbool ret = s.solve(); + EXPECT_EQ(ret, l_True); + EXPECT_EQ(s.get_sum_conflicts(), 0); + EXPECT_EQ(s.get_sum_propagations(), 10); + EXPECT_EQ(s.get_sum_decisions(), 10); +} + +TEST(statistics, two_confl) +{ + SATSolver s; + s.set_no_simplify(); + s.new_vars(10); + s.add_clause(str_to_cl("1, 2")); + s.add_clause(str_to_cl("1, -2")); + s.add_clause(str_to_cl("-1, 2")); + s.add_clause(str_to_cl("-1, -2")); + + lbool ret = s.solve(); + EXPECT_EQ(ret, l_False); + EXPECT_EQ(s.get_sum_conflicts(), 2); +} + +TEST(statistics, unsat) +{ + SATSolver s; + s.set_no_simplify(); + s.new_vars(10); + s.add_clause(str_to_cl("1, 2")); + s.add_clause(str_to_cl("1, -2")); + s.add_clause(str_to_cl("-1, 2")); + s.add_clause(str_to_cl("-1, -2")); + + lbool ret = s.solve(); + EXPECT_EQ(ret, l_False); + EXPECT_EQ(s.get_sum_conflicts(), 2); +} + +TEST(statistics, last_vs_sum_conflicts) +{ + SATSolver s; + s.set_no_simplify(); + s.new_vars(10); + s.add_clause(str_to_cl("1, 2")); + s.add_clause(str_to_cl("1, -2")); + s.add_clause(str_to_cl("-1, 2")); + s.add_clause(str_to_cl("-1, -2")); + + s.set_max_confl(0); + lbool ret = s.solve(); + EXPECT_EQ(ret, l_Undef); + EXPECT_EQ(s.get_sum_conflicts(), 0); + EXPECT_EQ(s.get_last_conflicts(), 0); + + s.set_max_confl(2); + ret = s.solve(); + EXPECT_EQ(ret, l_False); + EXPECT_EQ(s.get_sum_conflicts(), 2); + EXPECT_EQ(s.get_last_conflicts(), 2); +} + +TEST(propagate, trivial_1) +{ + SATSolver s; + s.new_vars(10); + s.add_clause(str_to_cl("-1")); + + vector lits = s.get_zero_assigned_lits(); + vector::iterator it; + it = std::find(lits.begin(), lits.end(), Lit(0, true)); + EXPECT_NE(it, lits.end()); + EXPECT_EQ(lits.size(), 1); +} + +TEST(propagate, trivial_2) +{ + SATSolver s; + s.new_vars(10); + s.add_clause(str_to_cl("-1")); + s.add_clause(str_to_cl("-2")); + + vector lits = s.get_zero_assigned_lits(); + vector::iterator it; + it = std::find(lits.begin(), lits.end(), Lit(0, true)); + EXPECT_NE(it, lits.end()); + it = std::find(lits.begin(), lits.end(), Lit(1, true)); + EXPECT_NE(it, lits.end()); + + EXPECT_EQ(lits.size(), 2); +} + +TEST(propagate, prop_1) +{ + SATSolver s; + s.new_vars(10); + s.add_clause(str_to_cl("1, 2")); + s.add_clause(str_to_cl("-1")); + + vector lits = s.get_zero_assigned_lits(); + vector::iterator it; + it = std::find(lits.begin(), lits.end(), Lit(0, true)); + EXPECT_NE(it, lits.end()); + it = std::find(lits.begin(), lits.end(), Lit(1, false)); + EXPECT_NE(it, lits.end()); + + EXPECT_EQ(lits.size(), 2); +} + +TEST(propagate, prop_1_alter) +{ + SATSolver s; + s.new_vars(10); + s.add_clause(str_to_cl("-1")); + s.add_clause(str_to_cl("1, 2")); + + vector lits = s.get_zero_assigned_lits(); + vector::iterator it; + it = std::find(lits.begin(), lits.end(), Lit(0, true)); + EXPECT_NE(it, lits.end()); + it = std::find(lits.begin(), lits.end(), Lit(1, false)); + EXPECT_NE(it, lits.end()); + EXPECT_EQ(lits.size(), 2); +} + +TEST(propagate, prop_many) +{ + SATSolver s; + s.new_vars(30); + for(unsigned i = 0; i < 10; i++) { + s.add_clause(vector{Lit(i*2, true), Lit(i*2+1, true)}); + s.add_clause(vector{Lit(i*2, false)}); + } + + vector lits = s.get_zero_assigned_lits(); + for(unsigned i = 0; i < 10; i++) { + vector::iterator it; + it = std::find(lits.begin(), lits.end(), Lit(i*2, false)); + EXPECT_NE(it, lits.end()); + it = std::find(lits.begin(), lits.end(), Lit(i*2+1, true)); + EXPECT_NE(it, lits.end()); + } + + EXPECT_EQ(lits.size(), 10*2); +} + +TEST(propagate, prop_complex) +{ + SATSolver s; + s.new_vars(30); + + s.add_clause(str_to_cl("-1")); + s.add_clause(str_to_cl("1, 2")); + + s.add_clause(str_to_cl("-5, 6")); + s.add_clause(str_to_cl("5")); + + s.add_clause(str_to_cl("1, -2, -5, -6, 7")); + + vector lits = s.get_zero_assigned_lits(); + vector::iterator it; + it = std::find(lits.begin(), lits.end(), Lit(6, true)); + EXPECT_EQ(lits.size(), 5); +} + +TEST(get_small_clauses, mixed) +{ + SATSolver s; + s.new_vars(30); + s.set_no_bve(); + s.set_no_bva(); + + s.add_clause(str_to_cl("1, 2")); + s.add_clause(str_to_cl("-5, 6")); + s.add_clause(str_to_cl("10")); + s.add_clause(str_to_cl("1, -2, -5, -6, 7")); + + s.start_getting_small_clauses(10000000, 10000000, false); + + vector lits; + bool ret; + + ret = s.get_next_small_clause(lits); + ASSERT_TRUE(ret); + std::sort(lits.begin(), lits.end()); + ASSERT_EQ(str_to_cl("10"), lits); + + ret = s.get_next_small_clause(lits); + ASSERT_TRUE(ret); + std::sort(lits.begin(), lits.end()); + ASSERT_EQ(str_to_cl(" 1, 2"), lits); + + ret = s.get_next_small_clause(lits); + ASSERT_TRUE(ret); + std::sort(lits.begin(), lits.end()); + ASSERT_EQ(str_to_cl(" -5, 6"), lits); + + ret = s.get_next_small_clause(lits); + ASSERT_TRUE(ret); + std::sort(lits.begin(), lits.end()); + ASSERT_EQ(str_to_cl("1, -2, -5, -6, 7"), lits); + + ret = s.get_next_small_clause(lits); + ASSERT_FALSE(ret); + + s.end_getting_small_clauses(); +} + +TEST(get_small_clauses, scc) +{ + SATSolver s; + s.new_vars(30); + s.set_no_bve(); + s.set_no_bva(); + + s.add_clause(str_to_cl("5, -6")); + s.add_clause(str_to_cl("-5, 6")); + s.simplify(); + auto x = s.get_all_binary_xors(); + ASSERT_EQ(1, x.size()); + + s.start_getting_small_clauses(10000000, 10000000, false); + + vector lits; + bool ret = s.get_next_small_clause(lits); + ASSERT_TRUE(ret); + std::sort(lits.begin(), lits.end()); + ASSERT_EQ(str_to_cl(" 5, -6"), lits); + + ret = s.get_next_small_clause(lits); + ASSERT_TRUE(ret); + std::sort(lits.begin(), lits.end()); + ASSERT_EQ(str_to_cl(" -5, 6"), lits); + + ret = s.get_next_small_clause(lits); + ASSERT_FALSE(ret); + + s.end_getting_small_clauses(); +} + +TEST(get_small_clauses, units) +{ + SATSolver s; + s.new_vars(30); + s.add_clause(str_to_cl("5")); + s.add_clause(str_to_cl("-6")); + s.simplify(); + + s.start_getting_small_clauses(10000000, 10000000, false); + + vector lits; + bool ret = s.get_next_small_clause(lits); + ASSERT_TRUE(ret); + std::sort(lits.begin(), lits.end()); + ASSERT_EQ(str_to_cl(" 5"), lits); + + ret = s.get_next_small_clause(lits); + ASSERT_TRUE(ret); + std::sort(lits.begin(), lits.end()); + ASSERT_EQ(str_to_cl("-6"), lits); + + ret = s.get_next_small_clause(lits); + ASSERT_FALSE(ret); + + s.end_getting_small_clauses(); +} + +TEST(get_small_clauses, unsat) +{ + SATSolver s; + s.new_vars(30); + s.add_clause(str_to_cl("5")); + s.add_clause(str_to_cl("-5")); + s.simplify(); + + s.start_getting_small_clauses(10000000, 10000000, false); + + vector lits; + bool ret = s.get_next_small_clause(lits); + ASSERT_TRUE(ret); + ASSERT_EQ(str_to_cl(""), lits); + + ret = s.get_next_small_clause(lits); + ASSERT_FALSE(ret); + + s.end_getting_small_clauses(); +} + +TEST(get_small_clauses, unsat_all) +{ + SATSolver s; + s.new_vars(30); + s.add_clause(str_to_cl("5")); + s.add_clause(str_to_cl("-5")); + s.simplify(); + + vector lits; + s.get_all_irred_clauses(lits); + ASSERT_EQ(str_to_cl("U"), lits); +} + +TEST(get_small_clauses, undef) +{ + SATSolver s; + s.new_vars(30); + s.add_clause(str_to_cl("5, -5")); + s.simplify(); + + vector lits; + s.get_all_irred_clauses(lits); + ASSERT_EQ(str_to_cl("5, -5, U"), lits); +} + +TEST(get_small_clauses, bve) +{ + SATSolver s; + s.new_vars(30); + s.add_clause(str_to_cl("5, 6")); + s.add_clause(str_to_cl("7, 8")); + s.simplify(); + + s.start_getting_small_clauses(10000000, 10000000, false); + + vector lits; + bool ret = s.get_next_small_clause(lits); + ASSERT_TRUE(ret); + std::sort(lits.begin(), lits.end()); + ASSERT_EQ(str_to_cl(" 5, 6"), lits); + + ret = s.get_next_small_clause(lits); + ASSERT_TRUE(ret); + std::sort(lits.begin(), lits.end()); + ASSERT_EQ(str_to_cl("7, 8"), lits); + + ret = s.get_next_small_clause(lits); + ASSERT_FALSE(ret); + + s.end_getting_small_clauses(); +} + +TEST(get_small_clauses, full) +{ + SATSolver s; + s.new_vars(30); + s.add_clause(str_to_cl("5, 6")); + s.add_clause(str_to_cl("7, 8")); + s.simplify(); + + vector lits; + s.get_all_irred_clauses(lits); + ASSERT_EQ(6, lits.size()); +} + +TEST(get_small_clauses, full_bins) +{ + SATSolver s; + s.new_vars(30); + s.add_clause(str_to_cl("5, 6")); + s.add_clause(str_to_cl("7, 8")); + s.simplify(); + + vector lits; + s.get_all_irred_clauses(lits); + + vector cl; + uint32_t found = 0; + for(const auto& l: lits) { + if (l != lit_Undef) { + cl.push_back(l); + } else { + std::sort(cl.begin(), cl.end()); + if (std::find(cl.begin(), cl.end(), Lit(5, false)) != cl.end()) { + ASSERT_EQ(str_to_cl("5, 6", false), cl); + } else { + ASSERT_EQ(str_to_cl("7, 8", false), cl); + } + cl.clear(); + found++; + } + } + ASSERT_EQ(2, found); +} + +TEST(get_small_clauses, full_units) +{ + SATSolver s; + s.new_vars(30); + s.add_clause(str_to_cl("5")); + s.add_clause(str_to_cl("7")); + s.simplify(); + + vector lits; + s.get_all_irred_clauses(lits); + ASSERT_EQ(str_to_cl("5, U, 7, U", false), lits); +} + +TEST(get_small_clauses, unit) +{ + SATSolver s; + s.new_vars(30); + s.set_no_bve(); + s.set_no_bva(); + + s.add_clause(str_to_cl("5")); + s.add_clause(str_to_cl("6")); + s.simplify(); + auto x = s.get_zero_assigned_lits(); + ASSERT_EQ(2, x.size()); + + s.start_getting_small_clauses(10000000, 10000000, false); + + vector lits; + bool ret = s.get_next_small_clause(lits); + ASSERT_TRUE(ret); + std::sort(lits.begin(), lits.end()); + ASSERT_EQ(str_to_cl(" 5"), lits); + + ret = s.get_next_small_clause(lits); + ASSERT_TRUE(ret); + std::sort(lits.begin(), lits.end()); + ASSERT_EQ(str_to_cl(" 6"), lits); + + ret = s.get_next_small_clause(lits); + ASSERT_FALSE(ret); + + s.end_getting_small_clauses(); +} + +TEST(sampling, indep1) +{ + SolverConf conf; + conf.simplify_at_startup = true; + SATSolver s(&conf); + + s.new_vars(30); + s.add_clause(str_to_cl("1, 2, 3, 4")); + s.add_clause(str_to_cl("-5, 6")); + + vector x{4U}; + s.set_sampling_vars(&x); + + lbool ret = s.solve(NULL, true); + EXPECT_EQ(ret, l_True); + EXPECT_EQ(s.get_model()[0], l_Undef); + EXPECT_EQ(s.get_model()[1], l_Undef); + EXPECT_NE(s.get_model()[4], l_Undef); + + ret = s.solve(); + EXPECT_EQ(ret, l_True); + EXPECT_NE(s.get_model()[0], l_Undef); + EXPECT_NE(s.get_model()[1], l_Undef); + EXPECT_NE(s.get_model()[4], l_Undef); +} + +TEST(sampling, indep2) +{ + SolverConf conf; + conf.simplify_at_startup = true; + SATSolver s(&conf); + + s.new_vars(30); + s.add_clause(str_to_cl("1, 2, 3, 4")); + s.add_clause(str_to_cl("-5, 6")); + + vector x = str_to_vars("1, 2, 3, 4, 5, 6"); + s.set_sampling_vars(&x); + + lbool ret = s.solve(NULL, true); + EXPECT_EQ(ret, l_True); + for(uint32_t i = 0; i < 6; i++) { + EXPECT_NE(s.get_model()[i], l_Undef); + } + EXPECT_EQ(s.get_model()[6], l_Undef); +} + + + +TEST(xor_recovery, find_1_3_xor) +{ + SATSolver s; + s.new_vars(30); + s.set_no_bve(); + + s.add_xor_clause(str_to_vars("1, 2, 3"), false); + s.simplify(); + + vector, bool> > xors = s.get_recovered_xors(false); + EXPECT_EQ(xors.size(), 1); +} + +TEST(xor_recovery, find_1_3_xor2) +{ + SATSolver s; + s.new_vars(30); + s.set_no_bve(); + + s.add_xor_clause(str_to_vars("1, 2, 3"), true); + s.simplify(); + + vector, bool> > xors = s.get_recovered_xors(false); + EXPECT_EQ(xors.size(), 1); +} + +TEST(xor_recovery, find_2_3_xor_2) +{ + SATSolver s; + s.new_vars(30); + s.set_no_bve(); + + s.add_clause(str_to_cl("1,2,3,4,5")); + s.add_xor_clause(str_to_vars("1, 2, 3"), false); + s.add_xor_clause(str_to_vars("4, 5, 6"), false); + s.simplify(); + + vector, bool> > xors = s.get_recovered_xors(true); + EXPECT_EQ(xors.size(), 2); + if (xors.size() == 2) { + EXPECT_EQ(xors[0].first, str_to_vars("1, 2, 3")); + EXPECT_EQ(xors[1].first, str_to_vars("4, 5, 6")); + EXPECT_EQ(xors[0].second, false); + EXPECT_EQ(xors[1].second, false); + } +} + +TEST(xor_recovery, find_1_3_xor_exact) +{ + SATSolver s; + s.new_vars(30); + s.set_no_bve(); + + s.add_xor_clause(str_to_vars("1, 2, 3"), false); + s.simplify(); + + vector, bool> > xors = s.get_recovered_xors(false); + EXPECT_EQ(xors.size(), 1); + EXPECT_EQ(xors[0].first, str_to_vars("1, 2, 3")); + EXPECT_EQ(xors[0].second, false); +} + +TEST(xor_recovery, find_1_3_xor_exact2) +{ + SATSolver s; + s.new_vars(30); + s.set_no_bve(); + + s.add_xor_clause(str_to_vars("1, 2, 3"), true); + s.simplify(); + + vector, bool> > xors = s.get_recovered_xors(false); + EXPECT_EQ(xors.size(), 1); + EXPECT_EQ(xors[0].first, str_to_vars("1, 2, 3")); + EXPECT_EQ(xors[0].second, true); +} + +TEST(xor_recovery, find_1_4_xor_exact) +{ + SATSolver s; + s.new_vars(30); + s.set_no_bve(); + + s.add_xor_clause(str_to_vars("1, 2, 3, 4"), false); + s.simplify(); + + vector, bool> > xors = s.get_recovered_xors(false); + EXPECT_EQ(xors.size(), 1); + EXPECT_EQ(xors[0].first, str_to_vars("1, 2, 3, 4")); +} + +TEST(xor_recovery, find_xor_one_only) +{ + SATSolver s; + s.new_vars(30); + s.set_no_bve(); + + s.add_xor_clause(str_to_vars("1, 2, 3, 4, 6"), false); + s.simplify(); + + vector, bool> > xors = s.get_recovered_xors(true); + EXPECT_EQ(xors.size(), 1); + std::sort(xors[0].first.begin(), xors[0].first.end()); + EXPECT_EQ(xors[0].first, str_to_vars("1, 2, 3, 4, 6")); + EXPECT_EQ(xors[0].second, false); +} + +TEST(xor_recovery, find_xor_one_only_inv) +{ + SATSolver s; + s.new_vars(30); + s.set_no_bve(); + + s.add_xor_clause(str_to_vars("1, 2, 3, 4, 6"), true); + s.simplify(); + + vector, bool> > xors = s.get_recovered_xors(true); + EXPECT_EQ(xors.size(), 1); + std::sort(xors[0].first.begin(), xors[0].first.end()); + EXPECT_EQ(xors[0].first, str_to_vars("1, 2, 3, 4, 6")); + EXPECT_EQ(xors[0].second, true); +} + +TEST(xor_recovery, find_xor_one_only_inv_external) +{ + SATSolver s; + s.new_vars(30); + s.set_no_bve(); + + s.add_xor_clause(str_to_vars("1, 2, 3, 4, 6"), true); + s.simplify(); + + vector, bool> > xors = s.get_recovered_xors(false); + + //it's zero because it's cut into 2 XORs and they both have a variable + //that is NOT part of the solver's original variables. + EXPECT_EQ(xors.size(), 0); +} + +TEST(xor_recovery, find_xor_one_that_is_xor_of_2) +{ + SATSolver s; + s.new_vars(30); + s.set_no_bve(); + + s.add_xor_clause(str_to_vars("1, 3, 4, 5"), true); + s.add_xor_clause(str_to_vars("1, 7, 8, 9"), true); + s.simplify(); + + vector, bool> > xors = s.get_recovered_xors(true); + EXPECT_EQ(xors.size(), 1); + std::sort(xors[0].first.begin(), xors[0].first.end()); + EXPECT_EQ(xors[0].first, str_to_vars("3, 4, 5, 7, 8, 9")); + EXPECT_EQ(xors[0].second, false); +} + +//TODO the renubmering make 31 out of 3 and then it's not "outside" anymore... +TEST(xor_recovery, DISABLED_find_xor_renumber) +{ + SATSolver s; + s.new_vars(30); + s.set_no_bve(); + s.set_verbosity(5); + + s.add_xor_clause(str_to_vars("1, 2"), false); + s.add_xor_clause(str_to_vars("1, 2, 3, 4, 5, 6, 7,8, 9, 10"), true); + s.simplify(); + s.simplify(); + + vector, bool> > xors = s.get_recovered_xors(true); + EXPECT_EQ(xors.size(), 1); + EXPECT_EQ(xors[0].first, str_to_vars("2, 3, 4, 5, 6, 7,8, 9, 10")); +} + + +int main(int argc, char **argv) { + ::testing::InitGoogleTest(&argc, argv); + return RUN_ALL_TESTS(); +} diff --git a/cryptominisat/cppsrc/tests/c_test.c b/cryptominisat/cppsrc/tests/c_test.c new file mode 100644 index 00000000..75b42f83 --- /dev/null +++ b/cryptominisat/cppsrc/tests/c_test.c @@ -0,0 +1,62 @@ +/****************************************** +Copyright (c) 2016, @Storyyeller + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. +***********************************************/ + + +#include "cryptominisat5/cryptominisat_c.h" +#include "assert.h" + +c_Lit new_lit(uint32_t var, bool neg) { + c_Lit x; + x.x = (var << 1) | neg; + return x; +} + +int main(void) { + int new; // make sure this is actually compiled as C + + SATSolver *solver = cmsat_new(); + cmsat_set_num_threads(solver, 4); + cmsat_new_vars(solver, 3); + + c_Lit clause[4]; + clause[0] = new_lit(0, false); + cmsat_add_clause(solver, clause, 1); + + clause[0] = new_lit(1, true); + cmsat_add_clause(solver, clause, 1); + + clause[0] = new_lit(0, true); + clause[1] = new_lit(1, false); + clause[2] = new_lit(2, false); + cmsat_add_clause(solver, clause, 3); + + c_lbool ret = cmsat_solve(solver); + assert(ret.x == L_TRUE); + + slice_lbool model = cmsat_get_model(solver); + assert(model.vals[0].x == L_TRUE); + assert(model.vals[1].x == L_FALSE); + assert(model.vals[2].x == L_TRUE); + + cmsat_free(solver); + return 0; +} diff --git a/cryptominisat/cppsrc/tests/cardfinder_test.cpp b/cryptominisat/cppsrc/tests/cardfinder_test.cpp new file mode 100644 index 00000000..0b4e4730 --- /dev/null +++ b/cryptominisat/cppsrc/tests/cardfinder_test.cpp @@ -0,0 +1,199 @@ +/****************************************** +Copyright (C) 2009-2020 Authors of CryptoMiniSat, see AUTHORS file + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. +***********************************************/ + +#include "gtest/gtest.h" + +#include + +#include "src/solver.h" +#include "src/cardfinder.h" +#include "src/solverconf.h" +using namespace CMSat; +#include "test_helper.h" + +struct card_finder : public ::testing::Test { + card_finder() + { + must_inter.store(false, std::memory_order_relaxed); + SolverConf conf; + //conf.verbosity = 1; + s = new Solver(&conf, &must_inter); + s->new_vars(50); + finder = new CardFinder(s); + } + ~card_finder() + { + delete finder; + delete s; + } + Solver* s = NULL; + CardFinder* finder = NULL; + std::atomic must_inter; +}; + +TEST_F(card_finder, find_none) +{ + s->add_clause_outside(str_to_cl("-1, -2")); + s->add_clause_outside(str_to_cl("-3, -4")); + + finder->find_cards(); + EXPECT_EQ(finder->get_cards().size(), 0U); +} + +TEST_F(card_finder, find_one) +{ + s->add_clause_outside(str_to_cl("-1, -2")); + s->add_clause_outside(str_to_cl("-1, -3")); + s->add_clause_outside(str_to_cl("-2, -3")); + + finder->find_cards(); + EXPECT_EQ(finder->get_cards().size(), 1U); +} + +TEST_F(card_finder, find_one_4) +{ + s->add_clause_outside(str_to_cl("-1, -2")); + s->add_clause_outside(str_to_cl("-1, -3")); + s->add_clause_outside(str_to_cl("-1, -4")); + s->add_clause_outside(str_to_cl("-2, -3")); + s->add_clause_outside(str_to_cl("-2, -4")); + s->add_clause_outside(str_to_cl("-3, -4")); + + finder->find_cards(); + ASSERT_EQ(finder->get_cards().size(), 1U); + vector lits = finder->get_cards()[0]; + std::sort(lits.begin(), lits.end()); + EXPECT_EQ(lits, str_to_cl("1,2,3,4")); +} + +TEST_F(card_finder, find_two) +{ + s->add_clause_outside(str_to_cl("-1, -2")); + s->add_clause_outside(str_to_cl("-1, -3")); + s->add_clause_outside(str_to_cl("-1, -4")); + s->add_clause_outside(str_to_cl("-2, -3")); + s->add_clause_outside(str_to_cl("-2, -4")); + s->add_clause_outside(str_to_cl("-3, -4")); + + s->add_clause_outside(str_to_cl("-11, -21")); + s->add_clause_outside(str_to_cl("-11, -31")); + s->add_clause_outside(str_to_cl("-11, -41")); + s->add_clause_outside(str_to_cl("-21, -31")); + s->add_clause_outside(str_to_cl("-21, -41")); + s->add_clause_outside(str_to_cl("-31, -41")); + + finder->find_cards(); + ASSERT_EQ(finder->get_cards().size(), 2U); +} + + +TEST_F(card_finder, find_large) +{ + s->add_clause_outside(str_to_cl("-1, -2")); + s->add_clause_outside(str_to_cl("-1, -3")); + s->add_clause_outside(str_to_cl("-1, -4")); + s->add_clause_outside(str_to_cl("-2, -3")); + s->add_clause_outside(str_to_cl("-2, -4")); + s->add_clause_outside(str_to_cl("-3, -4")); + + s->add_clause_outside(str_to_cl("4, -5")); + s->add_clause_outside(str_to_cl("4, -6")); + s->add_clause_outside(str_to_cl("4, -7")); + s->add_clause_outside(str_to_cl("-5, -6")); + s->add_clause_outside(str_to_cl("-5, -7")); + s->add_clause_outside(str_to_cl("-6, -7")); + + s->add_clause_outside(str_to_cl("-11, -12")); + s->add_clause_outside(str_to_cl("-11, -13")); + s->add_clause_outside(str_to_cl("-11, -14")); + s->add_clause_outside(str_to_cl("-12, -13")); + s->add_clause_outside(str_to_cl("-12, -14")); + s->add_clause_outside(str_to_cl("-13, -14")); + + s->add_clause_outside(str_to_cl("14, -15")); + s->add_clause_outside(str_to_cl("14, -16")); + s->add_clause_outside(str_to_cl("14, -17")); + s->add_clause_outside(str_to_cl("-15, -16")); + s->add_clause_outside(str_to_cl("-15, -17")); + s->add_clause_outside(str_to_cl("-16, -17")); + + s->add_clause_outside(str_to_cl("1, 11")); + s->add_clause_outside(str_to_cl("1, -20")); + s->add_clause_outside(str_to_cl("11, -20")); + + finder->find_cards(); + ASSERT_EQ(finder->get_cards().size(), 1U); +} + +TEST_F(card_finder, find_two_product) +{ + //c x1..x9 + //c rows: x 20..x22 + //c cols: x 30..x32 + //c -------------- + s->add_clause_outside(str_to_cl("-1, 20")); + s->add_clause_outside(str_to_cl("-1, 30")); + s->add_clause_outside(str_to_cl("-2, 21")); + s->add_clause_outside(str_to_cl("-2, 30")); + s->add_clause_outside(str_to_cl("-3, 22")); + s->add_clause_outside(str_to_cl("-3, 30")); + s->add_clause_outside(str_to_cl("-4, 20")); + s->add_clause_outside(str_to_cl("-4, 31")); + s->add_clause_outside(str_to_cl("-5, 21")); + s->add_clause_outside(str_to_cl("-5, 31")); + s->add_clause_outside(str_to_cl("-6, 22")); + s->add_clause_outside(str_to_cl("-6, 31")); + s->add_clause_outside(str_to_cl("-7, 20")); + s->add_clause_outside(str_to_cl("-7, 32")); + s->add_clause_outside(str_to_cl("-8, 21")); + s->add_clause_outside(str_to_cl("-8, 32")); + s->add_clause_outside(str_to_cl("-9, 22")); + s->add_clause_outside(str_to_cl("-9, 32")); + + //c ------ rows + s->add_clause_outside(str_to_cl("-20, -21")); + s->add_clause_outside(str_to_cl("-20, -22")); + s->add_clause_outside(str_to_cl("-21, -22")); + + //c ------ cols + s->add_clause_outside(str_to_cl("-30, -31")); + s->add_clause_outside(str_to_cl("-30, -32")); + s->add_clause_outside(str_to_cl("-31, -32")); + + finder->find_cards(); + ASSERT_EQ(finder->get_cards().size(), 3U); + + vector lits; + lits = finder->get_cards()[0]; + EXPECT_EQ(lits, str_to_cl("20, 21, 22")); + + lits = finder->get_cards()[1]; + EXPECT_EQ(lits, str_to_cl("30, 31, 32")); + + lits = finder->get_cards()[2]; + EXPECT_EQ(lits, str_to_cl("1, 2, 3, 4, 5, 6, 7, 8, 9")); +} + +int main(int argc, char **argv) { + ::testing::InitGoogleTest(&argc, argv); + return RUN_ALL_TESTS(); +} diff --git a/cryptominisat/cppsrc/tests/clause_alloc_test.cpp b/cryptominisat/cppsrc/tests/clause_alloc_test.cpp new file mode 100644 index 00000000..09dc75e4 --- /dev/null +++ b/cryptominisat/cppsrc/tests/clause_alloc_test.cpp @@ -0,0 +1,81 @@ +/****************************************** +Copyright (C) 2009-2020 Authors of CryptoMiniSat, see AUTHORS file + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. +***********************************************/ + +#include "gtest/gtest.h" + +#include +#include + +#include "src/solver.h" +#include "src/clauseallocator.h" +#include "src/solverconf.h" +using namespace CMSat; +#include "test_helper.h" + +struct clause_allocator : public ::testing::Test { + clause_allocator() + { + must_inter.store(false, std::memory_order_relaxed); + SolverConf conf; + conf.verbosity = 1; + s = new Solver(&conf, &must_inter); + s->new_vars(50000); + } + ~clause_allocator() + { + delete s; + } + Solver* s = NULL; + std::atomic must_inter; +}; + +TEST_F(clause_allocator, add_1) +{ + vector cl; + srand(0); + double t = cpuTime(); + + uint64_t num = 10ULL*1000ULL*1000ULL; + for(size_t i = 0; i < num; i++) { + int size = 100 + rand()%10; + int start = rand() % 50000/size; + cl.resize(size); + for(int i2 = 0; i2 < size; i2++) { + int sign = rand() % 2; + cl[i2] = Lit(start, sign); + start += rand() % (50000/size); + } + s->add_clause_outside(cl); + if (i % (300ULL*1000ULL) == 0) { + cout << "Added " << i/(3000LL*1000ULL) << "M" << " T:" << (cpuTime()-t) << endl; + s->cl_alloc.consolidate(s, true); + } + } + s->cl_alloc.consolidate(s, true); + lbool ret = s->solve_with_assumptions(NULL); + EXPECT_EQ(ret, l_True); +} + +int main(int argc, char **argv) { + ::testing::InitGoogleTest(&argc, argv); + return RUN_ALL_TESTS(); +} diff --git a/cryptominisat/cppsrc/tests/clause_cleaner_test.cpp b/cryptominisat/cppsrc/tests/clause_cleaner_test.cpp new file mode 100644 index 00000000..87478cef --- /dev/null +++ b/cryptominisat/cppsrc/tests/clause_cleaner_test.cpp @@ -0,0 +1,138 @@ +/****************************************** +Copyright (C) 2009-2020 Authors of CryptoMiniSat, see AUTHORS file + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. +***********************************************/ + +#include "gtest/gtest.h" + +#include + +#include "src/solver.h" +#include "src/clausecleaner.h" +#include "src/solverconf.h" +using namespace CMSat; +#include "test_helper.h" + +struct clause_clean_test : public ::testing::Test { + clause_clean_test() + { + must_inter.store(false, std::memory_order_relaxed); + SolverConf conf; + s = new Solver(&conf, &must_inter); + s->new_vars(20); + cc = s->clauseCleaner; + } + ~clause_clean_test() + { + delete s; + } + Solver* s = NULL; + ClauseCleaner* cc = NULL; + std::atomic must_inter; +}; + +TEST_F(clause_clean_test, no_clean) +{ + s->add_clause_outside(str_to_cl("1, 2, 3")); + s->add_clause_outside(str_to_cl("1, 2")); + + cc->remove_and_clean_all(); + EXPECT_EQ(s->binTri.irredBins, 1U); + std::string exp = "1, 2; 1, 2, 3"; + check_irred_cls_eq(s, exp); +} + +TEST_F(clause_clean_test, clean_bin_pos) +{ + s->add_clause_outside(str_to_cl("1, 2")); + s->add_clause_outside(str_to_cl("1")); + check_irred_cls_eq(s, "1, 2"); + + cc->remove_and_clean_all(); + EXPECT_EQ(s->binTri.irredBins, 0U); +} + +TEST_F(clause_clean_test, clean_bin_neg) +{ + s->add_clause_outside(str_to_cl("1, 2")); + s->add_clause_outside(str_to_cl("-1")); + check_irred_cls_eq(s, "1, 2"); + + cc->remove_and_clean_all(); + check_irred_cls_eq(s, ""); +} + +TEST_F(clause_clean_test, clean_tri_pos) +{ + s->add_clause_outside(str_to_cl("1, 2, 3")); + s->add_clause_outside(str_to_cl("1")); + check_irred_cls_eq(s, "1, 2, 3"); + + cc->remove_and_clean_all(); + check_irred_cls_eq(s, ""); +} + +TEST_F(clause_clean_test, clean_tri_neg) +{ + s->add_clause_outside(str_to_cl("1, 2, 3")); + s->add_clause_outside(str_to_cl("-1")); + check_irred_cls_eq(s, "1, 2, 3"); + + cc->remove_and_clean_all(); + EXPECT_EQ(s->binTri.irredBins, 1U); + check_irred_cls_eq(s, "2, 3"); +} + +TEST_F(clause_clean_test, clean_long_pos) +{ + s->add_clause_outside(str_to_cl("1, 2, 3, 4")); + s->add_clause_outside(str_to_cl("1")); + check_irred_cls_eq(s, "1, 2, 3, 4"); + + cc->remove_and_clean_all(); + check_irred_cls_eq(s, ""); +} + +TEST_F(clause_clean_test, clean_long_neg) +{ + s->add_clause_outside(str_to_cl("1, 2, 3, 4")); + s->add_clause_outside(str_to_cl("-1")); + check_irred_cls_eq(s, "1, 2, 3, 4"); + + cc->remove_and_clean_all(); + check_irred_cls_eq(s, "2, 3, 4"); +} + +TEST_F(clause_clean_test, clean_mix) +{ + s->add_clause_outside(str_to_cl("1, 2, 3, 4")); + s->add_clause_outside(str_to_cl("1, 2, 3")); + s->add_clause_outside(str_to_cl("1, 9")); + s->add_clause_outside(str_to_cl("-1")); + check_irred_cls_eq(s, "1, 2, 3, 4; 1, 2, 3; 1, 9"); + + cc->remove_and_clean_all(); + check_irred_cls_eq(s, "2, 3, 4; 2, 3"); +} + +int main(int argc, char **argv) { + ::testing::InitGoogleTest(&argc, argv); + return RUN_ALL_TESTS(); +} diff --git a/cryptominisat/cppsrc/tests/clause_test.cpp b/cryptominisat/cppsrc/tests/clause_test.cpp new file mode 100644 index 00000000..4110aad5 --- /dev/null +++ b/cryptominisat/cppsrc/tests/clause_test.cpp @@ -0,0 +1,81 @@ +/****************************************** +Copyright (C) 2009-2020 Authors of CryptoMiniSat, see AUTHORS file + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. +***********************************************/ + +#include "gtest/gtest.h" + +#include "src/clause.h" +#include +#include + +using namespace CMSat; + +struct F : public ::testing::Test { + F() { + } + + ~F() { + } + + Clause* allocate_space_for(size_t n, void*& tmp) + { + tmp = malloc(sizeof(Clause) + n*sizeof(Lit)); + std::vector lits; + for(size_t i = 0; i < n ; i++) { + lits.push_back(Lit(i, false)); + } + Clause* c_ptr = new(tmp) Clause(lits, 0, 1); + return c_ptr; + } +}; + +TEST_F(F, convert_to_string) +{ + void* tmp; + Clause& cl = *allocate_space_for(3, tmp); + cl[0] = Lit(0, false); + cl[1] = Lit(1, false); + cl[2] = Lit(2, false); + + std::stringstream ss; + ss << cl; + EXPECT_EQ( ss.str(), "1 2 3"); + free(tmp); +} + +TEST_F(F, convert_to_string2) +{ + void* tmp; + Clause& cl = *allocate_space_for(3, tmp); + cl[0] = Lit(0, false); + cl[1] = Lit(1, true); + cl[2] = Lit(2, false); + + std::stringstream ss; + ss << cl; + EXPECT_EQ( ss.str(), "1 -2 3"); + free(tmp); +} + +int main(int argc, char **argv) { + ::testing::InitGoogleTest(&argc, argv); + return RUN_ALL_TESTS(); +} diff --git a/cryptominisat/cppsrc/tests/cnf-files/CMakeLists.txt b/cryptominisat/cppsrc/tests/cnf-files/CMakeLists.txt new file mode 100644 index 00000000..e9dc224a --- /dev/null +++ b/cryptominisat/cppsrc/tests/cnf-files/CMakeLists.txt @@ -0,0 +1,47 @@ +# Copyright (C) 2009-2020 Authors of CryptoMiniSat, see AUTHORS file +# +# Permission is hereby granted, free of charge, to any person obtaining a copy +# of this software and associated documentation files (the "Software"), to deal +# in the Software without restriction, including without limitation the rights +# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +# copies of the Software, and to permit persons to whom the Software is +# furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in +# all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +# THE SOFTWARE. + +# Create llvm-lit configuration file +configure_file(lit.site.cfg.in lit.site.cfg.in2 @ONLY) + +if (MSVC) + file(GENERATE + OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/$/lit.site.cfg + INPUT ${CMAKE_CURRENT_BINARY_DIR}/lit.site.cfg.in2) + + + # Make sure this test-suite runs when "test" is target + add_test(NAME CNF + COMMAND "${Python3_EXECUTABLE}" "-m" "lit.main" ${LIT_ARGS} . + WORKING_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/$/" + ) +else() + file(GENERATE + OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/lit.site.cfg + INPUT ${CMAKE_CURRENT_BINARY_DIR}/lit.site.cfg.in2) + + + # Make sure this test-suite runs when "test" is target + add_test(NAME CNF + COMMAND "${Python3_EXECUTABLE}" "-m" "lit.main" ${LIT_ARGS} . + WORKING_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}" + ) +endif() + diff --git a/cryptominisat/cppsrc/tests/cnf-files/indep-1.cnf b/cryptominisat/cppsrc/tests/cnf-files/indep-1.cnf new file mode 100644 index 00000000..cf611a15 --- /dev/null +++ b/cryptominisat/cppsrc/tests/cnf-files/indep-1.cnf @@ -0,0 +1,4 @@ +c RUN: %solver --onlysampling --sampling 1 --presimp 1 --varelim 1 --verb=0 %s | %OutputCheck %s +1 2 3 0 +4 5 6 0 +c CHECK: ^v .*1 diff --git a/cryptominisat/cppsrc/tests/cnf-files/indep-2.cnf b/cryptominisat/cppsrc/tests/cnf-files/indep-2.cnf new file mode 100644 index 00000000..adeee642 --- /dev/null +++ b/cryptominisat/cppsrc/tests/cnf-files/indep-2.cnf @@ -0,0 +1,6 @@ +c RUN: %solver --verb=0 %s | %OutputCheck %s +c ind 1 0 +1 2 3 0 +2 0 +c CHECK: Sampling .*1 +c CHECK: ^s SATISFIABLE$ diff --git a/cryptominisat/cppsrc/tests/cnf-files/indep-3.cnf b/cryptominisat/cppsrc/tests/cnf-files/indep-3.cnf new file mode 100644 index 00000000..11477517 --- /dev/null +++ b/cryptominisat/cppsrc/tests/cnf-files/indep-3.cnf @@ -0,0 +1,4 @@ +c RUN: %solver --onlysampling --sampling 1 --presimp 1 --varelim 1 --verb=0 %s | %OutputCheck %s +1 2 3 0 +4 5 6 0 +c CHECK-NOT: ^v .*4 diff --git a/cryptominisat/cppsrc/tests/cnf-files/indep_vars.cnf b/cryptominisat/cppsrc/tests/cnf-files/indep_vars.cnf new file mode 100644 index 00000000..d4e0609f --- /dev/null +++ b/cryptominisat/cppsrc/tests/cnf-files/indep_vars.cnf @@ -0,0 +1,10 @@ +c RUN: %solver --maxsol 20 --verb=0 %s | %OutputCheck %s +c ind 1 0 +1 2 3 0 +-1 3 0 +-1 2 0 +2 3 0 +-2 -3 0 +c CHECK: ^s SATISFIABLE$ +c CHECK-NOT: ^s SATISFIABLE$ +c CHECK: UNSATISFIABLE diff --git a/cryptominisat/cppsrc/tests/cnf-files/indep_vars_2.cnf b/cryptominisat/cppsrc/tests/cnf-files/indep_vars_2.cnf new file mode 100644 index 00000000..715211ef --- /dev/null +++ b/cryptominisat/cppsrc/tests/cnf-files/indep_vars_2.cnf @@ -0,0 +1,11 @@ +c RUN: %solver --maxsol 20 --verb=0 %s | %OutputCheck %s +c ind 1 2 3 0 +1 2 3 0 +-1 3 0 +-1 2 0 +2 3 0 +-2 -3 0 +c CHECK: ^s SATISFIABLE$ +c CHECK: ^s SATISFIABLE$ +c CHECK-NOT: ^s SATISFIABLE$ +c CHECK: UNSATISFIABLE diff --git a/cryptominisat/cppsrc/tests/cnf-files/lit.cfg b/cryptominisat/cppsrc/tests/cnf-files/lit.cfg new file mode 100644 index 00000000..201001e4 --- /dev/null +++ b/cryptominisat/cppsrc/tests/cnf-files/lit.cfg @@ -0,0 +1,144 @@ +# -*- Python -*- + +# Configuration file for the 'lit' test runner. + +import os +import sys +import re +import platform + +import lit.util +import lit.formats + +# name: The name of this test suite. +config.name = 'cryptominisat cnf-files' + +# Choose between lit's internal shell pipeline runner and a real shell. If +# LIT_USE_INTERNAL_SHELL is in the environment, we use that as an override. +use_lit_shell = os.environ.get("LIT_USE_INTERNAL_SHELL") +if use_lit_shell: + # 0 is external, "" is default, and everything else is internal. + execute_external = (use_lit_shell == "0") +else: + # Otherwise we default to internal on Windows and external elsewhere, as + # bash on Windows is usually very slow. + execute_external = (not sys.platform in ['win32']) + +# testFormat: The test format to use to interpret tests. +config.test_format = lit.formats.ShTest(execute_external) + +# suffixes: A list of file extensions to treat as test files. This is overriden +# by individual lit.local.cfg files in the test subdirectories. +config.suffixes = ['.cnf'] + +# excludes: A list of directories to exclude from the testsuite. The 'Inputs' +# subdirectories contain auxiliary inputs for various tests in their parent +# directories. +config.excludes = [] + +# test_source_root: The root path where tests are located. +config.test_source_root = os.path.dirname(os.path.abspath(__file__)) + +# test_exec_root: The root path where tests should be run. +cryptominisat_obj_root = getattr(config, 'cryptominisat_obj_root', None) +if cryptominisat_obj_root is not None: + config.test_exec_root = os.path.join(cryptominisat_obj_root, 'tests', 'cnf-files') + +# Tweak the PATH to include the tools dir. +#if llvm_obj_root is not None: +# llvm_tools_dir = getattr(config, 'llvm_tools_dir', None) +# if not llvm_tools_dir: +# lit_config.fatal('No LLVM tools dir set!') +# path = os.path.pathsep.join((llvm_tools_dir, config.environment['PATH'])) +# config.environment['PATH'] = path + +# Propagate 'HOME' through the environment. +if 'HOME' in os.environ: + config.environment['HOME'] = os.environ['HOME'] + +# Propagate 'INCLUDE' through the environment. +if 'INCLUDE' in os.environ: + config.environment['INCLUDE'] = os.environ['INCLUDE'] + +# Propagate 'LIB' through the environment. +if 'LIB' in os.environ: + config.environment['LIB'] = os.environ['LIB'] + +# Propagate the temp directory. Windows requires this because it uses \Windows\ +# if none of these are present. +if 'TMP' in os.environ: + config.environment['TMP'] = os.environ['TMP'] +if 'TEMP' in os.environ: + config.environment['TEMP'] = os.environ['TEMP'] + +# Check Python executable +pythonExec = getattr(config, 'python_executable') +if sys.executable != os.path.realpath(pythonExec): + lit_config.warning('Python executable mis-match: {} != {}'.format(sys.executable, os.path.realpath(pythonExec))) + +# Propagate PYTHON_EXECUTABLE into the environment +config.environment['PYTHON_EXECUTABLE'] = pythonExec + +### + +import os + +# Check that the object root is known. +if config.test_exec_root is None: + lit_config.fatal('Could not determine execution root for tests!') + +### Add cryptominisat specific substitutions + +# Allow user to override the solver +solverExecutable = lit_config.params.get('solver', config.cryptominisat_executable) +if not lit.util.which(solverExecutable): + lit_config.fatal('Cannot find solver: {solver}\n'.format(solver=solverExecutable)) +else: + solverExecutable = lit.util.which( solverExecutable ) + +# Allow user to provide extra arguments to solver +solverParams = lit_config.params.get('solver_params','') +solverParams += ' --zero-exit-status ' + +if config.simple == "" : + if config.sqlite != "" : + solverParams += ' --sql 2 --sqlitedboverwrite 1' + elif config.mysql != "" : + #database may not be set up :( TODO: auto-setup database + solverParams += ' --sql 0' + +if len(solverParams) > 0: + solverExecutable = solverExecutable + ' ' + solverParams + +# Inform user what solver is being used +lit_config.note('Using solver: {solver}\n'.format(solver=solverExecutable)) + +config.substitutions.append( ('%solver', solverExecutable) ) + +# Find OutputCheck +OutputCheckTool = os.path.join( os.path.dirname( os.path.dirname( config.test_source_root ) ), + 'utils', + 'OutputCheck', + 'bin', + 'OutputCheck' + ) +if not os.path.exists(OutputCheckTool): + lit_config.fatal('Cannot find OutputCheck executable: {OutputCheck}'.format(OutputCheck=OutputCheckTool)) + +# Add OutputCheck bin directory to PATH (for not utility) +path = os.path.pathsep.join(( os.path.dirname(OutputCheckTool), config.environment['PATH'])) +config.environment['PATH'] = path + + +# Allow user to specify extra flags to OutputCheck (e.g. -l debug) +OutputCheckFlags = lit_config.params.get('outputcheck_params','') +OutputCheckFlags += " --comment='c'" +if len(OutputCheckFlags) > 0: + OutputCheckTool += ' ' + OutputCheckFlags +config.substitutions.append( ('%OutputCheck', pythonExec + ' ' +OutputCheckTool) ) + +### Features + +# Shell execution +if execute_external: + config.available_features.add('shell') diff --git a/cryptominisat/cppsrc/tests/cnf-files/lit.site.cfg.in b/cryptominisat/cppsrc/tests/cnf-files/lit.site.cfg.in new file mode 100644 index 00000000..33f23105 --- /dev/null +++ b/cryptominisat/cppsrc/tests/cnf-files/lit.site.cfg.in @@ -0,0 +1,14 @@ +import sys + +## Autogenerated by cryptominisat configuration. +# Do not edit! +config.cryptominisat_src_root = "@cryptominisat5_SOURCE_DIR@" +config.cryptominisat_obj_root = "@cryptominisat5_BINARY_DIR@" +config.python_executable = "@PYTHON_EXECUTABLE@" +config.cryptominisat_executable = "$" +config.sqlite = "@USING_SQLITE@" +config.mysql = "@USING_SQLITE@" +config.simple = "@SIMPLE@" + +# Let the main config do the real work. +lit_config.load_config(config, "@cryptominisat5_SOURCE_DIR@/tests/cnf-files/lit.cfg") diff --git a/cryptominisat/cppsrc/tests/cnf-files/reconftest.cnf b/cryptominisat/cppsrc/tests/cnf-files/reconftest.cnf new file mode 100644 index 00000000..bcd7507c --- /dev/null +++ b/cryptominisat/cppsrc/tests/cnf-files/reconftest.cnf @@ -0,0 +1,8 @@ +c RUN: %solver --reconfat 0 --reconf 15 %s | %OutputCheck %s +1 2 0 +-1 2 0 +3 4 0 +1 2 3 4 0 +1 2 3 -4 0 +4 -2 0 +c CHECK: reconfigured solver to config 15 diff --git a/cryptominisat/cppsrc/tests/cnf-files/simptest.cnf b/cryptominisat/cppsrc/tests/cnf-files/simptest.cnf new file mode 100644 index 00000000..6932e734 --- /dev/null +++ b/cryptominisat/cppsrc/tests/cnf-files/simptest.cnf @@ -0,0 +1,5 @@ +c RUN: %solver %s | %OutputCheck %s +p cnf 1 1 +1 0 +c CHECK: ^s SATISFIABLE$ +c CHECK-NEXT: ^v 1 0$ \ No newline at end of file diff --git a/cryptominisat/cppsrc/tests/cnf-files/simptest2.cnf b/cryptominisat/cppsrc/tests/cnf-files/simptest2.cnf new file mode 100644 index 00000000..46a33c21 --- /dev/null +++ b/cryptominisat/cppsrc/tests/cnf-files/simptest2.cnf @@ -0,0 +1,4 @@ +c RUN: %solver %s | %OutputCheck %s +1 0 +c CHECK: ^s SATISFIABLE$ +c CHECK-NEXT: ^v 1 0$ diff --git a/cryptominisat/cppsrc/tests/cnf-files/verbosity.cnf b/cryptominisat/cppsrc/tests/cnf-files/verbosity.cnf new file mode 100644 index 00000000..9ee5dc9e --- /dev/null +++ b/cryptominisat/cppsrc/tests/cnf-files/verbosity.cnf @@ -0,0 +1,4 @@ +c RUN: %solver --verb=0 %s | %OutputCheck %s +p cnf 1 1 +1 0 +c CHECK-NOT: ^c.*$ \ No newline at end of file diff --git a/cryptominisat/cppsrc/tests/cnf-files/xor.cnf b/cryptominisat/cppsrc/tests/cnf-files/xor.cnf new file mode 100644 index 00000000..cdd2f58f --- /dev/null +++ b/cryptominisat/cppsrc/tests/cnf-files/xor.cnf @@ -0,0 +1,5 @@ +c RUN: %solver %s | %OutputCheck %s +p cnf 1 1 +x1 0 +c CHECK: s SATISFIABLE +c CHECK: v 1 0 \ No newline at end of file diff --git a/cryptominisat/cppsrc/tests/cnf-files/xor_longer.cnf b/cryptominisat/cppsrc/tests/cnf-files/xor_longer.cnf new file mode 100644 index 00000000..47c4f5a0 --- /dev/null +++ b/cryptominisat/cppsrc/tests/cnf-files/xor_longer.cnf @@ -0,0 +1,14 @@ +c RUN: %solver %s | %OutputCheck %s +p cnf 10 10 +x1 2 3 4 5 6 7 8 9 10 0 +x-1 0 +x-2 0 +x-3 0 +x-4 0 +x-5 0 +x-6 0 +x-7 0 +x-8 0 +x-9 0 +c CHECK: s SATISFIABLE +c CHECK: v -1 -2 -3 -4 -5 -6 -7 -8 -9 10 0$ \ No newline at end of file diff --git a/cryptominisat/cppsrc/tests/definability_test.cpp b/cryptominisat/cppsrc/tests/definability_test.cpp new file mode 100644 index 00000000..efc1b871 --- /dev/null +++ b/cryptominisat/cppsrc/tests/definability_test.cpp @@ -0,0 +1,152 @@ +/****************************************** +Copyright (C) 2009-2020 Authors of CryptoMiniSat, see AUTHORS file + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. +***********************************************/ + +#include "gtest/gtest.h" + +#include + +#include "cryptominisat5/cryptominisat.h" +#include "test_helper.h" + +using namespace CMSat; + +struct definability : public ::testing::Test { + definability() + { + SolverConf conf; + s = new SATSolver; + s->new_vars(50); + for(uint32_t i = 0; i < 50; i++) { + vs.push_back(i); + } + } + ~definability() + { + delete s; + } + SATSolver* s = NULL; + vector vs; +}; + +TEST_F(definability, none_found) +{ + s->add_clause(str_to_cl("1, 2, 3")); + s->add_clause(str_to_cl("1, -2, 4")); + + auto defin = s->get_recovered_or_gates(); + EXPECT_EQ(0, defin.size()); + +} + +TEST_F(definability, do_1) +{ + s->add_clause(str_to_cl("1, -2")); + s->add_clause(str_to_cl("1, -3")); + s->add_clause(str_to_cl("2, 3, -1")); + + auto defin = s->get_recovered_or_gates(); + EXPECT_EQ(1, defin.size()); + EXPECT_EQ(0, defin[0].rhs.var()); +} + +TEST_F(definability, do_1_inv) +{ + s->add_clause(str_to_cl("-1, -2")); + s->add_clause(str_to_cl("-1, -3")); + s->add_clause(str_to_cl("2, 3, 1")); + + auto defin = s->get_recovered_or_gates(); + EXPECT_EQ(1, defin.size()); + EXPECT_EQ(0, defin[0].rhs.var()); +} + +TEST_F(definability, do_2) +{ + s->add_clause(str_to_cl("1, -2")); + s->add_clause(str_to_cl("1, -3")); + s->add_clause(str_to_cl("2, 3, -1")); + + s->add_clause(str_to_cl("11, -12")); + s->add_clause(str_to_cl("11, -13")); + s->add_clause(str_to_cl("12, 13, -11")); + + auto defin = s->get_recovered_or_gates(); + EXPECT_EQ(2, defin.size()); + + if (defin[0].rhs.var() > defin[1].rhs.var()) { + std::swap(defin[0], defin[1]); + } + EXPECT_EQ(0, defin[0].rhs.var()); + EXPECT_EQ(10, defin[1].rhs.var()); +} + +TEST_F(definability, circular) +{ + //2 and 3 define 1 + s->add_clause(str_to_cl("1, -2")); + s->add_clause(str_to_cl("1, -3")); + s->add_clause(str_to_cl("2, 3, -1")); + + s->add_clause(str_to_cl("3, -1")); + s->add_clause(str_to_cl("3, -4")); + s->add_clause(str_to_cl("4, 1, -3")); + + auto defin = s->get_recovered_or_gates(); + EXPECT_EQ(2, defin.size()); +} + +TEST_F(definability, circular_and_normal) +{ + //2 and 3 define 1 + s->add_clause(str_to_cl("1, -2")); + s->add_clause(str_to_cl("1, -3")); + s->add_clause(str_to_cl("2, 3, -1")); + + + s->add_clause(str_to_cl("3, -1")); + s->add_clause(str_to_cl("3, -4")); + s->add_clause(str_to_cl("4, 1, -3")); + + //12 and 13 define 11 + s->add_clause(str_to_cl("11, -12")); + s->add_clause(str_to_cl("11, -13")); + s->add_clause(str_to_cl("12, 13, -11")); + + auto defin = s->get_recovered_or_gates(); + EXPECT_EQ(3, defin.size()); + + //The non-circular one must be found + bool found = false; + for(const auto& v: defin) { + if (v.rhs.var() == 10) { + found = true; + break; + } + } + EXPECT_TRUE(found); +} + + +int main(int argc, char **argv) { + ::testing::InitGoogleTest(&argc, argv); + return RUN_ALL_TESTS(); +} diff --git a/cryptominisat/cppsrc/tests/distill_klee.cpp b/cryptominisat/cppsrc/tests/distill_klee.cpp new file mode 100644 index 00000000..1574f9d8 --- /dev/null +++ b/cryptominisat/cppsrc/tests/distill_klee.cpp @@ -0,0 +1,54 @@ +/****************************************** +Copyright (C) 2009-2020 Authors of CryptoMiniSat, see AUTHORS file + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. +***********************************************/ + +#include +using std::set; + +#include "src/solver.h" +#include "src/distillerlongwithimpl.h" +#include "src/solverconf.h" +using namespace CMSat; +#include "test_helper.h" +#include + +int main(int argc, char **argv) +{ + Solver* s; + DistillerLongWithImpl* distillwbin; + std::atomic must_inter; + SolverConf conf; + //conf.verbosity = 20; + must_inter.store(false, std::memory_order_relaxed); + s = new Solver(&conf, &must_inter); + distillwbin = s->dist_long_with_impl; + + s->new_vars(4); + s->add_clause_outside(str_to_cl("1, 2")); + s->add_clause_outside(str_to_cl("1, 2, 3, 4")); + distillwbin->distill_long_with_implicit(false); + //check_irred_cls_eq(s, "1, 2"); + + delete s; + + return 0; +} + diff --git a/cryptominisat/cppsrc/tests/distill_long_with_implicit_test.cpp b/cryptominisat/cppsrc/tests/distill_long_with_implicit_test.cpp new file mode 100644 index 00000000..51a6b750 --- /dev/null +++ b/cryptominisat/cppsrc/tests/distill_long_with_implicit_test.cpp @@ -0,0 +1,147 @@ +/****************************************** +Copyright (C) 2009-2020 Authors of CryptoMiniSat, see AUTHORS file + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. +***********************************************/ + +#include "gtest/gtest.h" + +#include +using std::set; + +#include "src/solver.h" +#include "src/distillerlongwithimpl.h" +#include "src/solverconf.h" +using namespace CMSat; +#include "test_helper.h" + +struct distill_long_with_impl : public ::testing::Test { + distill_long_with_impl() + { + must_inter.store(false, std::memory_order_relaxed); + SolverConf conf; + conf.do_hyperbin_and_transred = true; + //conf.verbosity = 20; + s = new Solver(&conf, &must_inter); + distillwbin = s->dist_long_with_impl; + } + ~distill_long_with_impl() + { + delete s; + } + + Solver* s; + DistillerLongWithImpl* distillwbin; + std::atomic must_inter; +}; + +//Subsume long with bin + +TEST_F(distill_long_with_impl, subsume_w_bin) +{ + s->new_vars(4); + s->add_clause_outside(str_to_cl("1, 2")); + s->add_clause_outside(str_to_cl("1, 2, 3, 4")); + + distillwbin->distill_long_with_implicit(false); + check_irred_cls_eq(s, "1, 2"); +} + +TEST_F(distill_long_with_impl, subsume_w_bin2) +{ + s->new_vars(5); + s->add_clause_outside(str_to_cl("1, 2")); + s->add_clause_outside(str_to_cl("1, 2, 3, 4")); + s->add_clause_outside(str_to_cl("1, 2, 4, -5")); + + distillwbin->distill_long_with_implicit(false); + check_irred_cls_eq(s, "1, 2"); +} + +TEST_F(distill_long_with_impl, subsume_w_bin3) +{ + s->new_vars(5); + s->add_clause_outside(str_to_cl("2, 3")); + s->add_clause_outside(str_to_cl("1, 2, 3, 4")); + s->add_clause_outside(str_to_cl("2, 3, -4, 5")); + + distillwbin->distill_long_with_implicit(false); + check_irred_cls_eq(s, "2, 3"); +} + +//No subsumption + +TEST_F(distill_long_with_impl, no_subsume) +{ + s->new_vars(5); + s->add_clause_outside(str_to_cl("1, 2")); + s->add_clause_outside(str_to_cl("2, 3, 4, 5")); + + distillwbin->distill_long_with_implicit(false); + check_irred_cls_eq(s, "1, 2; 2, 3, 4, 5"); +} + +TEST_F(distill_long_with_impl, no_subsume_tri) +{ + s->new_vars(5); + s->add_clause_outside(str_to_cl("1, 2")); + s->add_clause_outside(str_to_cl("2, 3, 4, 5")); + + distillwbin->distill_long_with_implicit(false); + check_irred_cls_eq(s, "1, 2; 2, 3, 4, 5"); +} + +//Strengthening long with bin + +TEST_F(distill_long_with_impl, str_w_bin) +{ + s->new_vars(5); + s->add_clause_outside(str_to_cl("1, -2")); + s->add_clause_outside(str_to_cl("1, 2, 3, 4")); + + distillwbin->distill_long_with_implicit(true); + check_irred_cls_contains(s, "1, 3, 4"); +} + +TEST_F(distill_long_with_impl, str_w_bin2) +{ + s->new_vars(5); + s->add_clause_outside(str_to_cl("-1, -2")); + s->add_clause_outside(str_to_cl("-1, 2, 3, 4")); + + distillwbin->distill_long_with_implicit(true); + check_irred_cls_contains(s, "-1, 3, 4"); +} + +TEST_F(distill_long_with_impl, str_w_bin3) +{ + s->new_vars(5); + s->add_clause_outside(str_to_cl("-2, -3")); + s->add_clause_outside(str_to_cl("-2, 3, 4, 5")); + s->add_clause_outside(str_to_cl("-1, 2, -3, 4")); + + distillwbin->distill_long_with_implicit(true); + check_irred_cls_contains(s, "-2, 4, 5"); + check_irred_cls_contains(s, "-1, -3, 4"); +} + +int main(int argc, char **argv) { + ::testing::InitGoogleTest(&argc, argv); + return RUN_ALL_TESTS(); +} diff --git a/cryptominisat/cppsrc/tests/distiller_test.cpp b/cryptominisat/cppsrc/tests/distiller_test.cpp new file mode 100644 index 00000000..5a65d4f4 --- /dev/null +++ b/cryptominisat/cppsrc/tests/distiller_test.cpp @@ -0,0 +1,192 @@ +/****************************************** +Copyright (C) 2009-2020 Authors of CryptoMiniSat, see AUTHORS file + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. +***********************************************/ + +#include "gtest/gtest.h" + +#include "solver.h" +#include "distillerlong.h" +#include "distillerlitrem.h" +#include "solverconf.h" +using namespace CMSat; +#include "test_helper.h" + +struct distill_test : public ::testing::Test { + distill_test() + { + must_inter.store(false, std::memory_order_relaxed); + SolverConf conf; + //conf.verbosity = 20; + s = new Solver(&conf, &must_inter); + distill_long_cls = s->distill_long_cls; + distill_lit_rem = s->distill_lit_rem; + } + ~distill_test() + { + delete s; + } + + Solver* s; + DistillerLong* distill_long_cls; + DistillerLitRem* distill_lit_rem; + std::atomic must_inter; +}; + +//BY-BY 1 + +TEST_F(distill_test, long_by1) +{ + s->new_vars(4); + s->add_clause_outside(str_to_cl("1, -2")); + s->add_clause_outside(str_to_cl("1, 2, 3, 4")); + + distill_long_cls->distill(false); + check_irred_cls_contains(s, "1, 3, 4"); +} + +TEST_F(distill_test, long_by1_transitive) +{ + s->new_vars(5); + s->add_clause_outside(str_to_cl("1, -5")); + s->add_clause_outside(str_to_cl("5, -2")); + s->add_clause_outside(str_to_cl("1, 2, 3, 4")); + + distill_long_cls->distill(false); + check_irred_cls_contains(s, "1, 3, 4"); +} + +TEST_F(distill_test, long_by1_2) +{ + s->new_vars(4); + s->add_clause_outside(str_to_cl("2, -3")); + s->add_clause_outside(str_to_cl("1, 2, 3, 4")); + + distill_long_cls->distill(false); + check_irred_cls_contains(s, "1, 2, 4"); +} + +TEST_F(distill_test, long_by1_nodistill +) +{ + s->new_vars(5); + s->add_clause_outside(str_to_cl("-1, 3")); + s->add_clause_outside(str_to_cl("1, 2, 3, 4")); + + distill_long_cls->distill(false); + check_irred_cls_contains(s, "1, 2, 3, 4"); +} + +TEST_F(distill_test, long_by1_nodistill2 +) +{ + s->new_vars(5); + s->add_clause_outside(str_to_cl("-1, -2")); + s->add_clause_outside(str_to_cl("1, 2, 3, 4")); + + distill_long_cls->distill(false); + check_irred_cls_contains(s, "1, 2, 3, 4"); +} + +TEST_F(distill_test, tri) +{ + s->new_vars(5); + s->add_clause_outside(str_to_cl("1, 2, -3")); + s->add_clause_outside(str_to_cl("1, 2, 3")); + + distill_long_cls->distill(false); + check_irred_cls_contains(s, "1, 2"); +} + +/* + * Can actually fail depending on literal ordering, clause skipping, etc. + * +TEST_F(distill_test, tri_transitive) +{ + s->new_vars(5); + s->add_clause_outside(str_to_cl("1, 2, 4")); + s->add_clause_outside(str_to_cl("-4, -3")); + s->add_clause_outside(str_to_cl("1, 2, 3")); + + distill_long_cls->distill(false); + check_irred_cls_contains(s, "1, 2"); +}*/ + +TEST_F(distill_test, remove_long) +{ + s->new_vars(10); + s->add_clause_outside(str_to_cl("1, 5")); + s->add_clause_outside(str_to_cl("1, 5, 6, 7")); + check_irred_cls_contains(s, "1, 5, 6, 7"); + + distill_long_cls->distill(false, true); + check_irred_cls_doesnt_contain(s, "1, 5, 6, 7"); +} + +TEST_F(distill_test, remove_long_trans) +{ + s->new_vars(10); + s->add_clause_outside(str_to_cl("1, -9")); + s->add_clause_outside(str_to_cl("9, 6")); + s->add_clause_outside(str_to_cl("1, 5, 6, 7")); + check_irred_cls_contains(s, "1, 5, 6, 7"); + + distill_long_cls->distill(false, true); + check_irred_cls_doesnt_contain(s, "1, 5, 6, 7"); +} + +TEST_F(distill_test, litrem_1) +{ + s->new_vars(5); + s->add_clause_outside(str_to_cl("1, 2, 3")); + s->add_clause_outside(str_to_cl("1, -2, 3")); + + distill_lit_rem->distill_lit_rem(); + check_irred_cls_contains(s, "1, 3"); +} + +TEST_F(distill_test, litrem_2) +{ + s->new_vars(5); + s->add_clause_outside(str_to_cl("1, 2, 3, 4")); + s->add_clause_outside(str_to_cl("1, -2, 3, 4")); + + distill_lit_rem->distill_lit_rem(); + check_irred_cls_contains(s, "1, 3, 4"); +} + +TEST_F(distill_test, litrem_3) +{ + s->new_vars(10); + s->add_clause_outside(str_to_cl("1, 2, 3, 4")); + s->add_clause_outside(str_to_cl("1, -2, 3, 4")); + s->add_clause_outside(str_to_cl("1, 2, 3, 7")); + s->add_clause_outside(str_to_cl("1, 2, -3, 7")); + + distill_lit_rem->distill_lit_rem(); + check_irred_cls_contains(s, "1, 3, 4"); + check_irred_cls_contains(s, "1, 2, 7"); +} + + +int main(int argc, char **argv) { + ::testing::InitGoogleTest(&argc, argv); + return RUN_ALL_TESTS(); +} diff --git a/cryptominisat/cppsrc/tests/gatefinder_test.cpp b/cryptominisat/cppsrc/tests/gatefinder_test.cpp new file mode 100644 index 00000000..73bd25b6 --- /dev/null +++ b/cryptominisat/cppsrc/tests/gatefinder_test.cpp @@ -0,0 +1,152 @@ +/****************************************** +Copyright (C) 2009-2020 Authors of CryptoMiniSat, see AUTHORS file + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. +***********************************************/ + +#include "gtest/gtest.h" + +#include +using std::set; + +#include "src/solver.h" +#include "src/solverconf.h" +using namespace CMSat; +#include "test_helper.h" + +struct gatefinder_test : public ::testing::Test { + gatefinder_test() + { + must_inter.store(false, std::memory_order_relaxed); + SolverConf conf; + //conf.verbosity = 20; + s = new Solver(&conf, &must_inter); + } + ~gatefinder_test() + { + delete s; + } + + Solver* s; + std::atomic must_inter; +}; + +//BY-BY 1 + +TEST_F(gatefinder_test, orgate_2) +{ + s->new_vars(20); + s->add_clause_outside(str_to_cl("1, -2")); + s->add_clause_outside(str_to_cl("1, -3")); + s->add_clause_outside(str_to_cl("-1, 2, 3")); + + const auto gs = s->get_recovered_or_gates(); + EXPECT_EQ( 1, gs.size()); + EXPECT_EQ( Lit(0, false), gs[0].rhs); +} + +TEST_F(gatefinder_test, orgate_3) +{ + s->new_vars(20); + s->add_clause_outside(str_to_cl("1, -2")); + s->add_clause_outside(str_to_cl("-1, -2")); + s->add_clause_outside(str_to_cl("1, -3")); + s->add_clause_outside(str_to_cl("-1, 2, 3")); + + const auto gs = s->get_recovered_or_gates(); + EXPECT_EQ( 1, gs.size()); + EXPECT_EQ( Lit(0, false), gs[0].rhs); +} + +TEST_F(gatefinder_test, orgate_4) +{ + s->new_vars(20); + s->add_clause_outside(str_to_cl("1, -2")); + s->add_clause_outside(str_to_cl("-1, -2")); + s->add_clause_outside(str_to_cl("1, -3")); + s->add_clause_outside(str_to_cl("-1, 2, 3")); + + const auto gs = s->get_recovered_or_gates(); + EXPECT_EQ( 1, gs.size()); + const auto tmp = gs[0].get_lhs(); + EXPECT_TRUE(find_lit(tmp, "2")); + EXPECT_TRUE(find_lit(tmp, "3")); +} + + +TEST_F(gatefinder_test, orgate_5) +{ + s->new_vars(20); + s->add_clause_outside(str_to_cl("-1, -2")); + s->add_clause_outside(str_to_cl("-1, -3")); + s->add_clause_outside(str_to_cl("1, 2, 3")); + + const auto gs = s->get_recovered_or_gates(); + EXPECT_EQ( str_to_lit("-1"), gs[0].rhs); + + EXPECT_EQ( 1, gs.size()); + const auto tmp = gs[0].get_lhs(); + EXPECT_TRUE(find_lit(tmp, "2")); + EXPECT_TRUE(find_lit(tmp, "3")); +} + + +TEST_F(gatefinder_test, orgate_6) +{ + s->new_vars(20); + s->add_clause_outside(str_to_cl("-1, 2")); + s->add_clause_outside(str_to_cl("-1, 3")); + s->add_clause_outside(str_to_cl("1, -2, -3")); + + const auto gs = s->get_recovered_or_gates(); + EXPECT_EQ( str_to_lit("-1"), gs[0].rhs); + + EXPECT_EQ( 1, gs.size()); + const auto tmp = gs[0].get_lhs(); + EXPECT_TRUE(find_lit(tmp, "-2")); + EXPECT_TRUE(find_lit(tmp, "-3")); +} + +//a = 1 +//f = 2 +//g = 3 +//x = 4 + +// -a V f V -x +// -a V g V x +// a V -f V -x +// a V -g V x +TEST_F(gatefinder_test, itegate_1) +{ + s->new_vars(20); + s->add_clause_outside(str_to_cl("-1, 2, -4")); + s->add_clause_outside(str_to_cl("-1, 3, 4")); + s->add_clause_outside(str_to_cl("1, -2, -4")); + s->add_clause_outside(str_to_cl("1, -3, 4")); + + const auto gs = s->get_recovered_ite_gates(); + + EXPECT_EQ( 2, gs.size()); + const auto tmp = gs[0].get_all(); + EXPECT_TRUE(find_lit(tmp, "-2")); + EXPECT_TRUE(find_lit(tmp, "-3")); + EXPECT_TRUE(find_lit(tmp, "-4")); + EXPECT_TRUE(find_lit(tmp, "1")); +} + diff --git a/cryptominisat/cppsrc/tests/gauss_test.cpp b/cryptominisat/cppsrc/tests/gauss_test.cpp new file mode 100644 index 00000000..6d7c30fb --- /dev/null +++ b/cryptominisat/cppsrc/tests/gauss_test.cpp @@ -0,0 +1,153 @@ +/****************************************** +Copyright (C) 2009-2020 Authors of CryptoMiniSat, see AUTHORS file + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. +***********************************************/ + +#include "gtest/gtest.h" + +#include +using std::set; + +#include "src/solver.h" +#include "src/gaussian.h" +#include "src/solverconf.h" +using namespace CMSat; +#include "test_helper.h" + +struct gauss : public ::testing::Test { + gauss() + { + must_inter.store(false, std::memory_order_relaxed); + SolverConf conf; + //conf.verbosity = 20; + s = new Solver(&conf, &must_inter); + s->new_vars(30); + } + ~gauss() + { + delete g; + delete s; + } + + Solver* s; + Gaussian* g = NULL; + std::vector vars; + std::atomic must_inter; + vector xs; + bool created; +}; + +//2 XORs inside + +TEST_F(gauss, propagate_1) +{ + s->conf.verbosity = 20; + xs.push_back(Xor(str_to_vars("1, 2, 3"), 0)); + xs.push_back(Xor(str_to_vars("1, 2, 3, 4"), 0)); + + g = new Gaussian(s, xs, 0); + bool ret = g->init_until_fixedpoint(created); + + EXPECT_EQ(ret, true); + EXPECT_EQ(s->ok, true); + check_zero_assigned_lits_eq(s, "-4"); +} + +TEST_F(gauss, propagate_2) +{ + //s->conf.verbosity = 20; + xs.push_back(Xor(str_to_vars("1, 2, 3"), 0)); + xs.push_back(Xor(str_to_vars("1, 2, 3, 4"), 1)); + + g = new Gaussian(s, xs, 0); + bool ret = g->init_until_fixedpoint(created); + + EXPECT_EQ(ret, true); + EXPECT_EQ(s->ok, true); + check_zero_assigned_lits_eq(s, "4"); +} + +TEST_F(gauss, propagate_3) +{ + //s->conf.verbosity = 20; + xs.push_back(Xor(str_to_vars("1, 3, 4, 5"), 0)); + xs.push_back(Xor(str_to_vars("1, 3, 5"), 1)); + + g = new Gaussian(s, xs, 0); + bool ret = g->init_until_fixedpoint(created); + + EXPECT_EQ(ret, true); + EXPECT_EQ(s->ok, true); + check_zero_assigned_lits_eq(s, "4"); +} + +TEST_F(gauss, propagate_4) +{ + //s->conf.verbosity = 20; + xs.push_back(Xor(str_to_vars("1, 3, 4, 5"), 0)); + xs.push_back(Xor(str_to_vars("1, 3, 5"), 1)); + xs.push_back(Xor(str_to_vars("1, 2, 4, 7"), 1)); + + g = new Gaussian(s, xs, 0); + bool ret = g->init_until_fixedpoint(created); + + EXPECT_EQ(ret, true); + EXPECT_EQ(s->ok, true); + check_zero_assigned_lits_eq(s, "4"); +} + +//UNSAT + +TEST_F(gauss, unsat_4) +{ + //s->conf.verbosity = 20; + xs.push_back(Xor(str_to_vars("1, 3, 5"), 0)); + xs.push_back(Xor(str_to_vars("1, 3, 5"), 1)); + + g = new Gaussian(s, xs, 0); + bool ret = g->init_until_fixedpoint(created); + + EXPECT_EQ(ret, false); + EXPECT_EQ(s->ok, false); +} + +//double prop + +TEST_F(gauss, propagate_unsat) +{ + //s->conf.verbosity = 20; + xs.push_back(Xor(str_to_vars("1, 3, 4, 5"), 0)); + xs.push_back(Xor(str_to_vars("1, 3, 5"), 0)); + //-> 4 = 0 + xs.push_back(Xor(str_to_vars("5, 6, 7"), 1)); + xs.push_back(Xor(str_to_vars("4, 5, 6, 7"), 0)); + //-> unsat + + g = new Gaussian(s, xs, 0); + bool ret = g->init_until_fixedpoint(created); + + EXPECT_EQ(ret, false); + EXPECT_EQ(s->ok, false); +} + +int main(int argc, char **argv) { + ::testing::InitGoogleTest(&argc, argv); + return RUN_ALL_TESTS(); +} diff --git a/cryptominisat/cppsrc/tests/heap_test.cpp b/cryptominisat/cppsrc/tests/heap_test.cpp new file mode 100644 index 00000000..50b27d85 --- /dev/null +++ b/cryptominisat/cppsrc/tests/heap_test.cpp @@ -0,0 +1,100 @@ +/****************************************** +Copyright (C) 2009-2020 Authors of CryptoMiniSat, see AUTHORS file + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. +***********************************************/ + +#include "gtest/gtest.h" + +#include "cryptominisat5/cryptominisat.h" + +#include "src/heap.h" + +using CMSat::Heap; + +struct Comp +{ + bool operator()(uint32_t a, uint32_t b) const + { + return a < b; + } +}; + +TEST(heap_minim, simple) +{ + Comp cmp; + Heap heap(cmp); + heap.insert(1); + heap.insert(2); + heap.insert(3); + EXPECT_EQ( heap.heap_property(), true); +} + +TEST(heap_minim, empty) +{ + Comp cmp; + Heap heap(cmp); + heap.insert(1); + heap.insert(2); + EXPECT_EQ(heap.removeMin(), 1); + EXPECT_EQ(heap.removeMin(), 2); + EXPECT_EQ( heap.heap_property(), true); +} + +TEST(heap_minim, empty2) +{ + Comp cmp; + Heap heap(cmp); + heap.insert(1); + heap.insert(2); + heap.insert(3); + EXPECT_EQ(heap.removeMin(), 1); + EXPECT_EQ(heap.removeMin(), 2); + EXPECT_EQ(heap.removeMin(), 3); + EXPECT_EQ( heap.heap_property(), true); +} + +TEST(heap_minim, empty_lots) +{ + Comp cmp; + Heap heap(cmp); + for(size_t i = 0; i < 100; i++) { + heap.insert(99-i); + EXPECT_EQ( heap.heap_property(), true); + } + for(int i = 0; i < 100; i++) { + EXPECT_EQ(heap.removeMin(), i); + EXPECT_EQ(heap.heap_property(), true); + } +} + +TEST(heap_minim, inserted_inside) +{ + Comp cmp; + Heap heap(cmp); + heap.insert(10); + heap.insert(20); + EXPECT_EQ(heap.inHeap(10), true); + EXPECT_EQ(heap.inHeap(20), true); +} + +int main(int argc, char **argv) { + ::testing::InitGoogleTest(&argc, argv); + return RUN_ALL_TESTS(); +} diff --git a/cryptominisat/cppsrc/tests/implied_by_test.cpp b/cryptominisat/cppsrc/tests/implied_by_test.cpp new file mode 100644 index 00000000..0e6f1f2e --- /dev/null +++ b/cryptominisat/cppsrc/tests/implied_by_test.cpp @@ -0,0 +1,176 @@ +/****************************************** +Copyright (C) 2009-2020 Authors of CryptoMiniSat, see AUTHORS file + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. +***********************************************/ + +#include "gtest/gtest.h" + +#include +#include + +#include "cryptominisat5/cryptominisat.h" +#include "src/solverconf.h" +#include "test_helper.h" +using namespace CMSat; +#include +using std::vector; + +struct impliedby : public ::testing::Test { + impliedby() + { + + SolverConf conf; + //conf.verbosity = 20; + s = new SATSolver(&conf); + s->set_bva(0); + s->set_no_bve(); + s->new_vars(30); + } + ~impliedby() + { + delete s; + } + + SATSolver* s; + vector lits; + vector out_implied_by; +}; + + +TEST_F(impliedby, noprop) +{ + s->add_clause(str_to_cl("1")); + lits = str_to_cl("1"); + bool ret = s->implied_by(lits, out_implied_by); + EXPECT_EQ(true, ret); + EXPECT_EQ(0, out_implied_by.size()); +} + +TEST_F(impliedby, prop_1) +{ + s->add_clause(str_to_cl("1, 2")); + lits = str_to_cl("-1"); + bool ret = s->implied_by(lits, out_implied_by); + EXPECT_EQ(true, ret); + EXPECT_EQ(str_to_cl("-1, 2"), out_implied_by); +} + +TEST_F(impliedby, replace_prop_1) +{ + s->add_clause(str_to_cl("1, 2")); + s->add_clause(str_to_cl("-1, -2")); + s->simplify(); + lits = str_to_cl("-1"); + bool ret = s->implied_by(lits, out_implied_by); + EXPECT_EQ(true, ret); + std::sort(out_implied_by.begin(), out_implied_by.end()); + EXPECT_EQ(str_to_cl("-1, 2"), out_implied_by); +} + +TEST_F(impliedby, replace_prop_2) +{ + s->add_clause(str_to_cl("1, 2")); + s->add_clause(str_to_cl("-1, -2")); + s->simplify(); + lits = str_to_cl("-2"); + bool ret = s->implied_by(lits, out_implied_by); + EXPECT_EQ(true, ret); + std::sort(out_implied_by.begin(), out_implied_by.end()); + EXPECT_EQ(str_to_cl("1, -2"), out_implied_by); +} + +TEST_F(impliedby, ret_false_1) +{ + s->add_clause(str_to_cl("1, 2")); + s->add_clause(str_to_cl("-1, -2")); + s->add_clause(str_to_cl("1, -2")); + s->add_clause(str_to_cl("-1, 2")); + s->simplify(); + lits = str_to_cl("3"); + bool ret = s->implied_by(lits, out_implied_by); + EXPECT_EQ(false, ret); +} + +TEST_F(impliedby, ret_false_2) +{ + s->add_clause(str_to_cl("1")); + s->simplify(); + lits = str_to_cl("-1"); + bool ret = s->implied_by(lits, out_implied_by); + EXPECT_EQ(false, ret); +} + +TEST_F(impliedby, ret_false_3) +{ + s->add_clause(str_to_cl("1, -2")); + s->simplify(); + lits = str_to_cl("-1, 2"); + bool ret = s->implied_by(lits, out_implied_by); + EXPECT_EQ(false, ret); +} + +TEST_F(impliedby, ret_false_4) +{ + s->add_clause(str_to_cl("1, -2")); + s->add_clause(str_to_cl("-1")); + s->simplify(); + lits = str_to_cl("2"); + bool ret = s->implied_by(lits, out_implied_by); + EXPECT_EQ(false, ret); +} + +TEST_F(impliedby, no_imply) +{ + s->add_clause(str_to_cl("1, -2")); + s->add_clause(str_to_cl("-1")); + s->simplify(); + lits = str_to_cl("-1"); + bool ret = s->implied_by(lits, out_implied_by); + EXPECT_EQ(true, ret); + EXPECT_EQ(0, out_implied_by.size()); +} + +TEST_F(impliedby, no_imply_2) +{ + s->add_clause(str_to_cl("-1")); + s->add_clause(str_to_cl("1, -2")); + s->simplify(); + lits = str_to_cl("-2"); + bool ret = s->implied_by(lits, out_implied_by); + EXPECT_EQ(true, ret); + EXPECT_EQ(0, out_implied_by.size()); +} + +TEST_F(impliedby, imply_3) +{ + s->add_clause(str_to_cl("1, -2")); + s->add_clause(str_to_cl("2, -3")); + s->simplify(); + lits = str_to_cl("-1"); + bool ret = s->implied_by(lits, out_implied_by); + EXPECT_EQ(true, ret); + std::sort(out_implied_by.begin(), out_implied_by.end()); + EXPECT_EQ(str_to_cl("-1, -2, -3"), out_implied_by); +} + +int main(int argc, char **argv) { + ::testing::InitGoogleTest(&argc, argv); + return RUN_ALL_TESTS(); +} diff --git a/cryptominisat/cppsrc/tests/intree_test.cpp b/cryptominisat/cppsrc/tests/intree_test.cpp new file mode 100644 index 00000000..76b560fb --- /dev/null +++ b/cryptominisat/cppsrc/tests/intree_test.cpp @@ -0,0 +1,174 @@ +/****************************************** +Copyright (C) 2009-2020 Authors of CryptoMiniSat, see AUTHORS file + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. +***********************************************/ + +#include "gtest/gtest.h" + +#include +using std::set; + +#include "src/solver.h" +#include "src/intree.h" +#include "src/solverconf.h" +using namespace CMSat; +#include "test_helper.h" + +struct intree : public ::testing::Test { + intree() + { + must_inter.store(false, std::memory_order_relaxed); + SolverConf conf; + conf.do_hyperbin_and_transred = true; + //conf.verbosity = 20; + s = new Solver(&conf, &must_inter); + s->new_vars(30); + inp = s->intree; + } + ~intree() + { + delete s; + } + + Solver* s; + InTree* inp; + std::atomic must_inter; +}; + + +//Fails + +TEST_F(intree, fail_1) +{ + //s->conf.verbosity = 20; + s->add_clause_outside(str_to_cl(" 1, 2")); + s->add_clause_outside(str_to_cl("-2, 3")); + s->add_clause_outside(str_to_cl("-2, -3")); + + inp->intree_probe(); + check_zero_assigned_lits_contains(s, "-2"); +} + + +TEST_F(intree, fail_2) +{ + //s->conf.verbosity = 20; + s->add_clause_outside(str_to_cl(" 1, 2")); + s->add_clause_outside(str_to_cl("-2, 3")); + s->add_clause_outside(str_to_cl("-2, 4")); + s->add_clause_outside(str_to_cl("-2, 5")); + s->add_clause_outside(str_to_cl("-3, -4, -5, 1")); + + inp->intree_probe(); + check_zero_assigned_lits_contains(s, "1"); +} + +TEST_F(intree, fail_3) +{ + //s->conf.verbosity = 20; + s->add_clause_outside(str_to_cl(" 1, 2")); + s->add_clause_outside(str_to_cl("-2, 3")); + s->add_clause_outside(str_to_cl("-2, 4")); + s->add_clause_outside(str_to_cl("-2, 5")); + s->add_clause_outside(str_to_cl("-3, -4, -5, 6")); + s->add_clause_outside(str_to_cl("-4, -5, -6")); + + inp->intree_probe(); + check_zero_assigned_lits_contains(s, "1"); +} + +//Hyper-binary resolution + +TEST_F(intree, hyper_bin_1) +{ + //s->conf.verbosity = 20; + s->add_clause_outside(str_to_cl(" 1, 2")); + s->add_clause_outside(str_to_cl("-2, 3")); + s->add_clause_outside(str_to_cl("-2, 4")); + s->add_clause_outside(str_to_cl("-3, -4, 5")); + + inp->intree_probe(); + check_red_cls_contains(s, "-2, 5"); +} + +TEST_F(intree, hyper_bin_2) +{ + //s->conf.verbosity = 20; + s->add_clause_outside(str_to_cl(" 1, 2")); + s->add_clause_outside(str_to_cl("-2, 3")); + s->add_clause_outside(str_to_cl("-2, 4")); + s->add_clause_outside(str_to_cl("-3, -4, 5")); + s->add_clause_outside(str_to_cl("-5, 6")); + s->add_clause_outside(str_to_cl("-5, 7")); + s->add_clause_outside(str_to_cl("-6, -7, 8")); + + inp->intree_probe(); + check_red_cls_contains(s, "-2, 5"); + check_red_cls_contains(s, "-5, 8"); +} + +//Transitive reduction + +TEST_F(intree, trans_red_1) +{ + //s->conf.verbosity = 20; + s->add_clause_outside(str_to_cl(" 1, 2")); + s->add_clause_outside(str_to_cl("-2, 3")); + s->add_clause_outside(str_to_cl("-2, 4")); + s->add_clause_outside(str_to_cl("-3, -4, 5")); + s->add_clause_outside(str_to_cl("1, 5")); + + inp->intree_probe(); + check_red_cls_doesnt_contain(s, "1, 5"); +} + +TEST_F(intree, trans_red_2) +{ + //s->conf.verbosity = 20; + s->add_clause_outside(str_to_cl(" 1, 2")); + s->add_clause_outside(str_to_cl("-2, 3")); + s->add_clause_outside(str_to_cl("-3, 4")); + s->add_clause_outside(str_to_cl("-4, 5")); + s->add_clause_outside(str_to_cl("1, 5")); + + inp->intree_probe(); + check_irred_cls_doesnt_contain(s, "1, 5"); +} + +//Transitive reduction and hyper-binary resolution +TEST_F(intree, trans_red_and_hyper_bin_1) +{ + //s->conf.verbosity = 20; + s->add_clause_outside(str_to_cl(" 1, 2")); + s->add_clause_outside(str_to_cl("-2, 3")); + s->add_clause_outside(str_to_cl("-3, 4")); + s->add_clause_outside(str_to_cl("-4, 5")); + s->add_clause_outside(str_to_cl("-3, -4, -5, 6")); + s->add_clause_outside(str_to_cl("1, 6")); + + inp->intree_probe(); + check_red_cls_doesnt_contain(s, "1, 6"); + check_red_cls_contains(s, "-3, 6"); +} + +int main(int argc, char **argv) { + ::testing::InitGoogleTest(&argc, argv); + return RUN_ALL_TESTS(); +} diff --git a/cryptominisat/cppsrc/tests/ipasir_example.c b/cryptominisat/cppsrc/tests/ipasir_example.c new file mode 100644 index 00000000..c1e92abd --- /dev/null +++ b/cryptominisat/cppsrc/tests/ipasir_example.c @@ -0,0 +1,42 @@ +/****************************************** +Copyright (C) 2009-2020 Authors of CryptoMiniSat, see AUTHORS file + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. +***********************************************/ + +#include "src/ipasir.h" +#include "assert.h" +#include "stdio.h" + +int main () { + printf("signaure: %s\n", ipasir_signature()); + + void* s = ipasir_init(); + ipasir_add(s, 1); + ipasir_add(s, 0); + + int ret = ipasir_solve(s); + assert(ret == 10); + + int val = ipasir_val(s, 1); + assert(val == 1); + + ipasir_release(s); + return 0; +} diff --git a/cryptominisat/cppsrc/tests/ipasir_test.cpp b/cryptominisat/cppsrc/tests/ipasir_test.cpp new file mode 100644 index 00000000..feba0395 --- /dev/null +++ b/cryptominisat/cppsrc/tests/ipasir_test.cpp @@ -0,0 +1,402 @@ +/****************************************** +Copyright (C) 2009-2020 Authors of CryptoMiniSat, see AUTHORS file + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. +***********************************************/ + +#include "gtest/gtest.h" +extern "C" { +#include "src/ipasir.h" +} + +TEST(ipasir_interface, start) +{ + void* s = ipasir_init(); + ipasir_release(s); +} + +TEST(ipasir_interface, sat) +{ + void* s = ipasir_init(); + ipasir_add(s, 1); + ipasir_add(s, 0); + + int ret = ipasir_solve(s); + EXPECT_EQ(ret, 10); + + int val = ipasir_val(s, 1); + EXPECT_EQ(val, 1); + + ipasir_release(s); +} + +TEST(ipasir_interface, sat2) +{ + void* s = ipasir_init(); + ipasir_add(s, -1); + ipasir_add(s, 2); + ipasir_add(s, 0); + + ipasir_add(s, 1); + ipasir_add(s, 0); + + int ret = ipasir_solve(s); + EXPECT_EQ(ret, 10); + + int val = ipasir_val(s, 1); + EXPECT_EQ(val, 1); + val = ipasir_val(s, 2); + EXPECT_EQ(val, 2); + + ipasir_release(s); +} + +TEST(ipasir_interface, sat4) +{ + void* s = ipasir_init(); + ipasir_add(s, -2); + ipasir_add(s, -3); + ipasir_add(s, 0); + + ipasir_add(s, -1); + ipasir_add(s, 2); + ipasir_add(s, 0); + + ipasir_add(s, 1); + ipasir_add(s, 0); + + int ret = ipasir_solve(s); + EXPECT_EQ(ret, 10); + + int val = ipasir_val(s, 1); + EXPECT_EQ(val, 1); + + val = ipasir_val(s, 2); + EXPECT_EQ(val, 2); + + val = ipasir_val(s, 3); + EXPECT_EQ(val, -3); + + ipasir_release(s); +} + + +TEST(ipasir_interface, unsat) +{ + void* s = ipasir_init(); + ipasir_add(s, 1); + ipasir_add(s, 0); + ipasir_add(s, -1); + ipasir_add(s, 0); + + int ret = ipasir_solve(s); + EXPECT_EQ(ret, 20); + + ipasir_release(s); +} + +TEST(ipasir_interface, unsat2) +{ + void* s = ipasir_init(); + ipasir_add(s, 1); + ipasir_add(s, 2); + ipasir_add(s, 0); + + ipasir_add(s, -1); + ipasir_add(s, -2); + ipasir_add(s, 0); + + ipasir_add(s, 1); + ipasir_add(s, -2); + ipasir_add(s, 0); + + ipasir_add(s, -1); + ipasir_add(s, 2); + ipasir_add(s, 0); + + int ret = ipasir_solve(s); + EXPECT_EQ(ret, 20); + + ipasir_release(s); +} + +TEST(ipasir_interface, unsat_empty) +{ + void* s = ipasir_init(); + ipasir_add(s, 0); + + int ret = ipasir_solve(s); + EXPECT_EQ(ret, 20); + + ipasir_release(s); +} + + +TEST(ipasir_interface, assump) +{ + void* s = ipasir_init(); + ipasir_add(s, 1); + ipasir_add(s, 0); + + ipasir_assume(s, -1); + + int ret = ipasir_solve(s); + EXPECT_EQ(ret, 20); + + int used = ipasir_failed(s, -1); + EXPECT_EQ(used, 1); + + ipasir_release(s); +} + +TEST(ipasir_interface, assump_multi) +{ + void* s = ipasir_init(); + ipasir_add(s, 1); + ipasir_add(s, 0); + + ipasir_assume(s, -1); + + int ret = ipasir_solve(s); + EXPECT_EQ(ret, 20); + EXPECT_EQ(ipasir_failed(s, -1), 1); + + //Redo with 2 + ipasir_add(s, 2); + ipasir_add(s, 0); + + ipasir_assume(s, -2); + ret = ipasir_solve(s); + EXPECT_EQ(ret, 20); + EXPECT_EQ(ipasir_failed(s, -1), 0); + EXPECT_EQ(ipasir_failed(s, -2), 1); + + //final, it should be SAT + ret = ipasir_solve(s); + EXPECT_EQ(ret, 10); + + ipasir_release(s); +} + +TEST(ipasir_interface, assump_multi2) +{ + void* s = ipasir_init(); + ipasir_add(s, 1); + ipasir_add(s, 2); + ipasir_add(s, 0); + + ipasir_assume(s, -1); + + int ret = ipasir_solve(s); + EXPECT_EQ(ret, 10); + + //add assump 2 as well + ipasir_assume(s, -1); + ipasir_assume(s, -2); + ret = ipasir_solve(s); + EXPECT_EQ(ret, 20); + EXPECT_EQ(ipasir_failed(s, -1), 1); + EXPECT_EQ(ipasir_failed(s, -2), 1); + + //final, it should be SAT + ret = ipasir_solve(s); + EXPECT_EQ(ret, 10); + + ipasir_release(s); +} + +TEST(ipasir_interface, assump_multi3) +{ + void* s = ipasir_init(); + ipasir_add(s, 1); + ipasir_add(s, 3); + ipasir_add(s, 0); + + ipasir_add(s, -7); + ipasir_add(s, -2); + ipasir_add(s, 0); + + ipasir_add(s, 1); + ipasir_add(s, 4); + ipasir_add(s, 6); + ipasir_add(s, 0); + + ipasir_assume(s, -1); + + int ret = ipasir_solve(s); + EXPECT_EQ(ret, 10); + + //one assum + ipasir_assume(s, -1); + ipasir_assume(s, -3); + ipasir_assume(s, -4); + ret = ipasir_solve(s); + EXPECT_EQ(ret, 20); + EXPECT_EQ(ipasir_failed(s, -1), 1); + EXPECT_EQ(ipasir_failed(s, -2), 0); + EXPECT_EQ(ipasir_failed(s, -3), 1); + EXPECT_EQ(ipasir_failed(s, -4), 0); + EXPECT_EQ(ipasir_failed(s, 4), 0); + EXPECT_EQ(ipasir_failed(s, -6), 0); + + + //one assum + ipasir_assume(s, 7); + ipasir_assume(s, 2); + ipasir_assume(s, -6); + ret = ipasir_solve(s); + EXPECT_EQ(ret, 20); + EXPECT_EQ(ipasir_failed(s, -1), 0); + EXPECT_EQ(ipasir_failed(s, 2), 1); + EXPECT_EQ(ipasir_failed(s, -3), 0); + EXPECT_EQ(ipasir_failed(s, 7), 1); + EXPECT_EQ(ipasir_failed(s, -6), 0); + EXPECT_EQ(ipasir_failed(s, 6), 0); + + //final, it should be SAT + ret = ipasir_solve(s); + EXPECT_EQ(ret, 10); + + ipasir_release(s); +} + + +TEST(ipasir_interface, assump_yevgeny) +{ + void* s = ipasir_init(); + + ipasir_add(s, -1); + ipasir_add(s, 0); + + int ret = ipasir_solve(s); + EXPECT_EQ(ret, 10); + + ipasir_assume(s, 1); + ret = ipasir_solve(s); + EXPECT_EQ(ret, 20); + + int failed = ipasir_failed(s, 1); + EXPECT_EQ(failed, 1); +} + +TEST(ipasir_interface, assump2) +{ + void* s = ipasir_init(); + ipasir_add(s, 1); + ipasir_add(s, 2); + ipasir_add(s, 3); + ipasir_add(s, 4); + ipasir_add(s, 0); + + ipasir_assume(s, -1); + ipasir_assume(s, -2); + ipasir_assume(s, -3); + ipasir_assume(s, -4); + + int ret = ipasir_solve(s); + EXPECT_EQ(ret, 20); + + //We check the ASSUMPTION LITERAL, not the conflict clause! + int used = ipasir_failed(s, -1); + EXPECT_EQ(used, 1); + int used2 = ipasir_failed(s, -2); + EXPECT_EQ(used2, 1); + int used3 = ipasir_failed(s, -3); + EXPECT_EQ(used3, 1); + int used4 = ipasir_failed(s, -4); + EXPECT_EQ(used4, 1); + + ipasir_release(s); +} + +TEST(ipasir_interface, assump3) +{ + void* s = ipasir_init(); + ipasir_add(s, 1); + ipasir_add(s, 2); + ipasir_add(s, -3); + ipasir_add(s, 0); + + ipasir_assume(s, -1); + ipasir_assume(s, -2); + ipasir_assume(s, 3); + + int ret = ipasir_solve(s); + EXPECT_EQ(ret, 20); + + int used = ipasir_failed(s, -1); + EXPECT_EQ(used, 1); + int used2 = ipasir_failed(s, -2); + EXPECT_EQ(used2, 1); + int used3 = ipasir_failed(s, 3); + EXPECT_EQ(used3, 1); + + ipasir_release(s); +} + +TEST(ipasir_interface, assump_clears) +{ + void* s = ipasir_init(); + ipasir_add(s, 1); + ipasir_add(s, 0); + + ipasir_assume(s, -1); + + int ret = ipasir_solve(s); + EXPECT_EQ(ret, 20); + + ret = ipasir_solve(s); + EXPECT_EQ(ret, 10); + + ipasir_release(s); +} + +TEST(ipasir_interface, ipasir_assump_beyond_problemvars) +{ + void* s = ipasir_init(); + ipasir_add(s, -7); + ipasir_add(s, 0); + ipasir_assume(s, 10); + int ret = ipasir_solve(s); + ASSERT_EQ(ret, 10); + + EXPECT_EQ(ipasir_val(s, 10), 10); +} + +TEST(ipasir_interface, ipasir_val) +{ + void* s = ipasir_init(); + ipasir_add(s, -7); + ipasir_add(s, 0); + ipasir_add(s, 8); + ipasir_add(s, 0); + int ret = ipasir_solve(s); + ASSERT_EQ(ret, 10); + + EXPECT_EQ(ipasir_val(s, -7), -7); + EXPECT_EQ(ipasir_val(s, 7), -7); + EXPECT_EQ(ipasir_val(s, -8), 8); + EXPECT_EQ(ipasir_val(s, 8), 8); +} + + +int main(int argc, char **argv) { + ::testing::InitGoogleTest(&argc, argv); + return RUN_ALL_TESTS(); +} diff --git a/cryptominisat/cppsrc/tests/lucky_test.cpp b/cryptominisat/cppsrc/tests/lucky_test.cpp new file mode 100644 index 00000000..07e1be1b --- /dev/null +++ b/cryptominisat/cppsrc/tests/lucky_test.cpp @@ -0,0 +1,131 @@ +/****************************************** +Copyright (C) 2009-2020 Authors of CryptoMiniSat, see AUTHORS file + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. +***********************************************/ + +#include "gtest/gtest.h" + +#include + +#include "cryptominisat5/cryptominisat.h" +#include "src/solverconf.h" +#include "test_helper.h" +#include "src/lucky.h" +using namespace CMSat; +#include +using std::vector; + + +struct lucky : public ::testing::Test { + lucky() + { + must_inter.store(false, std::memory_order_relaxed); + SolverConf conf; + s = new Solver(&conf, &must_inter); + s->new_vars(30); + l = new Lucky(s); + } + ~lucky() + { + delete l; + delete s; + } + Solver* s = NULL; + Lucky* l = NULL; + std::atomic must_inter; +}; + +TEST_F(lucky, pos1) +{ + s->add_clause_outside(str_to_cl("1, -12")); + s->add_clause_outside(str_to_cl("2, -3, -4, -5, -6")); + s->add_clause_outside(str_to_cl("2, -3, -4, -5, -7")); + + EXPECT_EQ(l->check_all(true), true); +} + +TEST_F(lucky, pos2) +{ + s->add_clause_outside(str_to_cl("1")); + s->add_clause_outside(str_to_cl("-9, -2, -5, 6")); + s->add_clause_outside(str_to_cl("-8, -4, -5, 7")); + + EXPECT_EQ(l->check_all(true), true); +} + +TEST_F(lucky, not_pos) +{ + s->add_clause_outside(str_to_cl("-1, -2, -3, -4")); + s->add_clause_outside(str_to_cl("2, 3, 4, 5, 7")); + s->add_clause_outside(str_to_cl("12, 13, 14, 15, 17")); + + EXPECT_EQ(l->check_all(true), false); +} + +TEST_F(lucky, neg) +{ + s->add_clause_outside(str_to_cl("1, 2, 3, -4")); + s->add_clause_outside(str_to_cl("2, 3, -4, 5, 7")); + s->add_clause_outside(str_to_cl("12, 13, 14, 15, -17")); + + EXPECT_EQ(l->check_all(false), true); +} + +TEST_F(lucky, neg2) +{ + s->add_clause_outside(str_to_cl("1,-4")); + s->add_clause_outside(str_to_cl("2, -4")); + s->add_clause_outside(str_to_cl("12, -4")); + + EXPECT_EQ(l->check_all(false), true); +} + +TEST_F(lucky, fwd1) +{ + s->add_clause_outside(str_to_cl("1, -4")); + s->add_clause_outside(str_to_cl("4, 5")); + s->add_clause_outside(str_to_cl("-6, 7")); + s->add_clause_outside(str_to_cl("7, -8")); + + EXPECT_EQ(l->search_fwd_sat(true), true); +} + +TEST_F(lucky, fwd1_fail) +{ + s->add_clause_outside(str_to_cl("1, -4")); + s->add_clause_outside(str_to_cl("-1, -4")); + s->add_clause_outside(str_to_cl("-1, 4")); + + EXPECT_EQ(l->search_fwd_sat(true), false); +} + +TEST_F(lucky, horn) +{ + s->add_clause_outside(str_to_cl("-1, -4, -5, 6")); + s->add_clause_outside(str_to_cl("-1, -2, -3, 5")); + s->add_clause_outside(str_to_cl("-5, -6, 7")); + + EXPECT_EQ(l->horn_sat(true), true); +} + +int main(int argc, char **argv) { + ::testing::InitGoogleTest(&argc, argv); + return RUN_ALL_TESTS(); +} diff --git a/cryptominisat/cppsrc/tests/matrixfinder_test.cpp b/cryptominisat/cppsrc/tests/matrixfinder_test.cpp new file mode 100644 index 00000000..4177daae --- /dev/null +++ b/cryptominisat/cppsrc/tests/matrixfinder_test.cpp @@ -0,0 +1,149 @@ +/****************************************** +Copyright (C) 2009-2020 Authors of CryptoMiniSat, see AUTHORS file + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. +***********************************************/ + +#include "gtest/gtest.h" + +#include +using std::set; + +#include "src/solver.h" +#include "src/matrixfinder.h" +#include "src/solverconf.h" +using namespace CMSat; +#include "test_helper.h" + +struct gauss : public ::testing::Test { + gauss() + { + must_inter.store(false, std::memory_order_relaxed); + SolverConf conf; + //conf.verbosity = 20; + s = new Solver(&conf, &must_inter); + s->new_vars(40); + s->conf.gaussconf.min_gauss_xor_clauses = 0; + mf = new MatrixFinder(s); + } + ~gauss() + { + delete mf; + delete s; + } + + Solver* s; + MatrixFinder* mf = NULL; + std::vector vars; + std::atomic must_inter; + vector xs; + bool can_detach; +}; + +TEST_F(gauss, min_rows) +{ + //s->conf.verbosity = 20; + s->conf.gaussconf.min_matrix_rows = 2; + xs.push_back(str_to_xors("1, 2, 3 = 0")[0]); + xs.push_back(str_to_xors("1, 2, 3, 4 = 0")[0]); + s->xor_clauses_updated = true; + s->xorclauses = xs; + + mf->find_matrices(can_detach); + + EXPECT_EQ(s->gmatrices.size(), 1); +} + +TEST_F(gauss, min_rows_2) +{ + //s->conf.verbosity = 20; + s->conf.gaussconf.min_matrix_rows = 3; + xs.push_back(str_to_xors("1, 2, 3 = 0")[0]); + xs.push_back(str_to_xors("1, 2, 3, 4 = 0")[0]); + s->xor_clauses_updated = true; + s->xorclauses = xs; + + mf->find_matrices(can_detach); + + EXPECT_EQ(s->gmatrices.size(), 0); +} + +TEST_F(gauss, separate_1) +{ + //s->conf.verbosity = 20; + s->conf.gaussconf.min_matrix_rows = 1; + xs.push_back(str_to_xors("1, 2, 3 = 0")[0]); + xs.push_back(str_to_xors("1, 2, 4, 5 = 0")[0]); + xs.push_back(str_to_xors("6, 7, 8 = 0")[0]); + xs.push_back(str_to_xors("6, 7, 9, 10 = 0")[0]); + s->xor_clauses_updated = true; + s->xorclauses = xs; + + mf->find_matrices(can_detach); + cout << "s->gmatrices.size(): " << s->gmatrices.size() << endl; + + EXPECT_EQ(s->gmatrices.size(), 2); +} + +TEST_F(gauss, separate_2) +{ + //s->conf.verbosity = 20; + s->conf.gaussconf.min_matrix_rows = 1; + xs.push_back(str_to_xors("1, 2, 3, 4 = 0")[0]); + xs.push_back(str_to_xors("4, 5, 6 = 0")[0]); + xs.push_back(str_to_xors("3, 4, 10 = 0")[0]); + + xs.push_back(str_to_xors("15, 16, 17, 18 = 0")[0]); + xs.push_back(str_to_xors("11, 15, 19 = 0")[0]); + xs.push_back(str_to_xors("19, 20, 12, 15 = 0")[0]); + s->xor_clauses_updated = true; + s->xorclauses = xs; + + mf->find_matrices(can_detach); + + EXPECT_EQ(s->gmatrices.size(), 2); +} + +TEST_F(gauss, separate_3) +{ + //s->conf.verbosity = 20; + s->conf.gaussconf.min_matrix_rows = 1; + xs.push_back(str_to_xors("1, 2, 3, 10 = 0")[0]); + xs.push_back(str_to_xors("4, 5, 6, 9 = 0")[0]); + xs.push_back(str_to_xors("3, 4, 10, 9 = 0")[0]); + + xs.push_back(str_to_xors("11, 15, 16, 17 = 0")[0]); + xs.push_back(str_to_xors("11, 15, 18, 19 = 0")[0]); + xs.push_back(str_to_xors("19, 18, 20, 12 = 0")[0]); + + xs.push_back(str_to_xors("21, 22, 23, 28, 29 = 0")[0]); + xs.push_back(str_to_xors("28, 29 = 0")[0]); + xs.push_back(str_to_xors("25, 21, 22, 27 = 0")[0]); + s->xor_clauses_updated = true; + s->xorclauses = xs; + + mf->find_matrices(can_detach); + + EXPECT_EQ(s->gmatrices.size(), 3); +} + +int main(int argc, char **argv) { + ::testing::InitGoogleTest(&argc, argv); + return RUN_ALL_TESTS(); +} diff --git a/cryptominisat/cppsrc/tests/ml_perf_test.cpp b/cryptominisat/cppsrc/tests/ml_perf_test.cpp new file mode 100644 index 00000000..4344a208 --- /dev/null +++ b/cryptominisat/cppsrc/tests/ml_perf_test.cpp @@ -0,0 +1,191 @@ +/****************************************** +Copyright (c) 2020, Mate Soos + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. +***********************************************/ + +#include "src/cl_predictors_abs.h" +#include "src/cl_predictors_xgb.h" +#include "src/clause.h" +#include "cryptominisat5/solvertypesmini.h" +#include +#include +#include +#include +using std::vector; +using std::string; +using namespace CMSat; +ClPredictorsAbst* pred; + +//TODO read in +struct Dat { + uint32_t props_made; + uint32_t orig_glue; + uint32_t glue; + uint32_t glue_before_minim; + uint32_t sum_uip1_used; + uint32_t num_antecedents; + uint32_t num_total_lits_antecedents; + uint32_t uip1_used; + float numResolutionsHistLT_avg; + float glueHist_longterm_avg; + float conflSizeHistLT_avg; + float branchDepthHistQueue_avg; + double act_ranking_rel; + uint32_t size; + uint64_t sumConflicts; //time_inside_the_solver + float correct_val; + + void print() + { + cout << "props_made: " << props_made << endl; + cout << "orig_glue: " << orig_glue << endl; + cout << "glue: " << glue << endl; + cout << "glue_before_minim: " << glue_before_minim << endl; + cout << "sum_uip1_used: " << sum_uip1_used << endl; + cout << "num_antecedents: " << num_antecedents << endl; + cout << "num_total_lits_antecedents: " << num_total_lits_antecedents << endl; + cout << "uip1_used: " << uip1_used << endl; + cout << "numResolutionsHistLT_avg: " << numResolutionsHistLT_avg << endl; + cout << "glueHist_longterm_avg: " << glueHist_longterm_avg << endl; + cout << "conflSizeHistLT_avg: " << conflSizeHistLT_avg << endl; + cout << "branchDepthHistQueue_avg: " << branchDepthHistQueue_avg << endl; + cout << "act_ranking_rel: " << act_ranking_rel << endl; + cout << "size: " << size << endl; + cout << "sumConflicts: " << sumConflicts << endl; + cout << "correct_val: " << correct_val << endl; + } +}; + +std::ifstream infile; + +bool get_val(Dat& dat) +{ + std::string line; + std::getline(infile, line); + if (!infile) { + return false; + } + std::istringstream iss(line); + + if (!( + iss + >> dat.props_made + >> dat.orig_glue + >> dat.glue + >> dat.glue_before_minim + >> dat.sum_uip1_used + >> dat.num_antecedents + >> dat.num_total_lits_antecedents + >> dat.uip1_used + >> dat.numResolutionsHistLT_avg + >> dat.glueHist_longterm_avg + >> dat.conflSizeHistLT_avg + >> dat.branchDepthHistQueue_avg + >> dat.act_ranking_rel + >> dat.size + >> dat.sumConflicts + >> dat.correct_val + )) { + assert(false); + } + return true; +} + +float get_predict(Clause* cl, const Dat& dat, predict_type pred_type) +{ + cl->stats.props_made = dat.props_made; + cl->stats.orig_glue = dat.orig_glue; + cl->stats.numResolutionsHistLT_avg = dat.numResolutionsHistLT_avg; + cl->stats.glue_before_minim = dat.glue_before_minim; + cl->stats.sum_uip1_used = dat.sum_uip1_used; + cl->stats.glue = dat.glue; + cl->stats.num_antecedents = dat.num_antecedents; + cl->stats.num_total_lits_antecedents = dat.num_total_lits_antecedents; + cl->stats.glueHist_longterm_avg = dat.glueHist_longterm_avg; +// cl->stats.conflSizeHistLT_avg = dat.conflSizeHistLT_avg; +// cl->stats.branchDepthHistQueue_avg = dat.branchDepthHistQueue_avg; + cl->stats.uip1_used = dat.uip1_used; + cl->resize(dat.size); + + + ReduceCommonData commondata(0, 0, 0, 0, 0); + float val = pred->predict( + pred_type, + cl, + dat.sumConflicts, //this is the age + dat.act_ranking_rel, + 0, + 0, + commondata + ); + return val; +} + +void run_one(string fname, predict_type pred_type) +{ + vector lits; + lits.resize(5000); + Clause* cl; + + infile.open(fname.c_str()); + if (!infile) { + cout << "ERROR: couldn't open file " << fname << endl; + exit(-1); + } + BASE_DATA_TYPE* mem = (BASE_DATA_TYPE*) malloc((5000+1000)*sizeof(BASE_DATA_TYPE)); + + double error = 0; + uint32_t num_done = 0; + while(true) { + Dat dat; + cl = new (mem) Clause(lits, 0); + bool ok = get_val(dat); + if (!ok) { + break; + } + num_done++; +// dat.print(); + float pred = get_predict(cl, dat, pred_type); +// cout << "predicted: " << pred << endl; +// cout << " --- " << endl; + error += std::pow(pred-dat.correct_val,2); + + } + free(mem); + cout << "For file " << fname << " error is: " << error/(double)num_done << " done: " << num_done << endl; + infile.close(); +} + +int main() +{ + pred = new ClPredictors; + string base = "../src/predict/"; + string s = "predictor_short.json"; + string l = "predictor_long.json"; + string f = "predictor_forever.json"; + pred->load_models(base+s, base+l, base+f); + + run_one("ml_perf_test.txt-short", predict_type::short_pred); + run_one("ml_perf_test.txt-long", predict_type::long_pred); + run_one("ml_perf_test.txt-forever", predict_type::forever_pred); + + delete pred; + return 0; +} diff --git a/cryptominisat/cppsrc/tests/multisol_test.cpp b/cryptominisat/cppsrc/tests/multisol_test.cpp new file mode 100644 index 00000000..daba7ff7 --- /dev/null +++ b/cryptominisat/cppsrc/tests/multisol_test.cpp @@ -0,0 +1,84 @@ +/****************************************** +Copyright (C) 2009-2020 Authors of CryptoMiniSat, see AUTHORS file + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. +***********************************************/ + +// How To compile on Linux: +// 1) compile cryptominsat +// 2) install cryptominisat: sudo make install +// 3) run ldconfig: sudo ldconfig +// 4) build: g++ -std=c++11 readme_test.cpp -lcryptominisat5 -o readme_test +// 5) run: ./readme_test + +#include +#include +#include +using std::vector; +using namespace CMSat; + +int main() +{ + SATSolver solver; + vector clause; + + //We need 3 variables + solver.new_var(); + solver.new_var(); + solver.new_var(); + + //adds "1 0" + clause.push_back(Lit(0, false)); + solver.add_clause(clause); + + //adds "-1 2 3 0" + clause.clear(); + clause.push_back(Lit(0, true)); + clause.push_back(Lit(1, false)); + clause.push_back(Lit(2, false)); + solver.add_clause(clause); + + lbool ret = l_True; + while(ret == l_True) { + ret = solver.solve(); + if (ret == l_True) { + std::cout + << "Solution is: " + << solver.get_model()[0] + << ", " << solver.get_model()[1] + << ", " << solver.get_model()[2] + << std::endl; + + clause.clear(); + for(size_t i = 0; i < 3; i++) { + if (solver.get_model()[i] != l_Undef) { + clause.push_back(Lit(i, solver.get_model()[i] == l_True)); + } + } + solver.add_clause(clause); + } else if (ret == l_False) { + std::cout << "No more solutions." << std::endl; + } else { + std::cout << "Solver returned that it didn't finish running." + "maybe you put a limit on its runtime?" << std::endl; + } + } + + return 0; +} diff --git a/cryptominisat/cppsrc/tests/pbsugar b/cryptominisat/cppsrc/tests/pbsugar new file mode 160000 index 00000000..3441462e --- /dev/null +++ b/cryptominisat/cppsrc/tests/pbsugar @@ -0,0 +1 @@ +Subproject commit 3441462ed0af5f3d7d2b6a7ce55938ae305f34f4 diff --git a/cryptominisat/cppsrc/tests/readme_test.cpp b/cryptominisat/cppsrc/tests/readme_test.cpp new file mode 100644 index 00000000..6242138c --- /dev/null +++ b/cryptominisat/cppsrc/tests/readme_test.cpp @@ -0,0 +1,76 @@ +/****************************************** +Copyright (C) 2009-2020 Authors of CryptoMiniSat, see AUTHORS file + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. +***********************************************/ + +// How To compile on Linux: +// 1) compile cryptominsat +// 2) install cryptominisat: sudo make install +// 3) run ldconfig: sudo ldconfig +// 4) build: g++ -std=c++11 readme_test.cpp -lcryptominisat5 -o readme_test +// 5) run: ./readme_test + +#include "cryptominisat5/cryptominisat.h" +#include +#include +using std::vector; +using namespace CMSat; + +int main() +{ + SATSolver solver; + vector clause; + + //Let's use 4 threads + solver.set_num_threads(4); + + //We need 3 variables + solver.new_vars(3); + + //adds "1 0" + clause.push_back(Lit(0, false)); + solver.add_clause(clause); + + //adds "-2 0" + clause.clear(); + clause.push_back(Lit(1, true)); + solver.add_clause(clause); + + //adds "-1 2 3 0" + clause.clear(); + clause.push_back(Lit(0, true)); + clause.push_back(Lit(1, false)); + clause.push_back(Lit(2, false)); + solver.add_clause(clause); + + lbool ret = solver.solve(); + assert(ret == l_True); + assert(solver.get_model()[0] == l_True); + assert(solver.get_model()[1] == l_False); + assert(solver.get_model()[2] == l_True); + std::cout + << "Solution is: " + << solver.get_model()[0] + << ", " << solver.get_model()[1] + << ", " << solver.get_model()[2] + << std::endl; + + return 0; +} diff --git a/cryptominisat/cppsrc/tests/scc_test.cpp b/cryptominisat/cppsrc/tests/scc_test.cpp new file mode 100644 index 00000000..72b2f56b --- /dev/null +++ b/cryptominisat/cppsrc/tests/scc_test.cpp @@ -0,0 +1,190 @@ +/****************************************** +Copyright (C) 2009-2020 Authors of CryptoMiniSat, see AUTHORS file + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. +***********************************************/ + +#include "gtest/gtest.h" + +#include +#include + +#include "src/solver.h" +#include "src/sccfinder.h" +#include "src/solverconf.h" +using namespace CMSat; +#include "test_helper.h" + +TEST(scc_test, find_1) +{ + SolverConf conf; + + std::unique_ptr> tmp(new std::atomic(false)); + Solver s(&conf, tmp.get()); + s.new_vars(2); + s.add_clause_outside(str_to_cl("1, 2")); + s.add_clause_outside(str_to_cl("-1, -2")); + + SCCFinder scc(&s); + scc.performSCC(); + EXPECT_EQ(scc.get_binxors().size(), 1U); +} + +TEST(scc_test, find_2) +{ + SolverConf conf; + + std::unique_ptr> tmp(new std::atomic(false)); + Solver s(&conf, tmp.get()); + s.new_vars(4); + s.add_clause_outside(str_to_cl("1, 2")); + s.add_clause_outside(str_to_cl("-1, -2")); + + s.add_clause_outside(str_to_cl("3, 4")); + s.add_clause_outside(str_to_cl("-3, -4")); + + SCCFinder scc(&s); + scc.performSCC(); + EXPECT_EQ(scc.get_binxors().size(), 2U); +} + +TEST(scc_test, find_circle_3) +{ + SolverConf conf; + + std::unique_ptr> tmp(new std::atomic(false)); + Solver s(&conf, tmp.get()); + s.new_vars(4); + s.add_clause_outside(str_to_cl("1, -2")); + s.add_clause_outside(str_to_cl("2, -3")); + s.add_clause_outside(str_to_cl("3, -1")); + + SCCFinder scc(&s); + scc.performSCC(); + EXPECT_EQ(scc.get_binxors().size(), 3U); +} + +TEST(scc_test, find_two_circle2_3) +{ + SolverConf conf; + + std::unique_ptr> tmp(new std::atomic(false)); + Solver s(&conf, tmp.get()); + s.new_vars(6); + s.add_clause_outside(str_to_cl("1, -2")); + s.add_clause_outside(str_to_cl("2, -3")); + s.add_clause_outside(str_to_cl("3, -1")); + + s.add_clause_outside(str_to_cl("4, -5")); + s.add_clause_outside(str_to_cl("5, -6")); + s.add_clause_outside(str_to_cl("6, -4")); + + SCCFinder scc(&s); + scc.performSCC(); + EXPECT_EQ(scc.get_binxors().size(), 6U); +} + +TEST(scc_test, find_1_diff) +{ + SolverConf conf; + + std::unique_ptr> tmp(new std::atomic(false)); + Solver s(&conf, tmp.get()); + s.new_vars(2); + s.add_clause_outside(str_to_cl("1, 2")); + s.add_clause_outside(str_to_cl("-1, -2")); + s.add_clause_outside(str_to_cl("1, -2")); + + SCCFinder scc(&s); + scc.performSCC(); + EXPECT_EQ(scc.get_binxors().size(), 1U); +} + +TEST(scc_test, find_0) +{ + SolverConf conf; + + std::unique_ptr> tmp(new std::atomic(false)); + Solver s(&conf, tmp.get()); + s.new_vars(4); + s.add_clause_outside(str_to_cl("1, 2")); + s.add_clause_outside(str_to_cl("1, -2")); + s.add_clause_outside(str_to_cl("3, -4")); + + SCCFinder scc(&s); + scc.performSCC(); + EXPECT_EQ(scc.get_binxors().size(), 0U); +} + + +TEST(scc_test, limit_test4) +{ + SolverConf conf; + conf.max_scc_depth = 4; + + std::unique_ptr> tmp(new std::atomic(false)); + Solver s(&conf, tmp.get()); + s.new_vars(4); + s.add_clause_outside(str_to_cl("1, 2")); + s.add_clause_outside(str_to_cl("-2, 3")); + s.add_clause_outside(str_to_cl("-3, -1")); + + SCCFinder scc(&s); + scc.performSCC(); + EXPECT_EQ(scc.get_binxors().size(), 3U); +} + +TEST(scc_test, limit_test3) +{ + SolverConf conf; + conf.max_scc_depth = 3; + + std::unique_ptr> tmp(new std::atomic(false)); + Solver s(&conf, tmp.get()); + s.new_vars(4); + s.add_clause_outside(str_to_cl("1, 2")); + s.add_clause_outside(str_to_cl("-2, 3")); + s.add_clause_outside(str_to_cl("-3, -1")); + + SCCFinder scc(&s); + scc.performSCC(); + EXPECT_EQ(scc.get_binxors().size(), 0U); +} + +TEST(scc_test, limit_test2) +{ + SolverConf conf; + conf.max_scc_depth = 2; + + std::unique_ptr> tmp(new std::atomic(false)); + Solver s(&conf, tmp.get()); + s.new_vars(4); + s.add_clause_outside(str_to_cl("1, 2")); + s.add_clause_outside(str_to_cl("-2, 3")); + s.add_clause_outside(str_to_cl("-3, -1")); + + SCCFinder scc(&s); + scc.performSCC(); + EXPECT_EQ(scc.get_binxors().size(), 0U); +} + +int main(int argc, char **argv) { + ::testing::InitGoogleTest(&argc, argv); + return RUN_ALL_TESTS(); +} diff --git a/cryptominisat/cppsrc/tests/searcher_test.cpp b/cryptominisat/cppsrc/tests/searcher_test.cpp new file mode 100644 index 00000000..56cd0aa9 --- /dev/null +++ b/cryptominisat/cppsrc/tests/searcher_test.cpp @@ -0,0 +1,114 @@ +/****************************************** +Copyright (C) 2009-2020 Authors of CryptoMiniSat, see AUTHORS file + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. +***********************************************/ + +#include "gtest/gtest.h" + +#include +using std::set; + +#include "src/solver.h" +#include "src/solverconf.h" +using namespace CMSat; +#include "test_helper.h" + +namespace CMSat { +struct SearcherTest : public ::testing::Test { + SearcherTest() + { + must_inter.store(false, std::memory_order_relaxed); + } + ~SearcherTest() + { + delete s; + } + + void set_var_polar(uint32_t var, bool polarity) + { + s->new_decision_level(); + //it must be inverted to set + s->enqueue(Lit(var, !polarity)); + s->cancelUntil(0); + } + + SolverConf conf; + Solver* s = NULL; + Searcher* ss = NULL; + std::vector vars; + std::atomic must_inter; +}; + +//Regular, 1UIP fails + +TEST_F(SearcherTest, pickpolar_rnd) +{ + conf.polarity_mode = PolarityMode::polarmode_rnd; + s = new Solver(&conf, &must_inter); + s->new_vars(30); + ss = (Searcher*)s; + + s->add_clause_outside(str_to_cl(" 1, 2")); + + uint32_t num = 0; + for(uint32_t i = 0 ; i < 1000000; i++) + num += (unsigned)ss->pick_polarity(0); + + //Not far off from avg + ASSERT_GT(num, 400000U); + ASSERT_LT(num, 600000U); +} + +TEST_F(SearcherTest, pickpolar_pos) +{ + conf.polarity_mode = PolarityMode::polarmode_pos; + s = new Solver(&conf, &must_inter); + s->new_vars(30); + ss = (Searcher*)s; + s->add_clause_outside(str_to_cl(" 1, 2")); + + uint32_t num = 0; + for(uint32_t i = 0 ; i < 100000; i++) + num += (unsigned)ss->pick_polarity(0); + + ASSERT_EQ(num, 100000U); +} + +TEST_F(SearcherTest, pickpolar_neg) +{ + conf.polarity_mode = PolarityMode::polarmode_neg; + s = new Solver(&conf, &must_inter); + s->new_vars(30); + ss = (Searcher*)s; + s->add_clause_outside(str_to_cl(" 1, 2")); + + uint32_t num = 0; + for(uint32_t i = 0 ; i < 100000; i++) + num += (unsigned)ss->pick_polarity(0); + + ASSERT_EQ(num, 0U); +} + +} + +int main(int argc, char **argv) { + ::testing::InitGoogleTest(&argc, argv); + return RUN_ALL_TESTS(); +} diff --git a/cryptominisat/cppsrc/tests/simp-checks/CMakeLists.txt b/cryptominisat/cppsrc/tests/simp-checks/CMakeLists.txt new file mode 100644 index 00000000..38a58b66 --- /dev/null +++ b/cryptominisat/cppsrc/tests/simp-checks/CMakeLists.txt @@ -0,0 +1,33 @@ +# Copyright (C) 2009-2020 Authors of CryptoMiniSat, see AUTHORS file +# +# Permission is hereby granted, free of charge, to any person obtaining a copy +# of this software and associated documentation files (the "Software"), to deal +# in the Software without restriction, including without limitation the rights +# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +# copies of the Software, and to permit persons to whom the Software is +# furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in +# all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +# THE SOFTWARE. + +# disable, it's too slow +# if (ENABLE_TESTING AND NOT MSVC AND NOT SLOW_DEBUG) +# add_test ( +# NAME simp_checks +# COMMAND "${Python3_EXECUTABLE}" +# "${CMAKE_CURRENT_SOURCE_DIR}/check_bve.py" +# "--minisat" $ +# "--cms" $ +# "--threads" "1" +# "${CMAKE_CURRENT_SOURCE_DIR}/simplifiy_testfiles/" +# WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} +# ) +# endif() diff --git a/cryptominisat/cppsrc/tests/simp-checks/check_bve.py b/cryptominisat/cppsrc/tests/simp-checks/check_bve.py new file mode 100755 index 00000000..d6353434 --- /dev/null +++ b/cryptominisat/cppsrc/tests/simp-checks/check_bve.py @@ -0,0 +1,238 @@ +#!/usr/bin/env python3 +# -*- coding: utf-8 -*- + +# Copyright (C) 2009-2020 Authors of CryptoMiniSat, see AUTHORS file +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; version 2 +# of the License. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +# 02110-1301, USA. + +from __future__ import print_function +import os +import optparse +import subprocess +import time +import gzip +import threading +import glob + + +class PlainHelpFormatter(optparse.IndentedHelpFormatter): + + def format_description(self, description): + if description: + return description + "\n" + else: + return "" + +usage = "usage: %prog [options] cryptominisat5-binary testfile(s)" +desc = """Test solver against some problems +""" + +parser = optparse.OptionParser(usage=usage, description=desc, + formatter=PlainHelpFormatter()) + +parser.add_option("--verbose", "-v", action="store_true", default=False, + dest="verbose", help="Print more output") +parser.add_option("--threads", "-t", default=4, type=int, + dest="threads", help="Number of threads") +parser.add_option("--minisat", type=str, + dest="minisat_exe", help="MiniSat location") +parser.add_option("--cms", type=str, + dest="cms_exe", help="CryptoMiniSat location") + + +(options, args) = parser.parse_args() +print_lock = threading.Lock() +todo_lock = threading.Lock() + +if len(args) < 1: + print("ERROR: You must call this script with at least one argument, a file to check") + exit(-1) + + +def go_through_cnf(f): + for line in f: + line = line.decode('ascii').strip() + if len(line) == 0: + continue + if line[0] == "p": + line = line.split() + assert line[1].strip() == "cnf" + assert line[2].isdigit() + return int(line[2]) + + assert False + + +def find_num_vars(fname): + + try: + with gzip.open(fname, 'rb') as f: + maxvar = go_through_cnf(f) + except IOError: + with open(fname, 'rb') as f: + maxvar = go_through_cnf(f) + + return maxvar + +todo = [] +exitnum = 0 + + +class MyThread(threading.Thread): + def __init__(self, threadID, extraopts): + threading.Thread.__init__(self) + self.threadID = threadID + self.extraopts = extraopts + + def run(self): + global todo + global exitnum + while len(todo) > 0: + with todo_lock: + fname = todo[0] + todo = todo[1:] + + if options.verbose: + with print_lock: + print("Thread %d pikced up %s" % (self.threadID, fname)) + + ret = self.test_velim_one_file(fname) + + with todo_lock: + exitnum |= ret + + if options.verbose: + with print_lock: + print("Finished thread %d" % self.threadID) + + def test_velim_one_file(self, fname): + orig_num_vars = find_num_vars(fname) + + simp_fname = "simp.out-%d" % self.threadID + try: + os.unlink(simp_fname) + except: + pass + + toprint = "" + + toexec = [options.cms_exe, "--zero-exit-status", + "--preproc", "1", "--verb", "0"] + toexec.extend(self.extraopts) + toexec.extend([fname, simp_fname]) + + toprint += "Executing: %s\n" % toexec + with print_lock: + print(toprint) + toprint = "" + + start = time.time() + cms_out_fname = "cms-%s.out" % os.path.split(fname)[1] + try: + with open(cms_out_fname, "w") as f: + subprocess.check_call(" ".join(toexec), stdout=f, shell=True) + except subprocess.CalledProcessError: + toprint += "*** ERROR CryptoMiniSat errored out!\n" + with print_lock: + print(toprint) + exit(-1) + return -1 + t_cms = time.time()-start + num_vars_after_cms_preproc = find_num_vars(simp_fname) + + start = time.time() + toexec = [options.minisat_exe, fname] + toprint += "Executing: %s\n" % toexec + minisat_out_fname = "minisat_elim_data.out-%d" % self.threadID + try: + with open(minisat_out_fname, "w") as f: + subprocess.check_call(" ".join(toexec), stdout=f, shell=True) + except subprocess.CalledProcessError: + toprint += "** Minisat errored out...\n" + with print_lock: + print(toprint) + exit(-1) + return -1 + t_msat = time.time()-start + + var_elimed = None + num_vars_after_ms_preproc = None + with open(minisat_out_fname, "r") as f: + for line in f: + line = line.strip() + if "num-vars-eliminated" in line: + var_elimed = int(line.split()[1]) + if "num-free-vars" in line: + num_vars_after_ms_preproc = int(line.split()[1]) + + assert var_elimed is not None, "Couldn't find var-elimed line, out: %s" % toprint + assert num_vars_after_ms_preproc is not None, "Couldn't find num-free-vars line, out: %s" % toprint + + toprint += "-> orig num vars: %d\n" % orig_num_vars + toprint += "-> T-cms : %-4.2f free vars after: %-9d\n" % (t_cms, num_vars_after_cms_preproc) + toprint += "-> T-msat: %-4.2f free vars after: %-9d\n" % (t_msat, num_vars_after_ms_preproc) + diff = num_vars_after_cms_preproc - num_vars_after_ms_preproc + limit = float(orig_num_vars)*0.05 + if diff < limit*8 and t_msat > t_cms*4 and t_msat > 20: + toprint += " * MiniSat didn't timeout, but we did, acceptable difference.\n" + with print_lock: + print(toprint) + return 0 + + if diff > limit: + toprint += "*** ERROR: No. vars difference %d is more than 5%% " % diff + toprint += "of original no. of vars, %d\n" % limit + with print_lock: + print(toprint) + return 1 + + toprint += "------------------[ thread %d ]------------------------" % self.threadID + + with print_lock: + print(toprint) + + return 0 + + +def test(extraopts): + global exitnum + exitnum = 0 + global todo + assert os.path.isdir(args[0]) + path = os.path.join(args[0], '') + todo = glob.glob(path+"/*.cnf.gz") + + threads = [] + for i in range(options.threads): + threads.append(MyThread(i, extraopts)) + + for t in threads: + t.start() + + for t in threads: + t.join() + + if exitnum == 0: + print("ALL PASSED") + else: + print("SOME CHECKS FAILED") + + return exitnum + +if __name__ == "__main__": + test(["--preschedule", "occ-bve,must-renumber"]) + if exitnum != 0: + exit(exitnum) diff --git a/cryptominisat/cppsrc/tests/simp-checks/simplifiy_testfiles b/cryptominisat/cppsrc/tests/simp-checks/simplifiy_testfiles new file mode 160000 index 00000000..345531cc --- /dev/null +++ b/cryptominisat/cppsrc/tests/simp-checks/simplifiy_testfiles @@ -0,0 +1 @@ +Subproject commit 345531cca666687830df6f57192e51d1f6ac52cc diff --git a/cryptominisat/cppsrc/tests/solver_test.cpp b/cryptominisat/cppsrc/tests/solver_test.cpp new file mode 100644 index 00000000..dc617444 --- /dev/null +++ b/cryptominisat/cppsrc/tests/solver_test.cpp @@ -0,0 +1,277 @@ +/****************************************** +Copyright (C) 2009-2020 Authors of CryptoMiniSat, see AUTHORS file + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. +***********************************************/ + +#include "gtest/gtest.h" + +#include +using std::set; + +#include "src/solver.h" +#include "src/solverconf.h" +using namespace CMSat; +#include "test_helper.h" + +namespace CMSat { +struct SolverTest : public ::testing::Test { + SolverTest() + { + must_inter.store(false, std::memory_order_relaxed); + } + ~SolverTest() + { + delete s; + } + + SolverConf conf; + Solver* s = NULL; + std::vector vars; + std::atomic must_inter; +}; + +TEST_F(SolverTest, get_bin) +{ + s = new Solver(&conf, &must_inter); + s->new_vars(30); + s->add_clause_outside(str_to_cl(" 2, 3")); + s->add_clause_int(str_to_cl(" 1, 2"), true); + + s->start_getting_small_clauses(2, 100); + vector lits; + bool ret = s->get_next_small_clause(lits, false); + ASSERT_TRUE(ret); + std::sort(lits.begin(), lits.end()); + ASSERT_EQ(lits, str_to_cl(" 1, 2")); + + ret = s->get_next_small_clause(lits, false); + ASSERT_FALSE(ret); + + s->end_getting_small_clauses(); +} + +TEST_F(SolverTest, get_long_lev0) +{ + Clause* c; + s = new Solver(&conf, &must_inter); + s->new_vars(30); + ClauseStats stats; + stats.glue = 5; + + s->add_clause_outside(str_to_cl(" 2, 3")); + c = s->add_clause_int(str_to_cl(" 1, 2, 3, 4"), true, &stats); + assert(c != NULL); + s->longRedCls[0].push_back(s->cl_alloc.get_offset(c)); + + s->start_getting_small_clauses(10, 100); + vector lits; + + bool ret = s->get_next_small_clause(lits, false); + ASSERT_TRUE(ret); + std::sort(lits.begin(), lits.end()); + ASSERT_EQ(lits, str_to_cl(" 1, 2, 3, 4")); + + ret = s->get_next_small_clause(lits, false); + ASSERT_FALSE(ret); + + s->end_getting_small_clauses(); +} + + +TEST_F(SolverTest, get_long_lev1) +{ + Clause* c; + s = new Solver(&conf, &must_inter); + s->new_vars(30); + ClauseStats stats; + stats.glue = 5; + + s->add_clause_outside(str_to_cl(" 2, 3")); + c = s->add_clause_int(str_to_cl(" 6, 2, 3, 4"), true, &stats); + assert(c != NULL); + s->longRedCls[1].push_back(s->cl_alloc.get_offset(c)); + + s->start_getting_small_clauses(10, 100); + vector lits; + + bool ret = s->get_next_small_clause(lits, false); + ASSERT_TRUE(ret); + std::sort(lits.begin(), lits.end()); + ASSERT_EQ(lits, str_to_cl(" 6, 2, 3, 4")); + + ret = s->get_next_small_clause(lits, false); + ASSERT_FALSE(ret); + + s->end_getting_small_clauses(); +} + +TEST_F(SolverTest, get_long_lev0_and_lev1) +{ + Clause* c; + s = new Solver(&conf, &must_inter); + s->new_vars(30); + ClauseStats stats; + stats.glue = 5; + + s->add_clause_outside(str_to_cl(" 2, 3")); + + c = s->add_clause_int(str_to_cl(" 3, -4, -7"), true, &stats); + assert(c != NULL); + s->longRedCls[1].push_back(s->cl_alloc.get_offset(c)); + + c = s->add_clause_int(str_to_cl(" 2, 4, 5, 6"), true, &stats); + assert(c != NULL); + s->longRedCls[0].push_back(s->cl_alloc.get_offset(c)); + + s->start_getting_small_clauses(10, 100); + vector lits; + + //Order is reverse because we get lev0 then lev1 + bool ret = s->get_next_small_clause(lits, false); + ASSERT_TRUE(ret); + std::sort(lits.begin(), lits.end()); + ASSERT_EQ(lits, str_to_cl(" 2, 4, 5, 6")); + + ret = s->get_next_small_clause(lits, false); + ASSERT_TRUE(ret); + std::sort(lits.begin(), lits.end()); + ASSERT_EQ(lits, str_to_cl(" 3, -4, -7")); + + ret = s->get_next_small_clause(lits, false); + ASSERT_FALSE(ret); + + s->end_getting_small_clauses(); +} + +TEST_F(SolverTest, get_long_toolarge) +{ + Clause* c; + s = new Solver(&conf, &must_inter); + s->new_vars(30); + ClauseStats stats; + stats.glue = 5; + + s->add_clause_outside(str_to_cl(" 2, 3")); + c = s->add_clause_int(str_to_cl(" 1, 2, 3, 4"), true, &stats); + assert(c != NULL); + s->longRedCls[0].push_back(s->cl_alloc.get_offset(c)); + + s->start_getting_small_clauses(2, 100); + vector lits; + + bool ret = s->get_next_small_clause(lits, false); + ASSERT_FALSE(ret); + + s->end_getting_small_clauses(); +} + +TEST_F(SolverTest, get_glue_toolarge) +{ + Clause* c; + s = new Solver(&conf, &must_inter); + s->new_vars(30); + ClauseStats stats; + stats.glue = 20; + + s->add_clause_outside(str_to_cl(" 2, 3")); + c = s->add_clause_int(str_to_cl(" 1, 2, 3, 4"), true, &stats); + assert(c != NULL); + s->longRedCls[0].push_back(s->cl_alloc.get_offset(c)); + + s->start_getting_small_clauses(100, 2); + vector lits; + + bool ret = s->get_next_small_clause(lits, false); + ASSERT_FALSE(ret); + + s->end_getting_small_clauses(); +} + +TEST_F(SolverTest, get_bin_and_long) +{ + s = new Solver(&conf, &must_inter); + s->new_vars(30); + ClauseStats stats; + stats.glue = 5; + + s->add_clause_outside(str_to_cl(" 2, 3")); + Clause* c; + c = s->add_clause_int(str_to_cl(" 1, 5 "), true); + assert(c == NULL); + c = s->add_clause_int(str_to_cl(" 1, 2, 3, 4"), true, &stats); + assert(c != NULL); + s->longRedCls[0].push_back(s->cl_alloc.get_offset(c)); + + s->start_getting_small_clauses(4, 100); + vector lits; + + bool ret = s->get_next_small_clause(lits, false); + ASSERT_TRUE(ret); + std::sort(lits.begin(), lits.end()); + ASSERT_EQ(lits, str_to_cl(" 1, 5")); + + ret = s->get_next_small_clause(lits, false); + ASSERT_TRUE(ret); + std::sort(lits.begin(), lits.end()); + ASSERT_EQ(lits, str_to_cl(" 1, 2, 3, 4")); + + ret = s->get_next_small_clause(lits, false); + ASSERT_FALSE(ret); + + s->end_getting_small_clauses(); +} + +TEST_F(SolverTest, get_irred_bin_and_long) +{ + s = new Solver(&conf, &must_inter); + s->new_vars(30); + + Clause* c; + c = s->add_clause_int(str_to_cl(" 1, 5 ")); + assert(c == NULL); + c = s->add_clause_int(str_to_cl(" 1, 2, 3, 4")); + assert(c != NULL); + s->longIrredCls.push_back(s->cl_alloc.get_offset(c)); + + s->start_getting_small_clauses(4, 100, false); + vector lits; + + bool ret = s->get_next_small_clause(lits, false); + ASSERT_TRUE(ret); + std::sort(lits.begin(), lits.end()); + ASSERT_EQ(str_to_cl(" 1, 5"), lits); + + ret = s->get_next_small_clause(lits, false); + ASSERT_TRUE(ret); + std::sort(lits.begin(), lits.end()); + ASSERT_EQ(str_to_cl(" 1, 2, 3, 4"), lits); + + ret = s->get_next_small_clause(lits, false); + ASSERT_FALSE(ret); + + s->end_getting_small_clauses(); +} + +} + +int main(int argc, char **argv) { + ::testing::InitGoogleTest(&argc, argv); + return RUN_ALL_TESTS(); +} diff --git a/cryptominisat/cppsrc/tests/stp_test.cpp b/cryptominisat/cppsrc/tests/stp_test.cpp new file mode 100644 index 00000000..3b4debf1 --- /dev/null +++ b/cryptominisat/cppsrc/tests/stp_test.cpp @@ -0,0 +1,129 @@ +/****************************************** +Copyright (C) 2009-2020 Authors of CryptoMiniSat, see AUTHORS file + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. +***********************************************/ + +#include "gtest/gtest.h" + +#include + +#include "cryptominisat5/cryptominisat.h" +#include "src/solverconf.h" +using namespace CMSat; +#include "test_helper.h" + +void add_clauses_for_simp_check(SATSolver& s) +{ + s.new_vars(4); + + // 1 = 2 + s.add_clause(str_to_cl("1, -2")); + s.add_clause(str_to_cl("-1, 2")); + + // 3 = 4 + s.add_clause(str_to_cl("3, -4")); + s.add_clause(str_to_cl("-3, 4")); + + //no elimination + s.add_clause(str_to_cl("3, 2")); + s.add_clause(str_to_cl("4, 1")); +} + +TEST(stp_test, no_simp_at_startup) +{ + SATSolver s; + s.set_no_simplify(); + add_clauses_for_simp_check(s); + + s.solve(); + auto eq_xors = s.get_all_binary_xors(); + EXPECT_EQ(eq_xors.size(), 0U); +} + +// Needs to be re-written when we can query clauses from the solver +// TEST(stp_test, simp_at_startup) +// { +// SATSolver s; +// add_clauses_for_simp_check(s); +// +// s.solve(); +// auto eq_xors = s.get_all_binary_xors(); +// EXPECT_EQ(eq_xors.size(), 2U); +// } + +TEST(stp_test, set_num_threads_true) +{ + SATSolver s; + s.set_num_threads(5); + s.new_vars(2); + s.add_clause(str_to_cl("1,2")); + s.add_clause(str_to_cl("1,-2")); + + lbool ret = s.solve(); + EXPECT_EQ(ret, l_True); + EXPECT_EQ(s.get_model()[0], l_True); +} + +TEST(stp_test, set_num_threads_false) +{ + SATSolver s; + s.set_no_simplify_at_startup(); + s.set_num_threads(5); + s.new_vars(2); + s.add_clause(str_to_cl("1,2")); + s.add_clause(str_to_cl("1,-2")); + s.add_clause(str_to_cl("-1,2")); + s.add_clause(str_to_cl("-1,-2")); + lbool ret = s.solve(); + EXPECT_EQ(ret, l_False); +} + +TEST(stp_test, default_polar_false) +{ + SATSolver s; + s.set_no_simplify_at_startup(); + s.set_default_polarity(false); + s.new_vars(4); + s.add_clause(str_to_cl("-1, -2, -3, -4")); + lbool ret = s.solve(); + EXPECT_EQ(ret, l_True); + for(size_t i = 0; i < 4; i++) { + EXPECT_EQ(s.get_model()[0], l_False); + } +} + +TEST(stp_test, default_polar_true) +{ + SATSolver s; + s.set_no_simplify_at_startup(); + s.set_default_polarity(true); + s.new_vars(4); + s.add_clause(str_to_cl("1, 2, 3, 4")); + lbool ret = s.solve(); + EXPECT_EQ(ret, l_True); + for(size_t i = 0; i < 4; i++) { + EXPECT_EQ(s.get_model()[0], l_True); + } +} + +int main(int argc, char **argv) { + ::testing::InitGoogleTest(&argc, argv); + return RUN_ALL_TESTS(); +} diff --git a/cryptominisat/cppsrc/tests/subsume_impl_test.cpp b/cryptominisat/cppsrc/tests/subsume_impl_test.cpp new file mode 100644 index 00000000..24bf3ad0 --- /dev/null +++ b/cryptominisat/cppsrc/tests/subsume_impl_test.cpp @@ -0,0 +1,105 @@ +/****************************************** +Copyright (C) 2009-2020 Authors of CryptoMiniSat, see AUTHORS file + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. +***********************************************/ + +#include "gtest/gtest.h" + +#include +using std::set; + +#include "src/solver.h" +#include "src/subsumeimplicit.h" +#include "src/solverconf.h" +using namespace CMSat; +#include "test_helper.h" + +struct sub_impl : public ::testing::Test { + sub_impl() + { + must_inter.store(false, std::memory_order_relaxed); + SolverConf conf; + //conf.verbosity = 20; + s = new Solver(&conf, &must_inter); + sub = s->subsumeImplicit; + } + ~sub_impl() + { + delete s; + } + + Solver* s; + SubsumeImplicit* sub; + std::atomic must_inter; +}; + +//SUB 2-by-2 +TEST_F(sub_impl, sub_2by2_1) +{ + s->new_vars(7); + s->add_clause_outside(str_to_cl("1, -2")); + s->add_clause_outside(str_to_cl("1, -2")); + + sub->subsume_implicit(); + check_irred_cls_eq(s, "1, -2"); +} + +TEST_F(sub_impl, sub_2by2_2) +{ + s->new_vars(7); + s->add_clause_outside(str_to_cl("1, -2")); + s->add_clause_outside(str_to_cl("1, 3")); + s->add_clause_outside(str_to_cl("1, -4")); + s->add_clause_outside(str_to_cl("1, -2")); + + sub->subsume_implicit(); + check_irred_cls_eq(s, "1, -2; 1, 3; 1, -4"); +} + +TEST_F(sub_impl, sub_2by2_3) +{ + s->new_vars(7); + s->add_clause_outside(str_to_cl("2, 1")); + s->add_clause_outside(str_to_cl("2, 4")); + s->add_clause_outside(str_to_cl("1, 3")); + s->add_clause_outside(str_to_cl("1, 3")); + s->add_clause_outside(str_to_cl("-1, -3")); + s->add_clause_outside(str_to_cl("1, 2")); + + sub->subsume_implicit(); + check_irred_cls_eq(s, "1, 2; 1, 3;2, 4;-1, -3"); +} + +TEST_F(sub_impl, sub_2by2_4) +{ + s->new_vars(7); + s->add_clause_outside(str_to_cl("1, 2, 3, 4")); + s->add_clause_outside(str_to_cl("1, 4")); + s->add_clause_outside(str_to_cl("-1, 2, 4")); + s->add_clause_outside(str_to_cl("1, 4")); + + sub->subsume_implicit(); + check_irred_cls_eq(s, "1, 4; 1, 2, 3, 4;-1, 2, 4"); +} + +int main(int argc, char **argv) { + ::testing::InitGoogleTest(&argc, argv); + return RUN_ALL_TESTS(); +} diff --git a/cryptominisat/cppsrc/tests/ternary_resolve_test.cpp b/cryptominisat/cppsrc/tests/ternary_resolve_test.cpp new file mode 100644 index 00000000..f17efbac --- /dev/null +++ b/cryptominisat/cppsrc/tests/ternary_resolve_test.cpp @@ -0,0 +1,143 @@ +/****************************************** +Copyright (C) 2009-2020 Authors of CryptoMiniSat, see AUTHORS file + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. +***********************************************/ + +#include "gtest/gtest.h" + +#include + +#include "src/solver.h" +#include "src/xorfinder.h" +#include "src/solverconf.h" +#include "src/occsimplifier.h" +#include "test_helper.h" + +using namespace CMSat; + +struct ternary_resolv : public ::testing::Test { + ternary_resolv() + { + must_inter.store(false, std::memory_order_relaxed); + SolverConf conf; + conf.ternary_max_create = 2.0; + s = new Solver(&conf, &must_inter); + s->new_vars(50); + occsimp = s->occsimplifier; + } + ~ternary_resolv() + { + delete s; + } + Solver* s = NULL; + OccSimplifier* occsimp = NULL; + std::atomic must_inter; +}; + +TEST_F(ternary_resolv, do_1) +{ + s->add_clause_outside(str_to_cl("1, 2, 3")); + s->add_clause_outside(str_to_cl("1, -2, 4")); + + occsimp->setup(); + occsimp->ternary_res(); + occsimp->finishUp(0); + check_red_cls_contains(s, "1, 3, 4"); +} + +TEST_F(ternary_resolv, do_2) +{ + s->add_clause_outside(str_to_cl("1, 2, 3")); + s->add_clause_outside(str_to_cl("1, -2, 4")); + s->add_clause_outside(str_to_cl("2, -3, 5")); + + occsimp->setup(); + occsimp->ternary_res(); + occsimp->finishUp(0); + check_red_cls_contains(s, "1, 3, 4"); + check_red_cls_contains(s, "1, 2, 5"); +} + +TEST_F(ternary_resolv, do_2_v2) +{ + s->add_clause_outside(str_to_cl("1, 2, 3")); + s->add_clause_outside(str_to_cl("1, -2, 4")); + + + s->add_clause_outside(str_to_cl("10, 20, 30")); + s->add_clause_outside(str_to_cl("10, -20, 40")); + + occsimp->setup(); + occsimp->ternary_res(); + occsimp->finishUp(0); + check_red_cls_contains(s, "1, 3, 4"); + check_red_cls_contains(s, "10, 30, 40"); +} + +TEST_F(ternary_resolv, do_1_v2) +{ + s->add_clause_outside(str_to_cl("-1, 2, 3")); + s->add_clause_outside(str_to_cl("-1, -2, 4")); + + occsimp->setup(); + occsimp->ternary_res(); + occsimp->finishUp(0); + check_red_cls_contains(s, "-1, 3, 4"); +} + +TEST_F(ternary_resolv, do_1_v3) +{ + s->add_clause_outside(str_to_cl("-1, 2, 3")); + s->add_clause_outside(str_to_cl("-1, -2, -4")); + + occsimp->setup(); + occsimp->ternary_res(); + occsimp->finishUp(0); + check_red_cls_contains(s, "-1, 3, -4"); +} + +TEST_F(ternary_resolv, do_1_v4) +{ + s->add_clause_outside(str_to_cl("-1, 2, -3")); + s->add_clause_outside(str_to_cl("-1, -2, -4")); + + occsimp->setup(); + occsimp->ternary_res(); + occsimp->finishUp(0); + check_red_cls_contains(s, "-1, -3, -4"); +} + +TEST_F(ternary_resolv, only_one_v1) +{ + s->add_clause_outside(str_to_cl("1, 2, 3")); + s->add_clause_outside(str_to_cl("1, -2, 4")); + + occsimp->setup(); + occsimp->ternary_res(); + occsimp->ternary_res(); + occsimp->ternary_res(); + occsimp->finishUp(0); + EXPECT_EQ(get_num_red_cls_contains(s, "1, 3, 4"), 1); +} + +int main(int argc, char **argv) { + ::testing::InitGoogleTest(&argc, argv); + return RUN_ALL_TESTS(); +} diff --git a/cryptominisat/cppsrc/tests/test_helper.h b/cryptominisat/cppsrc/tests/test_helper.h new file mode 100644 index 00000000..ee5faee7 --- /dev/null +++ b/cryptominisat/cppsrc/tests/test_helper.h @@ -0,0 +1,672 @@ +/****************************************** +Copyright (C) 2009-2020 Authors of CryptoMiniSat, see AUTHORS file + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. +***********************************************/ + +#ifndef TEST_HELPER__H +#define TEST_HELPER__H + +#ifdef KLEE +#include +#define EXPECT_EQ(a, b) klee_assume((a) == (b)) +#define EXPECT_TRUE(a) klee_assume((a) == true) +#else +#include "gtest/gtest.h" +#endif + +#include "cryptominisat5/solvertypesmini.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include "src/solver.h" +#include "src/xor.h" +#include "cryptominisat5/cryptominisat.h" + +using std::cout; +using std::endl; +using std::vector; +using std::string; +using std::istringstream; +using std::stringstream; +using namespace CMSat; + +// trim from start +static inline std::string <rim(std::string &s) { + s.erase(s.begin(), std::find_if(s.begin(), s.end(), std::not1(std::ptr_fun(std::isspace)))); + return s; +} + +// trim from end +static inline std::string &rtrim(std::string &s) { + s.erase(std::find_if(s.rbegin(), s.rend(), std::not1(std::ptr_fun(std::isspace))).base(), s.end()); + return s; +} + +// trim from both ends +static inline std::string &trim(std::string &s) { + return ltrim(rtrim(s)); +} + +long int str_to_long_int(string& token) +{ + string trimmed = trim(token); + size_t endptr; + long i = std::stol(trimmed, &endptr); + if (endptr != trimmed.size()) { + cout << "Error, input token: '" << token << "' wasn't completely used up, wrong token!" << endl; + exit(-1); + } + return i; +} + +Lit str_to_lit(const std::string& str) +{ + string mycopy = str; + long int i = str_to_long_int(mycopy); + assert(i == (int)i); + Lit lit(std::abs(i)-1, i < 0); + return lit; +} + +vector str_to_cl(const string& data, bool sort = true) +{ + vector tokens; + stringstream ss(data); + string token; + while (getline(ss,token, ',')) + { + tokens.push_back(token); + } + + vector ret; + for(string& token2: tokens) { + token2.erase(remove_if(token2.begin(), token2.end(), isspace), token2.end()); + if (token2 == "U") { + ret.push_back(lit_Undef); + continue; + } + long int i = str_to_long_int(token2); + assert(i == (int)i); + Lit lit(std::abs(i)-1, i < 0); + ret.push_back(lit); + } + //cout << "input is: " << data << " LITs is: " << ret << endl; + + if (sort) { + std::sort(ret.begin(), ret.end()); + } + return ret; +} + +vector str_to_vars(const string& data) +{ + vector lits = str_to_cl(data); + vector vars; + for(Lit lit: lits) { + assert(lit.sign() == false); + vars.push_back(lit.var()); + } + return vars; +} + +vector str_to_xors(const string& data) +{ + vector ret; + stringstream ss(data); + string token; + while (getline(ss,token, ';')) + { + stringstream ss2(token); + string token2; + int at = 0; + bool rhs = false; + vector vars; + vector clashes; + while (getline(ss2,token2, '=')) + { + //cout << "Token is: " << token2 << endl; + if (at == 0) { + vars = str_to_vars(token2); + } + if (at == 1) { + uint32_t at2 = 0; + stringstream ss3(token2); + string token3; + //cout << "parsing token2:" << token2 << endl; + while (getline(ss3,token3, 'c')) { + if (at2 == 0) { + long r = str_to_long_int(token3); + assert(r >= 0 && r <= 1); + rhs = r; + } else if (at2 == 1) { + clashes = str_to_vars(token3); + } + assert(at2 < 2 && "We can have only at most one 'c' sign in an XOR"); + at2++; + } + } + assert(at < 2 && "We can ony have one '=' sign in an XOR"); + at++; + } + + assert(at == 2 && "You forgot the =0/1 from the XOR"); + ret.push_back(Xor(vars, rhs, clashes)); + } + + return ret; +} + +vector > str_to_vecs(const string& data) +{ + vector > ret; + stringstream ss(data); + string token; + while (getline(ss,token, ';')) + { + ret.push_back(str_to_cl(token)); + } + + return ret; +} + +void add_cls(vector >& ret, + const Solver* s, + const vector& offsets) +{ + for(auto off: offsets) { + Clause& cl = *s->cl_alloc.ptr(off); + vector lits; + for(Lit l: cl) { + lits.push_back(l); + } + std::sort(lits.begin(), lits.end()); + ret.push_back(lits); + } +} + +void add_impl_cls( + vector >& ret, + const Solver* s, + const bool add_irred, + const bool add_red) +{ + for(size_t i = 0; i < s->nVars()*2; i++) { + Lit lit = Lit::toLit(i); + for(const Watched& ws: s->watches[lit]) { + if (ws.isBin() + && lit < ws.lit2() + && ((add_irred && !ws.red()) || (add_red && ws.red())) + ) { + vector cl; + cl.push_back(lit); + cl.push_back(ws.lit2()); + ret.push_back(cl); + } + } + } +} + +vector > get_irred_cls(const Solver* s) +{ + vector > ret; + add_cls(ret, s, s->longIrredCls); + add_impl_cls(ret, s, true, false); + + return ret; +} + + +vector > get_red_cls(const Solver* s) +{ + vector > ret; + add_cls(ret, s, s->longRedCls[0]); + add_cls(ret, s, s->longRedCls[1]); + add_cls(ret, s, s->longRedCls[2]); + add_impl_cls(ret, s, false, true); + + return ret; +} + +struct VecVecSorter +{ + bool operator()(const vector&a, const vector& b) const + { + if (a.size() != b.size()) { + return a.size() < b.size(); + } + + for(size_t i = 0; i < a.size(); i++) { + if (a[i] != b[i]) { + return a[i] < b[i]; + } + } + return false; + } +}; + +void check_fuzzy_equal( + vector >& cls_expected, + vector >& cls_actual) +{ + for(vector& x: cls_actual) { + std::sort(x.begin(), x.end()); + } + for(vector& x: cls_expected) { + std::sort(x.begin(), x.end()); + } + + VecVecSorter sorter; + std::sort(cls_actual.begin(), cls_actual.end(), sorter); + std::sort(cls_expected.begin(), cls_expected.end(), sorter); + + EXPECT_EQ(cls_expected, cls_actual); +} + +string print(const vector >& cls) +{ + std::stringstream ss; + for(const auto& cl: cls) { + ss << cl << endl; + } + return ss.str(); +} + +void check_irred_cls_eq(const Solver* s, const string& data) +{ + vector > cls_expected = str_to_vecs(data); + vector > cls = get_irred_cls(s); + + check_fuzzy_equal(cls_expected, cls); +} + +void check_red_cls_eq(const Solver* s, const string& data) +{ + vector > cls_expected = str_to_vecs(data); + vector > cls = get_red_cls(s); + + check_fuzzy_equal(cls_expected, cls); +} + +void check_irred_cls_contains(const Solver* s, const string& data) +{ + vector looking_for = str_to_cl(data); + vector > cls = get_irred_cls(s); + + bool found_cl = false; + for(const auto& cl: cls) { + if (cl == looking_for) { + found_cl = true; + break; + } + + } + if (!found_cl) { + cout << "Expected to find: " << looking_for << endl; + cout << "But only found : "; + for(const auto& cl: cls) { + cout << cl << ", "; + } + cout << endl; + } + EXPECT_TRUE(found_cl); +} + + +void check_red_cls_contains(const Solver* s, const string& data) +{ + vector looking_for = str_to_cl(data); + vector > cls = get_red_cls(s); + + bool found_cl = false; + for(const auto& cl: cls) { + if (cl == looking_for) { + found_cl = true; + break; + } + + } + if (!found_cl) { + cout << "Expected to find: " << looking_for << endl; + cout << "But only found : "; + for(const auto& cl: cls) { + cout << cl << ", "; + } + cout << endl; + } + EXPECT_TRUE(found_cl); +} + +unsigned get_num_red_cls_contains(const Solver* s, const string& data) +{ + unsigned found_cl = 0; + vector looking_for = str_to_cl(data); + vector > cls = get_red_cls(s); + + for(const auto& cl: cls) { + if (cl == looking_for) { + found_cl++; + } + } + + return found_cl; +} + + +void check_irred_cls_doesnt_contain(const Solver* s, const string& data) +{ + vector not_inside = str_to_cl(data); + vector > cls = get_irred_cls(s); + + bool not_found_cl = true; + for(const auto& cl: cls) { + //cout << "irred cl inside: " << cl << endl; + if (cl == not_inside) { + cout << "Expected not to find irred: " << not_inside << endl; + cout << "But found it"; + not_found_cl = false; + break; + } + + } + EXPECT_TRUE(not_found_cl); +} + +void check_red_cls_doesnt_contain(const Solver* s, const string& data) +{ + vector not_inside = str_to_cl(data); + vector > cls = get_red_cls(s); + + bool not_found_cl = true; + for(const auto& cl: cls) { + //cout << "red cl inside: " << cl << endl; + if (cl == not_inside) { + cout << "Expected not to find red: " << not_inside << endl; + cout << "But found it"; + not_found_cl = false; + break; + } + + } + EXPECT_TRUE(not_found_cl); +} + +void print_model(const SATSolver&s) +{ + assert(s.okay()); + for(size_t i = 0; i < s.nVars(); i++) { + cout << "Model [" << i << "]: " << s.get_model()[i] << endl; + } +} + +void check_set_lits(const Solver* s, const std::string& data) +{ + vector lits = str_to_cl(data); + std::sort(lits.begin(), lits.end()); + + vector set_lits = s->get_zero_assigned_lits(); + std::sort(set_lits.begin(), set_lits.end()); + EXPECT_EQ(lits, set_lits); +} + +struct XorSorter +{ + bool operator()(const Xor& a, const Xor& b) const + { + if (a.size() != b.size()) + return a.size() < b.size(); + + if (a.rhs != b.rhs) { + return a.rhs < b.rhs; + } + + for(size_t i = 0; i < a.size(); i++) { + if (a[i] != b[i]) { + return a[i] < b[i]; + } + } + + return false; + } +}; + + +void sort_xor(Xor& x) +{ + std::sort(x.vars.begin(), x.vars.end()); + std::sort(x.clash_vars.begin(), x.clash_vars.end()); +} + +void check_xors_eq(const vector& got_data, const std::string& expected) +{ + XorSorter xorsort; + + vector expected_sorted = str_to_xors(expected); + for(auto t: expected_sorted) { + std::sort(t.begin(), t.end()); + } + std::sort(expected_sorted.begin(), expected_sorted.end(), xorsort); + + vector got_data_sorted = got_data; + for(Xor& t: got_data_sorted) { + sort_xor(t); + } + + std::sort(got_data_sorted.begin(), got_data_sorted.end(), xorsort); + EXPECT_EQ(expected_sorted.size(), got_data_sorted.size()); + for(size_t i = 0; i < expected_sorted.size(); i++) { + EXPECT_EQ(expected_sorted[i].vars, got_data_sorted[i].vars); + EXPECT_EQ(expected_sorted[i].rhs, got_data_sorted[i].rhs); + EXPECT_EQ(expected_sorted[i].clash_vars, got_data_sorted[i].clash_vars); + } +} + +void check_xors_contains(const vector& got_data, const std::string& expected) +{ + vector expected_sorted = str_to_xors(expected); + assert(expected_sorted.size() == 1); + Xor expectedX = expected_sorted[0]; + std::sort(expectedX.begin(), expectedX.end()); + + vector got_data_sorted = got_data; + for(auto& t: got_data_sorted) { + sort_xor(t); + } + + bool found = false; + for(const Xor& x: got_data_sorted) { + if (x.vars == expectedX.vars && + x.rhs == expectedX.rhs && + x.clash_vars == expectedX.clash_vars + ) { + found = true; + break; + } + } + EXPECT_TRUE(found); +} + +void check_zero_assigned_lits_eq(Solver* s, const string& data) +{ + vector lits_exp = str_to_cl(data); + vector lits_act = s->get_zero_assigned_lits(); + EXPECT_EQ(lits_act, lits_exp); +} + +void check_zero_assigned_lits_contains(Solver* s, const string& data) +{ + vector lits_exp = str_to_cl(data); + vector lits_act = s->get_zero_assigned_lits(); + for (Lit e: lits_exp) { + bool found_lit = false; + for(Lit a: lits_act) { + if (e == a) { + found_lit = true; + } + } + if (!found_lit) { + cout << "Literal " << e << " was not assigned" << endl; + EXPECT_TRUE(found_lit); + } + } +} + +bool clause_satisfied(const string& data, vector& solution) +{ + vector lits = str_to_cl(data); + for(Lit l: lits) { + if (solution[l.var()] == l_Undef) { + continue; + } + if ((solution[l.var()] ^ l.sign()) == l_True) { + return true; + } + } + return false; +} + +uint32_t count_num_undef_in_solution(const Solver* s) +{ + uint32_t num = 0; + for(size_t i = 0; i < s->nVarsOuter(); i++) { + if (s->model_value(i) == l_Undef) { + num++; + } + } + return num; +} + +struct cnfdata { + int64_t num_cls_per_header = -1; + int64_t num_vars_per_header = -1; + vector> cls; + uint64_t num_vars = 0; +}; + +template +void split(const std::string &s, char delim, Out result) { + std::stringstream ss(s); + std::string item; + while (std::getline(ss, item, delim)) { + *(result++) = item; + } +} + +std::vector split(const std::string &s, char delim) { + std::vector elems; + split(s, delim, std::back_inserter(elems)); + return elems; +} + +cnfdata cnf_file_read(std::string fname) +{ + cnfdata cnfdat; + + std::ifstream file(fname); + std::string str; + std::string file_contents; + vector cl; + while (std::getline(file, str)) + { + //cout << "CNF LINE: " << str << endl; + if (str.find("cnf") != string::npos) { + str.erase(0,5); + vector s = split(rtrim(ltrim(str)), ' '); + assert(s.size() == 2); + cnfdat.num_vars_per_header = std::stoi(s[0]); + cnfdat.num_cls_per_header = std::stoi(s[1]); + continue; + } + + if (str.find("c ") == 0) { + continue; + } + + cl.clear(); + vector s = split(rtrim(ltrim(str)), ' '); + for(string& l: s) { + if (l.length() == 0) + continue; + + int x = std::stoi(l); + if (x == 0) { + break; + } + uint64_t var = std::abs(x)-1; + cnfdat.num_vars = std::max(cnfdat.num_vars, var+1); + bool sign = x < 0; + cl.push_back(Lit(var, sign)); + } + cnfdat.cls.push_back(cl); + } + return cnfdat; +} + +bool cl_eq(const vector& lits1, const vector& lits2) +{ + if (lits1.size() != lits2.size()) + return false; + + + + vector cl1_s = lits1; + std::sort(cl1_s.begin(), cl1_s.end()); + + vector cl2_s = lits2; + std::sort(cl2_s.begin(), cl2_s.end()); + for(size_t i = 0; i < cl1_s.size(); i++) { + if (cl1_s[i] != cl2_s[i]) + return false; + } + return true; +} + +bool cl_exists(const vector >& cls, const vector& cl) { + for(const vector& cli: cls) { + if (cl_eq(cli, cl)) { + return true; + } + } + return false; +} + +template +bool find_lit(const T& where, const string& lit) { + Lit l = str_to_lit(lit); + return std::find(where.begin(), where.end(), l) != where.end(); +} + +// string print(const vector& dat) { +// std::stringstream m; +// for(size_t i = 0; i < dat.size();) { +// m << dat[i]; +// i++; +// if (i < dat.size()) { +// m << ", "; +// } +// } +// return m.str(); +// } + +#endif //TEST_HELPER__H diff --git a/cryptominisat/cppsrc/tests/vrepl_test.cpp b/cryptominisat/cppsrc/tests/vrepl_test.cpp new file mode 100644 index 00000000..166fdd10 --- /dev/null +++ b/cryptominisat/cppsrc/tests/vrepl_test.cpp @@ -0,0 +1,175 @@ +/****************************************** +Copyright (C) 2009-2020 Authors of CryptoMiniSat, see AUTHORS file + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. +***********************************************/ + +#include "gtest/gtest.h" + +#include + +#include "src/solver.h" +#include "src/varreplacer.h" +#include "src/solverconf.h" +using namespace CMSat; +#include "test_helper.h" + +struct varreplace : public ::testing::Test { + varreplace() + { + must_inter.store(false, std::memory_order_relaxed); + SolverConf conf; + s = new Solver(&conf, &must_inter); + s->new_vars(20); + s->testing_set_solver_not_fresh(); + repl = s->varReplacer; + } + ~varreplace() + { + delete s; + } + Solver* s = NULL; + VarReplacer* repl = NULL; + std::atomic must_inter; +}; + +TEST_F(varreplace, find_one_1) +{ + s->add_clause_outside(str_to_cl("1, 2")); + s->add_clause_outside(str_to_cl("-1, -2")); + + s->add_clause_outside(str_to_cl("1, 3, 4, 5")); + s->add_clause_outside(str_to_cl("2, 3, 4, 5")); + + repl->replace_if_enough_is_found(); + EXPECT_EQ(repl->get_num_replaced_vars(), 1); + EXPECT_EQ(s->get_num_long_irred_cls(), 2); + check_irred_cls_eq(s, "-2, 3, 4, 5; 2, 3, 4, 5"); +} + +TEST_F(varreplace, find_one_2) +{ + s->add_clause_outside(str_to_cl("1, -3")); + s->add_clause_outside(str_to_cl("-1, 3")); + + s->add_clause_outside(str_to_cl("1, 4, 5")); + s->add_clause_outside(str_to_cl("2, 3, 4, 5")); + + repl->replace_if_enough_is_found(); + EXPECT_EQ(repl->get_num_replaced_vars(), 1); + check_irred_cls_eq(s, "3, 4, 5; 2, 3, 4, 5"); +} + +TEST_F(varreplace, remove_lit) +{ + s->add_clause_outside(str_to_cl("1, -2")); + s->add_clause_outside(str_to_cl("-1, 2")); + + s->add_clause_outside(str_to_cl("1, 2, 5")); + + repl->replace_if_enough_is_found(); + EXPECT_EQ(repl->get_num_replaced_vars(), 1); + check_irred_cls_eq(s, "2, 5"); +} + +TEST_F(varreplace, remove_cl) +{ + s->add_clause_outside(str_to_cl("1, -2")); + s->add_clause_outside(str_to_cl("-1, 2")); + + s->add_clause_outside(str_to_cl("1, -2, 5")); + + repl->replace_if_enough_is_found(); + EXPECT_EQ(repl->get_num_replaced_vars(), 1); + check_irred_cls_eq(s, ""); +} + +TEST_F(varreplace, replace_twice) +{ + s->add_clause_outside(str_to_cl("1, -2")); + s->add_clause_outside(str_to_cl("-1, 2")); + + repl->replace_if_enough_is_found(); + EXPECT_EQ(repl->get_num_replaced_vars(), 1); + + s->add_clause_outside(str_to_cl("3, -2")); + s->add_clause_outside(str_to_cl("-3, 2")); + + repl->replace_if_enough_is_found(); + EXPECT_EQ(repl->get_num_replaced_vars(), 2); + + s->add_clause_outside(str_to_cl("1, -2, 3")); + s->add_clause_outside(str_to_cl("1, 2, 3, 5")); + check_irred_cls_eq(s, "2, 5"); +} + +TEST_F(varreplace, replace_thrice) +{ + s->add_clause_outside(str_to_cl("1, -2")); + s->add_clause_outside(str_to_cl("-1, 2")); + + repl->replace_if_enough_is_found(); + EXPECT_EQ(repl->get_num_replaced_vars(), 1); + + s->add_clause_outside(str_to_cl("3, -2")); + s->add_clause_outside(str_to_cl("-3, 2")); + + repl->replace_if_enough_is_found(); + EXPECT_EQ(repl->get_num_replaced_vars(), 2); + + s->add_clause_outside(str_to_cl("4, -2")); + s->add_clause_outside(str_to_cl("-4, 2")); + + repl->replace_if_enough_is_found(); + EXPECT_EQ(repl->get_num_replaced_vars(), 3); + + s->add_clause_outside(str_to_cl("1, -2, 3")); + s->add_clause_outside(str_to_cl("1, 2, 4, 5")); + check_irred_cls_eq(s, "2, 5"); +} + +TEST_F(varreplace, replace_limit_check_below) +{ + s->add_clause_outside(str_to_cl("1, -2")); + s->add_clause_outside(str_to_cl("-1, 2")); + + s->add_clause_outside(str_to_cl("3, -2")); + s->add_clause_outside(str_to_cl("-3, 2")); + + repl->replace_if_enough_is_found(3); + EXPECT_EQ(repl->get_num_replaced_vars(), 0); +} + +TEST_F(varreplace, replace_limit_check_above) +{ + s->add_clause_outside(str_to_cl("1, -2")); + s->add_clause_outside(str_to_cl("-1, 2")); + + s->add_clause_outside(str_to_cl("3, -2")); + s->add_clause_outside(str_to_cl("-3, 2")); + + repl->replace_if_enough_is_found(2); + EXPECT_EQ(repl->get_num_replaced_vars(), 2); +} + + +int main(int argc, char **argv) { + ::testing::InitGoogleTest(&argc, argv); + return RUN_ALL_TESTS(); +} diff --git a/cryptominisat/cppsrc/tests/xor_cnf_tests b/cryptominisat/cppsrc/tests/xor_cnf_tests new file mode 160000 index 00000000..a0963d22 --- /dev/null +++ b/cryptominisat/cppsrc/tests/xor_cnf_tests @@ -0,0 +1 @@ +Subproject commit a0963d220a22e7f1433d7fb3c23d8f34a67a5611 diff --git a/cryptominisat/cppsrc/tests/xorfinder_test.cpp b/cryptominisat/cppsrc/tests/xorfinder_test.cpp new file mode 100644 index 00000000..0c1c0975 --- /dev/null +++ b/cryptominisat/cppsrc/tests/xorfinder_test.cpp @@ -0,0 +1,590 @@ +/****************************************** +Copyright (C) 2009-2020 Authors of CryptoMiniSat, see AUTHORS file + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. +***********************************************/ + +#include "gtest/gtest.h" + +#include + +#include "src/solver.h" +#include "src/xorfinder.h" +#include "src/solverconf.h" +#include "src/occsimplifier.h" +using namespace CMSat; +#include "test_helper.h" + +struct xor_finder : public ::testing::Test { + xor_finder() + { + must_inter.store(false, std::memory_order_relaxed); + SolverConf conf; + s = new Solver(&conf, &must_inter); + s->new_vars(30); + occsimp = s->occsimplifier; + } + ~xor_finder() + { + delete s; + } + Solver* s = NULL; + OccSimplifier* occsimp = NULL; + std::atomic must_inter; +}; + +TEST_F(xor_finder, find_none) +{ + s->add_clause_outside(str_to_cl("1, 2")); + s->add_clause_outside(str_to_cl("-1, -2")); + + occsimp->setup(); + XorFinder finder(occsimp, s); + finder.grab_mem(); + finder.find_xors(); + EXPECT_EQ(s->xorclauses.size(), 0U); +} + +TEST_F(xor_finder, find_tri_1) +{ + s->add_clause_outside(str_to_cl("1, 2, 3")); + s->add_clause_outside(str_to_cl("-1, -2, 3")); + s->add_clause_outside(str_to_cl("-1, 2, -3")); + s->add_clause_outside(str_to_cl("1, -2, -3")); + + occsimp->setup(); + XorFinder finder(occsimp, s); + finder.find_xors(); + check_xors_contains(s->xorclauses, "1, 2, 3 = 1"); +} + +TEST_F(xor_finder, find_tri_2) +{ + s->add_clause_outside(str_to_cl("-1, 2, 3")); + s->add_clause_outside(str_to_cl("1, -2, 3")); + s->add_clause_outside(str_to_cl("1, 2, -3")); + s->add_clause_outside(str_to_cl("-1, -2, -3")); + + occsimp->setup(); + XorFinder finder(occsimp, s); + finder.find_xors(); + check_xors_eq(s->xorclauses, "1, 2, 3 = 0"); +} + +TEST_F(xor_finder, find_tri_3) +{ + s->add_clause_outside(str_to_cl("-1, 2, 3")); + s->add_clause_outside(str_to_cl("1, -2, 3")); + s->add_clause_outside(str_to_cl("1, 2, -3")); + s->add_clause_outside(str_to_cl("-1, -2, -3")); + + s->add_clause_outside(str_to_cl("1, 2, 3")); + s->add_clause_outside(str_to_cl("-1, -2, 3")); + s->add_clause_outside(str_to_cl("-1, 2, -3")); + s->add_clause_outside(str_to_cl("1, -2, -3")); + + occsimp->setup(); + XorFinder finder(occsimp, s); + finder.find_xors(); + check_xors_contains(s->xorclauses, "1, 2, 3 = 0"); + check_xors_contains(s->xorclauses, "1, 2, 3 = 1"); +} + + +TEST_F(xor_finder, find_4_1) +{ + s->add_clause_outside(str_to_cl("-1, 2, 3, 4")); + s->add_clause_outside(str_to_cl("1, -2, 3, 4")); + s->add_clause_outside(str_to_cl("1, 2, -3, 4")); + s->add_clause_outside(str_to_cl("1, 2, 3, -4")); + + s->add_clause_outside(str_to_cl("1, -2, -3, -4")); + s->add_clause_outside(str_to_cl("-1, 2, -3, -4")); + s->add_clause_outside(str_to_cl("-1, -2, 3, -4")); + s->add_clause_outside(str_to_cl("-1, -2, -3, 4")); + + occsimp->setup(); + XorFinder finder(occsimp, s); + finder.find_xors(); + check_xors_eq(s->xorclauses, "1, 2, 3, 4 = 0;"); +} + +TEST_F(xor_finder, find_4_4) +{ + s->add_clause_outside(str_to_cl("-1, -2, 3, 4")); + s->add_clause_outside(str_to_cl("1, -2, -3, 4")); + s->add_clause_outside(str_to_cl("1, 2, -3, -4")); + s->add_clause_outside(str_to_cl("-1, 2, -3, 4")); + s->add_clause_outside(str_to_cl("-1, 2, 3, -4")); + s->add_clause_outside(str_to_cl("1, -2, 3, -4")); + s->add_clause_outside(str_to_cl("-1, -2, -3, -4")); + s->add_clause_outside(str_to_cl("1, 2, 3, 4")); + + occsimp->setup(); + XorFinder finder(occsimp, s); + finder.find_xors(); + check_xors_eq(s->xorclauses, "1, 2, 3, 4 = 1"); +} + +/* + * These tests only work if the matching is non-exact + * i.e. if size is not checked for equality + */ +TEST_F(xor_finder, find_4_2) +{ + s->add_clause_outside(str_to_cl("-1, 2, 3, 4")); + s->add_clause_outside(str_to_cl("1, -2, 3, 4")); + s->add_clause_outside(str_to_cl("1, 2, -3, 4")); + s->add_clause_outside(str_to_cl("1, 2, 3")); + + s->add_clause_outside(str_to_cl("1, -2, -3, -4")); + s->add_clause_outside(str_to_cl("-1, 2, -3, -4")); + s->add_clause_outside(str_to_cl("-1, -2, 3, -4")); + s->add_clause_outside(str_to_cl("-1, -2, -3, 4")); + + occsimp->setup(); + XorFinder finder(occsimp, s); + finder.find_xors(); + check_xors_eq(s->xorclauses, "1, 2, 3, 4 = 0;"); +} + +TEST_F(xor_finder, find_4_3) +{ + s->add_clause_outside(str_to_cl("-1, 2, 3, 4")); + s->add_clause_outside(str_to_cl("1, -2, 3, 4")); + s->add_clause_outside(str_to_cl("1, 2, -3, 4")); + s->add_clause_outside(str_to_cl("1, 2, 3")); + + s->add_clause_outside(str_to_cl("1, -2, -3, -4")); + s->add_clause_outside(str_to_cl("-1, 2, -3, -4")); + s->add_clause_outside(str_to_cl("-1, -2, 3, -4")); + s->add_clause_outside(str_to_cl("-1, -3, 4")); + + occsimp->setup(); + XorFinder finder(occsimp, s); + finder.find_xors(); + check_xors_eq(s->xorclauses, "1, 2, 3, 4 = 0;"); +} + +/* +//Finder pruning is too strong and we don't find this one +TEST_F(xor_finder, find_5_2) +{ + s->add_clause_outside(str_to_cl("-1, -2, 3, 4, 5")); + s->add_clause_outside(str_to_cl("-1, 2, -3")); + s->add_clause_outside(str_to_cl("-1, 2, 3")); + + s->add_clause_outside(str_to_cl("1, -2, -3, 4, 5")); + s->add_clause_outside(str_to_cl("1, -2, 3, -4, 5")); + s->add_clause_outside(str_to_cl("1, -2, 3, 4, -5")); + + s->add_clause_outside(str_to_cl("1, 2, -3, -4, 5")); + s->add_clause_outside(str_to_cl("1, 2, -3, 4, -5")); + + s->add_clause_outside(str_to_cl("1, 2, 3, -4, -5")); + + // + + s->add_clause_outside(str_to_cl("1, -2, -3, -4, -5")); + s->add_clause_outside(str_to_cl("-1, 2, -3, -4, -5")); + s->add_clause_outside(str_to_cl("-1, -2, 3, -4, -5")); + s->add_clause_outside(str_to_cl("-1, -2, -3, 4, -5")); + s->add_clause_outside(str_to_cl("-1, -2, -3, -4, 5")); + + s->add_clause_outside(str_to_cl("1, 2, 3, 4, 5")); + + occsimp->setup(); + XorFinder finder(occsimp, s); + finder.find_xors(); + check_xors_eq(s->xorclauses, "1, 2, 3, 4, 5 = 1;"); +}*/ + +TEST_F(xor_finder, find_4_5) +{ + s->add_clause_outside(str_to_cl("-1, -2, 3, 4")); + s->add_clause_outside(str_to_cl("1, -2, -3, 4")); + s->add_clause_outside(str_to_cl("1, 2, -3, -4")); + s->add_clause_outside(str_to_cl("-1, 2, -3, 4")); + s->add_clause_outside(str_to_cl("-1, 2, 3, -4")); + s->add_clause_outside(str_to_cl("1, -2, 3, -4")); + s->add_clause_outside(str_to_cl("-1, -2, -3, -4")); + s->add_clause_outside(str_to_cl("1, 2, 3")); + + s->add_clause_outside(str_to_cl("-1, 2, 3, 4")); + s->add_clause_outside(str_to_cl("1, -2, 3, 4")); + s->add_clause_outside(str_to_cl("1, 2, -3, 4")); + s->add_clause_outside(str_to_cl("1, 2, 3")); + + s->add_clause_outside(str_to_cl("1, -2, -3, -4")); + s->add_clause_outside(str_to_cl("-1, 2, -3, -4")); + s->add_clause_outside(str_to_cl("-1, -2, 3, -4")); + s->add_clause_outside(str_to_cl("-1, -3, 4")); + + occsimp->setup(); + XorFinder finder(occsimp, s); + finder.find_xors(); + check_xors_eq(s->xorclauses, "1, 2, 3, 4 = 1; 1, 2, 3, 4 = 0"); +} +/*** + * Specialty, non-matching XOR test end +*/ + +TEST_F(xor_finder, find_5_1) +{ + s->add_clause_outside(str_to_cl("-1, -2, 3, 4, 5")); + s->add_clause_outside(str_to_cl("-1, 2, -3, 4, 5")); + s->add_clause_outside(str_to_cl("-1, 2, 3, -4, 5")); + s->add_clause_outside(str_to_cl("-1, 2, 3, 4, -5")); + + s->add_clause_outside(str_to_cl("1, -2, -3, 4, 5")); + s->add_clause_outside(str_to_cl("1, -2, 3, -4, 5")); + s->add_clause_outside(str_to_cl("1, -2, 3, 4, -5")); + + s->add_clause_outside(str_to_cl("1, 2, -3, -4, 5")); + s->add_clause_outside(str_to_cl("1, 2, -3, 4, -5")); + + s->add_clause_outside(str_to_cl("1, 2, 3, -4, -5")); + + // + + s->add_clause_outside(str_to_cl("1, -2, -3, -4, -5")); + s->add_clause_outside(str_to_cl("-1, 2, -3, -4, -5")); + s->add_clause_outside(str_to_cl("-1, -2, 3, -4, -5")); + s->add_clause_outside(str_to_cl("-1, -2, -3, 4, -5")); + s->add_clause_outside(str_to_cl("-1, -2, -3, -4, 5")); + + s->add_clause_outside(str_to_cl("1, 2, 3, 4, 5")); + + occsimp->setup(); + XorFinder finder(occsimp, s); + finder.find_xors(); + check_xors_eq(s->xorclauses, "1, 2, 3, 4, 5 = 1;"); +} + + +//we don't find 6-long, too expensive +/*TEST_F(xor_finder, find_6_0) +{ + s->add_clause_outside(str_to_cl("1, -7, -3, -4, -5, -9")); + s->add_clause_outside(str_to_cl("-1, 7, -3, -4, -5, -9")); + s->add_clause_outside(str_to_cl("-1, -7, 3, -4, -5, -9")); + s->add_clause_outside(str_to_cl("1, 7, 3, -4, -5, -9")); + s->add_clause_outside(str_to_cl("-1, -7, -3, 4, -5, -9")); + s->add_clause_outside(str_to_cl("1, 7, -3, 4, -5, -9")); + s->add_clause_outside(str_to_cl("1, -7, 3, 4, -5, -9")); + s->add_clause_outside(str_to_cl("-1, 7, 3, 4, -5, -9")); + s->add_clause_outside(str_to_cl("-1, -7, -3, -4, 5, -9")); + s->add_clause_outside(str_to_cl("1, 7, -3, -4, 5, -9")); + s->add_clause_outside(str_to_cl("1, -7, 3, -4, 5, -9")); + s->add_clause_outside(str_to_cl("-1, 7, 3, -4, 5, -9")); + s->add_clause_outside(str_to_cl("1, -7, -3, 4, 5, -9")); + s->add_clause_outside(str_to_cl("-1, 7, -3, 4, 5, -9")); + s->add_clause_outside(str_to_cl("-1, -7, 3, 4, 5, -9")); + s->add_clause_outside(str_to_cl("1, 7, 3, 4, 5, -9")); + s->add_clause_outside(str_to_cl("-1, -7, -3, -4, -5, 9")); + s->add_clause_outside(str_to_cl("1, 7, -3, -4, -5, 9")); + s->add_clause_outside(str_to_cl("1, -7, 3, -4, -5, 9")); + s->add_clause_outside(str_to_cl("-1, 7, 3, -4, -5, 9")); + s->add_clause_outside(str_to_cl("1, -7, -3, 4, -5, 9")); + s->add_clause_outside(str_to_cl("-1, 7, -3, 4, -5, 9")); + s->add_clause_outside(str_to_cl("-1, -7, 3, 4, -5, 9")); + s->add_clause_outside(str_to_cl("1, 7, 3, 4, -5, 9")); + s->add_clause_outside(str_to_cl("1, -7, -3, -4, 5, 9")); + s->add_clause_outside(str_to_cl("-1, 7, -3, -4, 5, 9")); + s->add_clause_outside(str_to_cl("-1, -7, 3, -4, 5, 9")); + s->add_clause_outside(str_to_cl("1, 7, 3, -4, 5, 9")); + s->add_clause_outside(str_to_cl("-1, -7, -3, 4, 5, 9")); + s->add_clause_outside(str_to_cl("1, 7, -3, 4, 5, 9")); + s->add_clause_outside(str_to_cl("1, -7, 3, 4, 5, 9")); + s->add_clause_outside(str_to_cl("-1, 7, 3, 4, 5, 9")); + + occsimp->setup(); + XorFinder finder(occsimp, s); + finder.find_xors(); + check_xors_eq(s->xorclauses, "1, 7, 3, 4, 5, 9 = 0;"); +} + +TEST_F(xor_finder, find_6_1) +{ + s->add_clause_outside(str_to_cl("-6, -7, -3, -4, -5, -9")); + s->add_clause_outside(str_to_cl("6, 7, -3, -4, -5, -9")); + s->add_clause_outside(str_to_cl("6, -7, 3, -4, -5, -9")); + s->add_clause_outside(str_to_cl("-6, 7, 3, -4, -5, -9")); + s->add_clause_outside(str_to_cl("6, -7, -3, 4, -5, -9")); + s->add_clause_outside(str_to_cl("-6, 7, -3, 4, -5, -9")); + s->add_clause_outside(str_to_cl("-6, -7, 3, 4, -5, -9")); + s->add_clause_outside(str_to_cl("6, 7, 3, 4, -5, -9")); + s->add_clause_outside(str_to_cl("6, -7, -3, -4, 5, -9")); + s->add_clause_outside(str_to_cl("-6, 7, -3, -4, 5, -9")); + s->add_clause_outside(str_to_cl("-6, -7, 3, -4, 5, -9")); + s->add_clause_outside(str_to_cl("6, 7, 3, -4, 5, -9")); + s->add_clause_outside(str_to_cl("-6, -7, -3, 4, 5, -9")); + s->add_clause_outside(str_to_cl("6, 7, -3, 4, 5, -9")); + s->add_clause_outside(str_to_cl("6, -7, 3, 4, 5, -9")); + s->add_clause_outside(str_to_cl("-6, 7, 3, 4, 5, -9")); + s->add_clause_outside(str_to_cl("6, -7, -3, -4, -5, 9")); + s->add_clause_outside(str_to_cl("-6, 7, -3, -4, -5, 9")); + s->add_clause_outside(str_to_cl("-6, -7, 3, -4, -5, 9")); + s->add_clause_outside(str_to_cl("6, 7, 3, -4, -5, 9")); + s->add_clause_outside(str_to_cl("-6, -7, -3, 4, -5, 9")); + s->add_clause_outside(str_to_cl("6, 7, -3, 4, -5, 9")); + s->add_clause_outside(str_to_cl("6, -7, 3, 4, -5, 9")); + s->add_clause_outside(str_to_cl("-6, 7, 3, 4, -5, 9")); + s->add_clause_outside(str_to_cl("-6, -7, -3, -4, 5, 9")); + s->add_clause_outside(str_to_cl("6, 7, -3, -4, 5, 9")); + s->add_clause_outside(str_to_cl("6, -7, 3, -4, 5, 9")); + s->add_clause_outside(str_to_cl("-6, 7, 3, -4, 5, 9")); + s->add_clause_outside(str_to_cl("6, -7, -3, 4, 5, 9")); + s->add_clause_outside(str_to_cl("-6, 7, -3, 4, 5, 9")); + s->add_clause_outside(str_to_cl("-6, -7, 3, 4, 5, 9")); + s->add_clause_outside(str_to_cl("6, 7, 3, 4, 5, 9")); + + occsimp->setup(); + XorFinder finder(occsimp, s); + finder.find_xors(); + check_xors_eq(s->xorclauses, "6, 7, 3, 4, 5, 9 = 1;"); +}*/ + +struct xor_finder2 : public ::testing::Test { + xor_finder2() + { + must_inter.store(false, std::memory_order_relaxed); + SolverConf conf; + s = new Solver(&conf, &must_inter); + s->new_vars(30); + occsimp = s->occsimplifier; + finder = new XorFinder(occsimp, s); + finder->grab_mem(); + } + ~xor_finder2() + { + delete s; + delete finder; + } + Solver* s = NULL; + OccSimplifier* occsimp = NULL; + std::atomic must_inter; + XorFinder* finder; +}; + + +TEST_F(xor_finder2, clean_v1) +{ + s->xorclauses = str_to_xors("1, 2, 3 = 0;"); + finder->move_xors_without_connecting_vars_to_unused(); + EXPECT_EQ(s->xorclauses.size(), 0u); +} + +TEST_F(xor_finder2, clean_v2) +{ + s->xorclauses = str_to_xors("1, 2, 3 = 0; 1, 4, 5, 6 = 0"); + finder->move_xors_without_connecting_vars_to_unused(); + EXPECT_EQ(s->xorclauses.size(), 2u); +} + +TEST_F(xor_finder2, clean_v3) +{ + s->xorclauses = str_to_xors("1, 2, 3 = 0; 1, 4, 5, 6 = 0; 10, 11, 12, 13 = 1"); + finder->move_xors_without_connecting_vars_to_unused(); + EXPECT_EQ(s->xorclauses.size(), 2u); +} + +TEST_F(xor_finder2, clean_v4) +{ + s->xorclauses = str_to_xors("1, 2, 3 = 0; 1, 4, 5, 6 = 0; 10, 11, 12, 13 = 1; 10, 15, 16, 17 = 0"); + finder->move_xors_without_connecting_vars_to_unused(); + EXPECT_EQ(s->xorclauses.size(), 4u); +} + +TEST_F(xor_finder2, xor_1) +{ + s->xorclauses = str_to_xors("1, 2, 3 = 1; 1, 4, 5, 6 = 0;"); + finder->xor_together_xors(s->xorclauses); + check_xors_eq(s->xorclauses, "2, 3, 4, 5, 6 = 1 c 1;"); +} + +TEST_F(xor_finder2, xor_2) +{ + s->xorclauses = str_to_xors("1, 2, 3 = 0; 1, 4, 5, 6 = 0;"); + finder->xor_together_xors(s->xorclauses); + check_xors_eq(s->xorclauses, "2, 3, 4, 5, 6 = 0 c 1;"); +} + +TEST_F(xor_finder2, xor_3) +{ + s->xorclauses = str_to_xors("1, 2, 3 = 0; 10, 4, 5, 6 = 0;"); + finder->xor_together_xors(s->xorclauses); + check_xors_eq(s->xorclauses, "1, 2, 3 = 0; 10, 4, 5, 6 = 0;"); +} + +TEST_F(xor_finder2, xor_4) +{ + s->xorclauses = str_to_xors("1, 2, 3 = 0; 1, 4, 5, 6 = 0;" + "1, 9, 10, 11 = 0;"); + finder->xor_together_xors(s->xorclauses); + EXPECT_EQ(s->xorclauses.size(), 3u); +} + +TEST_F(xor_finder2, xor_5) +{ + s->xorclauses = str_to_xors( + "2, 3, 1 = 0;" + "1, 5, 6, 4 = 0;" + "4, 10, 11 = 0;"); + finder->xor_together_xors(s->xorclauses); + EXPECT_EQ(s->xorclauses.size(), 1u); + check_xors_contains(s->xorclauses, "2, 3, 5, 6, 10, 11 = 0 c 1, 4"); +} + +TEST_F(xor_finder2, xor_6) +{ + s->xorclauses = str_to_xors( + "1, 2 = 0;" + "1, 4 = 0;" + "6, 7 = 0;" + "6, 10 = 1"); + finder->xor_together_xors(s->xorclauses); + EXPECT_EQ(s->xorclauses.size(), 2u); + check_xors_eq(s->xorclauses, "2, 4 = 0 c 1; 7, 10 = 1 c 6"); +} + +TEST_F(xor_finder2, xor_7) +{ + s->xorclauses = str_to_xors( + "1, 2 = 0 c 10;" + "1, 4 = 0 c 11;" + "6, 7 = 0;" + "6, 9 = 1 c 18"); + finder->xor_together_xors(s->xorclauses); + EXPECT_EQ(s->xorclauses.size(), 2u); + check_xors_eq(s->xorclauses, + "2, 4 = 0 c 10, 11, 1;" + "7, 9 = 1 c 6, 18"); +} + +TEST_F(xor_finder2, xor_8) +{ + s->xorclauses = str_to_xors( + "1, 2 = 0 c 10;" + "1, 4, 7 = 0 c 11;" + "7, 8, 9 = 0 c 12;"); + finder->xor_together_xors(s->xorclauses); + EXPECT_EQ(s->xorclauses.size(), 1u); + check_xors_eq(s->xorclauses, + "2, 4, 8, 9 = 0 c 10, 11, 12, 1, 7;"); +} + + +TEST_F(xor_finder2, dont_xor_together_when_clash_more_than_one) +{ + s->xorclauses = str_to_xors( + "1, 2, 3, 4 = 0;" + "1, 2, 5, 6 = 0;"); + finder->xor_together_xors(s->xorclauses); + EXPECT_EQ(s->xorclauses.size(), 2u); + check_xors_eq(s->xorclauses, + "1, 2, 3, 4 = 0;" + "1, 2, 5, 6 = 0;"); +} + +TEST_F(xor_finder2, clash_1) +{ + s->xorclauses = str_to_xors("1, 2, 3, 4 = 0; 1, 2, 5, 6= 0;"); + finder->xor_together_xors(s->xorclauses); + EXPECT_EQ(s->xorclauses.size(), 2u); + check_xors_eq(s->xorclauses, "1, 2, 3, 4 = 0; 1, 2, 5, 6= 0;"); +} + +TEST_F(xor_finder2, dont_remove_xors) +{ + s->xorclauses = str_to_xors("1, 2 = 0; 1, 2= 0;"); + finder->xor_together_xors(s->xorclauses); + EXPECT_EQ(s->xorclauses.size(), 1U); +} + +TEST_F(xor_finder2, dont_remove_xors2) +{ + s->xorclauses = str_to_xors("1, 2, 3 = 0; 1, 2, 3= 0;"); + finder->xor_together_xors(s->xorclauses); + EXPECT_EQ(s->xorclauses.size(), 1U); +} + +/*TEST_F(xor_finder2, xor_pure_unit_unsat) +{ + s->xorclauses = str_to_xors("1 = 0; 1 = 1;"); + finder->xor_together_xors(s->xorclauses); + bool ret = finder->add_new_truths_from_xors(s->xorclauses); + EXPECT_FALSE(ret); +} + +TEST_F(xor_finder2, xor_add_truths) +{ + s->xorclauses = str_to_xors("1, 2 = 0; 1 = 1; 2 = 0"); + bool ret = finder->xor_together_xors(s->xorclauses); + EXPECT_TRUE(ret); + EXPECT_EQ(s->xorclauses.size(), 1U); + + ret = finder->add_new_truths_from_xors(s->xorclauses); + EXPECT_FALSE(ret); +} + +TEST_F(xor_finder2, xor_unit) +{ + s->xorclauses = str_to_xors("1 = 0; 1, 2, 3 = 1; 3 = 1"); + finder->xor_together_xors(s->xorclauses); + bool ret = finder->add_new_truths_from_xors(s->xorclauses); + EXPECT_TRUE(ret); + EXPECT_EQ(s->xorclauses.size(), 0u); +}*/ + +// TEST_F(xor_finder2, xor_binx) +// { +// s->xorclauses = str_to_xors("1, 2, 5 = 0; 1, 3 = 0; 2 = 0"); +// bool ret = finder->xor_together_xors(s->xorclauses); +// if (ret) { +// ret &= finder->add_new_truths_from_xors(s->xorclauses); +// } +// EXPECT_TRUE(ret); +// EXPECT_EQ(s->xorclauses.size(), 0u); +// check_red_cls_eq(s, "5, -3; -5, 3"); +// } +// +// TEST_F(xor_finder2, xor_binx_inv_not_found) +// { +// s->xorclauses = str_to_xors("3, 1 = 1; 1, 3 = 0;"); +// bool ret = finder->xor_together_xors(s->xorclauses); +// if (ret) { +// ret &= finder->add_new_truths_from_xors(s->xorclauses); +// } +// EXPECT_TRUE(ret); +// } + +TEST_F(xor_finder2, xor_recur_bug) +{ + s->xorclauses = str_to_xors("3, 7, 9 = 0; 1, 3, 4, 5 = 1;"); + bool ret = finder->xor_together_xors(s->xorclauses); + EXPECT_TRUE(ret); + check_xors_eq(s->xorclauses, "7, 9, 1, 4, 5 = 1 c 3;"); +} + + +int main(int argc, char **argv) { + ::testing::InitGoogleTest(&argc, argv); + return RUN_ALL_TESTS(); +} diff --git a/cryptominisat/cppsrc/utils/OutputCheck b/cryptominisat/cppsrc/utils/OutputCheck new file mode 160000 index 00000000..80d077dd --- /dev/null +++ b/cryptominisat/cppsrc/utils/OutputCheck @@ -0,0 +1 @@ +Subproject commit 80d077dd600c98245c49d92049b02999fd7e703d diff --git a/cryptominisat/cppsrc/utils/cnf-utils b/cryptominisat/cppsrc/utils/cnf-utils new file mode 160000 index 00000000..618bba66 --- /dev/null +++ b/cryptominisat/cppsrc/utils/cnf-utils @@ -0,0 +1 @@ +Subproject commit 618bba6618175cf9964e22020024e7921cb5c808 diff --git a/cryptominisat/cppsrc/utils/config/crypt4-params.pcs b/cryptominisat/cppsrc/utils/config/crypt4-params.pcs new file mode 100644 index 00000000..ca18bbf4 --- /dev/null +++ b/cryptominisat/cppsrc/utils/config/crypt4-params.pcs @@ -0,0 +1,65 @@ +#Config parametrization file for CryptoMiniSat +#All rights reserved. + +#restarts +gluehist [80,300][100]li +blkrest {0,1}[1] +blkrestlen [2000,10000][5000]li +blkrestlen | blkrest in {1} +blkrestmultip [1.1,2][1.4] +blkrestmultip | blkrest in {1} +burst {100,300,1000,2000}[300] +clbtwsimp [1,5][2]li + +# Red clause removal +ltclean [0.3,0.7][0.5] +cleanconflmult {0,1,2}[1] +lockuip [50,1000][500]i +locktop [0,2000][0]i +perfmult [0.00001,0.8][0.00001]l +startclean [100,50000][10000]li +incclean [1.02,1.8][1.1] + +# Variable branching +freq[0,0.05][0] +dompickf [100,10000][400]li +morebump {0,1}[1] +#topnrndpick [5,1000][20]il +#topnrndpickfreq [0.0000001,1][0.000001]l + +# Variable polarity +flippolf {0,400}[0] +calcpolar1st {0,1} [1] +calcpolarall {0,1} [1] + +# Conflict +# recur {0,1}[1] # not a good idea to set it to 0 +moreminimcache [20,600][200]il +moreminimbin [20,5000][100]il + +# Probing +probemaxm [800,4000][1600]i + +# Stamping +cachesize [1024,4096][2048]il + +calcreach {0,1}[1] +cachecutoff [600,5000][2000]il + +# Simplification +presimp {0,1}[0] +elimcoststrategy {0,1}[0] +bva2lit {0,1}[1] +eratio [0.05,1][0.12]l +occredmax [100,400][200]il + +# Equivalent literal +sccperc [0.001,0.5][0.02]l + +# Misc +viviflongmaxm [5,80][20]il +viviffastmaxm [100,1000][400]il + +# turn off verbosity +printsol {0}[0] +#verb {0}[0] diff --git a/cryptominisat/cppsrc/utils/gtest b/cryptominisat/cppsrc/utils/gtest new file mode 160000 index 00000000..4af4a54f --- /dev/null +++ b/cryptominisat/cppsrc/utils/gtest @@ -0,0 +1 @@ +Subproject commit 4af4a54fa6a0de521085f7f1a1dc844a9413ac27 diff --git a/cryptominisat/cppsrc/utils/licensecheck b/cryptominisat/cppsrc/utils/licensecheck new file mode 160000 index 00000000..74128e61 --- /dev/null +++ b/cryptominisat/cppsrc/utils/licensecheck @@ -0,0 +1 @@ +Subproject commit 74128e614361de8e57854d432fb0d22c28624737 diff --git a/cryptominisat/cppsrc/utils/lingeling-ala b/cryptominisat/cppsrc/utils/lingeling-ala new file mode 160000 index 00000000..464e8e17 --- /dev/null +++ b/cryptominisat/cppsrc/utils/lingeling-ala @@ -0,0 +1 @@ +Subproject commit 464e8e170a0ebff2674e69dbe5d23e6ff4f56b25 diff --git a/cryptominisat/cppsrc/utils/minimal_cms/CMakeLists.txt b/cryptominisat/cppsrc/utils/minimal_cms/CMakeLists.txt new file mode 100644 index 00000000..3f74ca72 --- /dev/null +++ b/cryptominisat/cppsrc/utils/minimal_cms/CMakeLists.txt @@ -0,0 +1,38 @@ +# Copyright (C) 2009-2020 Authors of CryptoMiniSat, see AUTHORS file +# +# Permission is hereby granted, free of charge, to any person obtaining a copy +# of this software and associated documentation files (the "Software"), to deal +# in the Software without restriction, including without limitation the rights +# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +# copies of the Software, and to permit persons to whom the Software is +# furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in +# all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +# THE SOFTWARE. + +include_directories( + ${PROJECT_BINARY_DIR}/cmsat5-src +) +add_sanitize_flags() + + +include_directories( + #${PROJECT_BINARY_DIR}/cmsat5-src + ${PROJECT_BINARY_DIR}/include +) + +# Minimal DRAT-enabled CMS binary +add_executable(minimal_cms + minimal_cms.cpp +) +target_link_libraries(minimal_cms + cryptominisat5 +) diff --git a/cryptominisat/cppsrc/utils/minimal_cms/minimal_cms.cpp b/cryptominisat/cppsrc/utils/minimal_cms/minimal_cms.cpp new file mode 100644 index 00000000..dde16b71 --- /dev/null +++ b/cryptominisat/cppsrc/utils/minimal_cms/minimal_cms.cpp @@ -0,0 +1,83 @@ +/****************************************** +Copyright (c) 2019, Alex Ozdemir + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. +***********************************************/ + +#include +#include +#include +#include +#include +#include + +using namespace std; + +int main(int argc, char **argv) { + std::vector args(argv, argv + argc); + assert(args.size() == 3); + const auto &dimacs = args[1]; + const auto &drat = args[2]; + + ifstream dimacs_stream{dimacs}; + + FILE* proof_stream = fopen(drat.c_str(), "wb"); + + CMSat::SATSolver solver{}; + + std::string p, cnf; + uint64_t n_vars, n_clauses; + dimacs_stream >> p >> cnf >> n_vars >> n_clauses; + assert(p == "p"); + assert(cnf == "cnf"); + solver.set_frat(proof_stream); + solver.new_vars(n_vars); + solver.set_verbosity(1); + + for (size_t c_i = 0; c_i < n_clauses; c_i++) { + std::vector clause; + int64_t i; + while (true) { + dimacs_stream >> i; + assert(dimacs_stream.good()); + if (i == 0) { + break; + } else { + uint32_t var = static_cast(abs(i)); + assert(var <= n_vars); + CMSat::Lit l{var - 1, i < 0}; + clause.push_back(l); + } + } + if (not solver.add_clause(clause)) { + std::cout << "UNSAT" << std::endl; + exit(-1); + } + } + std::cerr << "Clauses added" << std::endl; + + CMSat::lbool res = solver.solve(); + + fflush(proof_stream); + fclose(proof_stream); + + solver.print_stats(); + std::cerr << "Res: " << res << std::endl; + return 0; +} diff --git a/cryptominisat/cppsrc/utils/minisat b/cryptominisat/cppsrc/utils/minisat new file mode 160000 index 00000000..8d15474b --- /dev/null +++ b/cryptominisat/cppsrc/utils/minisat @@ -0,0 +1 @@ +Subproject commit 8d15474b1de5a27c954cddbaad98454f96eb8e8d diff --git a/cryptominisat/cppsrc/utils/minisat_only_elim_and_subsume b/cryptominisat/cppsrc/utils/minisat_only_elim_and_subsume new file mode 160000 index 00000000..a114747d --- /dev/null +++ b/cryptominisat/cppsrc/utils/minisat_only_elim_and_subsume @@ -0,0 +1 @@ +Subproject commit a114747d6509a53c24c7c9a862d1b9111bc874da diff --git a/cryptominisat/cppsrc/utils/sha1-sat b/cryptominisat/cppsrc/utils/sha1-sat new file mode 160000 index 00000000..96bfd786 --- /dev/null +++ b/cryptominisat/cppsrc/utils/sha1-sat @@ -0,0 +1 @@ +Subproject commit 96bfd7862963da289126927d452ef1368914faf3 diff --git a/cryptominisat/data b/cryptominisat/data new file mode 120000 index 00000000..4909e06e --- /dev/null +++ b/cryptominisat/data @@ -0,0 +1 @@ +../data \ No newline at end of file diff --git a/cryptominisat/src/lib.rs b/cryptominisat/src/lib.rs new file mode 100644 index 00000000..397e4533 --- /dev/null +++ b/cryptominisat/src/lib.rs @@ -0,0 +1,391 @@ +//! # rustsat-cryptominisat - Interface to the CryptoMiniSat SAT Solver for RustSAT +//! +//! The CryptoMiniSat SAT solver to be used with the [RustSAT](https://github.com/chrjabs/rustsat) library. +//! +//! ## Features +//! +//! - `debug`: if this feature is enables, the Cpp library will be built with debug and check +//! functionality if the Rust project is built in debug mode +//! +//! ## CryptoMiniSat Versions +//! +//! CryptoMiniSat versions can be selected via cargo crate features. +//! All CryptoMiniSat versions from +//! [Version 5.8.0](https://github.com/msoos/cryptominisat/releases/tag/5.8.0) +//! up to +//! [Version 5.11.21](https://github.com/msoos/cryptominisat/releases/tag/5.12.1) +//! are available. For the full list of versions and the changelog see +//! [the CryptoMiniSat releases](https://github.com/msoos/cryptominisat/releases). +//! +//! Without any features selected, the newest version will be used. +//! If conflicting CryptoMiniSat versions are requested, the newest requested version will be selected. +//! +//! If the determined version is _not_ the newest available, and no custom source directory is +//! specified (see customization below), the CryptoMiniSat source code is downloaded at compile time, +//! which requires network access. +//! +//! ## Customization +//! +//! In order to build a custom version of CaDiCaL, this crate supports two environment variables to +//! customize the Cpp source code that CaDiCaL is built from. +//! +//! - `CRYPTOMINISAT_SRC_DIR` allows for overriding where the Cpp library is built from. By default this +//! crate fetches the appropriate code from [the GitHub +//! repository](https://github.com/msoos/cryptominisat). If this variable is set, the directory specified +//! there is used instead. Note that when using this variable, the crate will not apply any +//! patches, the user is responsible for applying the appropriate and necessary patches from the +//! [`patches/`](https://github.com/chrjabs/rustsat/tree/main/cadical/patches) directory. + +#![warn(clippy::pedantic)] +#![warn(missing_docs)] + +use std::cmp; + +use cpu_time::ProcessTime; +use rustsat::{ + solvers::{ + Solve, SolveIncremental, SolveStats, SolverResult, SolverState, SolverStats, StateError, + }, + types::{Cl, Clause, Lit, TernaryVal, Var}, +}; + +#[derive(Debug, PartialEq, Eq, Default)] +enum InternalSolverState { + #[default] + Configuring, + Input, + Sat, + Unsat, +} + +impl InternalSolverState { + fn to_external(&self) -> SolverState { + match self { + InternalSolverState::Configuring => SolverState::Configuring, + InternalSolverState::Input => SolverState::Input, + InternalSolverState::Sat => SolverState::Sat, + InternalSolverState::Unsat => SolverState::Unsat, + } + } +} + +/// The CryptoMiniSat solver type +pub struct CryptoMiniSat { + handle: *mut ffi::SATSolver, + state: InternalSolverState, + stats: SolverStats, +} + +unsafe impl Send for CryptoMiniSat {} + +impl Default for CryptoMiniSat { + fn default() -> Self { + Self { + handle: unsafe { ffi::cmsat_new() }, + state: InternalSolverState::default(), + stats: SolverStats::default(), + } + } +} + +impl CryptoMiniSat { + #[allow(clippy::cast_precision_loss)] + #[inline] + fn update_avg_clause_len(&mut self, clause: &Cl) { + self.stats.avg_clause_len = + (self.stats.avg_clause_len * ((self.stats.n_clauses - 1) as f32) + clause.len() as f32) + / self.stats.n_clauses as f32; + } + + /// Set CryptoMiniSat options + pub fn set_option(&mut self, option: Options) { + match option { + Options::NumThreads(n) => unsafe { ffi::cmsat_set_num_threads(self.handle, n) }, + Options::Verbosity(n) => unsafe { ffi::cmsat_set_verbosity(self.handle, n) }, + Options::DefaultPolarity(pol) => unsafe { + ffi::cmsat_set_default_polarity(self.handle, i32::from(pol)); + }, + Options::NoSimplify => unsafe { ffi::cmsat_set_no_simplify(self.handle) }, + Options::NoSimplifyAtStartup => unsafe { + ffi::cmsat_set_no_simplify_at_startup(self.handle); + }, + Options::NoEquivalentLitReplacement => unsafe { + ffi::cmsat_set_no_equivalent_lit_replacement(self.handle); + }, + Options::NoBva => unsafe { ffi::cmsat_set_no_bva(self.handle) }, + Options::NoBve => unsafe { ffi::cmsat_set_no_bve(self.handle) }, + Options::MaxTime(max_time) => unsafe { ffi::cmsat_set_max_time(self.handle, max_time) }, + } + } + + /// Adds an XOR clause to the solver + /// + /// # Errors + /// + /// If reserving variables fails + pub fn add_xor_clause(&mut self, vars: &[Var], rhs: bool) -> anyhow::Result<()> { + self.state = InternalSolverState::Input; + if !vars.is_empty() { + let max_var = vars + .iter() + .fold(Var::new(0), |max, var| cmp::max(max, *var)); + self.reserve(max_var)?; + } + let n_vars = vars.len(); + if !unsafe { ffi::cmsat_add_xor_clause(self.handle, vars.as_ptr().cast(), n_vars, rhs) } { + self.state = InternalSolverState::Unsat; + } + Ok(()) + } +} + +impl Solve for CryptoMiniSat { + fn signature(&self) -> &'static str { + "cryptominisat 5.11.21" + } + + fn reserve(&mut self, max_var: Var) -> anyhow::Result<()> { + let n_new = if let Some(solver_max) = self.max_var() { + if solver_max > max_var { + return Ok(()); + } + max_var.idx() - solver_max.idx() + } else { + max_var.idx() + 1 + }; + unsafe { ffi::cmsat_new_vars(self.handle, n_new) }; + Ok(()) + } + + fn solve(&mut self) -> anyhow::Result { + // If already solved, return state + if let InternalSolverState::Sat = self.state { + return Ok(SolverResult::Sat); + } + if let InternalSolverState::Unsat = self.state { + return Ok(SolverResult::Unsat); + } + let start = ProcessTime::now(); + // Solve with CryptoMiniSat backend + let res: TernaryVal = unsafe { ffi::cmsat_solve(self.handle) }.into(); + self.stats.cpu_solve_time += start.elapsed(); + match res { + TernaryVal::True => { + self.stats.n_sat += 1; + self.state = InternalSolverState::Sat; + Ok(SolverResult::Sat) + } + TernaryVal::False => { + self.stats.n_unsat += 1; + self.state = InternalSolverState::Sat; + Ok(SolverResult::Unsat) + } + TernaryVal::DontCare => { + self.stats.n_terminated += 1; + self.state = InternalSolverState::Input; + Ok(SolverResult::Interrupted) + } + } + } + + fn lit_val(&self, lit: Lit) -> anyhow::Result { + if self.state != InternalSolverState::Sat { + return Err(StateError { + required_state: SolverState::Sat, + actual_state: self.state.to_external(), + } + .into()); + } + Ok(ffi::lbool_slice(unsafe { ffi::cmsat_get_model(self.handle) })[lit.vidx()].into()) + } + + fn add_clause_ref(&mut self, clause: &C) -> anyhow::Result<()> + where + C: AsRef + ?Sized, + { + let clause = clause.as_ref(); + // Update wrapper-internal state + self.stats.n_clauses += 1; + self.update_avg_clause_len(clause); + self.state = InternalSolverState::Input; + if let Some(max_var) = clause.max_var() { + self.reserve(max_var)?; + } + let clause = ffi::cms_lit_slice(clause.as_ref()); + if !unsafe { ffi::cmsat_add_clause(self.handle, clause.vals, clause.num_vals) } { + self.state = InternalSolverState::Unsat; + } + Ok(()) + } +} + +impl SolveIncremental for CryptoMiniSat { + fn solve_assumps(&mut self, assumps: &[Lit]) -> anyhow::Result { + let start = ProcessTime::now(); + // Solve with CryptoMiniSat backend + let assumps = ffi::cms_lit_slice(assumps); + let res: TernaryVal = unsafe { + ffi::cmsat_solve_with_assumptions(self.handle, assumps.vals, assumps.num_vals) + } + .into(); + self.stats.cpu_solve_time += start.elapsed(); + match res { + TernaryVal::True => { + self.stats.n_sat += 1; + self.state = InternalSolverState::Sat; + Ok(SolverResult::Sat) + } + TernaryVal::False => { + self.stats.n_unsat += 1; + self.state = InternalSolverState::Sat; + Ok(SolverResult::Unsat) + } + TernaryVal::DontCare => { + self.stats.n_terminated += 1; + self.state = InternalSolverState::Input; + Ok(SolverResult::Interrupted) + } + } + } + + fn core(&mut self) -> anyhow::Result> { + match &self.state { + InternalSolverState::Unsat => Ok(Vec::from(ffi::lit_slice(unsafe { + ffi::cmsat_get_conflict(self.handle) + }))), + other => Err(StateError { + required_state: SolverState::Unsat, + actual_state: other.to_external(), + } + .into()), + } + } +} + +impl Extend for CryptoMiniSat { + fn extend>(&mut self, iter: T) { + iter.into_iter() + .for_each(|cl| self.add_clause(cl).expect("Error adding clause in extend")); + } +} + +impl<'a, C> Extend<&'a C> for CryptoMiniSat +where + C: AsRef + ?Sized, +{ + fn extend>(&mut self, iter: T) { + iter.into_iter().for_each(|cl| { + self.add_clause_ref(cl) + .expect("Error adding clause in extend"); + }); + } +} + +impl SolveStats for CryptoMiniSat { + fn stats(&self) -> SolverStats { + let max_var_idx = unsafe { ffi::cmsat_nvars(self.handle) }; + let max_var = if max_var_idx > 0 { + Some(Var::new(max_var_idx - 1)) + } else { + None + }; + let mut stats = self.stats.clone(); + stats.max_var = max_var; + stats + } + + fn max_var(&self) -> Option { + let max_var_idx = unsafe { ffi::cmsat_nvars(self.handle) }; + if max_var_idx > 0 { + Some(Var::new(max_var_idx - 1)) + } else { + None + } + } +} + +impl Drop for CryptoMiniSat { + fn drop(&mut self) { + unsafe { ffi::cmsat_free(self.handle) } + } +} + +/// CryptoMiniSat configuration options +#[derive(Debug, Clone, Copy, PartialEq)] +pub enum Options { + /// The number of threads + NumThreads(u32), + /// Verbosity + Verbosity(u32), + /// Default polarity + DefaultPolarity(bool), + /// No simplify + NoSimplify, + /// No simplify at start-up + NoSimplifyAtStartup, + /// No equivalent literal replacement + NoEquivalentLitReplacement, + /// No bounded variable addition + NoBva, + /// No bounded variable elimination + NoBve, + /// Maximum time + MaxTime(f64), +} + +#[cfg(test)] +mod test { + rustsat_solvertests::basic_unittests!(super::CryptoMiniSat); + + #[test] + fn options() { + let mut solver = super::CryptoMiniSat::default(); + solver.set_option(super::Options::NumThreads(4)); + solver.set_option(super::Options::Verbosity(2)); + solver.set_option(super::Options::DefaultPolarity(false)); + solver.set_option(super::Options::NoSimplify); + solver.set_option(super::Options::NoSimplifyAtStartup); + solver.set_option(super::Options::NoEquivalentLitReplacement); + solver.set_option(super::Options::NoBva); + solver.set_option(super::Options::NoBve); + solver.set_option(super::Options::MaxTime(100.)); + } +} + +mod ffi { + #![allow(non_upper_case_globals)] + #![allow(non_camel_case_types)] + #![allow(non_snake_case)] + + use rustsat::types::{Lit, TernaryVal}; + + include!(concat!(env!("OUT_DIR"), "/bindings.rs")); + + impl From for TernaryVal { + fn from(val: c_lbool) -> Self { + match u32::from(val.x) { + L_TRUE => TernaryVal::True, + L_FALSE => TernaryVal::False, + L_UNDEF => TernaryVal::DontCare, + _ => unreachable!("invalid CryptoMiniSat c_lbool"), + } + } + } + + pub fn lbool_slice<'a>(ffi_slice: slice_lbool) -> &'a [c_lbool] { + unsafe { std::slice::from_raw_parts(ffi_slice.vals, ffi_slice.num_vals) } + } + + pub fn lit_slice<'a>(ffi_slice: slice_Lit) -> &'a [Lit] { + unsafe { std::slice::from_raw_parts(ffi_slice.vals.cast(), ffi_slice.num_vals) } + } + + pub fn cms_lit_slice(cl: &[Lit]) -> slice_Lit { + let num_vals = cl.len(); + let vals = cl.as_ptr(); + slice_Lit { + vals: vals.cast(), + num_vals, + } + } +} diff --git a/cryptominisat/tests/incremental.rs b/cryptominisat/tests/incremental.rs new file mode 100644 index 00000000..2878bcf1 --- /dev/null +++ b/cryptominisat/tests/incremental.rs @@ -0,0 +1 @@ +rustsat_solvertests::incremental_tests!(rustsat_cryptominisat::CryptoMiniSat); diff --git a/cryptominisat/tests/small.rs b/cryptominisat/tests/small.rs new file mode 100644 index 00000000..4ca43f07 --- /dev/null +++ b/cryptominisat/tests/small.rs @@ -0,0 +1,3 @@ +mod base { + rustsat_solvertests::base_tests!(rustsat_cryptominisat::CryptoMiniSat); +} diff --git a/flake.nix b/flake.nix index f5b630f9..004b841b 100644 --- a/flake.nix +++ b/flake.nix @@ -64,6 +64,7 @@ ["glucose"]="glucose/cppsrc" ["cadical"]="cadical/cppsrc" ["kissat"]="kissat/csrc" + ["cryptominisat"]="cryptominisat/csrc" ) case $CMD in @@ -196,11 +197,11 @@ check-added-large-files.enable = true; end-of-file-fixer = { enable = true; - excludes = [".+\\.(patch|log)$" "cadical/cppsrc/.+" "kissat/csrc/.+"]; + excludes = [".+\\.(patch|log)$" "cadical/cppsrc/.+" "kissat/csrc/.+" "cryptominisat/cppsrc/.+"]; }; trim-trailing-whitespace = { enable = true; - excludes = [".+\\.(patch|log)$" "cadical/cppsrc/.+" "kissat/csrc/.+"]; + excludes = [".+\\.(patch|log)$" "cadical/cppsrc/.+" "kissat/csrc/.+" "cryptominisat/cppsrc/.+"]; }; check-symlinks.enable = true; no-commit-to-branch.enable = true; diff --git a/src/types/constraints.rs b/src/types/constraints.rs index 3c74df06..f9f20f43 100644 --- a/src/types/constraints.rs +++ b/src/types/constraints.rs @@ -6,6 +6,7 @@ use core::slice; use std::{ + cmp, collections::TryReserveError, fmt, ops::{self, Not, RangeBounds}, @@ -14,7 +15,7 @@ use std::{ use itertools::Itertools; use thiserror::Error; -use super::{Assignment, IWLitIter, Lit, LitIter, RsHashSet, TernaryVal, WLitIter}; +use super::{Assignment, IWLitIter, Lit, LitIter, RsHashSet, TernaryVal, Var, WLitIter}; use crate::RequiresClausal; @@ -443,6 +444,19 @@ impl Cl { pub fn is_binary(&self) -> bool { self.lits.len() == 2 } + + /// Gets the highest variable in the clause + #[must_use] + pub fn max_var(&self) -> Option { + if self.is_empty() { + return None; + } + Some( + self.lits + .iter() + .fold(Var::new(0), |max, lit| cmp::max(max, lit.var())), + ) + } } impl AsRef<[Lit]> for Cl { @@ -1524,7 +1538,7 @@ impl PbUbConstr { let min_coeff: usize = self .lits .iter() - .fold(usize::MAX, |min, (_, coeff)| std::cmp::min(min, *coeff)); + .fold(usize::MAX, |min, (_, coeff)| cmp::min(min, *coeff)); // absolute is safe since is not unsat min_coeff > self.b.unsigned_abs() } @@ -1557,7 +1571,7 @@ impl PbUbConstr { let min_coeff: usize = self .lits .iter() - .fold(usize::MAX, |min, (_, coeff)| std::cmp::min(min, *coeff)); + .fold(usize::MAX, |min, (_, coeff)| cmp::min(min, *coeff)); // self.b >= 0 since not unsat self.weight_sum <= self.b.unsigned_abs() + min_coeff && self.weight_sum > self.b.unsigned_abs() @@ -1622,7 +1636,7 @@ impl PbLbConstr { let min_coeff: usize = self .lits .iter() - .fold(usize::MAX, |min, (_, coeff)| std::cmp::min(min, *coeff)); + .fold(usize::MAX, |min, (_, coeff)| cmp::min(min, *coeff)); // note: self.b <= self.weight_sum is checked in is_unsat self.b.unsigned_abs() + min_coeff > self.weight_sum } @@ -1655,7 +1669,7 @@ impl PbLbConstr { let min_coeff: usize = self .lits .iter() - .fold(usize::MAX, |min, (_, coeff)| std::cmp::min(min, *coeff)); + .fold(usize::MAX, |min, (_, coeff)| cmp::min(min, *coeff)); // self.b > 0 because is not tautology self.b.unsigned_abs() <= min_coeff } diff --git a/tools/default.nix b/tools/default.nix index 0f35e1d0..2bbaec20 100644 --- a/tools/default.nix +++ b/tools/default.nix @@ -30,6 +30,8 @@ in ../cadical/src ../cadical/cppsrc ../cadical/cpp-extension + ../cryptominisat/Cargo.toml + ../cryptominisat/src ../glucose/Cargo.toml ../glucose/src ../ipasir/Cargo.toml