将逻辑表达式转换为合取范式


10

目标:

编写一个完整的程序或函数,该程序或函数接受命题逻辑中的一个公式(以下称为逻辑表达式表达式),并以合并正规形式输出该公式。有两个常量,代表真假,一元运算符¬代表否定,和二元运算,和代表暗示,对等,协同和脱节,其分别遵守所有常见的逻辑运算(德·摩根定律双重否定消除等)。

合并范式定义如下:

  1. 任何原子表达式(包括)都是合取范式。
  2. 任何先前构建的表达式的取反是合取范式。
  3. 先前构造的任何两个表达式的析取为合取范式。
  4. 任何两个先前构造的表达式的合取为合取范式。
  5. 其他任何表达式都不是合取范式。

任何逻辑表达式都可以以合取范式形式(非唯一)转换为逻辑等效表达式(请参见此算法)。您无需使用该特定算法。

输入:

您可以采用任何方便的格式输入;例如,符号逻辑表达式(如果您的语言支持),字符串,其他某种数据结构。您不需要像我在此处那样对true,false和逻辑运算符使用相同的符号,但是您的选择应保持一致,如果不清楚,则应在答案中说明您的选择。您可能不接受任何其他输入或以您的输入格式对任何其他信息进行编码。您应该有一些表达任意数量的原子表达式的方法;例如整数,字符,字符串等。

输出:

公式可以是合取范式,也可以是任何方便的格式。它的格式不必与您输入的格式相同,但是您应该解释是否存在任何差异。

测试用例:

P ∧ (P ⇒ R) -> P ∧ R
P ⇔ (¬ P) -> ⊥
(¬ P) ∨ (Q ⇔ (P ∧ R)) -> ((¬ P) ∨ ((¬ Q) ∨ R)) ∧ ((¬ P) ∨ (Q ∨ (¬ R)))

笔记:

  1. 如果输入表达式是重言式,将是有效的输出。同样,如果输入表达式是矛盾的,则将是有效的输出。
  2. 输入和输出格式都应具有定义明确的操作顺序,以表示所有可能的逻辑表达式。您可能需要某种括号。
  3. 您可以对逻辑操作使用任何明确定义的后缀,前缀或后缀表示法。如果您的选择与标准不同(否定前缀,其余为中缀),请在回答中说明。
  4. 通常,合取范式不是唯一的(甚至不能重新排序)。您只需要输出一个有效的表格。
  5. 但是,您表示原子表达式时,它们必须与逻辑常数,运算符和分组符号(如果有)区别。
  6. 允许使用用于计算合取范式的内置函数。
  7. 禁止出现标准漏洞
  8. 这是;最短答案(以字节为单位)获胜。


1
CNF在重新排序之前不是唯一的:等效表达式P(P ∨ Q) ∧ (P ∨ (¬Q))都为合取范式。
格雷格·马丁

1
检查重言式/矛盾是与CNF转换无关的第二项任务,因此,我建议放弃这一要求,并将其置于自己的挑战中。
Laikoni '17

@Laikoni非常正确。我更新了一个问题,说这些是重言式和矛盾的可能输出,而不是必需的输出。
ngenisis'1

Answers:


1

最大值,4个字节

pcnf

在线试用!

您可以使用implieseqandor 分别寓意,对等,协同和脱节的运营商。


8

你会恨我...

Mathematica,23个字节

#~BooleanConvert~"CNF"&

输入将使用TrueFalse,而不是,否则会看起来非常相似问题的符号:所有的字符¬,和在数学(认可时使用UTF-8字符00AC,F523,29E6,2227输入,和分别为2228)和括号如您所愿。

默认情况下,输出将使用Mathematica的首选符号:例如,将输出最后一个测试用例(! P || ! Q || R) && (! P || Q || ! R)而不是((¬ P) ∨ ((¬ Q) ∨ R)) ∧ ((¬ P) ∨ (Q ∨ (¬ R)))。但是,将功能更改为

TraditionalForm[#~BooleanConvert~"CNF"]&

将使输出看起来很漂亮,并符合以下常用符号:

传统形式


2

JavaScript(ES6),127个字节

f=(s,t='',p=s.match(/[A-Z]/),r=RegExp(p,'g'))=>p?'('+f(s.replace(r,1),t+'|'+p)+')&('+f(s.replace(r,0),t+'|!'+p)+')':eval(s)?1:0+t

I / O格式如下(按优先顺序排列):

  • ((
  • ))
  • 1
  • 0
  • ¬!
  • <=
  • ==
  • &
  • |

例子:

P&(P<=R) -> ((1)&(0|P|!R))&((0|!P|R)&(0|!P|!R))
P==(!P) -> (0|P)&(0|!P)
(!P)|(Q==(P&R)) -> (((1)&(0|P|Q|!R))&((0|P|!Q|R)&(1)))&(((1)&(1))&((1)&(1)))

简单地重写该函数以产生析取范式:

f=(s,t='',p=s.match(/[A-Z]/),r=RegExp(p,'g'))=>p?'('f(s.replace(r,1),t+'&'+p)+')|('+f(s.replace(r,0),t+'&!'+p)+')':eval(s)?1+t:0

如果允许我也对输出使用上述优先级,则可以从此版本中节省8个字节,这将删除输出示例中的所有括号:

P&(P<=R) -> ((1&P&R)|(0))|((0)|(0))
P==(!P) -> (0)|(0)
(!P)|(Q==(P&R)) -> (((1&P&Q&R)|(0))|((0)|(1&P&!Q&!R)))|(((1&!P&Q&R)|(1&!P&Q&!R))|((1&!P&!Q&R)|(1&!P&!Q&!R)))
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.