Skip to content
This repository has been archived by the owner on Nov 17, 2023. It is now read-only.

[Numpy] random.randint() implemented #15956

Merged
merged 6 commits into from
Aug 27, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
66 changes: 65 additions & 1 deletion python/mxnet/ndarray/numpy/random.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,71 @@
from ...context import current_context
from . import _internal as _npi

__all__ = ['uniform']

__all__ = ['randint', 'uniform']


def randint(low, high=None, size=None, dtype=None, **kwargs):
"""Return random integers from `low` (inclusive) to `high` (exclusive).

Return random integers from the "discrete uniform" distribution of
the specified dtype in the "half-open" interval [`low`, `high`). If
`high` is None (the default), then results are from [0, `low`).

Parameters
----------
low : int
Lowest (signed) integer to be drawn from the distribution (unless
``high=None``, in which case this parameter is one above the
*highest* such integer).
high : int, optional
If provided, one above the largest (signed) integer to be drawn
from the distribution (see above for behavior if ``high=None``).
size : int or tuple of ints, optional
Output shape. If the given shape is, e.g., ``(m, n, k)``, then
``m * n * k`` samples are drawn. Default is None, in which case a
single value is returned.
dtype : dtype, optional
Desired dtype of the result. All dtypes are determined by their
name, i.e., 'int64', 'int', etc, so byteorder is not available
and a specific precision may have different C types depending
on the platform. The default value is 'np.int'.
haojin2 marked this conversation as resolved.
Show resolved Hide resolved
ctx : Context, optional
Device context of output. Default is current context.
out : ndarray, optional
The output ndarray (default is `None`).

Returns
-------
out : ndarray of ints
`size`-shaped array of random integers from the appropriate
distribution, or a single such random int if `size` not provided.

Examples
--------
>>> np.random.randint(2, size=10)
array([1, 0, 0, 0, 1, 1, 0, 0, 1, 0])
>>> np.random.randint(1, size=10)
array([0, 0, 0, 0, 0, 0, 0, 0, 0, 0])

Generate a 2 x 4 array of ints between 0 and 4, inclusive:

>>> np.random.randint(5, size=(2, 4))
array([[4, 0, 2, 1],
[3, 2, 2, 0]])
"""
ctx = kwargs.pop('ctx', None)
out = kwargs.pop('out', None)
if dtype is None:
dtype = 'int'
if ctx is None:
ctx = current_context()
if size is None:
size = 1
if high is None:
high = low
low = 0
return _npi.random_randint(low, high, shape=size, dtype=dtype, ctx=ctx, out=out)


def uniform(low=0.0, high=1.0, size=None, dtype=None, ctx=None, out=None):
Expand Down
55 changes: 54 additions & 1 deletion python/mxnet/numpy/random.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,60 @@
from __future__ import absolute_import
from ..ndarray import numpy as _mx_nd_np

__all__ = ['uniform']

__all__ = ["randint", "uniform"]


def randint(low, high=None, size=None, dtype=None, **kwargs):
"""Return random integers from `low` (inclusive) to `high` (exclusive).

Return random integers from the "discrete uniform" distribution of
the specified dtype in the "half-open" interval [`low`, `high`). If
`high` is None (the default), then results are from [0, `low`).

Parameters
----------
low : int
Lowest (signed) integer to be drawn from the distribution (unless
``high=None``, in which case this parameter is one above the
*highest* such integer).
high : int, optional
If provided, one above the largest (signed) integer to be drawn
from the distribution (see above for behavior if ``high=None``).
size : int or tuple of ints, optional
Output shape. If the given shape is, e.g., ``(m, n, k)``, then
``m * n * k`` samples are drawn. Default is None, in which case a
single value is returned.
dtype : dtype, optional
Desired dtype of the result. All dtypes are determined by their
name, i.e., 'int64', 'int', etc, so byteorder is not available
and a specific precision may have different C types depending
on the platform. The default value is 'np.int'.
ctx : Context, optional
Device context of output. Default is current context.
out : ndarray, optional
The output ndarray (default is `None`).

Returns
-------
out : ndarray of ints
`size`-shaped array of random integers from the appropriate
distribution, or a single such random int if `size` not provided.

Examples
--------
>>> np.random.randint(2, size=10)
array([1, 0, 0, 0, 1, 1, 0, 0, 1, 0])
>>> np.random.randint(1, size=10)
array([0, 0, 0, 0, 0, 0, 0, 0, 0, 0])

Generate a 2 x 4 array of ints between 0 and 4, inclusive:

>>> np.random.randint(5, size=(2, 4))
array([[4, 0, 2, 1],
[3, 2, 2, 0]])
"""
return _mx_nd_np.random.randint(low, high, size, dtype, **kwargs)


def uniform(low=0.0, high=1.0, size=None, dtype=None, ctx=None, out=None):
Expand Down
66 changes: 65 additions & 1 deletion python/mxnet/symbol/numpy/random.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,71 @@
from ...context import current_context
from . import _internal as _npi

__all__ = ['uniform']

__all__ = ['randint', 'uniform']


