msoos/cryptominisat

GitHub: msoos/cryptominisat

一个支持增量求解与 XOR 扩展的高级 SAT 求解器。

Stars: 926 | Forks: 198

[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT) ![build](https://static.pigsec.cn/wp-content/uploads/repos/2026/04/1ac3964f12195620.svg) # CryptoMiniSat SAT 求解器 该系统提供 CryptoMiniSat,这是一个先进的增量 SAT 求解器。 该系统具有 3 个接口:命令行、C++ 库和 Python。命令行 接口接受一个 [cnf](http://en.wikipedia.org/wiki/Conjunctive_normal_form) 作为输入,格式为 [DIMACS](http://www.satcompetition.org/2009/format-benchmarks2009.html) 并支持 XOR 子句的扩展。C++ 和 Python 接口模仿此行为, 也允许增量使用:假设和多次 `solve` 调用。还提供了一个兼容 C 和 Rust 的包装器。 在引用时,请始终参考我们的 [SAT 2009 会议论文](https://link.springer.com/chapter/10.1007%2F978-3-642-02777-2_24), 参考文献记录位于 [这里](http://dblp.uni-trier.de/rec/bibtex/conf/sat/SoosNC09)。 ## 编译 建议使用 [release 二进制文件](https://github.com/msoos/cryptominisat/releases)。次选方案是使用 Nix。只需 [安装 nix](https://nixos.org/download/),然后执行: ``` nix shell github:msoos/cryptominisat ``` 然后你将拥有 `cryptominisat` 二进制文件并可直接使用。 你也可以在无需安装任何内容的情况下,通过浏览器运行 CryptoMiniSat,[点击这里](https://www.msoos.org/cryptominisat/)。 ### 从源代码构建 首先安装系统依赖: ``` # Debian/Ubuntu sudo apt-get install build-essential cmake git libgmp-dev # macOS (brew) brew install cmake gmp ``` 然后进行构建 — cadical 和 cadiback 会自动获取并编译: ``` git clone https://github.com/msoos/cryptominisat cd cryptominisat mkdir build && cd build cmake .. make -j8 ``` 如果你已经构建了 cadical 和 cadiback,可以指向 cmake 以跳过自动获取: ``` cmake .. -Dcadical_DIR=/path/to/cadical/build -Dcadiback_DIR=/path/to/cadiback make -j8 ``` ### 在 Windows 上构建(MSYS2/MINGW64) 安装 [MSYS2](https://www.msys2.org/),然后在 MINGW64 shell 中安装依赖: ``` pacman -S mingw-w64-x86_64-gcc mingw-w64-x86_64-cmake mingw-w64-x86_64-ninja \ mingw-w64-x86_64-make mingw-w64-x86_64-gmp mingw-w64-x86_64-zlib make ``` 然后构建: ``` git clone --recurse-submodules https://github.com/msoos/cryptominisat cd cryptominisat mkdir build && cd build cmake -G Ninja -DCMAKE_BUILD_TYPE=Release .. cmake --build . -v ``` 若要生成完全静态的二进制文件(运行时无外部 DLL 依赖),添加 `-DBUILD_SHARED_LIBS=OFF`: ``` cmake -G Ninja -DCMAKE_BUILD_TYPE=Release -DBUILD_SHARED_LIBS=OFF .. cmake --build . -v ``` ## 命令行用法 以以下文件为例: ``` p cnf 3 3 1 0 -2 0 -1 2 3 0 ``` 该文件包含 3 个变量和 3 个子句,这在头部 `p cnf 3 3` 中体现,分别表示变量数量和子句数量。每个子句以 '0' 结尾。子句含义为:1 必须为真,2 必须为假,且 1 必须为假、2 必须为真 或 3 必须为真。该问题的唯一解为: ``` cryptominisat5 --verb 0 file.cnf s SATISFIABLE v 1 -2 3 0 ``` 这意味着将变量 1 设为真、变量 2 设为假、变量 3 设为真,可满足 CNF 中的约束条件。若文件内容为: ``` p cnf 3 4 1 0 -2 0 -3 0 -1 2 3 0 ``` 则问题无解,求解器将返回 `s UNSATISFIABLE`。 ## 增量 Python 用法 该 Python 模块兼容 Python 3。只需执行: ``` pip3 install pycryptosat ``` 随后可按如下方式以增量模式使用: ``` >>> 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]) # assume var 3 = False → UNSAT >>> print(sat) False >>> sat, solution = s.solve() # without assumption → still SAT >>> print(sat) True >>> s.add_clause([-3]) # permanently add -3 >>> sat, solution = s.solve() >>> print(sat) False ``` 若要从源代码构建 Python 包,构建过程会使用 [scikit-build-core](https://github.com/scikit-build/scikit-build-core), 它会自动驱动 CMake 并获取、编译 cadical 和 cadiback,因此无需手动安装 C++ 依赖(GMP 除外)。 ``` # Debian/Ubuntu sudo apt-get install build-essential cmake libgmp-dev python3-dev # macOS brew install cmake gmp git clone https://github.com/msoos/cryptominisat cd cryptominisat python3 -m venv venv source venv/bin/activate pip install scikit-build-core cmake ninja build pip install . --no-build-isolation ``` 或者在不安装的情况下生成 wheel 文件: ``` python -m build --wheel --no-isolation # wheel lands in dist/ pip install dist/pycryptosat-*.whl ``` ### 增量库用法 库使用的变量编号从 0 开始。由于 0 不能被取反,因此使用类 `Lit` 表示:`Lit(variable_number, is_negated)`。因此,上述第一个 CNF 可表示为: ``` #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; } ``` 库调用也支持假设。我们可以在上述代码的 `return 0;` 前添加以下行: ``` vector assumptions; assumptions.push_back(Lit(2, true)); lbool ret = solver.solve(&assumptions); assert(ret == l_False); ret = solver.solve(); // no assumption → solution exists again assert(ret == l_True); ``` 由于我们假设变量 2 必须为假,因此无解。但若再次求解(不带假设),则会恢复原始解。 假设允许我们在**单次运行**中假设某些文字的值,但并非所有运行——对于所有运行,可以简单地将这些假设作为长度为 1 的子句添加。 ## 多解求解 要查找问题的多个解,只需循环运行求解器并排除已找到的解: ``` 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); } ``` 上述循环将持续运行,直到没有更多解为止。**强烈建议**仅将**重要或主要变量**添加到新子句(`ban_solution`)中。不应添加仅用于将原始问题转换为 CNF 的变量。这样可避免产生与主要变量无关的虚假解。 ## Rust 绑定 要构建 Rust 绑定: ``` git clone https://github.com/msoos/cryptominisat-rs/ cd cryptominisat-rs cargo build --release cargo test ``` 你可以按照该 [README](https://github.com/msoos/cryptominisat-rs/blob/master/README.markdown) 使用。在 Rust 项目中引入 CryptoMiniSat,需在 `Cargo.toml` 中添加依赖: ``` cryptominisat = { git = "https://github.com/msoos/cryptominisat-rs", branch= "master" } ``` 你可以在 [此处](https://github.com/msoos/caqe/) 查看使用 CryptoMiniSat 的 Rust 示例项目。 ## 预处理 若希望将 CryptoMiniSat 用作预处理器,建议尝试我们的模型计数预处理器 [Arjun](https://www.github.com/meelgroup/arjun)。 ## 高斯消元 从 CryptoMiniSat 5.8 开始,高斯消元默认编译进求解器。但若求解器检测到高斯消元表现不佳,会自动关闭。要使用高斯消元,请提供包含 XOR 的 CNF(可以是纯 CNF 或 XOR+CNF 格式),并使用默认设置运行, 或按需调整: ``` 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. ``` 特别是,如果确定有帮助,可以设置 `--autodisablegauss 0`。 ## 证明验证 CryptoMiniSat 可以输出 FRAT 证明,可独立验证。运行求解器并指定证明输出文件: ``` ./cryptominisat5 input.cnf proof.frat ``` 然后使用 [meelgroup/frat-xor](https://github.com/meelgroup/frat-xor) 中的工具进行细化与检查: ``` grep -v "^c" proof.frat > proof_clean.frat ./frat-xor elab proof_clean.frat input.cnf proof.xlrup ./cake_xlrup input.cnf proof.xlrup ``` `cake_xlrup` 成功后输出 `s VERIFIED`。更多细节(包括调试验证失败)请参考 [README_VERIFIER.md](README_VERIFIER.md)。 ## CMake 参数 以下参数用于配置生成的构建产物。在运行 `make` 前指定选项:`cmake ..` - `-DBUILD_SHARED_LIBS=` — 构建共享(ON,默认)或静态(OFF)库与二进制文件。 - `-DSTATS=` — 高级统计信息(会降低性能)。需要安装 [louvain communities](https://github.com/meelgroup/louvain-community)。 - `-DENABLE_TESTING=` — 启用测试套件。 - `-DLARGEMEM=` — 为子句分配更多内存(但对多数问题会变慢)。 - `-DIPASIR=` — 构建 `libipasircryptominisat.so` 以支持 [IPASIR](https://www.cs.utexas.edu/users/moore/acl2/manuals/current/manual/index-seo.php/IPASIR____IPASIR) 接口。 - `-Dcadical_DIR=` — 指向已构建的 CaDiCaL `build/` 目录(包含 `libcadical.a`)。若未设置,将自动获取并构建。 - `-Dcadiback_DIR=` — 指向已构建的 CaDiBaCk 目录(包含 `libcadiback.a`)。若未设置,将自动获取并构建。 ## C 语言用法 详见 src/cryptominisat_c.h.in。此为实验性功能。 ## 许可证 默认构建所需的一切均采用 MIT 许可证。如果你 明确指示系统使用 Bliss(两者均为 GPL 许可证), 但默认情况下 CryptoMiniSat 不会启用这些组件。
标签:Bash脚本, C++库, C绑定, DIMACS, Nix, Rust绑定, SAT求解器, Web界面, XOR子句, 优化, 可满足性, 可视化界面, 增量求解, 密码学, 开源, 开源框架, 手动系统调用, 持续集成, 搜索引擎优化, 构建系统, 约束求解, 逆向工具