我有一个问题,我有一堆需要很长时间才能执行的函数,每个函数返回一个布尔值True / False。我将一个巨大的布尔表达式应用于所有函数,以获得整体的真/假分数。目前我的代码不是基于函数的,因此执行所有函数,然后应用大布尔表达式。我已经发现,使它们成为函数会允许使用短循环的子表达式来阻止某些函数调用。我现在需要的是一种重新排序表达式的方法,以便我有最少的调用次数。
考虑以下代码(可怕的代码示例,但您应该明白这一点):
def q():
print "q"
return False
def r():
print "r"
return False
def s():
print "s"
return False
def a():
print "a"
return False
def b():
print "b"
return False
def c():
print "c"
return False
def d():
print "d"
return False
def i():
print "i"
return False
def j():
print "j"
return False
(q() or r() or s()) and (a() and b() and c() and (i() or j()))
在这种情况下,您会看到q r s已打印。一切都是假的,所以它短路。但是在这种情况下,应首先评估b或c,因为如果其中任何一个为False,则整个表达式为False。假设最后的表达式是由用户生成的,这样我就不能硬编码最好的订单。我想我有一个非常简单的算法。
另外两件事:
1。)如果我允许其他逻辑如“不”怎么办? 2.)我可以根据运行所需的时间为每个功能分配一个分数,然后计算出来吗?
答案 0 :(得分:2)
要优化表达式,您需要了解两件事:每个函数的成本以及它将短路的可能性。完成后,您可以评估每个子表达式以生成相同的术语;尝试参数顺序的每个排列将显示哪种排列具有最低成本。
def evaluate_or(argument_evaluation_list):
total_cost = 0.0
probability_of_reaching = 1.0
for cost, probability_of_true in argument_evaluation_list:
total_cost += probability_of_reaching * cost
probability_of_reaching *= 1.0 - probability_of_true
return total_cost, 1.0 - probability_of_reaching
def evaluate_and(argument_evaluation_list):
total_cost = 0.0
probability_of_reaching = 1.0
for cost, probability_of_true in argument_evaluation_list:
total_cost += probability_of_reaching * cost
probability_of_reaching *= probability_of_true
return total_cost, probability_of_reaching
def evaluate_not(argument_evaluation)
cost, probability_of_true = argument_evaluation
return cost, 1.0 - probability_of_true
答案 1 :(得分:1)
你的公式在CNF中(顺便说一句,你不需要在顶级or
附近使用这些括号),这对于计算复杂性来说非常好,它是非常简单的公式。既然你目前还没有not
,我真的不知道是否有必要寻找某种复杂的算法,你的公式已经很简单了。但是你肯定可以尝试某种启发式方法(比如开始评估尽可能少的文字的子句,以便尽快失败...问题是即使你从一个只有一个字面的子句开始,到计算函数可能比计算更大的子句更昂贵,所以是的,根据大小而不是根据预期的计算复杂度对它们进行排序是有意义的。
在您合并not
的那一刻,您可以找到一些有用的其他内容。特别是如何将这些转换为CNF,以及来自resolution的想法对您有用。
答案 2 :(得分:0)
您可以将表达式转换为树结构,其中每个分支代表有序子级列表上的ANY或ALL进程。在第一个FALSE上ALL分支短路,在第一个TRUE上ANY分支短路。
如果所有条件的权重均相同,则应先放置简单条件(叶),然后再按其各自的复杂性数量递增(以其子代的复杂性总和递归度量)来对子分支进行排序。
因此,以这种树形结构表示的条件将如下所示:
ALL:
*--- ANY: q(), r(), q()
a()
b()
c()
*--- ANY: i(), j()
计算每个孩子的体重表明相对体重:
ALL:
3 *--- ANY: q(), r(), q()
1 a()
1 b()
1 c()
2 *--- ANY: i(), j()
---
8
这将允许您重新排列条件:
ALL:
1 a()
1 b()
1 c()
2 *--- ANY: i(), j()
3 *--- ANY: q(), r(), q()
---
8
至少要考虑另外两个因素,但是您将需要更多有关条件的见识:
需要花费更多时间/资源进行评估的条件应放在评估顺序的较低位置
更可能产生TRUE / FALSE的条件是,短路所处的ANY / ALL组的顺序应更高。 ANY / ALL组的可能性可以通过组合每个孩子的概率来计算(例如,ALL: 1-(1-P1)(1-P2)...(1-Pn)) 。资源成本也可以根据概率进行调整。在此处添加NOT:分组会有所不同
在这些其他因素之间找到合适的平衡可能是一门艺术,并且将非常取决于解决方案的领域。