创建随机 CNF 公式序言

Creating random CNF formulas prolog

对于我的论文,我正在研究知识库的特定属性以及这如何影响论证树的大小。我需要一个我已经拥有的 prolog 中的 sat 求解器,但我还需要一个创建随机子句的算法。 k-SAT 表示恰好长度为 k 的子句。为简单起见,我将 k 设置为 3,最大 4。我想将 K(每个子句的文字量)作为程序的参数。因此,如果我想要一个 3-sat,包含 1000 个子句和 300 个文字,那么我的程序应该创建一个包含 100 个长度为 3 的子句的知识库,其中所有这些文字都必须以一定比例的负数(50 /50 为简单起见)。我希望输出看起来像这样, Output: a set of clauses randomly created:

V1 :- V2, V3.

V2 :- -V3, -V4.

有人可以帮我解决这个问题吗?

Logtalk 提供了 user-extensible arbitrary library and QuickCheck support in its lgtunit developer tool. You can use both with most Prolog systems.

尝试做这样的事情:

random_knowledge_base(NumberOfClauses,
                      LiteralsPerClause,
                      AmountOfLiterals,
                      Ratio,
                      KnowledgeBase) :-
    length(KnowledgeBase, NumberOfClauses),
    maplist(random_clause(LiteralsPerClause, AmountOfLiterals, Ratio), KnowledgeBase).

random_clause(LiteralsPerClause, AmountOfLiterals, Ratio, Head :- Body) :-
    randseq(LiteralsPerClause, AmountOfLiterals, [Number|Numbers]),
    atom_concat(p, Number, Head),
    maplist(literal(Ratio), Numbers, Literals),
    comma_list(Body, Literals).

literal(Ratio, Number, Literal) :-
    atom_concat(p, Number, Proposition),
    (   maybe(Ratio)
    ->  Literal = Proposition
    ;   Literal = -Proposition ).

示例:

?- random_knowledge_base(5, 3, 9, 0.7, B).
B = [(p2 :- p5, -p6),  (p8 :- p3, p6),  (p9 :- p7, p2),  (p4 :- -p1, p6),  (p8 :- p1, p9)].

代码详解

  • ISO 谓词 atom_concat/3 连接两个原子形成第三个原子:
?- atom_concat(p, 2, A).
A = p2. 
  • 谓词maybe/1成功的概率为P,失败的概率为1-P:
?- maybe(0.5).
true.

?- maybe(0.5).
false.
?- (maybe(0.5) -> writeln(positive) ; writeln(negative)).
negative
true.

?- (maybe(0.5) -> writeln(positive) ; writeln(negative)).
positive
true.
  • 因此,例如,目标 literal(0.5, 1, L) 随机生成文字 p1-p1:
?- literal(0.5, 1, L).
L = -p1.

?- literal(0.5, 1, L).
L = p1.
  • 要在 1..M 范围内选择 K 个唯一的随机整数,我们可以使用 randseq/3。对于 K = 3 和 M = 5,我们有:
?- randseq(3, 5, Ns).
Ns = [4, 5, 2].

?- randseq(3, 5, Ns).
Ns = [1, 3, 2].
  • 要将 K 任意整数列表转换为 K 对应文字列表,我们可以使用 maplist/3
?- randseq(3, 5, Ns), maplist(literal(0.5), Ns, Ls).
Ns = [1, 3, 5],
Ls = [p1, p3, p5].
  • 谓词 comma_list/2 可用于将文字列表转换为连词:
?- randseq(3, 5, Ns), maplist(literal(0.5), Ns, Ls), comma_list(B, Ls).
Ns = [1, 5, 3],
Ls = [p1, p5, p3],
B =  (p1, p5, p3).

?- randseq(3, 5, Ns), maplist(literal(0.5), Ns, Ls), comma_list(B, Ls), C = (p3 :- B).
Ns = [1, 4, 2],
Ls = [-p1, p4, -p2],
B =  (-p1, p4, -p2),
C =  (p3 :- -p1, p4, -p2).
  • 把它们放在一起,我们有谓词 random_clause/4:
?- random_clause(3, 4, 0.5, C).
C =  (p3 :- p4, -p2).

?- random_clause(3, 4, 0.5, C).
C =  (p1 :- -p5, p4).

要创建一个随机知识库,例如包含 4 个子句:

?- length(KB, 4).
KB = [_, _, _, _].

?- length(KB, 4), maplist(random_clause(3,5,0.5), KB).
KB = [(p2 :-p1, -p3),  (p5 :-p2, p3),  (p3 :- -p4, p5),  (p3 :- -p1, p4)].

或者,使用谓词 random_knwoledge_base/5:

?- random_knowledge_base(4, 3, 5, 0.5, KB).
KB = [(p1 :- -p4, -p5),  (p2 :- p3, p4),  (p2 :-p3, -p5),  (p3 :- -p1, -p4)].