【问题标题】:Finding consistent assignments for logical formulas为逻辑公式找到一致的分配
【发布时间】:2017-06-07 13:28:46
【问题描述】:

我即将在 Prolog 中实现逻辑术语的证明器。我当前的代码不是很漂亮,因此,我只想说明我想让我的程序做什么,希望你能给我一些好的建议:)

它应该包含一个变量列表(可以说是逻辑参数),其次是一个包含这些参数的逻辑公式(例如'not'(A 'and' B) 'or' 'not'(B 'and' C) 'or' ... 等等)。

作为输出,我希望我的程序以可能的一致分配做出响应。单个参数可以是 true (1) 或 false (0)。

所以我的目标是返回 A=0, B=0, C=0 ; A=1 等。

我很高兴为我的程序提供每一个帮助:)

【问题讨论】:

  • Stack Overflow 的工作方式是,您向我们展示您遇到问题的代码,我们会帮助您修复它。这不是免费的代码为我服务。
  • Prolog SAT Solver的可能重复
  • 如果逻辑参数都出现在第二个参数的表达式中,是否需要第一个参数列出它们?是否要求表达式包含给定列表中的所有参数,并且没有不在列表中的其他参数?另外,我知道您觉得您的代码“不美观”,最好展示您开始使用的一些代码。然后它将为回答您的问题提供一个起点,以帮助您理解。
  • 另一个可能的重复truthtable split in prolog
  • 考虑clpb

标签: prolog boolean-logic clpb


【解决方案1】:

有几种方法可以解决这个问题。就语法而言,一种方便的方法是定义运算符,如下所示:

:- op(500, fx, not).
:- op(600, xfx, and).
:- op(700, xfx, or).

(我只是在这里猜测合理的优先级设置,但只是为了说明。有关详细信息,请参阅op documentation。)

完成后,您可以编写如下表达式:A and B,Prolog 会将其“视为”and(A, B)

| ?- write_canonical(A and B).
and(_23,_24)

从那里,您需要有一种方法来评估表达式。在这方面有很多关于 SO 的问题(在此站点中搜索 [prolog] boolean expression evaluation),但我将提供一个简单的示例。现在是关于如何表示结果以及递归。

当涉及到表示结果时,您可以使用 Prolog 的成功/失败机制,因为您正在处理布尔结果。或者,您可以有一个明确的结果,例如 0 和 1。让我们尝试 0 和 1,因为这是您对真假的表示。

% Describe a valid boolean
bool(0).
bool(1).

% The evaluation of a valid boolean is itself
exp_eval(X, X) :- bool(X).

% Evaluation of an 'and' expression
exp_eval(and(A, B), Result) :-
    exp_eval(A, ResultA),
    exp_eval(B, ResultB),
    Result #= ResultA * ResultB.

% Evaluation of an 'or' expression
exp_eval(or(A, B), Result) :-
    exp_eval(A, ResultA),
    exp_eval(B, ResultB),
    % Just a little trick to get 1 if either ResultA or ResultB or both are 1
    Result #= (ResultA + ResultB + 1) // 2.

% Evaluation of a 'not' expression
exp_eval(not(A), Result) :-
    exp_eval(A, ResultNot),
    Result #= 1 - ResultNot.  % 0 ---> 1, and 1 ---> 0

您可以将它们断言为事实,而不是像我在上面所做的那样计算“布尔”1/0 结果:

bool_not(0, 1).
bool_not(1, 0).

bool_and(0, 0, 0).
bool_and(0, 1, 0).
bool_and(1, 0, 0).
bool_and(1, 1, 1).

bool_or(0, 0, 0).
bool_or(0, 1, 1).
bool_or(1, 0, 1).
bool_or(1, 1, 1).

然后,例如,您可以使用 bool_or(ResultA, ResultB, Result),而不是 Result #= (ResultA + ResultB + 1) // 2

现在我们可以计算表达式,我们需要一个求解器:

solve(Exp) :-
    term_variables(Exp, Variables),
    maplist(bool, Variables),  % Variables should be valid booleans
    exp_eval(Exp, 1).          % We only want true results for the expression

请注意,在原始问题陈述中,据说变量列表将作为参数给出,但您可以使用term_variables/2 从表达式中获取变量。

然后你就可以运行求解器了:

| ?- solve(not(A and B) or not(B and C)).

A = 0
B = 0
C = 0 ? a

A = 0
B = 0
C = 1

A = 0
B = 1
C = 0

A = 0
B = 1
C = 1

A = 1
B = 0
C = 0

A = 1
B = 0
C = 1

A = 1
B = 1
C = 0

no
| ?-

我不知道你的表达方式是什么。但无论它是什么,您都可以将其映射到上述解决方案。我所展示的内容简单明了。您可以跳过 op/3 的内容并使用标准术语表达式,例如 or(not(and(A,B)), not(and(B,C))) 使用上面的代码。如果您将输入作为某种标记序列,例如[not, (, A, and, B, ...],那么您将不得不进行一些列表处理。

【讨论】:

  • 您是否知道<!-- language-all: erlang --> 语言突出显示规范,是否有机会?使代码真正闪耀。但不识别 /* ... */ cmets。
  • @WillNess & lurker:哦,租约!嘉年华从 11.11 开始。 11:11:11。
  • @false 嘿嘿抱歉... :)
猜你喜欢
  • 2011-03-21
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2022-01-14
相关资源
最近更新 更多