C++11 random piecewise_linear_distribution


C++11 random piecewise_linear_distribution

The C++11 random piecewise_linear_distribution produces floating point random values ‘x’ using a specific probability density function-the function is provided at the end of this post.The piecewise_linear_distribution template class declaration is shown below.

template<class RealType = double>
class piecewise_linear_distribution;

The default type of the distribution is ‘double’ type ,so the default constructed object always produce double 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,that is also why it’s type is mentioned as unspecified.

Constructors and reset function

piecewise_linear_distribution();
template<class InputIteratorB, class InputIteratorW>
piecewise_linear_distribution(InputIteratorB firstB, InputIteratorB lastB, InputIteratorW firstW);
template<class UnaryOperation>
piecewise_linear_distribution(initializer_list<RealType> bl, UnaryOperation fw);
template<class UnaryOperation>
piecewise_linear_distribution(size_t nw, RealType xmin, RealType xmax, UnaryOperation fw);
explicit piecewise_linear_distribution(const param_type& parm);
void reset( );

You can see that the piecewise_linear_distribution have five constructors:

a)The first constructor is the default constructor.

b)The second constructor accept three arguments:firstB and lastB iterator pointing to the first and one past the last element of the same container and the firstW iterator pointing to another different container.The container can be vector or an array or any equivalent type.And note the third iterator must point to container having at least the same number of elements as the container pointed by the first iterator.

c)The third constructor accept initializer_list and a function.The initializer_list type must be real type and the function must return a double type or any type convertible to double type.

d)The fourth constructor accept 4 arguments.Refer to the first three arguments type from the above declaration and 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 call all the constructors.

Code example

double func(double arg)
{
return arg;
}

int main( )
{
piecewise_linear_distribution< > pcd; //calls the default constructor

vector<int> vec={ 0 , 2 , 1 } , vec1={ 12 , 3 , 14 };

piecewise_linear_distribution< > pld1( vec.begin( ) , vec.end() , vec1.begin( ) ); //calls the second constructor

initializer_list< double > il={ 4.5 , 0.2 , 0.123 };
piecewise_linear_distribution< > pld2( il , func ); //calls the third constructor

piecewise_linear_distribution<float > pld3( 18 , 0 , 300 , func ); //calls the 4th constructor

piecewise_linear_distribution<float >::param_type pt;

piecewise_linear_distribution<float > pld4(pt) ; //calls the 5th constructor

piecewise_linear_distribution< > pld5(pt) ; //error! pt is ‘float’ type but pld5 is ‘double’ 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 generating functions give you an access to the random number sequence.

the first operator() function

The first overloaded operator() accept URNG(Uniform Random Number Generator) or engine.

Code example

piecewise_linear_distribution< > pld ;

mersenne_twister_engine<unsigned int , 32 , 624 , 397 , 31 ,
  0x9908b0dfUL, 11 ,
  0xffffffffUL, 7 ,
  0x9d2c5680UL, 15 ,
  0xefc60000UL, 18 , 1812433253UL > mte ;

cout<< pld( mte ) << ” ” << pld( mte ) ;

Output in Code::blocks,

0.835009   0.135477

Link :C++11 mersenne_twister_engine

the second operator( ) function

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

Code example

initializer_list< double > il={ 4.5 , 0.2 , 0.123 };

linear_congruential_engine<unsigned int , 193703 , 0 , 83474882 > lce ;

piecewise_linear_distribution< >::param_type pt( il , func );

piecewise_linear_distribution< >pld ;

cout<< pld( lce , pt ) << ” ” << pld( lce , pt ) ;

Output in Code::blocks,

-2.82485   -4.17875


Property functions

vector<result_type> intervals( ) const;
vector<result_type> densities( ) const;
param_type param() const;
void param(const param_type& parm);
result_type min( ) const;
result_type max( ) const;

vector<result_type> intervals( ) const;

This function returns vector of result_type.The content of the returned vector will depend on which constructor is called during the object creation:

a)If default constructor is called the return vector consists of only two elements 0 and 1.
b)If the second constructor is called the return vector content is same as the content of the container whose iterators pointing to the first and one past the last element is passed as the first and second argument.Simply if ‘vec.begin()’ and ‘vec.end()’ -vec is any vector object- are passed as the first and second iterator then ‘vec’ content is returned.
c)If the third constructor is called.The returned vector will have the element as the initializer_list content.
d)If the fourth constructor is called then the content is
bk=xmin+k · δ , k=0 , 1, 2 … n,

0 < δ= (xmax − xmin ) /n, xmax is the third argument and xmin is the fourth argument and ‘n’ is the first argument passed to the constructor.

e)If the fifth constructor is called,the param_type object may call any of the four constructors describe above then the content of the returned vector will hold true as described for each of the constructor called.

Code example

piecewise_linear_distribution< > pld ;

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

vec=pld.intervals( );

cout<< vec[0] << ” ” vec[1] << “\n\n” ;

vector< double > vec1={ 1.2 , 0.34 , 1.45 , .010 } , vec3={ 0 , 0 , 0 , 0};

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

piecewise_linear_distribution< >::param_type pt( vec1.begin( ) , vec1.end( ) , vec3.begin( ) );