def randint(low, high=None, size=None, dtype=None, **kwargs):
"""Return random integers from `low` (inclusive) to `high` (exclusive).

Return random integers from the "discrete uniform" distribution of
the specified dtype in the "half-open" interval [`low`, `high`). If
`high` is None (the default), then results are from [0, `low`).

Parameters
----------
low : int
Lowest (signed) integer to be drawn from the distribution (unless
``high=None``, in which case this parameter is one above the
*highest* such integer).
high : int, optional
If provided, one above the largest (signed) integer to be drawn
from the distribution (see above for behavior if ``high=None``).
size : int or tuple of ints, optional
Output shape. If the given shape is, e.g., ``(m, n, k)``, then
``m * n * k`` samples are drawn. Default is None, in which case a
single value is returned.
dtype : dtype, optional
Desired dtype of the result. All dtypes are determined by their
name, i.e., 'int64', 'int', etc, so byteorder is not available
and a specific precision may have different C types depending
on the platform. The default value is 'np.int'.
ctx : Context, optional
Device context of output. Default is current context.
out : symbol, optional
The output symbol (default is `None`).

Returns
-------
out : symbol
`size`-shaped array of random integers from the appropriate
distribution, or a single such random int if `size` not provided.

Examples
--------
>>> np.random.randint(2, size=10)
array([1, 0, 0, 0, 1, 1, 0, 0, 1, 0])
>>> np.random.randint(1, size=10)
array([0, 0, 0, 0, 0, 0, 0, 0, 0, 0])

Generate a 2 x 4 array of ints between 0 and 4, inclusive:

>>> np.random.randint(5, size=(2, 4))
array([[4, 0, 2, 1],
[3, 2, 2, 0]])
"""
ctx = kwargs.pop('ctx', None)
out = kwargs.pop('out', None)
if dtype is None:
dtype = 'int'
if ctx is None:
ctx = current_context()
if size is None:
size = 1
if high is None:
high = low
low = 0
return _npi.random_randint(low, high, shape=size, dtype=dtype, ctx=ctx, out=out)


def uniform(low=0.0, high=1.0, size=None, dtype=None, ctx=None, out=None):
Expand Down
1 change: 1 addition & 0 deletions src/operator/random/sample_op.cc
Original file line number Diff line number Diff line change
Expand Up @@ -182,6 +182,7 @@ Example::

MXNET_OPERATOR_REGISTER_SAMPLE(_random_randint, SampleRandIntParam)
.add_alias("random_randint")
.add_alias("_npi_random_randint")
.describe(R"code(Draw random samples from a discrete uniform distribution.

Samples are uniformly distributed over the half-open interval *[low, high)*
Expand Down
46 changes: 46 additions & 0 deletions tests/python/unittest/test_numpy_op.py
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,8 @@
from common import assertRaises, with_seed
import random
import collections
import scipy.stats as ss
from mxnet.test_utils import verify_generator, gen_buckets_probs_with_ppf, retry


@with_seed()
Expand Down Expand Up @@ -931,6 +933,50 @@ def hybrid_forward(self, F, a, *args):
assert same(mx_out.asnumpy(), np_out)


@with_seed()
@use_np
def test_np_randint():
ctx = mx.context.current_context()
# test shapes
params = [
(0, 10),
(5, None)
]
shapes = [
(3, 3),
(3, 4),
(0, 0),
(3, 3, 3),
(0, 0, 0),
(2, 2, 4, 3),
(2, 2, 4, 3),
(2, 0, 3, 0),
(2, 0, 2, 3)
]
for shape in shapes:
for (low, high) in params:
data_mx = np.random.randint(low, high, size=shape)
assert data_mx.shape == shape

# test generator
for dtype in ['int32', 'int64']:
for low, high in [(50000000, 50001000),(-50000100,-50000000),(-500,199)]:
scale = high - low
buckets, probs = gen_buckets_probs_with_ppf(lambda x: ss.uniform.ppf(x, loc=low, scale=scale), 5)
# Quantize bucket boundaries to reflect the actual dtype and adjust probs accordingly
buckets = _np.array(buckets, dtype=dtype).tolist()
probs = [(buckets[i][1] - buckets[i][0]) / float(scale) for i in range(5)]
generator_mx = lambda x: np.random.randint(low, high, size=x, dtype=dtype, ctx=ctx).asnumpy()
verify_generator(generator=generator_mx, buckets=buckets, probs=probs, nrepeat=100)
# Scipy uses alpha = 0.01 for testing discrete distribution generator but we are using default alpha=0.05 (higher threshold ensures robustness)
# Refer - https://github.com/scipy/scipy/blob/9f12af697763fb5f9767d5cb1280ce62456a3974/scipy/stats/tests/test_discrete_basic.py#L45
generator_mx_same_seed = \
lambda x: _np.concatenate(
[np.random.randint(low, high, size=x // 10, dtype=dtype, ctx=ctx).asnumpy()
for _ in range(10)])
verify_generator(generator=generator_mx_same_seed, buckets=buckets, probs=probs, nrepeat=100)


if __name__ == '__main__':
import nose
nose.runmodule()