C++11 random discrete_distribution


C++11 random discrete_distribution

The C++11 random discrete_distribution produces random integers ‘i’,using the discrete probability function-the function is shown at the end of this post.The discrete_distribution template class declaration is shown below.

template<class IntType = double >
class discrete_distribution;

The default type is int type ,so the default constructed object always produces int type random numbers.

All the distribution’s types and member function is given below.

Types

typedef IntType result_type;
typedef unspecified param_type;

The param_type is as structure whose definition is compiler dependent.

Constructors and reset function

discrete_distribution( );
template<class InputIterator>
discrete_distribution( InputIterator firstW , InputIterator lastW );
discrete_distribution( initializer_list<double> wl );
template<class UnaryOperation>
discrete_distribution( size_t nw , double xmin , double xmax , UnaryOperation fw );
explicit discrete_distribution(const param_type& parm);
void reset( );

You can see that the discrete_distribution have five constructors:

a)The first constructor is the default constructor.
b)The second constructor accept two arguments: firstW and lastW are iterators pointing to the first and one past the last element of the same container.The container can be vector or array or any equivalent type.
c)The third constructor accept initializer_list.
d)The fourth constructor accept 4 arguments.Refer to the first three arguments type from the above declaration but the fourth argument is a function which return a double type or a type convertible to double type.
e)The fifth constructor accept param_type object.

The program below shows how to declare the distribution’s object by calling the different constructors.

Code example

double func(double arg)
{
return arg;
}

int main( )
{
discrete_distribution< > dd; //calls the default constructor

vector<int> vec={ 20 , 30 , 4 , 67 , 90 , 41 , 51};

discrete_distribution< > dd1(vec.begin() , vec.end() ); //calls the second constructor

initializer_list< double > il={ 2.3 , 6.7 , 9.034 , 13.89 };

discrete_distribution< > dd2(il) ; //calls the third constructor

discrete_distribution<unsigned int > dd3( 9 , 0 , 100 , func ); //calls the 4th constructor

discrete_distribution<unsigned int >::param_type pt;

discrete_distribution<unsigned int > dd4(pt) ; //calls the 5th constructor

discrete_distribution< > dd5(pt) ; //error! pt is ‘unsigned int’ type but dd5 is ‘int’ type

return 0;
}

Link :C++ vector begin function

reset()

The reset() function reset the state of the distribution.It does nothing in discrete_distribution so you can neglect it.


 



Generating functions

template<class URNG>
result_type operator( )(URNG& g);
template<class URNG>
result_type operator( )(URNG& g, const param_type& parm);

the first operator() function

The random sequence is obtained using the operator() function.The first overloaded operator() accept URNG(Uniform Random Number Generator) or engine.

Code example

discrete_distribution< > dd;

default_random_engine dre ;

cout<< dd(dre ) << ” ” << dd(dre ) ; //generate two random numbers

discrete_distribution< > dd1dd5(9 , 0 , 100 , func ); //func is the function from before

cout<< dd1(dre ) << ” ” << dd1(dre ) ; //generate two random numbers

Output in Code::blocks,

0   0
6   3

If the distribution object is constructed by calling the default constructor the output will be always 0,so ‘dd’ will always give 0 as it’s random output.

the second operator( ) function

The second overloaded operator( ) function accept URNG and param_type object.

Code example

discrete_distribution<unsigned int >::param_type pt;

discrete_distribution<unsigned int > dd(pt) ;

default_random_engine dre ;

cout<< dd(dre , pt ) << ” ” << dd(dre , pt ) ;

Output,

0   0

Here ‘dd’ is also constructed by calling the default constructor so the output is 0 and 0.


Property functions

vector<double> probabilities( ) const;
param_type param() const;
void param(const param_type& parm);
result_type min() const;
result_type max() const;

probabilities() const; function

This function returns a vector of double type.The returned vector stores the probabilites of the random number generated by distribution.The nth element of the vector will correspond to the probabilities of the nth generated random number.

Code example

vector<double> vecRet={ 0 , 0 , 0 } ;

vector<int>vec={ 11 , 02 , 13 };

discrete_distribution< > dd( vec.begin() , vec.end() );

vecRet=dd.probabilities( );

for( auto elem:vecRet )
{
cout<< elem << ” ” ;
}

Output in code::blocks,

0.423077   0.0769231   0.5

Suppose if ‘dd’ generates a random numbers say ‘x , y , z’ using any engine,then x’s probability will be 0.423077 , y’s probability will be 0.0769231 and z’s probability will b 0.5.This also shows that the probability of any random number generated is not dependent on the engine’s used and also it is not dependent on the random number which the engine pass to the distribution.

Link :C++11 Range base for loop

param( )

This function returns the param_type object.

Code example

discrete_distribution< > dd( 15 , 0 , 100 , func) ; //func is from before

discrete_distribution< >::param_type pt;

pt=dd.param() ;

param(param_type)

Using this function we can change the parameter of the distribution to the parameter of the param_type object by passing the param_type object.

Code example

discrete_distribution< > dd( 15 , 0 , 100 , func) ,
dd1( 15 , 0 , 100 , func) ; //dd and dd1 will give the same random sequence

default_random_engine dre1 , dre2 ;

cout<< dd( dre1 ) << ” ” << dd(dre2) << endl
<< dd(dre1) << ” ” << dd(dre2) << endl ;

discrete_distribution< >::param_type( 25 , 0 , 8 , func );

dd1.param(pt);

cout<< dd( dre1 ) << ” ” << dd(dre2) ;

Output in code::blocks,

6   6
3   3
4   11

