任务 1:DIMACS 读写与结果解释
-
规则编号 逻辑公式 DIMACS 子句 1 1 2 02 -1 3 03 -2 4 04 -3 5 05 -4 5 06 -5 3 4 07 -3 -4 08 5 0 -
base.cnf文件内容如下:c S=1, L=2, D=3, F=4, P=5p cnf 5 81 2 0-1 3 0-2 4 0-3 5 0-4 5 0-5 3 4 0-3 -4 05 0MiniSAT 终端输出如下:
Terminal window ❯ minisat base.cnf base_result.txtWARNING: for repeatability, setting FPU to use double precision============================[ Problem Statistics ]=============================| || Number of variables: 5 || Number of clauses: 7 || Parse time: 0.00 s || Eliminated vars: 4 || Vars set : 1 || Eliminated clauses: 0.00 Mb || Simplification time: 0.00 s || |============================[ Search Statistics ]==============================| Conflicts | ORIGINAL | LEARNT | Progress || | Vars Clauses Literals | Limit Clauses Lit/Cl | |==============================================================================================================================================================restarts : 1conflicts : 0 (-nan /sec)decisions : 1 (0.00 % random) (inf /sec)propagations : 1 (inf /sec)conflict literals : 0 (-nan % deleted)Memory used : 11.75 MBCPU time : 0 sSATISFIABLE结果文件如下:
SAT1 -2 3 -4 5 0求解状态表示 SAT 可满足,其中一种可满足的模型为:S, D, P 为真;L, F 为假。
模型中正变量编号代表该变量为真,负变量编号代表该变量为假。
对应的软件配置为:启用服务器模式、数据库后端、持久化功能,不启用本地模式、文件储存后端。
检查八条业务规则:
- 满足:服务器模式已启用
- 满足:服务器模式已启用且数据库后端已启用
- 满足:本地模式未启用
- 满足:数据库后端已启用且持久化功能已启用
- 满足:文件存储后端未启用
- 满足:持久化功能已启用且数据库后端已启用
- 满足:数据库后端已启用且文件存储后端未启用
- 满足:持久化功能已启用
-
server_only.cnf文件内容如下:c S=1, L=2, D=3, F=4, P=5p cnf 5 91 2 0-1 3 0-2 4 0-3 5 0-4 5 0-5 3 4 0-3 -4 05 01 0MiniSAT 终端输出如下:
Terminal window ❯ minisat server_only.cnf server_only_result.txtWARNING: for repeatability, setting FPU to use double precision============================[ Problem Statistics ]=============================| || Number of variables: 5 || Number of clauses: 7 || Parse time: 0.00 s || Simplification time: 0.00 s || |============================[ Search Statistics ]==============================| Conflicts | ORIGINAL | LEARNT | Progress || | Vars Clauses Literals | Limit Clauses Lit/Cl | |==============================================================================================================================================================restarts : 1conflicts : 0 (-nan /sec)decisions : 1 (0.00 % random) (inf /sec)propagations : 5 (inf /sec)conflict literals : 0 (-nan % deleted)Memory used : 11.75 MBCPU time : 0 sSATISFIABLE结果文件如下:
SAT1 -2 3 -4 5 0no_persistence.cnf文件内容如下:c S=1, L=2, D=3, F=4, P=5p cnf 5 81 2 0-1 3 0-2 4 0-3 5 0-4 5 0-5 3 4 0-3 -4 0-5 0MiniSAT 终端输出如下:
Terminal window ❯ minisat no_persistence.cnf no_persistence_result.txtWARNING: for repeatability, setting FPU to use double precision============================[ Problem Statistics ]=============================| || Number of variables: 5 || Number of clauses: 7 || Parse time: 0.00 s || Simplification time: 0.00 s || |===============================================================================Solved by simplificationrestarts : 0conflicts : 0 (0 /sec)decisions : 0 (-nan % random) (0 /sec)propagations : 4 (4635 /sec)conflict literals : 0 (-nan % deleted)Memory used : 11.75 MBCPU time : 0.000863 sUNSATISFIABLE结果文件如下:
UNSAT版本 求解状态 模型 base.cnfSAT 1 -2 3 -4 5 0server_only.cnfSAT 1 -2 3 -4 5 0no_persistence.cnfUNSAT / -
实际使用的规则包括修改后的规则 8 (), 规则 4 (), 规则 5 (), 规则 2 (), 规则 3 (), 规则 1 ()
-
在解决实际软件工程问题中,我们将具体问题建模为对应的 SAT 问题求解,故求解结果需要结合变量语义和约束关系解释,还原为原有的实际问题并加以分析。
任务 2:诚实者与说谎者建模
-
变量表:
变量 编号 为真时的含义 A 1 Alice 是诚实者 B 2 Bob 是诚实者 C 3 Carol 是诚实者 D 4 David 是诚实者 E 5 Eve 是诚实者 陈述人 陈述内容 逻辑公式 Alice Bob 与 David 身份不同 Bob Alice 或 David 中至少一人诚实 Carol Alice 是说谎者 David Alice 或 Bob 中至少一人诚实 Eve Carol 是诚实者 / 至少两名诚实者 / 至少两名说谎者 对应的 CNF 为:
c A=1, B=2, C=3, D=4, E=5p cnf 5 24c Alice-1 2 4 0-1 -2 -4 01 -2 4 033 collapsed lines1 2 -4 0c Bob-2 1 4 02 -1 02 -4 0c Carol-3 -1 01 3 0c David-4 1 2 04 -1 04 -2 0c Eve-5 3 0-3 5 0c 2True1 2 3 4 01 2 3 5 01 2 4 5 01 3 4 5 02 3 4 5 0c 2False-1 -2 -3 -4 0-1 -2 -3 -5 0-1 -2 -4 -5 0-1 -3 -4 -5 0-2 -3 -4 -5 0输出为
Terminal window ❯ minisat task2.cnf task2_result.txtWARNING: for repeatability, setting FPU to use double precision============================[ Problem Statistics ]=============================| || Number of variables: 5 || Number of clauses: 24 || Parse time: 0.00 s || Simplification time: 0.00 s || |============================[ Search Statistics ]==============================| Conflicts | ORIGINAL | LEARNT | Progress || | Vars Clauses Literals | Limit Clauses Lit/Cl | |==============================================================================================================================================================restarts : 1conflicts : 0 (0 /sec)decisions : 1 (0.00 % random) (788 /sec)propagations : 5 (3940 /sec)conflict literals : 0 (-nan % deleted)Memory used : 11.75 MBCPU time : 0.001269 sSATISFIABLE运行结果为
SAT-1 -2 3 -4 5 0说明“Carol 与 Eve 是诚实者”为满足要求的一组解。
-
添加阻塞语句
1 2 -3 4 -5 0,再次运行,输出为Terminal window ❯ minisat task2.cnf task2_result.txtWARNING: for repeatability, setting FPU to use double precision============================[ Problem Statistics ]=============================| || Number of variables: 5 || Number of clauses: 25 || Parse time: 0.00 s || Simplification time: 0.00 s || |===============================================================================Solved by simplificationrestarts : 0conflicts : 0 (0 /sec)decisions : 0 (-nan % random) (0 /sec)propagations : 4 (4813 /sec)conflict literals : 0 (-nan % deleted)Memory used : 11.75 MBCPU time : 0.000831 sUNSATISFIABLE结果为
UNSAT,说明解唯一,该问题仅存在一组解。
任务 3:自选场景的 SAT 建模
以下为 LLM 生成的候选模型与候选方案,尚未由本人独立核验,也未运行 MiniSAT。
1. 本次 LLM 使用记录
本次实际提供给 LLM 的请求原文为:
完成任务3中需要LLM参与的部分,不要进行需要我完成的部分同时提供了现有报告 2.md 和任务书 实验2_命题逻辑与SAT求解_实验任务.pdf 作为上下文。任务书中任务 3 的生成要求为:从软件配置、测试用例选择、课程冲突或资源分配中选择一个场景;不少于 10 个有业务含义的布尔变量和 15 个 CNF 子句;至少包含依赖、互斥、至少一个、至多一个和条件组合中的三类关系;需求至少允许一个合法方案;生成场景说明、变量含义、编号需求、对应 CNF 和一份候选方案。
以上记录区分了实际提问和附件中的要求,没有将另拟的提示词记为已实际发送的提示词。
2. LLM 生成的场景说明
选择场景:团队协作平台的软件部署配置。
某团队协作平台支持云端托管和本地部署两种模式,数据库可以选择 PostgreSQL 或 SQLite,并可选配账号认证、单点登录、HTTPS、自动备份、附件上传、病毒扫描、Redis 缓存和后台任务。本模型只考虑这些功能是否启用;数据库选型、功能依赖和安全策略均按下述产品规则约束。
产品约定:内置自动备份仅支持 PostgreSQL,并通过后台任务执行;附件上传必须启用异步病毒扫描,病毒扫描也通过后台任务执行;后台任务使用 Redis 作为队列与缓存服务,而本产品的 Redis 组件不支持与 SQLite 搭配。云端部署上传附件时,还必须启用自动备份。
3. 候选变量表
| 变量 | 编号 | 为真时的业务含义 |
|---|---|---|
| 1 | 采用云端托管模式 | |
| 2 | 采用本地部署模式 | |
| 3 | 使用 PostgreSQL 数据库 | |
| 4 | 使用 SQLite 数据库 | |
| 5 | 启用账号认证 | |
| 6 | 启用单点登录(SSO) | |
| 7 | 启用 HTTPS | |
| 8 | 启用内置自动备份 | |
| 9 | 启用附件上传 | |
| 10 | 启用附件病毒扫描 | |
| 11 | 启用 Redis 队列与缓存服务 | |
| 12 | 启用后台任务 |
变量为假表示对应模式、数据库或功能未启用。全部 12 个变量均直接具有业务含义,不引入辅助变量。
4. 编号需求与候选 CNF 子句
用 标记子句;表中的整数按上述变量编号表示文字,末尾的 0 表示子句结束。
| 需求编号 | 自然语言需求 | 命题逻辑公式 | 对应 CNF 子句 | 整数编码 |
|---|---|---|---|---|
| R1 | 云端托管与本地部署必须恰好选择一种。 | ; | 1 2 0;-1 -2 0 | |
| R2 | PostgreSQL 与 SQLite 必须恰好选择一种。 | ; | 3 4 0;-3 -4 0 | |
| R3 | 云端托管必须使用 PostgreSQL。 | -1 3 0 | ||
| R4 | 云端托管必须启用 HTTPS。 | -1 7 0 | ||
| R5 | 云端托管必须启用账号认证。 | -1 5 0 | ||
| R6 | 单点登录依赖账号认证。 | -6 5 0 | ||
| R7 | 单点登录必须通过 HTTPS 使用。 | -6 7 0 | ||
| R8 | 内置自动备份要求使用 PostgreSQL。 | -8 3 0 | ||
| R9 | 内置自动备份要求启用后台任务。 | -8 12 0 | ||
| R10 | 后台任务要求启用 Redis 队列与缓存服务。 | -12 11 0 | ||
| R11 | Redis 队列与缓存服务和 SQLite 不能同时启用。 | -11 -4 0 | ||
| R12 | 附件上传要求启用病毒扫描。 | -9 10 0 | ||
| R13 | 病毒扫描要求启用后台任务。 | -10 12 0 | ||
| R14 | 同时采用云端托管并启用附件上传时,必须启用内置自动备份。 | -1 -9 8 0 |
候选 CNF 为 ,共 12 个业务变量、14 条自然语言需求、16 个子句。关系类型包括:R1、R2 中的至少一个与至多一个;R11 中的互斥;R3—R10、R12、R13 中的依赖;R14 中的条件组合。
5. LLM 给出的候选方案
候选业务方案:采用云端托管和 PostgreSQL,启用账号认证、HTTPS、内置自动备份、附件上传、病毒扫描、Redis 队列与缓存服务及后台任务;不采用本地部署或 SQLite,不启用单点登录。
| 变量 | ||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|
| 候选赋值 | 1 | 0 | 1 | 0 | 1 | 0 | 1 | 1 | 1 | 1 | 1 | 1 |
按变量编号表示的完整候选赋值为:
1 -2 3 -4 5 -6 7 8 9 10 11 12 0这份赋值由 LLM 提供,不是 MiniSAT 的运行输出。
本人仍需完成:整理和独立检查候选模型、必要的修正、候选方案对每条需求与 CNF 的代入检查、最终 DIMACS 文件、MiniSAT 求解及模型的业务解释与需求检查、关键截图,以及自行撰写的编码准确性结论。
LLM 生成内容核对无误,以下为人工部分:
DIMACS 文件:
c C=1, L=2, P=3, Q=4, A=5, S=6, T=7, B=8, U=9, V=10, R=11, J=12p cnf 12 16
1 2 0-1 -2 03 4 0-3 -4 0-1 3 0-1 7 0-1 5 0-6 5 0-6 7 0-8 3 0-8 12 0-12 11 0-11 -4 0-9 10 0-10 12 0-1 -9 8 0输出:
❯ minisat task3.cnf task3_result.txtWARNING: for repeatability, setting FPU to use double precision============================[ Problem Statistics ]=============================| || Number of variables: 12 || Number of clauses: 16 || Parse time: 0.00 s || Eliminated vars: 12 || Vars set : 0 || Eliminated clauses: 0.00 Mb || Simplification time: 0.00 s || |============================[ Search Statistics ]==============================| Conflicts | ORIGINAL | LEARNT | Progress || | Vars Clauses Literals | Limit Clauses Lit/Cl | |==============================================================================================================================================================restarts : 1conflicts : 0 (-nan /sec)decisions : 1 (0.00 % random) (inf /sec)propagations : 0 (-nan /sec)conflict literals : 0 (-nan % deleted)Memory used : 11.73 MBCPU time : 0 s
SATISFIABLE运行结果为:
SAT-1 2 -3 4 5 -6 7 -8 -9 -10 -11 -12 0其含义为:采用本地部署模式,使用SQLite数据库,启用账号认证,启用 HTTPS。
CNF 准确表达了需求
任务 4(编程题):实现 CNF 赋值检查器
代码补全如下:
#include <vector>bool satisfiesCnf( int variableCount, const std::vector<std::vector<int>>& clauses, const std::vector<int>& assignment) { for(const std::vector<int>& clause : clauses) { bool sat = false; for(int i : clause) { bool sign = (i < 0); int index = (sign ? -i : i) - 1; sat |= (assignment[index] ^ sign); if(sat) break; } if(!sat) return false; } return true;}测试代码如下:
#include <iostream>#include <vector>
bool satisfiesCnf( int variableCount, const std::vector<std::vector<int>>& clauses, const std::vector<int>& assignment);
int main() { int variableCount, clauseCount; std::cin >> variableCount >> clauseCount; std::vector<std::vector<int>> clauses(clauseCount); std::vector<int> assignment(variableCount); for(int i = 0; i < clauseCount; i++) { int var; while(true) { std :: cin >> var; if(var == 0) break; clauses[i].push_back(var); } } for(int i = 0; i < variableCount; i++) { std::cin >> assignment[i]; } std::cout << ( satisfiesCnf(variableCount, clauses, assignment) ? "AC" : "WA" ) << std::endl; return 0;}测试用例如下:
| 测试点编号 | variableCount | clauses | assignment | 预期解 | 返回结果 |
|---|---|---|---|---|---|
| 1 | 1 | {} | x1=true | AC | AC |
| 2 | 1 | {{1}} | x1=true | AC | AC |
| 3 | 1 | {{1}, {-1}} | x1=true | WA | WA |
| 4 | 2 | {{1, 2}, {-1, -2}} | x1=true, x2=true | WA | WA |
| 5 | 2 | {{1, 2}, {-1, -2}} | x1=true, x2=false | AC | AC |
| 6 | 3 | {{-1, 2}, {-2, 3}, {-3, 1}} | x1=true, x2=true, x3=true | AC | AC |
使用固定CNF {{1, 2}, {-1, 3}, {-2, -3}} 和 赋值 x1=true, x2=false, x3=true 测试结果如下:
❯ ./test_lab23 31 2 0-1 3 0-2 -3 01 0 1AC故返回值为 true, 将 x3 改为 false 后测试结果如下:
❯ ./test_lab23 31 2 0-1 3 0-2 -3 01 0 0WA此时cnf子句 -1 3 0 不满足。
CNF中“所有子句均满足”的含义是“对给定的同一组完整赋值,每个子句都至少有一个文字为真时,整个 CNF 才为真;只要有一个子句中的文字全部为假,整个 CNF 就为假。”
任务 5:使用阻塞子句寻找多个解
| 方案编号 | CNF运行结果 | 测试策略 | 加入的阻塞语句 | satisfiesCnf 检测结果 |
|---|---|---|---|---|
| 1 | 1 -2 -3 -4 0 | 执行单元测试 | -1 2 3 4 0 | AC |
| 2 | -1 2 -3 -4 0 | 执行集成测试 | 1 -2 3 4 0 | AC |
| 3 | 1 2 -3 -4 0 | 执行单元测试和集成测试 | -1 -2 3 4 0 | AC |
| 4 | 1 2 3 -4 0 | 执行单元测试,集成测试和静态分析 | -1 -2 -3 4 0 | AC |
| 5 | 1 -2 3 -4 0 | 执行单元测试和静态分析 | -1 2 -3 4 0 | AC |
| 6 | -1 2 -3 4 0 | 执行集成测试,并收集覆盖率 | 1 -2 3 -4 0 | AC |
| 7 | 1 2 -3 4 0 | 执行单元测试和集成测试,并收集覆盖率 | -1 -2 3 -4 0 | AC |
| / | UNSAT | 无测试策略 | / | / |
若存在其他完整合法赋值,则该组赋值可通过原始CNF,并不会被任何一条阻塞语句排除,最后输出UNSAT则说明不存在这样的赋值组合。
增加业务规则“必须执行静态分析”后,初始cnf如下:
c U=1, I=2, S=3, C=4p cnf 4 51 2 0-3 1 0-4 2 0-3 -4 03 0| 原方案编号 | CNF运行结果 | 测试策略 | 加入的阻塞语句 | satisfiesCnf 检测结果 |
|---|---|---|---|---|
| 5 | 1 -2 3 -4 0 | 执行单元测试和静态分析 | -1 2 -3 4 0 | AC |
| 4 | 1 2 3 -4 0 | 执行单元测试,集成测试和静态分析 | -1 -2 -3 4 0 | AC |
| / | UNSAT | 无测试策略 | / | / |
方案数由修改前的7降为2,原方案1, 2, 3, 6, 7被排除,即所有包含-3的方案被排除。
单个阻塞语句由被阻塞赋值逐项取反得到,这使得其具有针对性:排除这一种赋值组合并不影响其他赋值组合的判断。
任务 6:检查两份 CNF 是否等价
| 需求编号 | 逻辑公式 |
|---|---|
| 1 | |
| 2 | |
| 3 | |
| 4 | |
| 5 | |
| 6 |
运行 encoding_a.cnf 输出如下:
❯ minisat encoding_a.cnf encoding_a.txtWARNING: for repeatability, setting FPU to use double precision============================[ Problem Statistics ]=============================| || Number of variables: 6 || Number of clauses: 8 || Parse time: 0.00 s || Eliminated vars: 4 || Vars set : 2 || Eliminated clauses: 0.00 Mb || Simplification time: 0.00 s || |============================[ Search Statistics ]==============================| Conflicts | ORIGINAL | LEARNT | Progress || | Vars Clauses Literals | Limit Clauses Lit/Cl | |==============================================================================================================================================================restarts : 1conflicts : 0 (0 /sec)decisions : 1 (0.00 % random) (740 /sec)propagations : 2 (1480 /sec)conflict literals : 0 (-nan % deleted)Memory used : 11.73 MBCPU time : 0.001351 s
SATISFIABLE结果如下:
SAT1 -2 3 -4 5 6 0运行 encoding_b.cnf 输出如下:
❯ minisat encoding_b.cnf encoding_b.txtWARNING: for repeatability, setting FPU to use double precision============================[ Problem Statistics ]=============================| || Number of variables: 6 || Number of clauses: 12 || Parse time: 0.00 s || Eliminated vars: 4 || Vars set : 2 || Eliminated clauses: 0.00 Mb || Simplification time: 0.00 s || |============================[ Search Statistics ]==============================| Conflicts | ORIGINAL | LEARNT | Progress || | Vars Clauses Literals | Limit Clauses Lit/Cl | |==============================================================================================================================================================restarts : 1conflicts : 0 (0 /sec)decisions : 1 (0.00 % random) (912 /sec)propagations : 2 (1825 /sec)conflict literals : 0 (-nan % deleted)Memory used : 11.73 MBCPU time : 0.001096 s
SATISFIABLE结果如下:
SAT1 -2 3 -4 5 6 0检查函数如下:
std::vector<int> check() { int variableCount = 6; std::vector<std::vector<int>> encoding_a = {8 collapsed lines
{1, 2}, {-1, 3}, {-3, 1}, {-2, 4}, {-4, 3}, {-3, 5}, {-6, 5}, {-5, 6} };
std::vector<std::vector<int>> encoding_b = {12 collapsed lines
{-4, 3}, {-3, 5}, {-6, 5}, {-5, 6}, {1, 2, 4}, {1, 2, -4}, {-1, 3, 6}, {-1, 3, -6}, {-3, 1, 2}, {-3, 1, -2}, {-2, 4, 5}, {-2, 4, -5}, };
std::vector<int> assignment(variableCount), diff; for(int i = 0; i < 64; i ++) { for(int j = 0; j < variableCount; j++) { assignment[j] = (i >> j) & 1; } if( satisfiesCnf(variableCount, encoding_a, assignment) != satisfiesCnf(variableCount, encoding_b, assignment) ) diff.push_back(i); } return diff;}运行后返回的 diff 为空,故 encoding_a 与 encoding_b 等价
(K OR x) AND (K OR NOT x)≡ K OR (x AND NOT x) (分配律)≡ K OR FALSE (矛盾律)≡ K (恒等律)删除 B 中 1 2 4 0 子句,并删除检查函数中变量 encoding_b 中元素 {1, 2, 4} ,再次运行检查函数,返回 diff 为 {0, 48},得到如下结果:
diff 内的元素 | 赋值组合 | 服务配置 | encoding_a 中不满足的子句 | 不满足的需求编号 |
|---|---|---|---|---|
| 0 | A=false, W=false, D=false, C=false, L=false, M=false | 不启用任何业务 | 1 2 0 | 1 |
| 48 | A=false, W=false, D=false, C=false, L=true, M=true | 启用日志与监控 | 1 2 0 | 1 |
语法形式不同的cnf可能在命题逻辑等价性上属于同一等价类,故仍可能表达相同模型集合。