3D 高斯 generator/transform
3D gaussian generator/transform
如何生成 3 个高斯变量?我知道 Box-Muller algorithm 可用于将两个 (U1,U2) 统一变量转换为两个 (X,Y) 高斯变量,但如何生成第三个变量? (Z).
一个简单的方法:
在这种游戏中,您不太可能只需要一次 3 个高斯变量。
你需要一些存储变量,它可以包含高斯变量的三元组或 nothing(Null,Nothing,Empty,无论你的编程语言是什么,你都没有告诉我们是哪一个)。
最初,商店中没有任何东西(空的)。
当被问及三胞胎时:
如果商店包含一个三胞胎,则 return 那个三胞胎。
并将商店标记为空。
如果商店是空的,运行 Box-Muller 3次。
这给了你 2 个三胞胎。
将第二个三胞胎放在商店里。
Return第一个三胞胎。
适合喜欢数学的程序员的另一种方法:
如果只是尝试使 Box-Muller 适应 3 维,唯一棘手的部分是获得随机 3D 向量的 norm。剩下的就是关于2个球面角θ(theta)和φ(phi),这很容易。
事实证明,在 3 维中,该范数涉及 incomplete gamma function 的倒数。
如果您有 Python 和 Numpy/Scipy,这就是函数 scipy.special.gammaincinv。
我们可以这样写代码:
import math
import numpy.random as rd
import scipy.special as sp
# convert 3 uniform [0,1) variates into 3 unit Gaussian variates:
def boxMuller3d(u3):
u0,u1,u2 = u3 # 3 uniform random numbers in [0,1)
gamma = u0
norm2 = 2.0 * sp.gammaincinv(1.5, gamma) # "regularized" versions
norm = math.sqrt(norm2)
zr = (2.0 * u1) - 1.0 # sin(theta)
hr = math.sqrt(1.0 - zr*zr) # cos(theta)
phi = 2.0 * math.pi * u2
xr = hr * math.cos(phi)
yr = hr * math.sin(phi)
g3 = list(map(lambda c: c*norm, [xr, yr, zr]))
return g3
# generate 3 uniform variates and convert them into 3 unit Gaussian variates:
def gauss3(rng):
u3 = rng.uniform(0.0, 1.0, 3)
g3 = boxMuller3d(u3)
return g3
为了(部分)检查正确性,我们可以有这个小主程序,它显示生成的随机序列的 1 到 4 阶统计矩:
randomSeed = 42
rng = rd.default_rng(randomSeed)
count = 3000000 # (X,Y,Z) triplet count
variates = []
for i in range(count):
g3 = gauss3(rng)
variates += g3
ln = len(variates)
print("length=%d\n" % ln)
# Checking statistical moments of order 1 to 4:
m1 = sum(variates) / ln
m2 = sum( map(lambda x: x*x, variates) ) / ln
m3 = sum( map(lambda x: x**3, variates) ) / ln
m4 = sum( map(lambda x: x**4, variates) ) / ln
print("m1=%g m2=%g m3=%g m4=%g\n" % (m1,m2,m3,m4))
测试程序输出:
length=9000000
m1=-0.000455911 m2=1.00025 m3=-0.000563454 m4=3.00184
因此我们可以看到这些矩相当接近它们的数学预期值,分别为 0、1、0、3。
如何生成 3 个高斯变量?我知道 Box-Muller algorithm 可用于将两个 (U1,U2) 统一变量转换为两个 (X,Y) 高斯变量,但如何生成第三个变量? (Z).
一个简单的方法:
在这种游戏中,您不太可能只需要一次 3 个高斯变量。
你需要一些存储变量,它可以包含高斯变量的三元组或 nothing(Null,Nothing,Empty,无论你的编程语言是什么,你都没有告诉我们是哪一个)。
最初,商店中没有任何东西(空的)。
当被问及三胞胎时:
如果商店包含一个三胞胎,则 return 那个三胞胎。 并将商店标记为空。
如果商店是空的,运行 Box-Muller 3次。 这给了你 2 个三胞胎。 将第二个三胞胎放在商店里。 Return第一个三胞胎。
适合喜欢数学的程序员的另一种方法:
如果只是尝试使 Box-Muller 适应 3 维,唯一棘手的部分是获得随机 3D 向量的 norm。剩下的就是关于2个球面角θ(theta)和φ(phi),这很容易。
事实证明,在 3 维中,该范数涉及 incomplete gamma function 的倒数。
如果您有 Python 和 Numpy/Scipy,这就是函数 scipy.special.gammaincinv。
我们可以这样写代码:
import math
import numpy.random as rd
import scipy.special as sp
# convert 3 uniform [0,1) variates into 3 unit Gaussian variates:
def boxMuller3d(u3):
u0,u1,u2 = u3 # 3 uniform random numbers in [0,1)
gamma = u0
norm2 = 2.0 * sp.gammaincinv(1.5, gamma) # "regularized" versions
norm = math.sqrt(norm2)
zr = (2.0 * u1) - 1.0 # sin(theta)
hr = math.sqrt(1.0 - zr*zr) # cos(theta)
phi = 2.0 * math.pi * u2
xr = hr * math.cos(phi)
yr = hr * math.sin(phi)
g3 = list(map(lambda c: c*norm, [xr, yr, zr]))
return g3
# generate 3 uniform variates and convert them into 3 unit Gaussian variates:
def gauss3(rng):
u3 = rng.uniform(0.0, 1.0, 3)
g3 = boxMuller3d(u3)
return g3
为了(部分)检查正确性,我们可以有这个小主程序,它显示生成的随机序列的 1 到 4 阶统计矩:
randomSeed = 42
rng = rd.default_rng(randomSeed)
count = 3000000 # (X,Y,Z) triplet count
variates = []
for i in range(count):
g3 = gauss3(rng)
variates += g3
ln = len(variates)
print("length=%d\n" % ln)
# Checking statistical moments of order 1 to 4:
m1 = sum(variates) / ln
m2 = sum( map(lambda x: x*x, variates) ) / ln
m3 = sum( map(lambda x: x**3, variates) ) / ln
m4 = sum( map(lambda x: x**4, variates) ) / ln
print("m1=%g m2=%g m3=%g m4=%g\n" % (m1,m2,m3,m4))
测试程序输出:
length=9000000
m1=-0.000455911 m2=1.00025 m3=-0.000563454 m4=3.00184
因此我们可以看到这些矩相当接近它们的数学预期值,分别为 0、1、0、3。