我正在使用一些流行的python包作为基础,为图形和网络开发一个开源近似算法库。主要目标是在图形和网络上包含NP-Complete问题的最新近似算法。原因是1)我还没有看到一个很好的(现代)整合软件包来涵盖这个和2)它将是一个很好的教学工具,用于学习NP-Hard优化问题的近似算法。
在构建这个库时,我使用单元测试来进行健全性检查(正如任何适当的开发人员所做的那样)。我对我的单元测试有些谨慎,因为它们本质上是近似算法可能无法返回正确的解决方案。目前我正在手工解决一些小实例,然后确保返回的结果与之匹配,但这在实现意义上是不可取的,也不是可扩展的。
单元测试近似算法的最佳方法是什么?生成随机实例并确保返回的结果小于算法保证的界限?这似乎有误报(测试时间很幸运,不能保证所有实例都低于限制)。
答案 0 :(得分:3)
您需要在此处分开两个问题。您的近似算法的质量和这些算法的实现的正确性。
测试近似算法的质量通常不适用于软件开发中使用的单元测试方法。例如,您需要生成代表问题实际大小的随机问题。您可能需要进行数学工作以获得一些上限/下限来判断无法解决的大型实例的算法质量。或者使用具有已知或最知名解决方案的问题测试集并比较您的结果。但无论如何,单元测试对提高近似算法的质量没有多大帮助。这是您在优化和数学方面的领域知识有用的地方。
实施的正确性是单元测试真正有用的地方。您可以在此处使用玩具大小的问题,并比较已知结果(手动解决,或通过代码中仔细的逐步调试验证)与您的代码生成的内容。有小问题不仅足够,而且在这里也是可取的,因此测试运行速度快,并且可以在开发周期中运行多次。这些类型的测试确保整体算法得出正确的结果。它介于单元测试和集成测试之间,因为您将大部分代码测试为黑盒子。但我发现这些类型的测试在优化领域非常有用。我建议对这种类型的测试做的一件事是通过固定种子为随机数生成器去除算法中的所有随机性。这些测试应始终以确定的方式运行,并在100%的时间内给出完全相同的结果。 我还建议在算法的低级模块中进行单元测试。隔离为图形上的弧分配权重的方法,并检查是否分配了正确的权重。隔离你的目标函数值计算函数和单元测试。你明白了我的意思。
削减这两个切片的另一个问题是性能。小玩具问题无法可靠地测试性能。还需要实现快速降低性能的工作算法的改变。一旦运行了算法版本,就可以在测量性能时创建更大的测试问题,并将其自动化为性能/集成测试。您可以不那么频繁地运行它们,因为它们将花费更多时间,但至少会在重构期间或算法的新功能添加中尽早通知您新引入的性能瓶颈
答案 1 :(得分:2)
检查生成的解决方案的有效性是显而易见的第一步。
此外,一个攻角可以regression testing使用已知预期近似解的实例(例如通过手动执行算法或使用其他人对相同算法的实现获得)。
还存在具有已知(最佳)解决方案的问题实例的存储库,例如TSPLIB
用于类似TSP的问题。也许这些可能有用。
如果所讨论的算法存在已知的上限,则生成许多随机实例并针对上限验证启发式解决方案可能会证明是富有成效的。如果你这样做,我会敦促你使运行重现(例如,总是使用相同的随机数发生器和种子)。
最后要注意的是:对于某些问题,完全随机的实例平均很容易找到好的近似解决方案。具有均匀且独立选择的弧重的非对称TSP就是这样的一个例子。我之所以提到这一点,可能会影响您的测试策略。
答案 2 :(得分:1)
通常可以检查一些东西 - 例如,您的算法总是会返回满足其约束条件的解决方案,即使它们不是最佳的。您还应该在每个可能的机会进行断言检查 - 这些将特定于您的程序,但可能会检查某些数量是否被保留,或者某些应该增加或最坏的情况不会减少,或者某些应该是本地的最佳确实是局部最优。
考虑到这些类型的检查,以及对已经提到的边界的检查,我赞成对大量随机生成的小问题运行测试,选择随机种子,如果它在问题102324上失败您可以重复该调试失败而不会遇到之前的102323问题。由于存在大量问题,您可能会增加基础错误导致错误明显足以导致检查失败的可能性。如果遇到小问题,您就有可能找到并修复错误。