【问题标题】:Automated computation of algorithm time complexity for terminating algorithms终止算法的算法时间复杂度的自动计算
【发布时间】:2012-11-02 11:43:55
【问题描述】:

这里有很多关于 SO 的相关问题,但他们都询问是否编写程序来计算任意算法的复杂度(这显然是无法确定的)。我愿意对输入做如下限制:

  1. 算法终止
  2. 算法是纯函数式的

问题是,是否可以编写一个程序来通过静态分析计算这种算法的时间复杂度?如果输入算法没有终止,则程序行为未定义(它可能会崩溃、返回谎言或无法终止)。

【问题讨论】:

  • 您可以编辑并实际提出可以回答的问题吗?我看到了要求声明,但没有实际问题。
  • @KenWhite 问题在标题中,但我已经更新以在正文中更清楚地说明:)
  • :-) 我读了标题中的一个声明(完全没有问题)。现在你的实际要求更清楚了。谢谢,+1。

标签: computer-science big-o code-analysis time-complexity halting-problem


【解决方案1】:
【解决方案2】:

您不能 100% 确定您从任何技术中得到正确答案,以根据实际运行时间估算复杂性。这是因为确切的运行时间可能涉及一个非常复杂的函数,这意味着运行时间理论上可以跟随任何其他函数,而输入大小低于某个非常大的数字。当输入大小趋于无穷大时,运行时间只需要趋向于复杂度函数(一些倍数)。这假设您想要找到一个tight bound(它存在于许多但不是所有的算法中),而不仅仅是一个上限或下限。

但您可以对复杂性做出一些合理的估计,通常应该相当准确。

另请注意,对于相同大小的不同输入,许多算法具有不同的运行时间。您可以尝试对相同大小的几个不同输入运行以下命令,并对结果进行平均以减轻这种情况。这也将有助于缓解可能影响运行时间的系统条件。尽管如果您不知道要用于这些情况的具体输入,您可能无法估计最坏和最好情况的复杂性(因为它们可能太少了,以至于您在传递随机数据时无法获取它们)。

如何做到这一点:

记录一些足够大和足够不同大小的输入的时间(例如,您可以针对大小等于 10 的不同幂的输入运行它,例如 100、1000 和 10000,这些应该足够大,可以运行至少几秒钟以减少数据的噪音)。让我们使用 3 个输入大小。严格来说,您只需要 2 个输入大小,但您可以使用 3 个或更多作为附加验证。

现在我们可以尝试将我们得到的这 3 个结果映射到一组复杂性中的一个,例如 O(1)O(log(n))O(sqrt(n))O(n)O(n log n)O(n<sup>2</sup>)O(n<sup>3</sup>)、等等

如果您尝试手动匹配它,您可以将获得的运行时间与上述每个函数的图形(适当缩放)一起放在一个图表上,看看哪个最匹配。

如果您尝试将其自动化,您可以尝试将每个函数映射到输入大小并查看其匹配程度。

有更好的方法可以做到这一点,但一种非常简单的方法如下:

假设你有这些运行时间:

input size   running time
100          21 seconds
1000         29 seconds
10000        40 seconds

现在您可以尝试将其中一个(比如最大的一个,这可能是最准确的)与上述函数之一的倍数相匹配。

O(n):     k x n     = k x 10000     = 40,    k = 40 / 10000     = 0.004
O(log n): k x log n = k x log 10000 = 40,    k = 40 / log 10000 = 10
O(n²):    k x n²    = k x 10000²    = 40,    k = 40 / 10000²    = 0.0000004

现在将等式给出的结果与其他输入大小的实际运行时间进行比较:

For n = 1000, actual running time = 29 seconds
O(n):     0.004 x 1000      = 4 seconds
O(log n): 10 x log 1000     = 30 seconds
O(n²):    0.0000004 x 1000² = 0.4 seconds

For n = 100, actual running time = 21 seconds
O(n):     0.004 x 100      = 0.4 seconds
O(log n): 10 x log 100     = 20 seconds
O(n²):    0.0000004 x 100² = 0.004 seconds

看这个,我们可以清楚地看到O(log n) 是最接近的,两种情况下实际运行时间和预测运行时间仅相差 1 秒。这就是我们对复杂性的猜测。

【讨论】:

    【解决方案3】:

    考虑到算法停止的限制,这是可能的。为每个可能的输入执行算法并测量执行时间。接下来,选择一个函数作为可能的上限,并针对每个结果对其进行测试。如果不够好,增加边界并重新测试。重复直到边界足够好。

    编辑: 该解决方案假设真实计算机程序的边界,即不同输入的数量不是无限的。否则,无法计算通用算法的复杂度。考虑复杂度为O(n) = nO(n-1) 的算法。由于输入是无限的,因此您将找不到任何可以限制复杂性的函数f

    【讨论】:

    • 为什么不满意?这个问题纯粹是理论上的,答案也是如此。我想它可以优化,但没有看到这样做的理由
    • 就个人而言,我会在一个实用的解决方案中找到价值——你能想象编译器警告关于无意的 n**3 算法吗?但作为一个理论上的答案,在寻找边界函数的启发式方法中,它仍然存在一些不足之处。不过,我同意这个设置并没有提供太多改进它的动力。
    • 我会说,找出一个 general 算法是否以 O(n3) 为界至少需要 O(n3) 次计算,在编译时或运行时 - 我认为在正常情况下都不可接受
    • 这个解决方案不太可能在大多数终止输入上终止(因为通常有无限数量的可能输入),而且也不是很严格,主要是启发式的。
    • @singpolyma 我已经编辑了答案以解决您提出的问题。
    猜你喜欢
    • 2011-06-21
    • 1970-01-01
    • 2021-08-25
    • 1970-01-01
    • 2015-03-09
    • 2018-10-15
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多