
.. _program_listing_file_library_include_rocrand_rocrand.hpp:

Program Listing for File rocrand.hpp
====================================

|exhale_lsh| :ref:`Return to documentation for file <file_library_include_rocrand_rocrand.hpp>` (``library/include/rocrand/rocrand.hpp``)

.. |exhale_lsh| unicode:: U+021B0 .. UPWARDS ARROW WITH TIP LEFTWARDS

.. code-block:: cpp

   // Copyright (c) 2017-2022 Advanced Micro Devices, Inc. All rights reserved.
   //
   // Permission is hereby granted, free of charge, to any person obtaining a copy
   // of this software and associated documentation files (the "Software"), to deal
   // in the Software without restriction, including without limitation the rights
   // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
   // copies of the Software, and to permit persons to whom the Software is
   // furnished to do so, subject to the following conditions:
   //
   // The above copyright notice and this permission notice shall be included in
   // all copies or substantial portions of the Software.
   //
   // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
   // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
   // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
   // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
   // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
   // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
   // THE SOFTWARE.
   
   #ifndef ROCRAND_HPP_
   #define ROCRAND_HPP_
   
   // At least C++11 required
   #if defined(__cplusplus) && __cplusplus >= 201103L
   
       #include "rocrand/rocrand.h"
       #include "rocrand/rocrand_kernel.h"
   
       #include <exception>
       #include <limits>
       #include <random>
       #include <sstream>
       #include <string>
       #include <type_traits>
   
   namespace rocrand_cpp {
   
   
   class error : public std::exception
   {
   public:
       typedef rocrand_status error_type;
   
       error(error_type error) noexcept
           : m_error(error),
             m_error_string(to_string(error))
       {
       }
   
       ~error() noexcept
       {
       }
   
       error_type error_code() const noexcept
       {
           return m_error;
       }
   
       std::string error_string() const noexcept
       {
           return m_error_string;
       }
   
       const char* what() const noexcept
       {
           return m_error_string.c_str();
       }
   
       static std::string to_string(error_type error)
       {
           switch(error)
           {
               case ROCRAND_STATUS_SUCCESS:
                   return "Success";
               case ROCRAND_STATUS_VERSION_MISMATCH:
                   return "Header file and linked library version do not match";
               case ROCRAND_STATUS_NOT_CREATED:
                   return "Generator was not created using rocrand_create_generator";
               case ROCRAND_STATUS_ALLOCATION_FAILED:
                   return "Memory allocation failed during execution";
               case ROCRAND_STATUS_TYPE_ERROR:
                   return "Generator type is wrong";
               case ROCRAND_STATUS_OUT_OF_RANGE:
                   return "Argument out of range";
               case ROCRAND_STATUS_LENGTH_NOT_MULTIPLE:
                   return "Length requested is not a multiple of dimension";
               case ROCRAND_STATUS_DOUBLE_PRECISION_REQUIRED:
                   return "GPU does not have double precision";
               case ROCRAND_STATUS_LAUNCH_FAILURE:
                   return "Kernel launch failure";
               case ROCRAND_STATUS_INTERNAL_ERROR:
                   return "Internal library error";
               default: {
                   std::stringstream s;
                   s << "Unknown rocRAND error (" << error << ")";
                   return s.str();
               }
           }
       }
   
       friend
       bool operator==(const error& l, const error& r)
       {
           return l.error_code() == r.error_code();
       }
   
       friend
       bool operator!=(const error& l, const error& r)
       {
           return !(l == r);
       }
   
   private:
       error_type m_error;
       std::string m_error_string;
   };
   
   template<class IntType = unsigned int>
   class uniform_int_distribution
   {
       static_assert(std::is_same<unsigned char, IntType>::value
                         || std::is_same<unsigned short, IntType>::value
                         || std::is_same<unsigned long long int, IntType>::value
                         || std::is_same<unsigned int, IntType>::value,
                     "Only unsigned char, unsigned short, unsigned int and unsigned long long int "
                     "types are supported in uniform_int_distribution");
   
   public:
       typedef IntType result_type;
   
       uniform_int_distribution()
       {
       }
   
       void reset()
       {
       }
   
       IntType min() const
       {
           return 0;
       }
   
       IntType max() const
       {
           return std::numeric_limits<IntType>::max();
       }
   
       template<class Generator>
       void operator()(Generator& g, IntType * output, size_t size)
       {
           rocrand_status status;
           status = this->generate(g, output, size);
           if(status != ROCRAND_STATUS_SUCCESS) throw rocrand_cpp::error(status);
       }
   
       bool operator==(const uniform_int_distribution<IntType>& other)
       {
           (void) other;
           return true;
       }
   
       bool operator!=(const uniform_int_distribution<IntType>& other)
       {
           return !(*this == other);
       }
   
   private:
       template<class Generator>
       rocrand_status generate(Generator& g, unsigned char * output, size_t size)
       {
           return rocrand_generate_char(g.m_generator, output, size);
       }
   
       template<class Generator>
       rocrand_status generate(Generator& g, unsigned short * output, size_t size)
       {
           return rocrand_generate_short(g.m_generator, output, size);
       }
   
       template<class Generator>
       rocrand_status generate(Generator& g, unsigned int * output, size_t size)
       {
           return rocrand_generate(g.m_generator, output, size);
       }
   
       template<class Generator>
       rocrand_status generate(Generator& g, unsigned long long int* output, size_t size)
       {
           return rocrand_generate_long_long(g.m_generator, output, size);
       }
   };
   
   template<class RealType = float>
   class uniform_real_distribution
   {
       static_assert(
           std::is_same<float, RealType>::value
           || std::is_same<double, RealType>::value
           || std::is_same<half, RealType>::value,
           "Only float, double, and half types are supported in uniform_real_distribution"
       );
   
   public:
       typedef RealType result_type;
   
       uniform_real_distribution()
       {
       }
   
       void reset()
       {
       }
   
       RealType min() const
       {
           if(std::is_same<float, RealType>::value)
           {
               return static_cast<RealType>(ROCRAND_2POW32_INV);
           }
           return static_cast<RealType>(ROCRAND_2POW32_INV_DOUBLE);
       }
   
       RealType max() const
       {
           return 1.0;
       }
   
       template<class Generator>
       void operator()(Generator& g, RealType * output, size_t size)
       {
           rocrand_status status;
           status = this->generate(g, output, size);
           if(status != ROCRAND_STATUS_SUCCESS) throw rocrand_cpp::error(status);
       }
   
       bool operator==(const uniform_real_distribution<RealType>& other)
       {
           (void) other;
           return true;
       }
   
       bool operator!=(const uniform_real_distribution<RealType>& other)
       {
           return !(*this == other);
       }
   
   private:
       template<class Generator>
       rocrand_status generate(Generator& g, float * output, size_t size)
       {
           return rocrand_generate_uniform(g.m_generator, output, size);
       }
   
       template<class Generator>
       rocrand_status generate(Generator& g, double * output, size_t size)
       {
           return rocrand_generate_uniform_double(g.m_generator, output, size);
       }
   
       template<class Generator>
       rocrand_status generate(Generator& g, half * output, size_t size)
       {
           return rocrand_generate_uniform_half(g.m_generator, output, size);
       }
   };
   
   template<class RealType = float>
   class normal_distribution
   {
       static_assert(
           std::is_same<float, RealType>::value
           || std::is_same<double, RealType>::value
           || std::is_same<half, RealType>::value,
           "Only float, double and half types are supported in normal_distribution"
       );
   
   public:
       typedef RealType result_type;
   
       class param_type
       {
       public:
           using distribution_type = normal_distribution<RealType>;
           param_type(RealType mean = 0.0, RealType stddev = 1.0)
               : m_mean(mean), m_stddev(stddev)
           {
           }
   
           param_type(const param_type& params) = default;
   
           RealType mean() const
           {
               return m_mean;
           }
   
           RealType stddev() const
           {
               return m_stddev;
           }
   
           bool operator==(const param_type& other)
           {
               return m_mean == other.m_mean && m_stddev == other.m_stddev;
           }
   
           bool operator!=(const param_type& other)
           {
               return !(*this == other);
           }
       private:
           RealType m_mean;
           RealType m_stddev;
       };
   
       normal_distribution(RealType mean = 0.0, RealType stddev = 1.0)
           : m_params(mean, stddev)
       {
       }
   
       normal_distribution(const param_type& params)
           : m_params(params)
       {
       }
   
       void reset()
       {
       }
   
       RealType mean() const
       {
           return m_params.mean();
       }
   
       RealType stddev() const
       {
           return m_params.stddev();
       }
   
       RealType min() const
       {
           return std::numeric_limits<RealType>::lowest();
       }
   
       RealType max() const
       {
           return std::numeric_limits<RealType>::max();
       }
   
       param_type param() const
       {
           return m_params;
       }
   
       void param(const param_type& params)
       {
           m_params = params;
       }
   
       template<class Generator>
       void operator()(Generator& g, RealType * output, size_t size)
       {
           rocrand_status status;
           status = this->generate(g, output, size);
           if(status != ROCRAND_STATUS_SUCCESS) throw rocrand_cpp::error(status);
       }
   
       bool operator==(const normal_distribution<RealType>& other)
       {
           return this->m_params == other.m_params;
       }
   
       bool operator!=(const normal_distribution<RealType>& other)
       {
           return !(*this == other);
       }
   
   private:
       template<class Generator>
       rocrand_status generate(Generator& g, float * output, size_t size)
       {
           return rocrand_generate_normal(
               g.m_generator, output, size, this->mean(), this->stddev()
           );
       }
   
       template<class Generator>
       rocrand_status generate(Generator& g, double * output, size_t size)
       {
           return rocrand_generate_normal_double(
               g.m_generator, output, size, this->mean(), this->stddev()
           );
       }
   
       template<class Generator>
       rocrand_status generate(Generator& g, half * output, size_t size)
       {
           return rocrand_generate_normal_half(
               g.m_generator, output, size, this->mean(), this->stddev()
           );
       }
   
       param_type m_params;
   };
   
   template<class RealType = float>
   class lognormal_distribution
   {
       static_assert(
           std::is_same<float, RealType>::value
           || std::is_same<double, RealType>::value
           || std::is_same<half, RealType>::value,
           "Only float, double and half types are supported in lognormal_distribution"
       );
   
   public:
       typedef RealType result_type;
   
       class param_type
       {
       public:
           using distribution_type = lognormal_distribution<RealType>;
           param_type(RealType m = 0.0, RealType s = 1.0)
               : m_mean(m), m_stddev(s)
           {
           }
   
           param_type(const param_type& params) = default;
   
           RealType m() const
           {
               return m_mean;
           }
   
           RealType s() const
           {
               return m_stddev;
           }
   
           bool operator==(const param_type& other)
           {
               return m_mean == other.m_mean && m_stddev == other.m_stddev;
           }
   
           bool operator!=(const param_type& other)
           {
               return !(*this == other);
           }
       private:
           RealType m_mean;
           RealType m_stddev;
       };
   
       lognormal_distribution(RealType m = 0.0, RealType s = 1.0)
           : m_params(m, s)
       {
       }
   
       lognormal_distribution(const param_type& params)
           : m_params(params)
       {
       }
   
       void reset()
       {
       }
   
       RealType m() const
       {
           return m_params.m();
       }
   
       RealType s() const
       {
           return m_params.s();
       }
   
       param_type param() const
       {
           return m_params;
       }
   
       void param(const param_type& params)
       {
           m_params = params;
       }
   
       RealType min() const
       {
           return 0;
       }
   
       RealType max() const
       {
           return std::numeric_limits<RealType>::max();
       }
   
       template<class Generator>
       void operator()(Generator& g, RealType * output, size_t size)
       {
           rocrand_status status;
           status = this->generate(g, output, size);
           if(status != ROCRAND_STATUS_SUCCESS) throw rocrand_cpp::error(status);
       }
   
       bool operator==(const lognormal_distribution<RealType>& other)
       {
           return this->m_params == other.m_params;
       }
   
       bool operator!=(const lognormal_distribution<RealType>& other)
       {
           return !(*this == other);
       }
   
   private:
       template<class Generator>
       rocrand_status generate(Generator& g, float * output, size_t size)
       {
           return rocrand_generate_log_normal(
               g.m_generator, output, size, this->m(), this->s()
           );
       }
   
       template<class Generator>
       rocrand_status generate(Generator& g, double * output, size_t size)
       {
           return rocrand_generate_log_normal_double(
               g.m_generator, output, size, this->m(), this->s()
           );
       }
   
       template<class Generator>
       rocrand_status generate(Generator& g, half * output, size_t size)
       {
           return rocrand_generate_log_normal_half(
               g.m_generator, output, size, this->m(), this->s()
           );
       }
   
       param_type m_params;
   };
   
   template<class IntType = unsigned int>
   class poisson_distribution
   {
       static_assert(
           std::is_same<unsigned int, IntType>::value,
           "Only unsigned int type is supported in poisson_distribution"
       );
   
   public:
       typedef IntType result_type;
   
       class param_type
       {
       public:
           using distribution_type = poisson_distribution<IntType>;
           param_type(double mean = 1.0)
               : m_mean(mean)
           {
           }
   
           param_type(const param_type& params) = default;
   
           double mean() const
           {
               return m_mean;
           }
   
           bool operator==(const param_type& other)
           {
               return m_mean == other.m_mean;
           }
   
           bool operator!=(const param_type& other)
           {
               return !(*this == other);
           }
   
       private:
           double m_mean;
       };
   
       poisson_distribution(double mean = 1.0)
           : m_params(mean)
       {
       }
   
       poisson_distribution(const param_type& params)
           : m_params(params)
       {
       }
   
       void reset()
       {
       }
   
       double mean() const
       {
           return m_params.mean();
       }
   
       IntType min() const
       {
           return 0;
       }
   
       IntType max() const
       {
           return std::numeric_limits<IntType>::max();
       }
   
       param_type param() const
       {
           return m_params;
       }
   
       void param(const param_type& params)
       {
           m_params = params;
       }
   
       template<class Generator>
       void operator()(Generator& g, IntType * output, size_t size)
       {
           rocrand_status status;
           status = rocrand_generate_poisson(g.m_generator, output, size, this->mean());
           if(status != ROCRAND_STATUS_SUCCESS) throw rocrand_cpp::error(status);
       }
   
       bool operator==(const poisson_distribution<IntType>& other)
       {
           return this->m_params == other.m_params;
       }
   
       bool operator!=(const poisson_distribution<IntType>& other)
       {
           return !(*this == other);
       }
   
   private:
       param_type m_params;
   };
   
   template<unsigned long long DefaultSeed = ROCRAND_PHILOX4x32_DEFAULT_SEED>
   class philox4x32_10_engine
   {
   public:
       typedef unsigned int result_type;
       // \typedef order_type
       typedef rocrand_ordering order_type;
       typedef unsigned long long offset_type;
       typedef unsigned long long seed_type;
       static constexpr seed_type default_seed = DefaultSeed;
   
       philox4x32_10_engine(seed_type   seed_value   = DefaultSeed,
                            offset_type offset_value = 0,
                            order_type  order_value  = ROCRAND_ORDERING_PSEUDO_DEFAULT)
       {
           rocrand_status status;
           status = rocrand_create_generator(&m_generator, this->type());
           if(status != ROCRAND_STATUS_SUCCESS) throw rocrand_cpp::error(status);
           try
           {
               if(offset_value > 0)
               {
                   this->offset(offset_value);
               }
               this->order(order_value);
               this->seed(seed_value);
           }
           catch(...)
           {
               (void)rocrand_destroy_generator(m_generator);
               throw;
           }
       }
   
       philox4x32_10_engine(rocrand_generator& generator)
           : m_generator(generator)
       {
           if(generator == NULL)
           {
               throw rocrand_cpp::error(ROCRAND_STATUS_NOT_CREATED);
           }
           generator = NULL;
       }
   
       ~philox4x32_10_engine() noexcept(false)
       {
           rocrand_status status = rocrand_destroy_generator(m_generator);
           if(status != ROCRAND_STATUS_SUCCESS) throw rocrand_cpp::error(status);
       }
   
       void stream(hipStream_t value)
       {
           rocrand_status status = rocrand_set_stream(m_generator, value);
           if(status != ROCRAND_STATUS_SUCCESS) throw rocrand_cpp::error(status);
       }
   
       void order(order_type value)
       {
           rocrand_status status = rocrand_set_ordering(this->m_generator, value);
           if(status != ROCRAND_STATUS_SUCCESS)
               throw rocrand_cpp::error(status);
       }
   
       void offset(offset_type value)
       {
           rocrand_status status = rocrand_set_offset(this->m_generator, value);
           if(status != ROCRAND_STATUS_SUCCESS) throw rocrand_cpp::error(status);
       }
   
       void seed(seed_type value)
       {
           rocrand_status status = rocrand_set_seed(this->m_generator, value);
           if(status != ROCRAND_STATUS_SUCCESS) throw rocrand_cpp::error(status);
       }
   
       template<class Generator>
       void operator()(result_type * output, size_t size)
       {
           rocrand_status status;
           status = rocrand_generate(m_generator, output, size);
           if(status != ROCRAND_STATUS_SUCCESS) throw rocrand_cpp::error(status);
       }
   
       result_type min() const
       {
           return 0;
       }
   
       result_type max() const
       {
           return std::numeric_limits<unsigned int>::max();
       }
   
       static constexpr rocrand_rng_type type()
       {
           return ROCRAND_RNG_PSEUDO_PHILOX4_32_10;
       }
   
   private:
       rocrand_generator m_generator;
   
       template<class T>
       friend class ::rocrand_cpp::uniform_int_distribution;
   
       template<class T>
       friend class ::rocrand_cpp::uniform_real_distribution;
   
       template<class T>
       friend class ::rocrand_cpp::normal_distribution;
   
       template<class T>
       friend class ::rocrand_cpp::lognormal_distribution;
   
       template<class T>
       friend class ::rocrand_cpp::poisson_distribution;
   };
   
   template<unsigned long long DefaultSeed>
   constexpr typename philox4x32_10_engine<DefaultSeed>::seed_type philox4x32_10_engine<DefaultSeed>::default_seed;
   
   template<unsigned long long DefaultSeed = ROCRAND_XORWOW_DEFAULT_SEED>
   class xorwow_engine
   {
   public:
       typedef unsigned int result_type;
       typedef rocrand_ordering order_type;
       typedef unsigned long long offset_type;
       typedef unsigned long long seed_type;
       static constexpr seed_type default_seed = DefaultSeed;
   
       xorwow_engine(seed_type   seed_value   = DefaultSeed,
                     offset_type offset_value = 0,
                     order_type  order_value  = ROCRAND_ORDERING_PSEUDO_DEFAULT)
       {
           rocrand_status status;
           status = rocrand_create_generator(&m_generator, this->type());
           if(status != ROCRAND_STATUS_SUCCESS) throw rocrand_cpp::error(status);
           try
           {
               this->order(order_value);
               if(offset_value > 0)
               {
                   this->offset(offset_value);
               }
               this->seed(seed_value);
           }
           catch(...)
           {
               (void)rocrand_destroy_generator(m_generator);
               throw;
           }
       }
   
       xorwow_engine(rocrand_generator& generator)
           : m_generator(generator)
       {
           if(generator == NULL)
           {
               throw rocrand_cpp::error(ROCRAND_STATUS_NOT_CREATED);
           }
           generator = NULL;
       }
   
       ~xorwow_engine() noexcept(false)
       {
           rocrand_status status = rocrand_destroy_generator(m_generator);
           if(status != ROCRAND_STATUS_SUCCESS) throw rocrand_cpp::error(status);
       }
   
       void stream(hipStream_t value)
       {
           rocrand_status status = rocrand_set_stream(m_generator, value);
           if(status != ROCRAND_STATUS_SUCCESS) throw rocrand_cpp::error(status);
       }
   
       void order(order_type value)
       {
           rocrand_status status = rocrand_set_ordering(this->m_generator, value);
           if(status != ROCRAND_STATUS_SUCCESS)
               throw rocrand_cpp::error(status);
       }
   
       void offset(offset_type value)
       {
           rocrand_status status = rocrand_set_offset(this->m_generator, value);
           if(status != ROCRAND_STATUS_SUCCESS) throw rocrand_cpp::error(status);
       }
   
       void seed(seed_type value)
       {
           rocrand_status status = rocrand_set_seed(this->m_generator, value);
           if(status != ROCRAND_STATUS_SUCCESS) throw rocrand_cpp::error(status);
       }
   
       template<class Generator>
       void operator()(result_type * output, size_t size)
       {
           rocrand_status status;
           status = rocrand_generate(m_generator, output, size);
           if(status != ROCRAND_STATUS_SUCCESS) throw rocrand_cpp::error(status);
       }
   
       result_type min() const
       {
           return 0;
       }
   
       result_type max() const
       {
           return std::numeric_limits<unsigned int>::max();
       }
   
       static constexpr rocrand_rng_type type()
       {
           return ROCRAND_RNG_PSEUDO_XORWOW;
       }
   
   private:
       rocrand_generator m_generator;
   
       template<class T>
       friend class ::rocrand_cpp::uniform_int_distribution;
   
       template<class T>
       friend class ::rocrand_cpp::uniform_real_distribution;
   
       template<class T>
       friend class ::rocrand_cpp::normal_distribution;
   
       template<class T>
       friend class ::rocrand_cpp::lognormal_distribution;
   
       template<class T>
       friend class ::rocrand_cpp::poisson_distribution;
   };
   
   template<unsigned long long DefaultSeed>
   constexpr typename xorwow_engine<DefaultSeed>::seed_type xorwow_engine<DefaultSeed>::default_seed;
   
   template<unsigned long long DefaultSeed = ROCRAND_MRG31K3P_DEFAULT_SEED>
   class mrg31k3p_engine
   {
   public:
       typedef unsigned int result_type;
       typedef rocrand_ordering order_type;
       typedef unsigned long long offset_type;
       typedef unsigned long long seed_type;
       static constexpr seed_type default_seed = DefaultSeed;
   
       mrg31k3p_engine(seed_type   seed_value   = DefaultSeed,
                       offset_type offset_value = 0,
                       order_type  order_value  = ROCRAND_ORDERING_PSEUDO_DEFAULT)
       {
           rocrand_status status;
           status = rocrand_create_generator(&m_generator, this->type());
           if(status != ROCRAND_STATUS_SUCCESS)
               throw rocrand_cpp::error(status);
           try
           {
               this->order(order_value);
               if(offset_value > 0)
               {
                   this->offset(offset_value);
               }
               this->seed(seed_value);
           }
           catch(...)
           {
               (void)rocrand_destroy_generator(m_generator);
               throw;
           }
       }
   
       mrg31k3p_engine(rocrand_generator& generator) : m_generator(generator)
       {
           if(generator == NULL)
           {
               throw rocrand_cpp::error(ROCRAND_STATUS_NOT_CREATED);
           }
           generator = NULL;
       }
   
       ~mrg31k3p_engine() noexcept(false)
       {
           rocrand_status status = rocrand_destroy_generator(m_generator);
           if(status != ROCRAND_STATUS_SUCCESS)
               throw rocrand_cpp::error(status);
       }
   
       void stream(hipStream_t value)
       {
           rocrand_status status = rocrand_set_stream(m_generator, value);
           if(status != ROCRAND_STATUS_SUCCESS)
               throw rocrand_cpp::error(status);
       }
   
       void order(order_type value)
       {
           rocrand_status status = rocrand_set_ordering(this->m_generator, value);
           if(status != ROCRAND_STATUS_SUCCESS)
               throw rocrand_cpp::error(status);
       }
   
       void offset(offset_type value)
       {
           rocrand_status status = rocrand_set_offset(this->m_generator, value);
           if(status != ROCRAND_STATUS_SUCCESS)
               throw rocrand_cpp::error(status);
       }
   
       void seed(seed_type value)
       {
           rocrand_status status = rocrand_set_seed(this->m_generator, value);
           if(status != ROCRAND_STATUS_SUCCESS)
               throw rocrand_cpp::error(status);
       }
   
       template<class Generator>
       void operator()(result_type* output, size_t size)
       {
           rocrand_status status;
           status = rocrand_generate(m_generator, output, size);
           if(status != ROCRAND_STATUS_SUCCESS)
               throw rocrand_cpp::error(status);
       }
   
       result_type min() const
       {
           return 1;
       }
   
       result_type max() const
       {
           return std::numeric_limits<unsigned int>::max();
       }
   
       static constexpr rocrand_rng_type type()
       {
           return ROCRAND_RNG_PSEUDO_MRG31K3P;
       }
   
   private:
       rocrand_generator m_generator;
   
       template<class T>
       friend class ::rocrand_cpp::uniform_int_distribution;
   
       template<class T>
       friend class ::rocrand_cpp::uniform_real_distribution;
   
       template<class T>
       friend class ::rocrand_cpp::normal_distribution;
   
       template<class T>
       friend class ::rocrand_cpp::lognormal_distribution;
   
       template<class T>
       friend class ::rocrand_cpp::poisson_distribution;
   };
   
   template<unsigned long long DefaultSeed>
   constexpr
       typename mrg31k3p_engine<DefaultSeed>::seed_type mrg31k3p_engine<DefaultSeed>::default_seed;
   
   template<unsigned long long DefaultSeed = ROCRAND_MRG32K3A_DEFAULT_SEED>
   class mrg32k3a_engine
   {
   public:
       typedef unsigned int result_type;
       typedef rocrand_ordering order_type;
       typedef unsigned long long offset_type;
       typedef unsigned long long seed_type;
       static constexpr seed_type default_seed = DefaultSeed;
   
       mrg32k3a_engine(seed_type   seed_value   = DefaultSeed,
                       offset_type offset_value = 0,
                       order_type  order_value  = ROCRAND_ORDERING_PSEUDO_DEFAULT)
       {
           rocrand_status status;
           status = rocrand_create_generator(&m_generator, this->type());
           if(status != ROCRAND_STATUS_SUCCESS) throw rocrand_cpp::error(status);
           try
           {
               this->order(order_value);
               if(offset_value > 0)
               {
                   this->offset(offset_value);
               }
               this->seed(seed_value);
           }
           catch(...)
           {
               (void)rocrand_destroy_generator(m_generator);
               throw;
           }
       }
   
       mrg32k3a_engine(rocrand_generator& generator)
           : m_generator(generator)
       {
           if(generator == NULL)
           {
               throw rocrand_cpp::error(ROCRAND_STATUS_NOT_CREATED);
           }
           generator = NULL;
       }
   
       ~mrg32k3a_engine() noexcept(false)
       {
           rocrand_status status = rocrand_destroy_generator(m_generator);
           if(status != ROCRAND_STATUS_SUCCESS) throw rocrand_cpp::error(status);
       }
   
       void stream(hipStream_t value)
       {
           rocrand_status status = rocrand_set_stream(m_generator, value);
           if(status != ROCRAND_STATUS_SUCCESS) throw rocrand_cpp::error(status);
       }
   
       void order(order_type value)
       {
           rocrand_status status = rocrand_set_ordering(this->m_generator, value);
           if(status != ROCRAND_STATUS_SUCCESS)
               throw rocrand_cpp::error(status);
       }
   
       void offset(offset_type value)
       {
           rocrand_status status = rocrand_set_offset(this->m_generator, value);
           if(status != ROCRAND_STATUS_SUCCESS) throw rocrand_cpp::error(status);
       }
   
       void seed(seed_type value)
       {
           rocrand_status status = rocrand_set_seed(this->m_generator, value);
           if(status != ROCRAND_STATUS_SUCCESS) throw rocrand_cpp::error(status);
       }
   
       template<class Generator>
       void operator()(result_type * output, size_t size)
       {
           rocrand_status status;
           status = rocrand_generate(m_generator, output, size);
           if(status != ROCRAND_STATUS_SUCCESS) throw rocrand_cpp::error(status);
       }
   
       result_type min() const
       {
           return 1;
       }
   
       result_type max() const
       {
           return std::numeric_limits<unsigned int>::max();
       }
   
       static constexpr rocrand_rng_type type()
       {
           return ROCRAND_RNG_PSEUDO_MRG32K3A;
       }
   
   private:
       rocrand_generator m_generator;
   
       template<class T>
       friend class ::rocrand_cpp::uniform_int_distribution;
   
       template<class T>
       friend class ::rocrand_cpp::uniform_real_distribution;
   
       template<class T>
       friend class ::rocrand_cpp::normal_distribution;
   
       template<class T>
       friend class ::rocrand_cpp::lognormal_distribution;
   
       template<class T>
       friend class ::rocrand_cpp::poisson_distribution;
   };
   
   template<unsigned long long DefaultSeed>
   constexpr typename mrg32k3a_engine<DefaultSeed>::seed_type mrg32k3a_engine<DefaultSeed>::default_seed;
   
   template<unsigned long long DefaultSeed = 0>
   class mtgp32_engine
   {
   public:
       typedef unsigned int result_type;
       typedef rocrand_ordering order_type;
       typedef unsigned long long offset_type;
       typedef unsigned long long seed_type;
       static constexpr seed_type default_seed = DefaultSeed;
   
       mtgp32_engine(seed_type  seed_value  = DefaultSeed,
                     order_type order_value = ROCRAND_ORDERING_PSEUDO_DEFAULT)
       {
           rocrand_status status;
           status = rocrand_create_generator(&m_generator, this->type());
           if(status != ROCRAND_STATUS_SUCCESS) throw rocrand_cpp::error(status);
           try
           {
               this->order(order_value);
               this->seed(seed_value);
           }
           catch(...)
           {
               (void)rocrand_destroy_generator(m_generator);
               throw;
           }
       }
   
       mtgp32_engine(rocrand_generator& generator)
           : m_generator(generator)
       {
           if(generator == NULL)
           {
               throw rocrand_cpp::error(ROCRAND_STATUS_NOT_CREATED);
           }
           generator = NULL;
       }
   
       ~mtgp32_engine() noexcept(false)
       {
           rocrand_status status = rocrand_destroy_generator(m_generator);
           if(status != ROCRAND_STATUS_SUCCESS) throw rocrand_cpp::error(status);
       }
   
       void stream(hipStream_t value)
       {
           rocrand_status status = rocrand_set_stream(m_generator, value);
           if(status != ROCRAND_STATUS_SUCCESS) throw rocrand_cpp::error(status);
       }
   
       void order(order_type value)
       {
           rocrand_status status = rocrand_set_ordering(this->m_generator, value);
           if(status != ROCRAND_STATUS_SUCCESS)
               throw rocrand_cpp::error(status);
       }
   
       void seed(seed_type value)
       {
           rocrand_status status = rocrand_set_seed(this->m_generator, value);
           if(status != ROCRAND_STATUS_SUCCESS) throw rocrand_cpp::error(status);
       }
   
       template<class Generator>
       void operator()(result_type * output, size_t size)
       {
           rocrand_status status;
           status = rocrand_generate(m_generator, output, size);
           if(status != ROCRAND_STATUS_SUCCESS) throw rocrand_cpp::error(status);
       }
   
       result_type min() const
       {
           return 0;
       }
   
       result_type max() const
       {
           return std::numeric_limits<unsigned int>::max();
       }
   
       static constexpr rocrand_rng_type type()
       {
           return ROCRAND_RNG_PSEUDO_MTGP32;
       }
   
   private:
       rocrand_generator m_generator;
   
       template<class T>
       friend class ::rocrand_cpp::uniform_int_distribution;
   
       template<class T>
       friend class ::rocrand_cpp::uniform_real_distribution;
   
       template<class T>
       friend class ::rocrand_cpp::normal_distribution;
   
       template<class T>
       friend class ::rocrand_cpp::lognormal_distribution;
   
       template<class T>
       friend class ::rocrand_cpp::poisson_distribution;
   };
   
   template<unsigned long long DefaultSeed>
   constexpr typename mtgp32_engine<DefaultSeed>::seed_type mtgp32_engine<DefaultSeed>::default_seed;
   
   template<unsigned int DefaultSeedX = ROCRAND_LFSR113_DEFAULT_SEED_X,
            unsigned int DefaultSeedY = ROCRAND_LFSR113_DEFAULT_SEED_Y,
            unsigned int DefaultSeedZ = ROCRAND_LFSR113_DEFAULT_SEED_Z,
            unsigned int DefaultSeedW = ROCRAND_LFSR113_DEFAULT_SEED_W>
   class lfsr113_engine
   {
   public:
       typedef unsigned int result_type;
       typedef rocrand_ordering order_type;
       typedef uint4 seed_type;
       static constexpr seed_type default_seed
           = {DefaultSeedX, DefaultSeedY, DefaultSeedZ, DefaultSeedW};
   
       lfsr113_engine(seed_type  seed_value = {DefaultSeedX, DefaultSeedY, DefaultSeedZ, DefaultSeedW},
                      order_type order_value = ROCRAND_ORDERING_QUASI_DEFAULT)
       {
           rocrand_status status;
           status = rocrand_create_generator(&m_generator, this->type());
           if(status != ROCRAND_STATUS_SUCCESS)
               throw rocrand_cpp::error(status);
           try
           {
               this->order(order_value);
               this->seed(seed_value);
           }
           catch(...)
           {
               (void)rocrand_destroy_generator(m_generator);
               throw;
           }
       }
   
       lfsr113_engine(rocrand_generator& generator) : m_generator(generator)
       {
           if(generator == NULL)
           {
               throw rocrand_cpp::error(ROCRAND_STATUS_NOT_CREATED);
           }
           generator = NULL;
       }
   
       ~lfsr113_engine() noexcept(false)
       {
           rocrand_status status = rocrand_destroy_generator(m_generator);
           if(status != ROCRAND_STATUS_SUCCESS)
               throw rocrand_cpp::error(status);
       }
   
       void stream(hipStream_t value)
       {
           rocrand_status status = rocrand_set_stream(m_generator, value);
           if(status != ROCRAND_STATUS_SUCCESS)
               throw rocrand_cpp::error(status);
       }
   
       void order(order_type value)
       {
           rocrand_status status = rocrand_set_ordering(this->m_generator, value);
           if(status != ROCRAND_STATUS_SUCCESS)
               throw rocrand_cpp::error(status);
       }
   
       void seed(unsigned long long value)
       {
           rocrand_status status = rocrand_set_seed(this->m_generator, value);
           if(status != ROCRAND_STATUS_SUCCESS)
               throw rocrand_cpp::error(status);
       }
   
       void seed(seed_type value)
       {
           rocrand_status status = rocrand_set_seed_uint4(this->m_generator, value);
           if(status != ROCRAND_STATUS_SUCCESS)
               throw rocrand_cpp::error(status);
       }
   
       template<class Generator>
       void operator()(result_type* output, size_t size)
       {
           rocrand_status status;
           status = rocrand_generate(m_generator, output, size);
           if(status != ROCRAND_STATUS_SUCCESS)
               throw rocrand_cpp::error(status);
       }
   
       result_type min() const
       {
           return 0;
       }
   
       result_type max() const
       {
           return std::numeric_limits<unsigned int>::max();
       }
   
       static constexpr rocrand_rng_type type()
       {
           return ROCRAND_RNG_PSEUDO_LFSR113;
       }
   
   private:
       rocrand_generator m_generator;
   
       template<class T>
       friend class ::rocrand_cpp::uniform_int_distribution;
   
       template<class T>
       friend class ::rocrand_cpp::uniform_real_distribution;
   
       template<class T>
       friend class ::rocrand_cpp::normal_distribution;
   
       template<class T>
       friend class ::rocrand_cpp::lognormal_distribution;
   
       template<class T>
       friend class ::rocrand_cpp::poisson_distribution;
   };
   
   template<unsigned int DefaultSeedX,
            unsigned int DefaultSeedY,
            unsigned int DefaultSeedZ,
            unsigned int DefaultSeedW>
   constexpr typename lfsr113_engine<DefaultSeedX, DefaultSeedY, DefaultSeedZ, DefaultSeedW>::seed_type
       lfsr113_engine<DefaultSeedX, DefaultSeedY, DefaultSeedZ, DefaultSeedW>::default_seed;
   
   template<unsigned long long DefaultSeed = 0ULL>
   class mt19937_engine
   {
   public:
       typedef unsigned int result_type;
       typedef unsigned long long seed_type;
       static constexpr seed_type default_seed = DefaultSeed;
   
       mt19937_engine(seed_type seed_value = DefaultSeed)
       {
           rocrand_status status;
           status = rocrand_create_generator(&m_generator, this->type());
           if(status != ROCRAND_STATUS_SUCCESS)
               throw rocrand_cpp::error(status);
           try
           {
               this->seed(seed_value);
           }
           catch(...)
           {
               (void)rocrand_destroy_generator(m_generator);
               throw;
           }
       }
   
       mt19937_engine(rocrand_generator& generator) : m_generator(generator)
       {
           if(generator == NULL)
           {
               throw rocrand_cpp::error(ROCRAND_STATUS_NOT_CREATED);
           }
           generator = NULL;
       }
   
       mt19937_engine(const mt19937_engine&) = delete;
   
       mt19937_engine(mt19937_engine&&) = delete;
   
       mt19937_engine& operator=(const mt19937_engine&) = delete;
   
       mt19937_engine& operator=(mt19937_engine&&) = delete;
   
       ~mt19937_engine() noexcept(false)
       {
           rocrand_status status = rocrand_destroy_generator(m_generator);
           if(status != ROCRAND_STATUS_SUCCESS)
               throw rocrand_cpp::error(status);
       }
   
       void stream(hipStream_t value)
       {
           rocrand_status status = rocrand_set_stream(m_generator, value);
           if(status != ROCRAND_STATUS_SUCCESS)
               throw rocrand_cpp::error(status);
       }
   
       void seed(seed_type value)
       {
           rocrand_status status = rocrand_set_seed(this->m_generator, value);
           if(status != ROCRAND_STATUS_SUCCESS)
               throw rocrand_cpp::error(status);
       }
   
       template<class Generator>
       void operator()(result_type* output, size_t size)
       {
           rocrand_status status;
           status = rocrand_generate(m_generator, output, size);
           if(status != ROCRAND_STATUS_SUCCESS)
               throw rocrand_cpp::error(status);
       }
   
       result_type min() const
       {
           return 0;
       }
   
       result_type max() const
       {
           return std::numeric_limits<unsigned int>::max();
       }
   
       static constexpr rocrand_rng_type type()
       {
           return ROCRAND_RNG_PSEUDO_MT19937;
       }
   
   private:
       rocrand_generator m_generator;
   
       template<class T>
       friend class ::rocrand_cpp::uniform_int_distribution;
   
       template<class T>
       friend class ::rocrand_cpp::uniform_real_distribution;
   
       template<class T>
       friend class ::rocrand_cpp::normal_distribution;
   
       template<class T>
       friend class ::rocrand_cpp::lognormal_distribution;
   
       template<class T>
       friend class ::rocrand_cpp::poisson_distribution;
   };
   
   template<unsigned long long DefaultSeed>
   constexpr typename mt19937_engine<DefaultSeed>::seed_type mt19937_engine<DefaultSeed>::default_seed;
   
   template<unsigned int DefaultNumDimensions = 1>
   class sobol32_engine
   {
   public:
       typedef unsigned int result_type;
       typedef rocrand_ordering order_type;
       typedef unsigned long long offset_type;
       typedef unsigned int dimensions_num_type;
       static constexpr dimensions_num_type default_num_dimensions = DefaultNumDimensions;
   
       sobol32_engine(dimensions_num_type num_of_dimensions = DefaultNumDimensions,
                      offset_type         offset_value      = 0,
                      order_type          order_value       = ROCRAND_ORDERING_QUASI_DEFAULT)
       {
           rocrand_status status;
           status = rocrand_create_generator(&m_generator, this->type());
           if(status != ROCRAND_STATUS_SUCCESS) throw rocrand_cpp::error(status);
           try
           {
               this->order(order_value);
               if(offset_value > 0)
               {
                   this->offset(offset_value);
               }
               this->dimensions(num_of_dimensions);
           }
           catch(...)
           {
               (void)rocrand_destroy_generator(m_generator);
               throw;
           }
       }
   
       sobol32_engine(rocrand_generator& generator)
           : m_generator(generator)
       {
           if(generator == NULL)
           {
               throw rocrand_cpp::error(ROCRAND_STATUS_NOT_CREATED);
           }
           generator = NULL;
       }
   
       ~sobol32_engine() noexcept(false)
       {
           rocrand_status status = rocrand_destroy_generator(m_generator);
           if(status != ROCRAND_STATUS_SUCCESS) throw rocrand_cpp::error(status);
       }
   
       void stream(hipStream_t value)
       {
           rocrand_status status = rocrand_set_stream(m_generator, value);
           if(status != ROCRAND_STATUS_SUCCESS) throw rocrand_cpp::error(status);
       }
   
       void order(order_type value)
       {
           rocrand_status status = rocrand_set_ordering(this->m_generator, value);
           if(status != ROCRAND_STATUS_SUCCESS)
               throw rocrand_cpp::error(status);
       }
   
       void offset(offset_type value)
       {
           rocrand_status status = rocrand_set_offset(this->m_generator, value);
           if(status != ROCRAND_STATUS_SUCCESS) throw rocrand_cpp::error(status);
       }
   
       void dimensions(dimensions_num_type value)
       {
           rocrand_status status =
               rocrand_set_quasi_random_generator_dimensions(this->m_generator, value);
           if(status != ROCRAND_STATUS_SUCCESS) throw rocrand_cpp::error(status);
       }
   
       template<class Generator>
       void operator()(result_type * output, size_t size)
       {
           rocrand_status status;
           status = rocrand_generate(m_generator, output, size);
           if(status != ROCRAND_STATUS_SUCCESS) throw rocrand_cpp::error(status);
       }
   
       result_type min() const
       {
           return 0;
       }
   
       result_type max() const
       {
           return std::numeric_limits<unsigned int>::max();
       }
   
       static constexpr rocrand_rng_type type()
       {
           return ROCRAND_RNG_QUASI_SOBOL32;
       }
   
   private:
       rocrand_generator m_generator;
   
       template<class T>
       friend class ::rocrand_cpp::uniform_int_distribution;
   
       template<class T>
       friend class ::rocrand_cpp::uniform_real_distribution;
   
       template<class T>
       friend class ::rocrand_cpp::normal_distribution;
   
       template<class T>
       friend class ::rocrand_cpp::lognormal_distribution;
   
       template<class T>
       friend class ::rocrand_cpp::poisson_distribution;
   };
   
   template<unsigned int DefaultNumDimensions>
   constexpr typename sobol32_engine<DefaultNumDimensions>::dimensions_num_type
       sobol32_engine<DefaultNumDimensions>::default_num_dimensions;
   
   template<unsigned int DefaultNumDimensions = 1>
   class scrambled_sobol32_engine
   {
   public:
       typedef unsigned int result_type;
       typedef unsigned long long offset_type;
       typedef rocrand_ordering order_type;
       typedef unsigned int dimensions_num_type;
       static constexpr dimensions_num_type default_num_dimensions = DefaultNumDimensions;
   
       scrambled_sobol32_engine(dimensions_num_type num_of_dimensions = DefaultNumDimensions,
                                offset_type         offset_value      = 0,
                                order_type          order_value       = ROCRAND_ORDERING_QUASI_DEFAULT)
       {
           rocrand_status status;
           status = rocrand_create_generator(&m_generator, this->type());
           if(status != ROCRAND_STATUS_SUCCESS)
               throw rocrand_cpp::error(status);
           try
           {
               this->order(order_value);
               if(offset_value > 0)
               {
                   this->offset(offset_value);
               }
               this->dimensions(num_of_dimensions);
           }
           catch(...)
           {
               (void)rocrand_destroy_generator(m_generator);
               throw;
           }
       }
   
       scrambled_sobol32_engine(rocrand_generator& generator) : m_generator(generator)
       {
           if(generator == NULL)
           {
               throw rocrand_cpp::error(ROCRAND_STATUS_NOT_CREATED);
           }
           generator = NULL;
       }
   
       ~scrambled_sobol32_engine() noexcept(false)
       {
           rocrand_status status = rocrand_destroy_generator(m_generator);
           if(status != ROCRAND_STATUS_SUCCESS)
               throw rocrand_cpp::error(status);
       }
   
       void stream(hipStream_t value)
       {
           rocrand_status status = rocrand_set_stream(m_generator, value);
           if(status != ROCRAND_STATUS_SUCCESS)
               throw rocrand_cpp::error(status);
       }
   
       void order(order_type value)
       {
           rocrand_status status = rocrand_set_ordering(this->m_generator, value);
           if(status != ROCRAND_STATUS_SUCCESS)
               throw rocrand_cpp::error(status);
       }
   
       void offset(offset_type value)
       {
           rocrand_status status = rocrand_set_offset(this->m_generator, value);
           if(status != ROCRAND_STATUS_SUCCESS)
               throw rocrand_cpp::error(status);
       }
   
       void dimensions(dimensions_num_type value)
       {
           rocrand_status status
               = rocrand_set_quasi_random_generator_dimensions(this->m_generator, value);
           if(status != ROCRAND_STATUS_SUCCESS)
               throw rocrand_cpp::error(status);
       }
   
       template<class Generator>
       void operator()(result_type* output, size_t size)
       {
           rocrand_status status;
           status = rocrand_generate(m_generator, output, size);
           if(status != ROCRAND_STATUS_SUCCESS)
               throw rocrand_cpp::error(status);
       }
   
       result_type min() const
       {
           return 0;
       }
   
       result_type max() const
       {
           return std::numeric_limits<unsigned int>::max();
       }
   
       static constexpr rocrand_rng_type type()
       {
           return ROCRAND_RNG_QUASI_SCRAMBLED_SOBOL32;
       }
   
   private:
       rocrand_generator m_generator;
   
       template<class T>
       friend class ::rocrand_cpp::uniform_int_distribution;
   
       template<class T>
       friend class ::rocrand_cpp::uniform_real_distribution;
   
       template<class T>
       friend class ::rocrand_cpp::normal_distribution;
   
       template<class T>
       friend class ::rocrand_cpp::lognormal_distribution;
   
       template<class T>
       friend class ::rocrand_cpp::poisson_distribution;
   };
   
   template<unsigned int DefaultNumDimensions>
   constexpr typename scrambled_sobol32_engine<DefaultNumDimensions>::dimensions_num_type
       scrambled_sobol32_engine<DefaultNumDimensions>::default_num_dimensions;
   
   template<unsigned int DefaultNumDimensions = 1>
   class sobol64_engine
   {
   public:
       typedef unsigned long long int result_type;
       typedef unsigned long long int offset_type;
       typedef rocrand_ordering order_type;
       typedef unsigned int dimensions_num_type;
       static constexpr dimensions_num_type default_num_dimensions = DefaultNumDimensions;
   
       sobol64_engine(dimensions_num_type num_of_dimensions = DefaultNumDimensions,
                      offset_type         offset_value      = 0,
                      order_type          order_value       = ROCRAND_ORDERING_QUASI_DEFAULT)
       {
           rocrand_status status;
           status = rocrand_create_generator(&m_generator, this->type());
           if(status != ROCRAND_STATUS_SUCCESS) throw rocrand_cpp::error(status);
           try
           {
               this->order(order_value);
               if(offset_value > 0)
               {
                   this->offset(offset_value);
               }
               this->dimensions(num_of_dimensions);
           }
           catch(...)
           {
               (void)rocrand_destroy_generator(m_generator);
               throw;
           }
       }
   
       sobol64_engine(rocrand_generator& generator)
           : m_generator(generator)
       {
           if(generator == NULL)
           {
               throw rocrand_cpp::error(ROCRAND_STATUS_NOT_CREATED);
           }
           generator = NULL;
       }
   
       ~sobol64_engine() noexcept(false)
       {
           rocrand_status status = rocrand_destroy_generator(m_generator);
           if(status != ROCRAND_STATUS_SUCCESS) throw rocrand_cpp::error(status);
       }
   
       void stream(hipStream_t value)
       {
           rocrand_status status = rocrand_set_stream(m_generator, value);
           if(status != ROCRAND_STATUS_SUCCESS) throw rocrand_cpp::error(status);
       }
   
       void order(order_type value)
       {
           rocrand_status status = rocrand_set_ordering(this->m_generator, value);
           if(status != ROCRAND_STATUS_SUCCESS)
               throw rocrand_cpp::error(status);
       }
   
       void offset(offset_type value)
       {
           rocrand_status status = rocrand_set_offset(this->m_generator, value);
           if(status != ROCRAND_STATUS_SUCCESS) throw rocrand_cpp::error(status);
       }
   
       void dimensions(dimensions_num_type value)
       {
           rocrand_status status =
               rocrand_set_quasi_random_generator_dimensions(this->m_generator, value);
           if(status != ROCRAND_STATUS_SUCCESS) throw rocrand_cpp::error(status);
       }
   
       template<class Generator>
       void operator()(result_type * output, size_t size)
       {
           rocrand_status status;
           status = rocrand_generate_long_long(m_generator, output, size);
           if(status != ROCRAND_STATUS_SUCCESS) throw rocrand_cpp::error(status);
       }
   
       result_type min() const
       {
           return 0;
       }
   
       result_type max() const
       {
           return std::numeric_limits<result_type>::max();
       }
   
       static constexpr rocrand_rng_type type()
       {
           return ROCRAND_RNG_QUASI_SOBOL64;
       }
   
   private:
       rocrand_generator m_generator;
   
       template<class T>
       friend class ::rocrand_cpp::uniform_int_distribution;
   
       template<class T>
       friend class ::rocrand_cpp::uniform_real_distribution;
   
       template<class T>
       friend class ::rocrand_cpp::normal_distribution;
   
       template<class T>
       friend class ::rocrand_cpp::lognormal_distribution;
   
       template<class T>
       friend class ::rocrand_cpp::poisson_distribution;
   };
   
   template<unsigned int DefaultNumDimensions>
   constexpr typename sobol64_engine<DefaultNumDimensions>::dimensions_num_type
       sobol64_engine<DefaultNumDimensions>::default_num_dimensions;
   
   template<unsigned int DefaultNumDimensions = 1>
   class scrambled_sobol64_engine
   {
   public:
       typedef unsigned long long int result_type;
       typedef rocrand_ordering order_type;
       typedef unsigned long long int offset_type;
       typedef unsigned int dimensions_num_type;
       static constexpr dimensions_num_type default_num_dimensions = DefaultNumDimensions;
   
       scrambled_sobol64_engine(dimensions_num_type num_of_dimensions = DefaultNumDimensions,
                                offset_type         offset_value      = 0,
                                order_type          order_value       = ROCRAND_ORDERING_QUASI_DEFAULT)
       {
           rocrand_status status;
           status = rocrand_create_generator(&m_generator, this->type());
           if(status != ROCRAND_STATUS_SUCCESS)
               throw rocrand_cpp::error(status);
           try
           {
               this->order(order_value);
               if(offset_value > 0)
               {
                   this->offset(offset_value);
               }
               this->dimensions(num_of_dimensions);
           }
           catch(...)
           {
               (void)rocrand_destroy_generator(m_generator);
               throw;
           }
       }
   
       scrambled_sobol64_engine(rocrand_generator& generator) : m_generator(generator)
       {
           if(generator == NULL)
           {
               throw rocrand_cpp::error(ROCRAND_STATUS_NOT_CREATED);
           }
           generator = NULL;
       }
   
       ~scrambled_sobol64_engine() noexcept(false)
       {
           rocrand_status status = rocrand_destroy_generator(m_generator);
           if(status != ROCRAND_STATUS_SUCCESS)
               throw rocrand_cpp::error(status);
       }
   
       void stream(hipStream_t value)
       {
           rocrand_status status = rocrand_set_stream(m_generator, value);
           if(status != ROCRAND_STATUS_SUCCESS)
               throw rocrand_cpp::error(status);
       }
   
       void order(order_type value)
       {
           rocrand_status status = rocrand_set_ordering(this->m_generator, value);
           if(status != ROCRAND_STATUS_SUCCESS)
               throw rocrand_cpp::error(status);
       }
   
       void offset(offset_type value)
       {
           rocrand_status status = rocrand_set_offset(this->m_generator, value);
           if(status != ROCRAND_STATUS_SUCCESS)
               throw rocrand_cpp::error(status);
       }
   
       void dimensions(dimensions_num_type value)
       {
           rocrand_status status
               = rocrand_set_quasi_random_generator_dimensions(this->m_generator, value);
           if(status != ROCRAND_STATUS_SUCCESS)
               throw rocrand_cpp::error(status);
       }
   
       template<class Generator>
       void operator()(result_type* output, size_t size)
       {
           rocrand_status status;
           status = rocrand_generate_long_long(m_generator, output, size);
           if(status != ROCRAND_STATUS_SUCCESS)
               throw rocrand_cpp::error(status);
       }
   
       result_type min() const
       {
           return 0;
       }
   
       result_type max() const
       {
           return std::numeric_limits<result_type>::max();
       }
   
       static constexpr rocrand_rng_type type()
       {
           return ROCRAND_RNG_QUASI_SCRAMBLED_SOBOL64;
       }
   
   private:
       rocrand_generator m_generator;
   
       template<class T>
       friend class ::rocrand_cpp::uniform_int_distribution;
   
       template<class T>
       friend class ::rocrand_cpp::uniform_real_distribution;
   
       template<class T>
       friend class ::rocrand_cpp::normal_distribution;
   
       template<class T>
       friend class ::rocrand_cpp::lognormal_distribution;
   
       template<class T>
       friend class ::rocrand_cpp::poisson_distribution;
   };
   
   template<unsigned int DefaultNumDimensions>
   constexpr typename scrambled_sobol64_engine<DefaultNumDimensions>::dimensions_num_type
       scrambled_sobol64_engine<DefaultNumDimensions>::default_num_dimensions;
   
   template<unsigned long long DefaultSeed = 0>
   class threefry2x32_20_engine
   {
   public:
       typedef unsigned int result_type;
       typedef rocrand_ordering order_type;
       typedef unsigned long long offset_type;
       typedef unsigned long long seed_type;
       static constexpr seed_type default_seed = DefaultSeed;
   
       threefry2x32_20_engine(seed_type   seed_value   = DefaultSeed,
                              offset_type offset_value = 0,
                              order_type  order_value  = ROCRAND_ORDERING_PSEUDO_DEFAULT)
       {
           rocrand_status status;
           status = rocrand_create_generator(&m_generator, this->type());
           if(status != ROCRAND_STATUS_SUCCESS)
               throw rocrand_cpp::error(status);
           try
           {
               if(offset_value > 0)
               {
                   this->offset(offset_value);
               }
               this->order(order_value);
               this->seed(seed_value);
           }
           catch(...)
           {
               (void)rocrand_destroy_generator(m_generator);
               throw;
           }
       }
   
       threefry2x32_20_engine(rocrand_generator& generator) : m_generator(generator)
       {
           if(generator == NULL)
           {
               throw rocrand_cpp::error(ROCRAND_STATUS_NOT_CREATED);
           }
           generator = NULL;
       }
   
       ~threefry2x32_20_engine() noexcept(false)
       {
           rocrand_status status = rocrand_destroy_generator(m_generator);
           if(status != ROCRAND_STATUS_SUCCESS)
               throw rocrand_cpp::error(status);
       }
   
       void stream(hipStream_t value)
       {
           rocrand_status status = rocrand_set_stream(m_generator, value);
           if(status != ROCRAND_STATUS_SUCCESS)
               throw rocrand_cpp::error(status);
       }
   
       void order(order_type value)
       {
           rocrand_status status = rocrand_set_ordering(this->m_generator, value);
           if(status != ROCRAND_STATUS_SUCCESS)
               throw rocrand_cpp::error(status);
       }
   
       void offset(offset_type value)
       {
           rocrand_status status = rocrand_set_offset(this->m_generator, value);
           if(status != ROCRAND_STATUS_SUCCESS)
               throw rocrand_cpp::error(status);
       }
   
       void seed(seed_type value)
       {
           rocrand_status status = rocrand_set_seed(this->m_generator, value);
           if(status != ROCRAND_STATUS_SUCCESS)
               throw rocrand_cpp::error(status);
       }
   
       template<class Generator>
       void operator()(result_type* output, size_t size)
       {
           rocrand_status status;
           status = rocrand_generate(m_generator, output, size);
           if(status != ROCRAND_STATUS_SUCCESS)
               throw rocrand_cpp::error(status);
       }
   
       result_type min() const
       {
           return 0;
       }
   
       result_type max() const
       {
           return std::numeric_limits<unsigned int>::max();
       }
   
       static constexpr rocrand_rng_type type()
       {
           return ROCRAND_RNG_PSEUDO_THREEFRY2_32_20;
       }
   
   private:
       rocrand_generator m_generator;
   
       template<class T>
       friend class ::rocrand_cpp::uniform_int_distribution;
   
       template<class T>
       friend class ::rocrand_cpp::uniform_real_distribution;
   
       template<class T>
       friend class ::rocrand_cpp::normal_distribution;
   
       template<class T>
       friend class ::rocrand_cpp::lognormal_distribution;
   
       template<class T>
       friend class ::rocrand_cpp::poisson_distribution;
   };
   
   template<unsigned long long DefaultSeed>
   constexpr typename threefry2x32_20_engine<DefaultSeed>::seed_type
       threefry2x32_20_engine<DefaultSeed>::default_seed;
   
   template<unsigned long long DefaultSeed = 0>
   class threefry2x64_20_engine
   {
   public:
       typedef unsigned long long result_type;
       typedef rocrand_ordering order_type;
       typedef unsigned long long offset_type;
       typedef unsigned long long seed_type;
       static constexpr seed_type default_seed = DefaultSeed;
   
       threefry2x64_20_engine(seed_type   seed_value   = DefaultSeed,
                              offset_type offset_value = 0,
                              order_type  order_value  = ROCRAND_ORDERING_PSEUDO_DEFAULT)
       {
           rocrand_status status;
           status = rocrand_create_generator(&m_generator, this->type());
           if(status != ROCRAND_STATUS_SUCCESS)
               throw rocrand_cpp::error(status);
           try
           {
               if(offset_value > 0)
               {
                   this->offset(offset_value);
               }
               this->order(order_value);
               this->seed(seed_value);
           }
           catch(...)
           {
               (void)rocrand_destroy_generator(m_generator);
               throw;
           }
       }
   
       threefry2x64_20_engine(rocrand_generator& generator) : m_generator(generator)
       {
           if(generator == NULL)
           {
               throw rocrand_cpp::error(ROCRAND_STATUS_NOT_CREATED);
           }
           generator = NULL;
       }
   
       ~threefry2x64_20_engine() noexcept(false)
       {
           rocrand_status status = rocrand_destroy_generator(m_generator);
           if(status != ROCRAND_STATUS_SUCCESS)
               throw rocrand_cpp::error(status);
       }
   
       void stream(hipStream_t value)
       {
           rocrand_status status = rocrand_set_stream(m_generator, value);
           if(status != ROCRAND_STATUS_SUCCESS)
               throw rocrand_cpp::error(status);
       }
   
       void order(order_type value)
       {
           rocrand_status status = rocrand_set_ordering(this->m_generator, value);
           if(status != ROCRAND_STATUS_SUCCESS)
               throw rocrand_cpp::error(status);
       }
   
       void offset(offset_type value)
       {
           rocrand_status status = rocrand_set_offset(this->m_generator, value);
           if(status != ROCRAND_STATUS_SUCCESS)
               throw rocrand_cpp::error(status);
       }
   
       void seed(seed_type value)
       {
           rocrand_status status = rocrand_set_seed(this->m_generator, value);
           if(status != ROCRAND_STATUS_SUCCESS)
               throw rocrand_cpp::error(status);
       }
   
       template<class Generator>
       void operator()(result_type* output, size_t size)
       {
           rocrand_status status;
           status = rocrand_generate_long_long(m_generator, output, size);
           if(status != ROCRAND_STATUS_SUCCESS)
               throw rocrand_cpp::error(status);
       }
   
       result_type min() const
       {
           return 0;
       }
   
       result_type max() const
       {
           return std::numeric_limits<unsigned int>::max();
       }
   
       static constexpr rocrand_rng_type type()
       {
           return ROCRAND_RNG_PSEUDO_THREEFRY2_64_20;
       }
   
   private:
       rocrand_generator m_generator;
   
       template<class T>
       friend class ::rocrand_cpp::uniform_int_distribution;
   
       template<class T>
       friend class ::rocrand_cpp::uniform_real_distribution;
   
       template<class T>
       friend class ::rocrand_cpp::normal_distribution;
   
       template<class T>
       friend class ::rocrand_cpp::lognormal_distribution;
   
       template<class T>
       friend class ::rocrand_cpp::poisson_distribution;
   };
   
   template<unsigned long long DefaultSeed>
   constexpr typename threefry2x64_20_engine<DefaultSeed>::seed_type
       threefry2x64_20_engine<DefaultSeed>::default_seed;
   
   template<unsigned long long DefaultSeed = 0>
   class threefry4x32_20_engine
   {
   public:
       typedef unsigned int result_type;
       typedef rocrand_ordering order_type;
       typedef unsigned long long offset_type;
       typedef unsigned long long seed_type;
       static constexpr seed_type default_seed = DefaultSeed;
   
       threefry4x32_20_engine(seed_type   seed_value   = DefaultSeed,
                              offset_type offset_value = 0,
                              order_type  order_value  = ROCRAND_ORDERING_PSEUDO_DEFAULT)
       {
           rocrand_status status;
           status = rocrand_create_generator(&m_generator, this->type());
           if(status != ROCRAND_STATUS_SUCCESS)
               throw rocrand_cpp::error(status);
           try
           {
               if(offset_value > 0)
               {
                   this->offset(offset_value);
               }
               this->order(order_value);
               this->seed(seed_value);
           }
           catch(...)
           {
               (void)rocrand_destroy_generator(m_generator);
               throw;
           }
       }
   
       threefry4x32_20_engine(rocrand_generator& generator) : m_generator(generator)
       {
           if(generator == NULL)
           {
               throw rocrand_cpp::error(ROCRAND_STATUS_NOT_CREATED);
           }
           generator = NULL;
       }
   
       ~threefry4x32_20_engine() noexcept(false)
       {
           rocrand_status status = rocrand_destroy_generator(m_generator);
           if(status != ROCRAND_STATUS_SUCCESS)
               throw rocrand_cpp::error(status);
       }
   
       void stream(hipStream_t value)
       {
           rocrand_status status = rocrand_set_stream(m_generator, value);
           if(status != ROCRAND_STATUS_SUCCESS)
               throw rocrand_cpp::error(status);
       }
   
       void order(order_type value)
       {
           rocrand_status status = rocrand_set_ordering(this->m_generator, value);
           if(status != ROCRAND_STATUS_SUCCESS)
               throw rocrand_cpp::error(status);
       }
   
       void offset(offset_type value)
       {
           rocrand_status status = rocrand_set_offset(this->m_generator, value);
           if(status != ROCRAND_STATUS_SUCCESS)
               throw rocrand_cpp::error(status);
       }
   
       void seed(seed_type value)
       {
           rocrand_status status = rocrand_set_seed(this->m_generator, value);
           if(status != ROCRAND_STATUS_SUCCESS)
               throw rocrand_cpp::error(status);
       }
   
       template<class Generator>
       void operator()(result_type* output, size_t size)
       {
           rocrand_status status;
           status = rocrand_generate(m_generator, output, size);
           if(status != ROCRAND_STATUS_SUCCESS)
               throw rocrand_cpp::error(status);
       }
   
       result_type min() const
       {
           return 0;
       }
   
       result_type max() const
       {
           return std::numeric_limits<unsigned int>::max();
       }
   
       static constexpr rocrand_rng_type type()
       {
           return ROCRAND_RNG_PSEUDO_THREEFRY4_32_20;
       }
   
   private:
       rocrand_generator m_generator;
   
       template<class T>
       friend class ::rocrand_cpp::uniform_int_distribution;
   
       template<class T>
       friend class ::rocrand_cpp::uniform_real_distribution;
   
       template<class T>
       friend class ::rocrand_cpp::normal_distribution;
   
       template<class T>
       friend class ::rocrand_cpp::lognormal_distribution;
   
       template<class T>
       friend class ::rocrand_cpp::poisson_distribution;
   };
   
   template<unsigned long long DefaultSeed>
   constexpr typename threefry4x32_20_engine<DefaultSeed>::seed_type
       threefry4x32_20_engine<DefaultSeed>::default_seed;
   
   template<unsigned long long DefaultSeed = 0>
   class threefry4x64_20_engine
   {
   public:
       typedef unsigned long long result_type;
       typedef rocrand_ordering order_type;
       typedef unsigned long long offset_type;
       typedef unsigned long long seed_type;
       static constexpr seed_type default_seed = DefaultSeed;
   
       threefry4x64_20_engine(seed_type   seed_value   = DefaultSeed,
                              offset_type offset_value = 0,
                              order_type  order_value  = ROCRAND_ORDERING_PSEUDO_DEFAULT)
       {
           rocrand_status status;
           status = rocrand_create_generator(&m_generator, this->type());
           if(status != ROCRAND_STATUS_SUCCESS)
               throw rocrand_cpp::error(status);
           try
           {
               if(offset_value > 0)
               {
                   this->offset(offset_value);
               }
               this->order(order_value);
               this->seed(seed_value);
           }
           catch(...)
           {
               (void)rocrand_destroy_generator(m_generator);
               throw;
           }
       }
   
       threefry4x64_20_engine(rocrand_generator& generator) : m_generator(generator)
       {
           if(generator == NULL)
           {
               throw rocrand_cpp::error(ROCRAND_STATUS_NOT_CREATED);
           }
           generator = NULL;
       }
   
       ~threefry4x64_20_engine() noexcept(false)
       {
           rocrand_status status = rocrand_destroy_generator(m_generator);
           if(status != ROCRAND_STATUS_SUCCESS)
               throw rocrand_cpp::error(status);
       }
   
       void stream(hipStream_t value)
       {
           rocrand_status status = rocrand_set_stream(m_generator, value);
           if(status != ROCRAND_STATUS_SUCCESS)
               throw rocrand_cpp::error(status);
       }
   
       void offset(offset_type value)
       {
           rocrand_status status = rocrand_set_offset(this->m_generator, value);
           if(status != ROCRAND_STATUS_SUCCESS)
               throw rocrand_cpp::error(status);
       }
   
       void seed(seed_type value)
       {
           rocrand_status status = rocrand_set_seed(this->m_generator, value);
           if(status != ROCRAND_STATUS_SUCCESS)
               throw rocrand_cpp::error(status);
       }
   
       template<class Generator>
       void operator()(result_type* output, size_t size)
       {
           rocrand_status status;
           status = rocrand_generate_long_long(m_generator, output, size);
           if(status != ROCRAND_STATUS_SUCCESS)
               throw rocrand_cpp::error(status);
       }
   
       result_type min() const
       {
           return 0;
       }
   
       result_type max() const
       {
           return std::numeric_limits<unsigned int>::max();
       }
   
       static constexpr rocrand_rng_type type()
       {
           return ROCRAND_RNG_PSEUDO_THREEFRY4_64_20;
       }
   
   private:
       rocrand_generator m_generator;
   
       template<class T>
       friend class ::rocrand_cpp::uniform_int_distribution;
   
       template<class T>
       friend class ::rocrand_cpp::uniform_real_distribution;
   
       template<class T>
       friend class ::rocrand_cpp::normal_distribution;
   
       template<class T>
       friend class ::rocrand_cpp::lognormal_distribution;
   
       template<class T>
       friend class ::rocrand_cpp::poisson_distribution;
   };
   
   template<unsigned long long DefaultSeed>
   constexpr typename threefry4x64_20_engine<DefaultSeed>::seed_type
       threefry4x64_20_engine<DefaultSeed>::default_seed;
   
   typedef philox4x32_10_engine<> philox4x32_10;
   typedef xorwow_engine<> xorwow;
   typedef mrg31k3p_engine<> mrg31k3a;
   typedef mrg32k3a_engine<> mrg32k3a;
   typedef mtgp32_engine<> mtgp32;
   typedef lfsr113_engine<> lfsr113;
   typedef mt19937_engine<> mt19937;
   typedef threefry2x32_20_engine<> threefry2x32;
   typedef threefry2x64_20_engine<> threefry2x64;
   typedef threefry4x32_20_engine<> threefry4x32;
   typedef threefry4x64_20_engine<> threefry4x64;
   typedef sobol32_engine<> sobol32;
   typedef scrambled_sobol32_engine<> scrambled_sobol32;
   typedef sobol64_engine<> sobol64;
   typedef scrambled_sobol64_engine<> scrambled_sobol64;
   
   typedef xorwow default_random_engine;
   
   typedef std::random_device random_device;
   
   inline int version()
   {
       int x;
       rocrand_status status = rocrand_get_version(&x);
       if(status != ROCRAND_STATUS_SUCCESS)
       {
           throw rocrand_cpp::error(status);
       }
       return x;
   }
   
   
   } // end namespace rocrand_cpp
   
   #endif // #if __cplusplus >= 201103L
   #endif // ROCRAND_HPP_