piecewise_linear_distribution< > pld1( pt ) ;

vecRet=pcd1.intervals( );

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

Output,

0   1
1.2   0.34   1.45   .010

The ‘pt’ accepted ‘vec.begin()’ and ‘vec.end()’ as the first and second iterator so the returned vector vecRet content is same as the content of ‘vec’.

Link :C++11 Range base for loop

densities( ) const; function

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

Code example

vector<int> vec={ 9 , 0.7 , 1.23 } , vec1={ 9 , 0.7 , 1.23 };

vector<int> vecret={ 0 , 0 , 0};

piecewise_linear_distribution< > pld(vec.begin() , vec.end() , vec1.begin() ) ;

vecRet=pld.densities( ) ;

cout<< vecRet[0] << ” ” << vecRet[1] << ” ” vecRet[2] ;

Output,

1.54772   0.120378   0.211522

param( )

This function returns the param_type object.

Code example

piecewise_linear_distribution< >pld ;

piecewise_linear_distribution< >::param_type pt ;

pt=pcd.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

initializer_list< double > il ={ 0.12 , 30.23 } ,
il1={ 90 , 100 };

vector<double > vec1={0 , 0} ,
vec2={ 0 , 0}

piecewise_linear_distribution< > pcd(il) ;

vec1=pcd.interval( );

cout<< vec1[0] << ” ” << vec1[1] << endl;

piecewise_linear_distribution< >::param_type pt(il1 , func) ; //func is same as func from the constructor section code.

pcd.param( pt );

vec2=pcd.intervals( );

cout<< vec1[0] << ” ” << vec1[1] ;

Output ,

0.12   30.23
90   100

Calling param(pt) changes the parameter of the pcd to pt parameter values.

min() function

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

Code example

piecewise_linear_distribution< > pld ;

cout<< pcd.min( ) ;

Output ,

0

max() function

The max() returns the largest value the distribution can generate.

Code example

piecewise_linear_distribution< > pld( 90 , 0 , 500 , func );

cout<< pld.max( ) ;

Output ,

500


 


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

piecewise_linear_distribution< > pld ,
pld1( 9 , 0 , 100 , func ) , pld2( 9 , 0 , 100 , func ) ;

cout<< (pld==pld1) << endl
<< (pld!=pld1) << endl
<< (pld1==pld2) ;

piecewise_linear_distribution<long double >pld3( 9 , 0 , 100 , func ) ;

cout<< (pld1==pld3) ; //error! type does not match

Output,

0
1
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

piecewise_linear_distribution<>pldIO1(25 , 0 , 80 , func) , pldIO2(25 , 0 , 80 , func) ;

default_random_engine dre1 , dre2 ;

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

disState<< pldIO1 ;  //Save the 2nd distribution state of pldIO 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<< pldIO1( dre1 ) << ” ” ;
cout<< pldIO1(dre1) << endl ;

disState>> pldIO2 ;  //reassign the distribution state saved in disState to pldIO2
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<< pldIO1( dre2 ) << ” ” ;
cout<< pldIO1( dre2 ) << endl ;

cin.get( );
return 0;
}

Output in Visual Studio,

28.297
Second and third state output of ddIO1 and dre1
74.3192   43.3804

Outputting the random sequence using ddIO2 and dre2 current state
74.3192   43.3804

The second sate of pldIO1 and dre1 has been assigned to pldIO2 and dre2,so the numbers generated by the second sate and it’s consecutive state of pldIO1 and dre1 will be same as the sequence generated by the pldIO2 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

piecewise_linear_distribution produces random numbers x, b0 ≤x < bn , uniformly distributed over each subinterval [bi , bi+1) according to the probability density function,

piecewise_constant_distribution probability function one

Here,bi < bi+1 , for i= 0 , … , n−1 and

piecewise_constant_distribution probability function two

The value of ‘n’ and the sequence ‘b’ and the sequence ‘w’ is dependent on which constructor is called by the object,how to determine them is shown below.

i)If the distribution object calls the default constructor then n= 1 , ρ0 = ρ1= 1 , b0= 0, and b1= 1.

ii)If second constructor is used :
    a)If firstB == lastB or ++firstB == lastB ,let n= 1, ρ0 = ρ1= 1, b0=0, and b1=1 .
    b) Else ‘b’ sequence is given by the content of [firstB , lastB) of length ‘n+1’ , and w sequence by the content pointed to by firstW iterator and any wk for k ≥n shall be ignore,

iii)If third constructor is called:
    a)If bl.size() < 2,let n=1, w0= 1 , ρ0 = ρ1= 1, b0=0, and b1= 1.
    b)Else [bl.begin() , bl.end()) form a sequence b0,…, bn ,and wk=fw( bk) for k= 0,…,n−1.

iv)If the fourth constructor is called and if nw= 0, let n=1, otherwise let n=nw and 0< δ= (xmax – xmin)/n shall hold.And bk=xmin+k·δ for k= 0,…,n, and wk=fw(bk ) for k= 0,…,n−1.

v)If the fifth constructor is called identify which constructor is called among the four by the param_type object and determine the value of ‘n’ and the sequence ‘w’ and ‘b’ accordingly.