我正在使用递归函数来解决使用完整KK算法的分区问题。
我的算法搜索可能分区的树。我希望通过阻止特定的树枝来修剪那棵树。我的“修剪器”想跟踪最小结果(事实上到目前为止发现的两个子集之和之间的最小差异)。
我的代码格式为:
def prune(branch):
def pruner(list_):
# If only single element in list, reached end of branch
if len(list_) == 1:
return list_[0]
# ... pruning code here ...
# Decision to prune depends on pruner.min
# If didn't prune, calculate as usual
# tracking minimum
min_branch = branch(list_)
pruner.min = min(pruner.min, min_branch)
return min_branch
pruner.__name__ = branch.__name__
pruner.min = float("inf")
return pruner
@prune
def branch(list_):
# ... code to make two new branches here ...
return min(branch(list_1), branch(list_2))
它适用于单个对branch
的调用 - pruner.min
在我的装饰器的开头设置一次 - 而branch
会返回正确答案
问题是如果我连续两次或更多次使用该功能。在这种情况下,每次调用后都不会重置pruner.min
,导致我决定修剪分支时出现问题。
对于pruner.min = float("inf")
函数的每次初始(即非递归)调用,我如何(优雅地)重置branch
?我唯一能想到的是添加一个first
关键字参数def branch(list_, first=True)
,我将其设置为False
,以便在branch
函数内进行递归调用。我的装饰师可以看看这个论点。这是最好的方式吗?
为了完整性,这是一个可运行的示例,可以得到正确的答案。欢迎任何更一般的评论。
import copy
def prune(CKK_branch):
def pruner(list_):
internal_list = copy.deepcopy(list_)
# Check whether end of branch or whether optimal solution achieved
if pruner.min == 0.:
return pruner.min
elif len(internal_list) == 1:
return list_[0]
# Sort branch
internal_list.sort(reverse=True)
# Prune branch
if pruner.min < internal_list[0] - sum(internal_list[1:]):
return internal_list[0]
# Find minimum in branch and track minimum of all branches
min_branch = CKK_branch(internal_list)
pruner.min = min(pruner.min, min_branch)
return min_branch
pruner.__name__ = CKK_branch.__name__
pruner.min = float("inf")
return pruner
@prune
def CKK(list_):
internal_list = copy.deepcopy(list_)
# Replace maximum two numbers by their difference and their sum in two
# branches
diff = internal_list[0] - internal_list[1]
sum_ = internal_list[0] + internal_list[1]
sum_tree = copy.deepcopy(internal_list)
diff_tree = copy.deepcopy(internal_list)
del sum_tree[0:2]
del diff_tree[0:2]
sum_tree.append(sum_)
diff_tree.append(diff)
return min(CKK(diff_tree), CKK(sum_tree))
example_list_1 = [1.4,
10.1,
19.55,
11.71,
51.7,
122.1
]
example_list_2 = [10,
5,
1,
1
]
print CKK(example_list_1)
print CKK(example_list_2)
print CKK(example_list_1)
# 27.64 # Correct (122.1) - (1.4, ...)
# 3 # Correct (10) - (5, 1, 1)
# 122.1 # Something went wrong
答案 0 :(得分:1)
你可以设置一个标志为None
,并在CKK中传递任何值,就像使用默认的arg一样:
import copy
def prune(CKK_branch):
def pruner(list_, flag=None):
internal_list = copy.deepcopy(list_)
if flag is None:
pruner.min = float("inf")
# Check whether end of branch or whether optimal solution achieved
if pruner.min == 0.:
return pruner.min
elif len(internal_list) == 1:
return list_[0]
# Sort branch
internal_list.sort(reverse=True)
# Prune branch
if pruner.min < internal_list[0] - sum(internal_list[1:]):
return internal_list[0]
# Find minimum in branch and track minimum of all branches
min_branch = CKK_branch(internal_list)
pruner.min = min(pruner.min, min_branch)
return min_branch
pruner.__name__ = CKK_branch.__name__
return pruner
@prune
def CKK(list_):
internal_list = copy.deepcopy(list_)
# Replace maximum two numbers by their difference and their sum in two
# branches
diff = internal_list[0] - internal_list[1]
sum_ = internal_list[0] + internal_list[1]
sum_tree = copy.deepcopy(internal_list)
diff_tree = copy.deepcopy(internal_list)
del sum_tree[0:2]
del diff_tree[0:2]
sum_tree.append(sum_)
diff_tree.append(diff)
return min(CKK(diff_tree,True), CKK(sum_tree,True))
每次调用min(CKK(diff_tree,True), CKK(sum_tree,True))
时,您都会将最小值重置为inf。
In [26]: CKK(example_list_1)
Out[26]: 27.639999999999993
In [27]: CKK(example_list_2)
Out[27]: 3
In [28]: CKK(example_list_1)
Out[28]: 27.639999999999993
答案 1 :(得分:0)
为什么不添加另一个图层?
def prune(f):
def wrapper(branch):
def wrapped(branch):
...
wrapper.min = float('inf')
return wrapped(branch)
return wrapper
现在你的装饰器将返回一个调用其嵌套函数的闭包。