Skip to content

Commit 50762cd

Browse files
ENH: impl random.logistic (#522)
1 parent 05658e0 commit 50762cd

File tree

8 files changed

+121
-4
lines changed

8 files changed

+121
-4
lines changed

dpnp/backend/include/dpnp_iface.hpp

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -773,6 +773,22 @@ INP_DLLEXPORT void dpnp_rng_gumbel_c(void* result, double loc, double scale, siz
773773
template <typename _DataType>
774774
INP_DLLEXPORT void dpnp_rng_laplace_c(void* result, double loc, double scale, size_t size);
775775

776+
/**
777+
* @ingroup BACKEND_API
778+
* @brief math library implementation of random number generator (logistic distribution)
779+
*
780+
* @param [in] size Number of elements in `result` arrays.
781+
*
782+
* @param [in] loc The position of the distribution peak.
783+
*
784+
* @param [in] scale The exponential decay.
785+
*
786+
* @param [out] result Output array.
787+
*
788+
*/
789+
template <typename _DataType>
790+
INP_DLLEXPORT void dpnp_rng_logistic_c(void* result, double loc, double scale, size_t size);
791+
776792
/**
777793
* @ingroup BACKEND_API
778794
* @brief math library implementation of random number generator (lognormal distribution)

dpnp/backend/include/dpnp_iface_fptr.hpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -132,6 +132,7 @@ enum class DPNPFuncName : size_t
132132
DPNP_FN_RNG_GUMBEL, /**< Used in numpy.random.gumbel() implementation */
133133
DPNP_FN_RNG_HYPERGEOMETRIC, /**< Used in numpy.random.hypergeometric() implementation */
134134
DPNP_FN_RNG_LAPLACE, /**< Used in numpy.random.laplace() implementation */
135+
DPNP_FN_RNG_LOGISTIC, /**< Used in numpy.random.logistic() implementation */
135136
DPNP_FN_RNG_LOGNORMAL, /**< Used in numpy.random.lognormal() implementation */
136137
DPNP_FN_RNG_MULTINOMIAL, /**< Used in numpy.random.multinomial() implementation */
137138
DPNP_FN_RNG_MULTIVARIATE_NORMAL, /**< Used in numpy.random.multivariate_normal() implementation */

dpnp/backend/kernels/dpnp_krnl_random.cpp

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -301,6 +301,30 @@ void dpnp_rng_laplace_c(void* result, double loc, double scale, size_t size)
301301
event_out.wait();
302302
}
303303

304+
/* Logistic(loc, scale) ~ loc + scale * log(u/(1.0 - u)) */
305+
template <typename _DataType>
306+
void dpnp_rng_logistic_c(void* result, double loc, double scale, size_t size)
307+
{
308+
if (!size)
309+
{
310+
return;
311+
}
312+
cl::sycl::vector_class<cl::sycl::event> no_deps;
313+
314+
const _DataType d_zero = _DataType(0.0);
315+
const _DataType d_one = _DataType(1.0);
316+
317+
_DataType* result1 = reinterpret_cast<_DataType*>(result);
318+
319+
mkl_rng::uniform<_DataType> distribution(d_zero, d_one);
320+
auto event_out = mkl_rng::generate(distribution, DPNP_RNG_ENGINE, size, result1);
321+
event_out.wait();
322+
323+
for(size_t i = 0; i < size; i++) result1[i] = log(result1[i]/(1.0 - result1[i]));
324+
325+
for(size_t i = 0; i < size; i++) result1[i] = loc + scale * result1[i];
326+
}
327+
304328
template <typename _DataType>
305329
void dpnp_rng_lognormal_c(void* result, _DataType mean, _DataType stddev, size_t size)
306330
{
@@ -721,6 +745,8 @@ void func_map_init_random(func_map_t& fmap)
721745

722746
fmap[DPNPFuncName::DPNP_FN_RNG_LAPLACE][eft_DBL][eft_DBL] = {eft_DBL, (void*)dpnp_rng_laplace_c<double>};
723747

748+
fmap[DPNPFuncName::DPNP_FN_RNG_LOGISTIC][eft_DBL][eft_DBL] = {eft_DBL, (void*)dpnp_rng_logistic_c<double>};
749+
724750
fmap[DPNPFuncName::DPNP_FN_RNG_LOGNORMAL][eft_DBL][eft_DBL] = {eft_DBL, (void*)dpnp_rng_lognormal_c<double>};
725751

726752
fmap[DPNPFuncName::DPNP_FN_RNG_MULTINOMIAL][eft_INT][eft_INT] = {eft_INT, (void*)dpnp_rng_multinomial_c<int>};

dpnp/dpnp_algo/dpnp_algo.pxd

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -105,6 +105,7 @@ cdef extern from "dpnp_iface_fptr.hpp" namespace "DPNPFuncName": # need this na
105105
DPNP_FN_RNG_GUMBEL
106106
DPNP_FN_RNG_HYPERGEOMETRIC
107107
DPNP_FN_RNG_LAPLACE
108+
DPNP_FN_RNG_LOGISTIC
108109
DPNP_FN_RNG_LOGNORMAL
109110
DPNP_FN_RNG_MULTINOMIAL
110111
DPNP_FN_RNG_MULTIVARIATE_NORMAL

dpnp/random/dpnp_algo_random.pyx

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,7 @@ __all__ = [
5353
"dpnp_hypergeometric",
5454
"dpnp_laplace",
5555
"dpnp_lognormal",
56+
"dpnp_rng_logistic",
5657
"dpnp_multinomial",
5758
"dpnp_multivariate_normal",
5859
"dpnp_negative_binomial",
@@ -84,6 +85,7 @@ ctypedef void(*fptr_dpnp_rng_gaussian_c_1out_t)(void *, double, double, size_t)
8485
ctypedef void(*fptr_dpnp_rng_gumbel_c_1out_t)(void *, double, double, size_t) except +
8586
ctypedef void(*fptr_dpnp_rng_hypergeometric_c_1out_t)(void *, int, int, int, size_t) except +
8687
ctypedef void(*fptr_dpnp_rng_laplace_c_1out_t)(void *, double, double, size_t) except +
88+
ctypedef void(*fptr_dpnp_rng_logistic_c_1out_t)(void *, double, double, size_t) except +
8789
ctypedef void(*fptr_dpnp_rng_lognormal_c_1out_t)(void *, double, double, size_t) except +
8890
ctypedef void(*fptr_dpnp_rng_multinomial_c_1out_t)(void * result, int, const double *, const size_t, size_t) except +
8991
ctypedef void(*fptr_dpnp_rng_multivariate_normal_c_1out_t)(void *,
@@ -402,6 +404,32 @@ cpdef dparray dpnp_laplace(double loc, double scale, size):
402404
return result
403405

404406

407+
cpdef dparray dpnp_rng_logistic(double loc, double scale, size):
408+
"""
409+
Returns an array populated with samples from logistic distribution.
410+
`dpnp_rng_logistic` generates a matrix filled with random floats sampled from a
411+
univariate logistic distribution.
412+
413+
"""
414+
415+
# convert string type names (dparray.dtype) to C enum DPNPFuncType
416+
cdef DPNPFuncType param1_type = dpnp_dtype_to_DPNPFuncType(numpy.float64)
417+
418+
# get the FPTR data structure
419+
cdef DPNPFuncData kernel_data = get_dpnp_function_ptr(DPNP_FN_RNG_LOGISTIC, param1_type, param1_type)
420+
421+
result_type = dpnp_DPNPFuncType_to_dtype( < size_t > kernel_data.return_type)
422+
# ceate result array with type given by FPTR data
423+
cdef dparray result = dparray(size, dtype=result_type)
424+
425+
cdef fptr_dpnp_rng_logistic_c_1out_t func = < fptr_dpnp_rng_logistic_c_1out_t > kernel_data.ptr
426+
# call FPTR function
427+
func(result.get_data(), loc, scale, result.size)
428+
429+
return result
430+
431+
432+
405433
cpdef dparray dpnp_lognormal(double mean, double stddev, size):
406434
"""
407435
Returns an array populated with samples from lognormal distribution.

dpnp/random/dpnp_iface_random.py

Lines changed: 25 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -527,13 +527,34 @@ def logistic(loc=0.0, scale=1.0, size=None):
527527
528528
For full documentation refer to :obj:`numpy.random.logistic`.
529529
530-
Notes
531-
-----
532-
The function uses `numpy.random.logistic` on the backend and will be
533-
executed on fallback backend.
530+
Limitations
531+
-----------
532+
Parameters ``loc`` and ``scale`` are supported as scalar.
533+
Otherwise, :obj:`numpy.random.logistic(loc, scale, size)` samples are drawn.
534+
Output array data type is :obj:`dpnp.float64`.
535+
536+
Examples
537+
--------
538+
>>> loc, scale = 0., 1.
539+
>>> s = dpnp.random.logistic(loc, scale, 1000)
534540
535541
"""
536542

543+
if not use_origin_backend(loc):
544+
# TODO:
545+
# array_like of floats for `loc` and `scale`
546+
if not dpnp.isscalar(loc):
547+
pass
548+
elif not dpnp.isscalar(scale):
549+
pass
550+
elif scale < 0:
551+
pass
552+
else:
553+
if size == None or size == 1:
554+
return dpnp_rng_logistic(loc, scale, size)[0]
555+
else:
556+
return dpnp_rng_logistic(loc, scale, size)
557+
537558
return call_origin(numpy.random.logistic, loc, scale, size)
538559

539560

tests/test_random.py

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -395,6 +395,28 @@ def test_seed(self):
395395
self.check_seed('laplace', {'loc': loc, 'scale': scale})
396396

397397

398+
class TestDistributionsLogistic(TestDistribution):
399+
400+
def test_moments(self):
401+
loc = 2.56
402+
scale = 0.8
403+
expected_mean = loc
404+
expected_var = (scale ** 2) * (numpy.pi ** 2) / 3
405+
self.check_moments('logistic', expected_mean,
406+
expected_var, {'loc': loc, 'scale': scale})
407+
408+
def test_invalid_args(self):
409+
loc = 3.0 # OK
410+
scale = -1.0 # non-negative `scale` is expected
411+
self.check_invalid_args('logistic',
412+
{'loc': loc, 'scale': scale})
413+
414+
def test_seed(self):
415+
loc = 2.56
416+
scale = 0.8
417+
self.check_seed('logistic', {'loc': loc, 'scale': scale})
418+
419+
398420
class TestDistributionsLognormal(TestDistribution):
399421

400422
def test_extreme_value(self):

tests_external/skipped_tests_numpy.tbl

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1474,6 +1474,7 @@ tests/test_random.py::TestRandomDist::test_gumbel_0
14741474
tests/test_random.py::TestRandomDist::test_hypergeometric
14751475
tests/test_random.py::TestRandomDist::test_laplace
14761476
tests/test_random.py::TestRandomDist::test_laplace_0
1477+
tests/test_random.py::TestRandomDist::test_logistic
14771478
tests/test_random.py::TestRandomDist::test_lognormal
14781479
tests/test_random.py::TestRandomDist::test_lognormal_0
14791480
tests/test_random.py::TestRandomDist::test_multinomial
@@ -1567,6 +1568,7 @@ tests/test_randomstate.py::TestRandomDist::test_gumbel_0
15671568
tests/test_randomstate.py::TestRandomDist::test_hypergeometric
15681569
tests/test_randomstate.py::TestRandomDist::test_laplace
15691570
tests/test_randomstate.py::TestRandomDist::test_laplace_0
1571+
tests/test_randomstate.py::TestRandomDist::test_logistic
15701572
tests/test_randomstate.py::TestRandomDist::test_lognormal
15711573
tests/test_randomstate.py::TestRandomDist::test_lognormal_0
15721574
tests/test_randomstate.py::TestRandomDist::test_multinomial

0 commit comments

Comments
 (0)