【问题标题】:How to implement a fast, lazy KDTree in Haskell?如何在 Haskell 中实现一个快速、懒惰的 KDTree?
【发布时间】:2013-12-03 19:32:02
【问题描述】:

我正在尝试在 Haskell 中实现一个 kdtree(请参阅 implementation),但我尝试在实现最近邻算法时变得聪明并利用 Haskells 的惰性(请参阅第 46 行)。

虽然它在技术上是正确的,但就是:

minimumBy (compare `on` qd q) vs == head . nearestNeighbours (kdtree 5 vs) $ q
==> True

基于 kdtree 的版本要慢得多(标准:5.38 毫秒 vs 138.44 毫秒,数据点为 500k)。我最初认为这是由于 ordMerge(第 59 行)中的模式匹配过于严格,但我重写了它,根据我的理解,bs 现在应该只根据需要进行评估。

如果是这种情况,算法应该只下降到匹配的桶,并在检查当前最佳最近邻居是否真的是最佳候选时重新下降。

我做了一些分析,nearestNeighhbors 被调用了大约 800 次。给定 8 和 100 个测试用例的树深度,这听起来很合理,不是吗?


刚刚将我的代码上传到github:https://github.com/fhaust/threesg

这应该让你开始:

git clone https://github.com/fhaust/threesg
cd threesg
cabal sandbox init
cabal install --enable-benchmarks --enable-tests
cabal test
cabal bench --benchmark-options="+RTS -K100M -RTS"

(需要-K100M,因为测试集是从 500k 点创建的)


在为 github 创建测试集时,我注意到在正态分布点上,kdtree 搜索的运行速度比线性搜索快很多……可能我的问题不是算法……而是我的测试集:(

【问题讨论】:

  • 是的......但这对我没有帮助。它大部分时间都花在nearestNeighbors.nnlnearestNeighbors.nnr
  • 你是在比较 kd 树的构造,然后用蛮力找到最近的邻居找到它的最近邻居吗?
  • @DiegoNolan ...在进行基准测试之前不强制kdtree。我希望我写的the NFData instance是正确的。
  • 你有我们可以使用的main 函数和示例数据吗?我注意到的主要事情是ordMerge 可能没有被内联,as it's recursive:尝试应用蹩脚的静态参数转换技巧,或尝试ordMerge f q p n d = go where go = ...(更好的无点样式),因此递归在常量参数上是封闭的。希望结合dist' 的内联将fpq 的应用程序共享暴露给编译器。让我们知道您发现了什么

标签: haskell lazy-evaluation nearest-neighbor kdtree


【解决方案1】:

最后,这是一个跟踪评估顺序的问题。我在github上传了最新版本。

看看line 74:只有当第一个列表的第一个条目不符合“不可能有更好的候选人”标准时,才会评估第二个列表。

适当的标准,我做了一些benchmarking 并且 kd-tree 确实更快。

您如何看待这个解决方案?我认为代码非常简洁易读。是否有任何明显的性能损失?

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2015-09-06
    • 1970-01-01
    • 2015-09-06
    • 2011-07-19
    • 1970-01-01
    • 2011-05-14
    • 2015-04-02
    • 1970-01-01
    相关资源
    最近更新 更多