如何对启发式算法进行单元测试?


10

假设我们有路线查找算法:

def myHeuristicTSP(graph):
    /*implementation*/
    return route

现在我们要对此进行单元测试:

class TestMyHeuristicTSP:
    def testNullGraphRaiseValueError(self):
        self.assertRaises(ValueError, myHueristicTSP(None))

    def testSimpleTwoNodeGraphReturnsRoute:
        self.assertEquals(expectedResult, myHeuristicTSP(input))

问题是,对于非启发式TSP算法,我们可以给出各种图形,并检查它们是否始终返回绝对最短的路线。

但是因为启发式算法虽然仍然是确定性的,但它的可预测性较差,仅是为了了解该算法的工作原理并找到那些极端情况?


Answers:


11

对于一个试探性算法,该算法应该不会返回理想值,而是一个“足够好”的解决方案,您将拥有各种测试用例并进行检查

  1. 解决方案实际上有效吗?您当然想确保路由查找算法不会返回不可能的路径或从头到尾实际上未引出的路径。您可能无法证明该解决方案是理想的,但是至少应该能够验证返回值实际上一个解决方案。
  2. 解决方案“足够好”吗?您应该具有一些要求,以定义该算法比理想解决方案可能差多少。您应该拥有已知理想解决方案的测试用例(或至少是被认为足以用作比较标准的解决方案),并确认算法提供的解决方案的恶化不超过x%。
  3. 算法足够快吗?当您认为它们可以通过提高速度来弥补精度不足时,通常会使用启发式方法。为了验证这一点,您应该测量它们的运行时间,并确保它们确实比获得确切解决方案的算法更快。运行时测量总是有点模糊,因此超出预期的运行时应该是警告,而不是错误(当您的单元测试框架允许警告和错误之间有所区别时)。

您能否提供建议,以测试如何确定一条路线有效?
dwjohnston

@dwjohnston只需绘制图形,确定路径,然后尝试遍历图形上的路径即可。验证路径的每个边都从当前节点开始,并且路径在正确的节点处开始和结束。您还可以验证在结束之前没有到达结束节点。
菲利普

您还可以验证路径中没有节点被使用两次,因为这表明不必要的循环。当然,除非您有一些使环路有用的特殊规则,例如UPS路线查找系统偏向于三个向右转而不是向左转
Philipp

3

大多数优化算法(包括启发式算法)通过对某些配置(例如路由)进行操作。本身的操作应确保它们仅提供有效的配置,因此首先应针对每个配置进行单元测试。当您确定确定优化算法仅使用那些操作时,通常就不需要对算法结果进行有效性测试。

为了为任何一种更复杂的算法创建良好的单元测试,实际上必须详细了解算法本身。对于像“爬山”这样的简单启发式方法,通常可以预测少量输入的结果。例如,对于3到5分的初始路线,按一定顺序给出时,您可以预测会发生什么。对于我所知道的大多数确定性启发式算法,这都是正确的,因此这可能是一个不错的起点。

对于更复杂的算法和更大的输入,当您仅将输入馈入算法并尝试检查输出时,实际上您就不再在进行单元测试,而是在进行验收或集成测试。之所以要对这种算法进行“单元测试”存在问题,是因为它通常由几个较小的部分(单个单元)组成。因此,对于真正的单元测试这种算法,您将必须识别这些部分并分别进行测试。此外,您可以使用代码覆盖率或分支覆盖率技术来确保您有足够的测试用例。

如果您不是在寻找单元测试,而是自动化的验收或集成测试,则可以尝试@Phillip在(2)或(3)下建议的内容

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.