我昨天在一个修改后发布了这个问题没有意识到我的帐户在9个月后仍然有效,对于双重帖子感到抱歉,我已经修复了我在软糖指出的例子中的错误,我将进一步阐述上下文问题。
我正在尝试处理在python中表示为嵌套列表和字符串的一阶逻辑公式,以便它处于析取范式,
即
[
'&',
['|', 'a', 'b'],
['|', 'c', 'd']
]
变成
[
'|',
[
'|',
['&', 'a', 'c'],
['&', 'b', 'c']
],
[
'|',
['&', 'a', 'd'],
['&', 'b', 'd']
]
]`
其中|
或 且&
为 和 。
目前我正在使用递归实现,它对公式进行多次传递,直到找不到'ands'的列表参数内的任何嵌套'或'符号。它用于处理一组嵌套公式,表示为通用computational tree logic的字符串和列表,因此它不仅具有|
和&
s,而且还包含时间运算符。
这是我的实现,performDNF(form)
是切入点。现在,它使用dnfDistributivity()
对公式执行单次传递,适用于较小的输入,但是当您使用较大的输入时,while循环检查函数(checkDistributivity()
)在|
内找不到&
{1}}并终止。帮助任何人,这让我很生气。
def dnfDistributivity(self, form):
if isinstance(form, type([])):
if len(form) == 3:
if form[0] == '&':
if form[1][0] == '|':
form = [
'|',
['&', form[2], form[1][1]],
['&', form[2], form[1][2]]
]
elif form[2][0] == '|':
form = [
'|',
['&', form[1], form[2][1]],
['&', form[1], form[2][2]]
]
form[1] = self.dnfDistributivity(form[1])
form[2] = self.dnfDistributivity(form[2])
elif len(form) == 2:
form[1] = self.dnfDistributivity(form[1])
return form
def checkDistributivity(self, form, result = 0):
if isinstance(form, type([])):
if len(form) == 3:
if form[0] == '&':
print "found &"
if isinstance(form[1], type([])):
if form[1][0] == '|':
return 1
elif isinstance(form[2], type([])):
if form[2][0] == '|':
return 1
else:
result = self.checkDistributivity(form[1], result)
print result
if result != 1:
result = self.checkDistributivity(form[2], result)
print result
elif len(form) == 2:
result = self.checkDistributivity(form[1], result)
print result
return result
def performDNF(self, form):
while self.checkDistributivity(form):
form = self.dnfDistributivity(self.dnfDistributivity(form))
return form
答案 0 :(得分:3)
首先,关于您的代码的两个一般性评论:
return True
代替return 1
。isinstance(form, list)
代替isinstance(form, type([]))
。其次,其他一些观察结果:
除此之外,我认为这段代码的可读性可以大大提高。我会给出一个我认为正确的替代实现。让我知道下面的代码是否适合您;我没有为创建表达式而疯狂,所以我可能错过了一个边缘案例。最后,我将只关注常规命题连接词。应该清楚如何应用涉及CTL特异性结缔组织的转化。
创建一个代表运算符(连接词)的类Op
:
class Op(list):
def __init__(self, *args):
super().__init__(args)
__init__
的参数是操作数。此代码使用super
中定义的PEP 3135,仅适用于Python 3.x在Python 2.x中,您必须使用super
中定义的PEP 367:
class Op(list):
def __init__(self, *args):
super(Op, self).__init__(args)
为每个运算符创建Op
的简单子类。出于调试目的,您可能希望实现自定义__str__
方法:
class Neg(Op):
def __str__(self):
return '!(%s)' % tuple(self)
class And(Op):
def __str__(self):
return '(%s) & (%s)' % tuple(self)
class Or(Op):
def __str__(self):
return '(%s) | (%s)' % tuple(self)
class AX(Op):
def __str__(self):
return 'AX (%s)' % tuple(self)
...
现在公式!(a& b)可以创建为Neg(And('a', 'b'))
。
创建非常简单的函数,这些函数应用一次。这将使实施保持清洁。 Annotate这些函数提供了有关如何应用它们的一些信息。应该从上到下应用预订函数:首先转换表达式树的根,然后递归。在递归地将表达式应用于子表达式之后,应将 postorder 函数应用于表达式。使用isinstance
检查连接词的类型。
我们从容易开始:函数removeDoubleNeg
删除了双重否定:
@expressionTransformation('postorder')
def removeDoubleNeg(expr):
if isinstance(expr, Neg) and isinstance(expr[0], Neg):
return expr[0][0]
接下来,我们来定义DeMorgan的法律之一:
@expressionTransformation('preorder')
def deMorgan(expr):
if isinstance(expr, Neg) and isinstance(expr[0], And):
return Or(Neg(expr[0][0]), Neg(expr[0][1]))
现在这个问题的功能就是:
@expressionTransformation('preorder', 'postorder')
def distribute(expr):
if isinstance(expr, And):
if isinstance(expr[0], Or):
return Or(And(expr[0][0], expr[1]), And(expr[0][1], expr[1]))
if isinstance(expr[1], Or):
return Or(And(expr[0], expr[1][0]), And(expr[0], expr[1][1]))
哇!这是更少的代码!
好的,这是怎么回事?观察表达式转换 f 的任何天真实现都将涉及样板代码:
根据 f ,可能需要撤消步骤1和2( postorder 而不是预订)。不过, f 的每个实现看起来都很相似。您将需要避免使用样板代码,尤其是在您计划定义更多转换时。缺少这种样板,使前一步骤中定义的功能变得简洁(因此易于调试!)。函数expressionTransformation
返回的装饰器解决了这个问题。其实施如下:
from functools import wraps
def expressionTransformation(*args):
def wrap(f):
@wraps(f)
def recursiveTransformation(expr):
if not isinstance(expr, Op):
return expr
if 'postorder' in args:
expr[:] = map(recursiveTransformation, expr)
res = f(expr)
expr = expr if res is None else res
if 'preorder' in args:
expr[:] = map(recursiveTransformation, expr)
return expr
return recursiveTransformation
return wrap
这里会发生以下情况:
expressionTransformation
返回一个装饰器(名为wrap
),它接收转换函数f
作为其参数。wrap
返回一个递归函数recursiveTransformation
,只有当这个参数是连接词时才会将f
应用于它的参数expr
。args
的{{1}}参数,{<1}}将在之前或之后之前应用 >和之后将 f 应用于子表达式。expressionTransformation
可能会返回f
。函数functools.wraps
用于将f
的某些属性(例如其名称)复制到None
。此功能不是必需的。
(请注意,创建前序和后序转换比使用测试f
和recursiveTransformation
反复进行更有效的方法,但为了清晰起见,我选择了这一点。)
这就是全部。我们现在可以轻松地组合这些功能(请注意,此功能不应该被装饰):
'postorder' in args
您可以使用以下语句测试代码:
'preorder' in args
答案 1 :(得分:0)
你有:
elif len(form) == 2:
result = self.checkDistributivity(form[1], result)
print result
不应该是:
elif len(form) == 2:
result_1 = self.checkDistributivity(form[1], result)
result_2 = self.checkDistributivity(form[2], result)
if result_1 or result_2:
return 1