The first and second output of both the dd and dd1 objects are same because they have the same parameters but after calling param(pt) the parameters of dd1 is changed to the parameter of pt.Since different parameter will give different output the third output of dd and dd1 is different.

min() function

The min() returns the smallest value the distribution can generate,which is the value 0.

Code example

discrete_distribution< > dd( 15 , 0 , 100 , func) ;

cout<< dd.min() ;

Output ,

0

The minimum value is always 0.

max() function

The max() returns the largest value the distribution can generate.To determine the largest value the distribution can generate we will examine the constructors called by the object’s during it’s declaration.

a)If the object calls the default constructor,the maximum value is always 0.
b)If the object accept vector as it’s argument then the maximum value the distribution can generate is the number of elements of the vector minus 1:vector object size() – 1 .If the vector contains no element then 0 is the maximum value.
c)If the object accept initializer_list object as it’s argument then the maximum value the distribution can generate is the size of the initializer_list object minus 1 .If the object contains no element then 0 is the maximum value.
c)If the object calls the constructor that accept four arguments than the maximum value is the first argument minus 1.

Code example

discrete_distribution< > dd ;

cout<< dd.max() << endl ;

discrete_distribution< > dd1( 15 , 0 , 100 , func ) ;

cout<< dd1.max() ;

Output ,

0
14

For dd1 the first argument is 15 so the maximum value is 14(15-1).You can check yourself the maximum value of object accepting vector and initializer_list object during the constructor call.


 


Stop wasting time,earn money($$$) from your website-Join Now!

operator== and operator!=

The two functions operator== and operator!= check if the parameters value are equal.If the parameters are equal operator== returns true and operator!= returns 0.The operator== returns true (and operator!= false) as long as the parameters value are equal no matter what state the distribution object is in.

Code example

discrete_distribution< > dd , dd1 ;

cout<< (dd==dd1) << ” ” << (dd!=dd1) << endl ;

discrete_distribution< > dd2(12 , 0 , 50 , func) ,
dd3( 20 , 0 , 60 , func );

cout<< (dd2==dd3) << ” ” << (dd2!=dd3) << endl ;

Output,

1   0
0   1


operator<< and operator>>

The function operator<< allows you to save the state of the distribution.This function also allows you to save the state of the engine.The state saved can later be regained by using the operator>> function.Using this regained state we can reproduce the same random sequence which was generated earlier when the distribution was at that state.Note for the distribution to reproduce the same sequence not only the distribution’s state but also the engine’s state must be the same.

In the code below we will try to save the distribution state and also save the engine’s state,in this way we will be able to reproduce the same random sequence.

Code example

#include <iostream>
#include <random>
#include <sstream>

using namespace std;

double func(double arg) { return arg; }

int main( )
{
stringstream engState ,  //object to save the engine state
disState ;  //object to save the distribution state

discrete_distribution<>ddIO1(25 , 0 , 80 , func) , ddIO2(25 , 0 , 80 , func) ;

default_random_engine dre1 , dre2 ;

cout<< ddIO1(dre1) << endl ;  //first random number

disState<< ddIO1 ;  //Save the 2nd distribution state of ddIO to disState
engState<< dre1 ;  //Save the 2nd engine state of dre1 to engState

cout<< “Second and third state output of ddIO1 and dre1 \n”;
cout<< ddIO1( dre1 ) << ” ” ;
cout<< ddIO1(dre1) << endl ;

disState>> ddIO2 ;  //reassign the distribution state saved in disState to ddIO2
engState>> dre2 ;  //reassign the engine’s state saved in engState to dre2

cout<< “\n\nOutputting the random sequence using ddIO2 and dre2 current state\n”;
cout<< ddIO1( dre2 ) << ” ” ;
cout<< ddIO1( dre2 ) << endl ;

cin.get( );
return 0;
}

Output in Code::blocks,

9
Second and third state output of ddIO1 and dre1
16   11

Outputting the random sequence using ddIO2 and dre2 current state
16   11

The second sate of ddIO1 and dre1 has been assigned to ddIO2 and dre2,so the numbers generated by the second sate and it’s consecutive state of ddIO1 and dre1 will be same as the sequence generated by the ddIO2 and dre2 current state and it’s consecutive state.Note reproducing the same sequence can be useful for debugging purpose.

More about saving and recovering the engine’s state is given here C++11 Saving the state of the engine to reproduce the same random sequence.


*Side Note

discrete_distribution produces random integers i,0≤ i < n,distributed according to the discrete probability function,

  P(i/p0, … , pn-1) = pi

  The ‘n’ value is ‘max()+1’ (look at the max( ) function given above).
  And,
  pk=wk / S ;
    k=0, 1 , … , n-1
    0<S=w0 + … + wn-1

  To know the sequence ‘w’ consider the cases given below,
Each overloaded constructor can be referred from the Constructor section above.

i)If the default constructor is called , n= 1 and p0= 1, and such default constructed object always give the value 0.

ii)If vector is passed to the constructor :
  a)If firstW == lastW(vector contains no element) , let n=1 and w0=1
  b)Else [firstW , lastW) form the sequence ‘w‘ and n=vector size-1 .

iii)If initializer_list is passed as the constructor argument it is same as when vector is pass and in this case firstW=il.begin() and lastW=il.end().

iv)If four arguments is passed to the constructor,
  a)If the first argument nw=0, then n=0 and w0=1.
  b)Else n=nw , 0 < δ= ( xmax − xmin ) /n ,and wk=fw(xmin + k·δ + δ/2),
    k=0, 1 , … , n-1

v)if param_type object is passed then any of the rules above will apply depending on the argument type the param_type object accepted when it was constructed.