如何在八面体内生成随机点而不丢弃?

我需要八面体内随机分布的点。我将八面体定​​义为所有点都满足abs(x) + abs(y) + abs(z) <= 1的体积,其中abs给出绝对值。 IE:六个顶点中的每个顶点都在一个轴上,距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是多维数据集。因此,我暗示可能存在一个简单的函数,可以将立方体中的任何点转换为八面体,但这只是我一直在探索的一种直觉。

ghostap 回答:如何在八面体内生成随机点而不丢弃?

这里是想法-从D + 1中的Dirichlet distribution采样点,选择D点,以使您在单形中是统一的

x 0 + x 1 + x 2 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,x2)
    elif octant == 1:
        return (x0,-x1,x2)
    elif octant == 2:
        return (x0,-x2)
    elif octant == 3:
        return (x0,-x2)
    elif octant == 4:
        return (-x0,x2)
    elif octant == 5:
        return (-x0,x2)
    elif octant == 6:
        return (-x0,-x2)
    elif octant == 7:
        return (-x0,-x2)

    return None

for _ in range(0,2000):
    x0,x2 = OctahedronSampling()

    print(f"{x0}   {x1}   {x2}")

这是2K点的快速图形

enter image description here

,

编辑:如@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
,

您知道如何在具有均匀分布的多维数据集中选择点,并且可以将多维数据集分解为八个方形金字塔。 (抱歉,我无法提供图形。)

我将从一个多维数据集开始: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
本文链接:https://www.f2er.com/3148605.html

大家都在问