我需要八面体内随机分布的点。我将八面体定义为所有点都满足abs(x) + abs(y) + abs(z) <= 1
的体积,其中abs给出绝对值。 IE:六个顶点中的每个顶点都在一个轴上,距0,0,0的距离为1。也许您可以将其称为单位八面体。
牢记定义,我可以像这样天真的产生一个点:
val x: Double = nextDouble() // 0-1 range
val y = nextDouble(1.0 -x) // 1-x is upper bound, probably <1
val z = nextDouble(1.0 -(x+y))
问题在于,这倾向于较小的y值和较小的z值。显然分布不均。同样清楚的是,所有这些点仅在八个象限之一中。
我正在避免使用 discard方法,因为该函数将被大量调用,而且看来我应该比丢掉大多数分数更好。
请注意,dual of the octahedron是多维数据集。因此,我暗示可能存在一个简单的函数,可以将立方体中的任何点转换为八面体,但这只是我一直在探索的一种直觉。
答案 0 :(得分:1)
这里是想法-从D + 1中的Dirichlet distribution采样点,选择D点,以使您在单形中是统一的
x 0 + x 1 + x 2 <= 1,x i > = 0 >
要制成八面体,请随机选择八角形以表示观点。
Python代码
import math
import random
def Dirichlet():
"""sample 4d Dirichlet"""
x0 = -math.log(1.0 - random.random()) # exponential
x1 = -math.log(1.0 - random.random()) # exponential
x2 = -math.log(1.0 - random.random()) # exponential
x3 = -math.log(1.0 - random.random()) # exponential
s = 1.0/(x0+x1+x2+x3) # scaling
return (x0*s, x1*s, x2*s, x3*s)
def OctahedronSampling():
x0, x1, x2, _ = Dirichlet()
octant = random.randint(0, 7)
if octant == 0:
return (x0, x1, x2)
elif octant == 1:
return (x0, -x1, x2)
elif octant == 2:
return (x0, x1, -x2)
elif octant == 3:
return (x0, -x1, -x2)
elif octant == 4:
return (-x0, x1, x2)
elif octant == 5:
return (-x0, -x1, x2)
elif octant == 6:
return (-x0, x1, -x2)
elif octant == 7:
return (-x0, -x1, -x2)
return None
for _ in range(0, 2000):
x0, x1, x2 = OctahedronSampling()
print(f"{x0} {x1} {x2}")
这是2K点的快速图形
答案 1 :(得分:0)
编辑:如@Tonci所述,三个统一随机变量的和不是统一随机变量。实际上,对于a,b,c,d
,接近0的概率约为接近1(或接近-1)的概率的1.5倍。因此,下面的答案只是一个近似值。我把它留在这里,因为它也许可以给人正确的灵感。
八面体由8个定界平面定义。这些平面的方程式是abs(x) + abs(y) + abs(z) <= 1
的概括,其中abs
每次可以为正或负。所以:
x + y + z <= 1; x + y - z <= 1; x - y + z <= 1; x - y - z <= 1;
-x + y + z <= 1; -x + y - z <= 1; -x - y + z <= 1; -x - y - z <= 1
结合相反的平面方程:
-1 <= x + y + z <= 1; -1 <= x + y - z <= 1; -1 <= x - y + z <= 1; -1 <= x - y - z <= 1
现在,为以下每个表达式选择值:
x + y + z = a; x - y + z = b; x - y - z = c; x + y - z = d
或者对于八面体中的每个随机x,y,z,我们有4个值:
-1 <= a <= 1; -1 <= b <= 1; -1 <= c <= 1; -1 <= d <= 1
相反,如果我们有a,b,c,d的值,我们可以找到对应的x,y,z。这些方程是线性相关的,随机选择a,b,c,d中的3个,我们可以计算出第四个,也可以计算出x,y,z。
因此,我们在三个方向上选择随机数a,b,c,都在-1和1之间:
x + y + z = a
x - y + z = b
x - y - z = c
求解x,y,z:x: a/2 + c/2, y: a/2 - b/2, z: b/2 - c/2
。
在代码中:
val a: Double = 2*nextDouble()-1 // range -1..1
val b: Double = 2*nextDouble()-1 // range -1..1
val c: Double = 2*nextDouble()-1 // range -1..1
val x: Double = (a+c) / 2
val y: Double = (a-b) / 2
val z: Double = (b-c) / 2
或者更少的操作:
val a: Double = nextDouble() // range 0..1
val b: Double = nextDouble() // range 0..1
val c: Double = nextDouble() // range 0..1
val x: Double = a+c-1
val y: Double = a-b
val z: Double = b-c
答案 2 :(得分:0)
您知道如何在具有均匀分布的多维数据集中选择点,并且可以将多维数据集分解为八个方形金字塔。 (抱歉,我无法提供图形。)
我将从一个多维数据集开始:abs(x) <= 1; abs(y) <= 1; abs(z) <= 1
在其中选取一个点(列向量(x, y, z)
),然后进行反射以将其带入“顶部和底部”金字塔:
if abs(x) > abs(z), swap x and z. Equivalently, multiply by
0 0 1
0 1 0
1 0 0
if abs(y) > abs(z), swap y and z. Equivalently, multiply by
1 0 0
0 0 1
0 1 0
然后将两个金字塔颠倒成一个八面体:
if z>0
z = 1-z
if z<0
z = -1-z
然后旋转并缩放:
multiply by
1/2 -1/2 0
1/2 1/2 0
0 0 1