Hash 散列2D、3D和nD向量

Hash 散列2D、3D和nD向量,hash,vector,3d,geometry,Hash,Vector,3d,Geometry,对于对由IEEE 32位浮点组成的2d和3d向量进行散列,什么是好的散列函数(快速、良好的分布、很少的冲突)。我假设一般的3d向量,但是假设法线(总是在[-1,1])的算法也很受欢迎。我也不害怕位操纵,因为IEEE浮点数也是IEEE浮点数 另一个更普遍的问题是散列Nd浮点向量,其中N非常小(3-12)且为常量,但在编译时未知。目前,我只是将这些浮点数作为uint并将它们异或在一起,这可能不是最好的解决方案。中介绍了一个空间哈希函数。他们使用散列函数 散列(x,y,z)=(x p1 xor y p

对于对由IEEE 32位浮点组成的2d和3d向量进行散列,什么是好的散列函数(快速、良好的分布、很少的冲突)。我假设一般的3d向量,但是假设法线(总是在[-1,1])的算法也很受欢迎。我也不害怕位操纵,因为IEEE浮点数也是IEEE浮点数


另一个更普遍的问题是散列Nd浮点向量,其中N非常小(3-12)且为常量,但在编译时未知。目前,我只是将这些浮点数作为uint并将它们异或在一起,这可能不是最好的解决方案。

中介绍了一个空间哈希函数。他们使用散列函数

散列(x,y,z)=(x p1 xor y p2 xor z p3)模块n

其中p1、p2、p3较大 素数,在我们的例子73856093中, 分别为19349663、83492791。这个 值n是哈希表大小


在本文中,x、y和z是离散坐标;您也可以使用浮动的二进制值。

我有两个建议

  • 假设一个大小为l的网格单元,通过计算ix=楼层(x/l)、iy=楼层(y/l)和iz=楼层(z/l),量化x、y和z坐标,其中ix、iy和iz是整数。现在使用中定义的哈希函数
如果你不做量化,它就不会对接近度(局部性)敏感

  • 已经提到对高维向量进行散列。为什么不将它们也用于3d或2d矢量?LSH的一个变体使用了适用于欧氏距离度量(这是我们对2d和3d向量所需要的),称为使用p-稳定分布的局部敏感散列。这是一个非常可读的教程

我是根据这里看到的评论用Python写的

l = 5
n = 5
p1,p2,p3 = 73856093, 19349663, 83492791

x1 = [33,4,11]
x2 = [31,1,14]
x3 = [10,44,19]

def spatial_hash(x):
    ix,iy,iz = np.floor(x[0]/l), np.floor(x[1]/l), np.floor(x[2]/l)
    return (int(ix*p1) ^ int(iy*p2) ^ int(iz*p3)) % n

print (spatial_hash(x1))
print (spatial_hash(x2))
print (spatial_hash(x3))
它给

1
1
3
这似乎奏效了

在C中++

#include <cstdlib>
#include <iostream>
#include <unordered_map>
#include <vector>
#include <random>

#include <eigen3/Eigen/Dense>
using namespace Eigen;

using namespace std;
const int HASH_SIZE = 200;    
//const float MAX = 500.0;
const float L = 0.2f;
const float mmin = -1.f;
const float mmax = 1.f;

unordered_map<int, vector<Vector3d>> map ;

inline size_t hasha(Vector3d &p) {
    int ix = (unsigned int)((p[0]+2.f) / L);
    int iy = (unsigned int)((p[1]+2.f) / L);
    int iz = (unsigned int)((p[2]+2.f) / L);
    return (unsigned int)((ix * 73856093) ^ (iy * 19349663) ^ (iz * 83492791)) % HASH_SIZE;
}


int main(int argc, char** argv) {

    std::default_random_engine generator;
    std::uniform_real_distribution<double> distribution(-1.0,1.0);

    
    for(size_t i=0;i<300;i++){
    float x = distribution(generator);
    float y = distribution(generator);
    float z = distribution(generator);
        Vector3d v(x,y,z);
        std::cout << hasha(v)  << " " << v[0] << " " << v[1] << " " << v[2] << std::endl;
    map[hasha(v)].push_back(v);
    vector<Vector3d> entry = map[hasha(v)];
    std::cout << "size " << entry.size() << std::endl;
    }

    for (const auto & [ key, value ] : map) {
    cout << key << std::endl;
    vector<Vector3d> v = map[key];
    float average = 0.0f;
    for (int i=0; i<v.size(); i++){
        for (int j=0; j<v.size(); j++){
        if (i!=j){
            Vector3d v1 = v[i];
            Vector3d v2 = v[j];
            std::cout << "   dist " <<  (v1-v2).norm() << std::endl;
        }
        } 
    }

    }
    

}
#包括
#包括
#包括
#包括
#包括
#包括
使用名称空间特征;
使用名称空间std;
const int HASH_SIZE=200;
//常量浮点最大值=500.0;
常数浮点L=0.2f;
常量浮点mmin=-1.f;
常量浮点mmax=1.f;
无序地图;
内联大小\u t hasha(Vector3d&p){
int ix=(无符号int)((p[0]+2.f)/L);
int-iy=(无符号int)((p[1]+2.f)/L);
int-iz=(无符号int)((p[2]+2.f)/L);
返回(无符号整数)((ix*73856093)^(iy*19349663)^(iz*83492791))%HASH_SIZE;
}
int main(int argc,字符**argv){
std::默认随机引擎生成器;
标准:均匀实分布(-1.0,1.0);

对于(size_t i=0;i…您是否使用普通XOR方法测试了散列的分布情况?您可能会感到惊讶。@Matti看起来至少3d向量的分布情况不是很糟糕(在Stanford bunny 35k Vert上测试,散列表大小为65537).我只是觉得有人可能有一个更专业的解决方案,因为我不久前在网上搜索了一下,没有找到任何关于这个主题的内容。65537听起来比你可能想使用的数字大(或者是一个打字错误)相关:@StevenLu:绝对不是。++2的幂几乎总是一个很好的安全方法。这是避免模相关所必需的,因此,使哈希表的大小非常棒。请注意,19349663不是素数(它是41和471943的乘积)我发现在二维情况下使用质数p1和p3可以得到非常好的分布。当他们写
xp1xor yp2xor zp3
时,他们的意思是
(x*p1)xor(y*p2)xor(z*p3)
还是
x*(p1xor y)*(p2xor z)*p3
?@tuple_cat我相信是
(x*p1)xor(y*p2)xor(z*p3)
非常有趣!有什么实现吗?我正在尝试用scipy/numpy实现它。谢谢。