【问题标题】:STL: sorting and searching in enormous dataSTL:在海量数据中排序和搜索
【发布时间】:2017-04-15 20:56:35
【问题描述】:

我有两组点(source 和 target)。目标是在target 中为每个source 点找到一个唯一的1:1 最近邻 点。

我的尝试按预期工作,但速度慢得离谱。我已经测试了几千点,但在实际场景中点数将是数百万。我不是 STL 方面的专家。有什么建议可以优化吗?

std::vector<UT_Vector3> targetPosVector;
for (auto i = 0; i < targetNumPoints; i++)
{
    auto pos = target->getPos3(i);

    targetPosVector.push_back(pos);
}

std::vector<int> uniqueNeighborVector;
for (auto ptoff = 0; ptoff < sourceNumPoints; ptoff++)
{
    std::vector<std::pair<int, fpreal>> nearpointVector; // neighbor vector in form of "(idx, dist)"

    auto pos = source->getPos3(ptoff);
    for (auto j = 0; j < targetNumPoints; j++)
    {
        fpreal dist = pos.distance(targetPosVector[j]);

        std::pair<int, fpreal> neighbor {j, dist};
        nearpointVector.push_back(neighbor);
    }
    std::sort(nearpointVector.begin(), nearpointVector.end(), [](const std::pair<int, fpreal> &left,
                                                                 const std::pair<int, fpreal> &right)
                                                                { return left.second < right.second; });

    std::vector<int> neighborVector;
    for (auto i : nearpointVector)
    {
        neighborVector.push_back(i.first);
    }

    // trying to imitate Python's next() function
    // uniqueNeighborList[]
    // uneighbor = next(i for i in neighborVector if i not in uniqueNeighborVector)
    // uniqueNeighborVector = set(uniqueNeighborList.append(uneighbor))
    for (auto i : neighborVector)
    {     
        if (std::find(uniqueNeighborVector.begin(), uniqueNeighborVector.end(), i) == uniqueNeighborVector.end())
        {
            int uneighbor = i; // later on binds to the geometry attribute

            uniqueNeighborVector.push_back(i);

            break;
        }
    }
}

在哪里:

  • source 和 target 是Detail Geometry数据
  • distance 是一个计算两个向量之间距离的函数
  • getPos3 是获取3-float vector 点位置的函数
  • fpreal又名64-bit float
  • UT_Vector3 是 3-float vector
  • sourceNumPoints 和 targetNumPoints 是点数 source 和 target 几何。

【问题讨论】:

  • 标准库确实没有针对这个任务进行优化。看看专门的库,比如PCL。
  • 这里的问题与其说是 STL,不如说是所选择的算法。您正在生成二次距离对,因此这种方法不会扩展到数百万个点。您将需要使用某种形式的空间细分来快速拒绝不可能的配对,而不是盲目地尝试所有组合。
  • 即便如此,即使是目前的蛮力实现也显得不必要地令人费解。我收集到一个目标点可能只匹配一次,低阶源获得第一个 dib。如果是这样,那么与其生成和排序一个临时向量,然后线性扫描整个目标集,我建议删除使用过的目标(通过交换回)并在没有中间缓冲和排序的情况下在线选择最佳匹配。诚然,它不会让您进入数百万美元,但它可能是一个开始。
  • 目标点随机分布。让我们假设第一个点的最近邻居是 1203,而第二个点可能是 719123 之类的任何东西或具有巨大跳跃的东西。
  • @Pradeep Barua:太好了,(均匀的)随机分布应该让事情相对容易处理。例如,您可以尝试将目标点划分为 3D 网格结构。然后在搜索过程中直接索引最近的网格条目并逐渐向外扫描,返回并删除找到的第一个点。随着网格大小调整到密度,我相信这应该大致是线性的。

标签: c++ algorithm stl computational-geometry point-clouds


【解决方案1】:

正如 cmets 中提到的,当尝试计算数百万个点时,二次复杂度是失败的。即使您优化了代码,如果方法没有改变,二次复杂度将保持不变。

在我看来,这听起来像是 R3 中的经典 NN 问题。一个众所周知的方法是使用k-d trees,它们允许 O(log n) 查询时间在 O(n log n) 构建时间和线性空间内。可以通过各种库寻求实现:nanoflann、kdtree(这些来自快速搜索,我敢肯定还有包含 k-d 树的复杂库。)

简短回顾:我会使用 3-d 树并在您的目标点集上构建它。然后取每个源点(一个接一个)并在 O(log n) 时间内找到 3-d 树中的最近邻居,每个都将导致 O(|source| log |target|) 时间和 O(|目标|) 大小。

一个相关的question。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-07-10
    • 2018-10-10
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多