Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Lang] Add ti.randn #2266

Merged
merged 9 commits into from
Apr 25, 2021
5 changes: 5 additions & 0 deletions docs/arithmetics.rst
Original file line number Diff line number Diff line change
Expand Up @@ -123,6 +123,11 @@ Random number generator

.. function:: ti.random(dtype = float)

Generates a uniform random float or integer number.

.. function:: ti.randn(dtype = None)

Generates a random floating point number from the standard normal distribution.

Element-wise arithmetics for vectors and matrices
-------------------------------------------------
Expand Down
10 changes: 8 additions & 2 deletions python/taichi/lang/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
import os
from copy import deepcopy as _deepcopy

import taichi as ti
from taichi.core.util import ti_core as _ti_core
from taichi.lang import impl
from taichi.lang.impl import *
Expand All @@ -19,8 +20,6 @@
taichi_scope, to_numpy_type, to_pytorch_type,
to_taichi_type)

import taichi as ti

# TODO(#2223): Remove
core = _ti_core

Expand Down Expand Up @@ -290,6 +289,13 @@ def svd(A, dt=None):
return svd(A, dt)


def randn(dt=None):
if dt is None:
dt = impl.get_runtime().default_fp
from .random import randn
return randn(dt)


determinant = deprecated('ti.determinant(a)',
'a.determinant()')(Matrix.determinant)
tr = deprecated('ti.tr(a)', 'a.trace()')(Matrix.trace)
Expand Down
17 changes: 17 additions & 0 deletions python/taichi/lang/random.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
import math

import taichi as ti


@ti.func
def randn(dt):
'''
Generates a random number from standard normal distribution
using the Box-Muller transform.
'''
assert dt == ti.f32 or dt == ti.f64
u1 = ti.random(dt)
u2 = ti.random(dt)
r = ti.sqrt(-2 * ti.log(u1))
c = ti.cos(math.tau * u2)
return r * c
29 changes: 27 additions & 2 deletions tests/python/test_random.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ def fill():

fill()
X = x.to_numpy()
for i in range(4):
for i in range(1, 4):
assert (X**i).mean() == approx(1 / (i + 1), rel=1e-2)


Expand All @@ -44,7 +44,7 @@ def fill():

fill()
X = x.to_numpy()
for i in range(4):
for i in range(1, 4):
assert (X**i).mean() == approx(1 / (i + 1), rel=1e-2)


Expand Down Expand Up @@ -125,3 +125,28 @@ def foo() -> ti.f64:
foo()
frac, _ = np.modf(x.to_numpy() * 4294967296)
assert np.max(frac) > 0


@archs_support_random
def test_randn():
'''
Tests the generation of Gaussian random numbers.
'''
for precision in [ti.f32, ti.f64]:
ti.init()
n = 1024
x = ti.field(ti.f32, shape=(n, n))

@ti.kernel
def fill():
for i in range(n):
for j in range(n):
x[i, j] = ti.randn(precision)

fill()
X = x.to_numpy()

# https://en.wikipedia.org/wiki/Normal_distribution#Moments
moments = [0.0, 1.0, 0.0, 3.0]
for i in range(4):
assert (X**(i + 1)).mean() == approx(moments[i], abs=3e-2)