! Imported by MJ from:
! http://www.math.sci.hiroshima-u.ac.jp/~m-mat/MT/VERSIONS/FORTRAN/mt95.f90
! Modified and added genrand_real4 so that it gives the same random
! numbers as other mt implementations..
! DAS: Commented out parts we do not use because ifort -O3 takes forever to
! optimize this file otherwise. Now it is much faster.
!============================================================================

! A C-program for MT19937, with initialization improved 2002/1/26.
! Coded by Takuji Nishimura and Makoto Matsumoto.                 

! Code converted to Fortran 95 by José Rui Faustino de Sousa
! Date: 2002-02-01

! Enhanced version by José Rui Faustino de Sousa
! Date: 2003-04-30

! Interface:
!
! Kinds:
!   genrand_intg
!     Integer kind used must be at least 32 bits.
!   genrand_real
!     Real kind used 
!
! Types:
!   genrand_state
!     Internal representation of the RNG state.
!   genrand_srepr
!     Public representation of the RNG state. Should be used to save the RNG state.
!
! Procedures:
!   assignment(=)
!     Converts from type genrand_state to genrand_srepr and vice versa.
!   genrand_init
!     Internal RNG state initialization subroutine accepts either an genrand_intg integer
!     or a vector as seed or a new state using "put=" returns the present state using
!     "get=". If it is called with "get=" before being seeded with "put=" returns a state
!     initialized with a default seed.
!   genrand_int32
!     Subroutine returns an array or scalar whose elements are random integer on the
!     [0,0xffffffff] interval.
!   genrand_int31
!     Subroutine returns an array or scalar whose elements are random integer on the
!     [0,0x7fffffff] interval.
!   genrand_real1
!     Subroutine returns an array or scalar whose elements are random real on the
!     [0,1] interval.
!   genrand_real2
!     Subroutine returns an array or scalar whose elements are random real on the
!     [0,1[ interval.
!   genrand_real3
!     Subroutine returns an array or scalar whose elements are random real on the
!     ]0,1[ interval.
!   genrand_res53
!     Subroutine returns an array or scalar whose elements are random real on the
!     [0,1[ interval with 53-bit resolution.

! Before using, initialize the state by using genrand_init( put=seed )  

! This library is free software.                                  
! This library is distributed in the hope that it will be useful, 
! but WITHOUT ANY WARRANTY; without even the implied warranty of  
! MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.            

! Copyright (C) 1997, 2002 Makoto Matsumoto and Takuji Nishimura. 
! Any feedback is very welcome.                                   
! http://www.math.keio.ac.jp/matumoto/emt.html                    
! email: matumoto@math.keio.ac.jp                                 
!module mt95

#include "f_defs.h"

module random_m

  use global_m  
  implicit none

  public :: genrand_init, genrand_real4

  private

!  public  :: genrand_init, assignment(=)
!  public  :: genrand_int32, genrand_int31, genrand_real1
!  public  :: genrand_real2, genrand_real3, genrand_res53
!  public  :: genrand_real4
!  private :: init_by_scalar, next_state, genrand_int32_0d, uiadd, uimlt
!  private :: uiadd, uisub, uimlt, uidiv, uimod
!  private :: init_by_type, init_by_scalar, init_by_array, next_state
!  private :: genrand_encode, genrand_decode, genrand_load_state, genrand_dump_state
!  private :: genrand_int32_0d, genrand_int32_1d, genrand_int32_2d, genrand_int32_3d
!  private :: genrand_int32_4d, genrand_int32_5d, genrand_int32_6d, genrand_int32_7d
!  private :: genrand_int31_0d, genrand_int31_1d, genrand_int31_2d, genrand_int31_3d
!  private :: genrand_int31_4d, genrand_int31_5d, genrand_int31_6d, genrand_int31_7d
!  private :: genrand_real1_0d, genrand_real1_1d, genrand_real1_2d, genrand_real1_3d
!  private :: genrand_real1_4d, genrand_real1_5d, genrand_real1_6d, genrand_real1_7d
!  private :: genrand_real2_0d, genrand_real2_1d, genrand_real2_2d, genrand_real2_3d
!  private :: genrand_real2_4d, genrand_real2_5d, genrand_real2_6d, genrand_real2_7d
!  private :: genrand_real3_0d, genrand_real3_1d, genrand_real3_2d, genrand_real3_3d
!  private :: genrand_real3_4d, genrand_real3_5d, genrand_real3_6d, genrand_real3_7d
!  private :: genrand_res53_0d, genrand_res53_1d, genrand_res53_2d, genrand_res53_3d
!  private :: genrand_res53_4d, genrand_res53_5d, genrand_res53_6d, genrand_res53_7d

!  intrinsic :: selected_int_kind, selected_real_kind

!  integer, public, parameter  :: genrand_intg = selected_int_kind( 9 )
!  integer, public, parameter  :: genrand_real = selected_real_kind( 15 )

!  integer, private, parameter :: wi = genrand_intg
!  integer, private, parameter :: wr = genrand_real
  integer, private, parameter :: wi = kind(1)
  integer, private, parameter :: wr = DP

  ! Period parameters   
  integer(kind=wi), private, parameter :: n = 624_wi
  integer(kind=wi), private, parameter :: m = 397_wi

  integer(kind=wi), private, parameter :: default_seed = 5489_wi

  integer(kind=wi), private, parameter :: fbs = 32_wi
  integer(kind=wi), private, parameter :: hbs = fbs / 2_wi
  integer(kind=wi), private, parameter :: qbs = hbs / 2_wi
  integer(kind=wi), private, parameter :: tbs = 3_wi * qbs

  real(kind=wr), private, parameter :: p231       = 2147483648.0_wr
  real(kind=wr), private, parameter :: p232       = 4294967296.0_wr
  real(kind=wr), private, parameter :: p232_1     = p232 - 1.0_wr
  real(kind=wr), private, parameter :: pi232      = 1.0_wr / p232
  real(kind=wr), private, parameter :: pi232_1    = 1.0_wr / p232_1
  real(kind=wr), private, parameter :: pi227      = 1.0_wr / 134217728.0_wr
  real(kind=wr), private, parameter :: pi253      = 1.0_wr / 9007199254740992.0_wr
  real(kind=wr), private, parameter :: p231d232_1 = p231 / p232_1
  real(kind=wr), private, parameter :: p231_5d232 = ( p231 + 0.5_wr ) / p232

  character(len=*), private, parameter  :: alph = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"
  character(len=*), private, parameter  :: sepr = "&"
  integer(kind=wi), private, parameter  :: alps = 62_wi
  integer(kind=wi), private, parameter  :: clen = ( n + 1_wi ) * 7_wi !n * ( ceiling( fbs * log( 2.0 ) / log( alps ) ) + 1 )

  type, public :: genrand_state
    private
    logical(kind=wi)                :: ini = .false._wi
    integer(kind=wi)                :: cnt = n+1_wi
    integer(kind=wi), dimension(n)  :: val = 0_wi
  end type genrand_state

!  type, public :: genrand_srepr
!    character(len=clen) :: repr
!  end type genrand_srepr

  type(genrand_state), private, save  :: state

!  interface assignment( = )
!    module procedure genrand_load_state
!    module procedure genrand_dump_state
!  end interface assignment( = )

  interface genrand_init
!    module procedure init_by_type
    module procedure init_by_scalar
!    module procedure init_by_array
  end interface genrand_init

!  interface genrand_int32
!    module procedure genrand_int32_0d
!    module procedure genrand_int32_1d
!    module procedure genrand_int32_2d
!    module procedure genrand_int32_3d
!    module procedure genrand_int32_4d
!    module procedure genrand_int32_5d
!    module procedure genrand_int32_6d
!    module procedure genrand_int32_7d
!  end interface genrand_int32
!
!  interface genrand_int31
!    module procedure genrand_int31_0d
!    module procedure genrand_int31_1d
!    module procedure genrand_int31_2d
!    module procedure genrand_int31_3d
!    module procedure genrand_int31_4d
!    module procedure genrand_int31_5d
!    module procedure genrand_int31_6d
!    module procedure genrand_int31_7d
!  end interface genrand_int31
!
!  interface genrand_real1
!    module procedure genrand_real1_0d
!    module procedure genrand_real1_1d
!    module procedure genrand_real1_2d
!    module procedure genrand_real1_3d
!    module procedure genrand_real1_4d
!    module procedure genrand_real1_5d
!    module procedure genrand_real1_6d
!    module procedure genrand_real1_7d
!  end interface genrand_real1
!
!  interface genrand_real2
!    module procedure genrand_real2_0d
!    module procedure genrand_real2_1d
!    module procedure genrand_real2_2d
!    module procedure genrand_real2_3d
!    module procedure genrand_real2_4d
!    module procedure genrand_real2_5d
!    module procedure genrand_real2_6d
!    module procedure genrand_real2_7d
!  end interface genrand_real2
!
!  interface genrand_real3
!    module procedure genrand_real3_0d
!    module procedure genrand_real3_1d
!    module procedure genrand_real3_2d
!    module procedure genrand_real3_3d
!    module procedure genrand_real3_4d
!    module procedure genrand_real3_5d
!    module procedure genrand_real3_6d
!    module procedure genrand_real3_7d
!  end interface genrand_real3
!
!  interface genrand_res53
!    module procedure genrand_res53_0d
!    module procedure genrand_res53_1d
!    module procedure genrand_res53_2d
!    module procedure genrand_res53_3d
!    module procedure genrand_res53_4d
!    module procedure genrand_res53_5d
!    module procedure genrand_res53_6d
!    module procedure genrand_res53_7d
!  end interface genrand_res53

  contains

  elemental function uiadd( a, b ) result( c )

!    intrinsic :: ibits, ior, ishft

    integer( kind = wi ), intent( in )  :: a, b

    integer( kind = wi )  :: c

    integer( kind = wi )  :: a1, a2, b1, b2, s1, s2

    a1 = ibits( a, 0, hbs )
    a2 = ibits( a, hbs, hbs )
    b1 = ibits( b, 0, hbs )
    b2 = ibits( b, hbs, hbs )
    s1 = a1 + b1
    s2 = a2 + b2 + ibits( s1, hbs, hbs )
    c  = ior( ishft( s2, hbs ), ibits( s1, 0, hbs ) )
    return

  end function uiadd
  
!  elemental function uisub( a, b ) result( c )
!
!    intrinsic :: ibits, ior, ishft
!
!    integer( kind = wi ), intent( in )  :: a, b
!
!    integer( kind = wi )  :: c
!
!    integer( kind = wi )  :: a1, a2, b1, b2, s1, s2
!
!    a1 = ibits( a, 0, hbs )
!    a2 = ibits( a, hbs, hbs )
!    b1 = ibits( b, 0, hbs )
!    b2 = ibits( b, hbs, hbs )
!    s1 = a1 - b1
!    s2 = a2 - b2 + ibits( s1, hbs, hbs )
!    c  = ior( ishft( s2, hbs ), ibits( s1, 0, hbs ) )
!    return
!
!  end function uisub
!  
  elemental function uimlt( a, b ) result( c )

!    intrinsic :: ibits, ior, ishft

    integer(kind=wi), intent(in)  :: a, b

    integer(kind=wi)  :: c

    integer(kind=wi)  :: a0, a1, a2, a3
    integer(kind=wi)  :: b0, b1, b2, b3
    integer(kind=wi)  :: p0, p1, p2, p3

    a0 = ibits( a, 0, qbs )
    a1 = ibits( a, qbs, qbs )
    a2 = ibits( a, hbs, qbs )
    a3 = ibits( a, tbs, qbs )
    b0 = ibits( b, 0, qbs )
    b1 = ibits( b, qbs, qbs )
    b2 = ibits( b, hbs, qbs )
    b3 = ibits( b, tbs, qbs )
    p0 = a0 * b0
    p1 = a1 * b0 + a0 * b1 + ibits( p0, qbs, tbs )
    p2 = a2 * b0 + a1 * b1 + a0 * b2 + ibits( p1, qbs, tbs )
    p3 = a3 * b0 + a2 * b1 + a1 * b2 + a0 * b3 + ibits( p2, qbs, tbs )
    c  = ior( ishft( p1, qbs ), ibits( p0, 0, qbs ) )
    c  = ior( ishft( p2, hbs ), ibits( c, 0, hbs ) )
    c  = ior( ishft( p3, tbs ), ibits( c, 0, tbs ) )
    return

  end function uimlt
!
!  elemental function uidiv( a, b ) result( c )
!    
!    intrinsic :: btest, ishft
!
!    integer(kind=wi), intent(in)  :: a, b
!
!    integer(kind=wi)  :: c
!
!    integer(kind=wi)  :: dl, rl
!
!    if ( btest( a, fbs-1 ) ) then
!      if ( btest( b, fbs-1 ) ) then
!        if ( a < b ) then
!          c = 0
!        else
!          c = 1
!        end if
!      else
!        dl = ishft( ishft( a, -1 ) / b, 1 )
!        rl = uisub( a, uimlt( b, dl ) )
!        if ( rl < b ) then
!          c = dl
!        else
!          c = uiadd( dl, 1 )
!        end if
!      end if
!    else
!      if ( btest( b, fbs-1 ) ) then
!        c = 0
!      else
!        c = a / b
!      end if
!    end if
!    return
!
!  end function uidiv
!
!  elemental function uimod( a, b ) result( c )
!    
!    intrinsic :: modulo, btest, ishft
!
!    integer(kind=wi), intent(in)  :: a, b
!
!    integer(kind=wi)  :: c
!
!    integer(kind=wi)  :: dl, rl
!
!    if ( btest( a, fbs-1 ) ) then
!      if ( btest( b, fbs-1 ) ) then
!        if ( a < b ) then
!          c = a
!        else
!          c = uisub( a, b )
!        end if
!      else
!        dl = ishft( ishft( a, -1 ) / b, 1 )
!        rl = uisub( a, uimlt( b, dl ) )
!        if ( rl < b ) then
!          c = rl
!        else
!          c = uisub( rl, b )
!        end if
!      end if
!    else
!      if ( btest( b, fbs-1 ) ) then
!        c = a
!      else
!        c = modulo( a, b )
!      end if
!    end if
!    return
!
!  end function uimod
!
!  subroutine init_by_type( put, get )
!
!    intrinsic :: present
!
!    type(genrand_state), optional, intent(in ) :: put
!    type(genrand_state), optional, intent(out) :: get
!
!    if ( present( put ) ) then
!      if ( put%ini ) state = put
!    else if ( present( get ) ) then
!      if ( .not. state%ini ) call init_by_scalar( default_seed )
!      get = state
!    else
!      call init_by_scalar( default_seed )
!    end if
!    return
!
!  end subroutine init_by_type

  ! initializes mt[N] with a seed
  subroutine init_by_scalar( put )

!    intrinsic :: ishft, ieor, ibits

    integer(kind=wi), parameter :: mult_a = 1812433253_wi !z'6C078965'

    integer(kind=wi), intent(in)  :: put

    integer(kind=wi)  :: i

    state%ini = .true._wi
    state%val(1) = ibits( put, 0, fbs )
    do i = 2, n, 1
      state%val(i) = ieor( state%val(i-1), ishft( state%val(i-1), -30 ) )
      state%val(i) = uimlt( state%val(i), mult_a )
      state%val(i) = uiadd( state%val(i), i-1_wi )
      ! See Knuth TAOCP Vol2. 3rd Ed. P.106 for multiplier. 
      ! In the previous versions, MSBs of the seed affect   
      ! only MSBs of the array mt[].                        
      ! 2002/01/09 modified by Makoto Matsumoto             
      state%val(i) = ibits( state%val(i), 0, fbs )
      ! for >32 bit machines 
    end do
    state%cnt = n + 1_wi
    return

  end subroutine init_by_scalar

  ! initialize by an array with array-length 
  ! init_key is the array for initializing keys 
  ! key_length is its length
!  subroutine init_by_array( put )
!
!    intrinsic :: size, max, ishft, ieor, ibits
!    
!    integer(kind=wi), parameter :: seed_d =    19650218_wi !z'12BD6AA'
!    integer(kind=wi), parameter :: mult_a =     1664525_wi !z'19660D'
!    integer(kind=wi), parameter :: mult_b =  1566083941_wi !z'5D588B65'
!    integer(kind=wi), parameter :: msb1_d = ishft( 1_wi, fbs-1 ) !z'80000000'
!
!    integer(kind=wi), dimension(:), intent(in)  :: put
!
!    integer(kind=wi)  :: i, j, k, tp, key_length
!
!    call init_by_scalar( seed_d )
!    key_length = size( put, dim=1 )
!    i = 2_wi
!    j = 1_wi
!    do k = max( n, key_length ), 1, -1
!      tp = ieor( state%val(i-1), ishft( state%val(i-1), -30 ) )
!      tp = uimlt( tp, mult_a )
!      state%val(i) = ieor( state%val(i), tp )
!      state%val(i) = uiadd( state%val(i), uiadd( put(j), j-1_wi ) ) ! non linear 
!      state%val(i) = ibits( state%val(i), 0, fbs ) ! for WORDSIZE > 32 machines 
!      i = i + 1_wi
!      j = j + 1_wi
!      if ( i > n ) then
!        state%val(1) = state%val(n)
!        i = 2_wi
!      end if
!      if ( j > key_length) j = 1_wi
!    end do
!    do k = n-1, 1, -1
!      tp = ieor( state%val(i-1), ishft( state%val(i-1), -30 ) )
!      tp = uimlt( tp, mult_b )
!      state%val(i) = ieor( state%val(i), tp )
!      state%val(i) = uisub( state%val(i), i-1_wi ) ! non linear 
!      state%val(i) = ibits( state%val(i), 0, fbs ) ! for WORDSIZE > 32 machines 
!      i = i + 1_wi
!      if ( i > n ) then
!        state%val(1) = state%val(n)
!        i = 2_wi
!      end if
!    end do
!    state%val(1) = msb1_d ! MSB is 1; assuring non-zero initial array
!    return
!
!  end subroutine init_by_array

  subroutine next_state( )

!    intrinsic :: ishft, ieor, btest, ibits, mvbits

    integer(kind=wi), parameter :: matrix_a = -1727483681_wi !z'9908b0df'

    integer(kind=wi)  :: i, mld

    if ( .not. state%ini ) call init_by_scalar( default_seed )
    do i = 1, n-m, 1
      mld = ibits( state%val(i+1), 0, 31 )
      call mvbits( state%val(i), 31, 1, mld, 31 )
      state%val(i) = ieor( state%val(i+m), ishft( mld, -1 ) )
      if ( btest( state%val(i+1), 0 ) ) state%val(i) = ieor( state%val(i), matrix_a )
    end do
    do i = n-m+1, n-1, 1
      mld = ibits( state%val(i+1), 0, 31 )
      call mvbits( state%val(i), 31, 1, mld, 31 )
      state%val(i) = ieor( state%val(i+m-n), ishft( mld, -1 ) )
      if ( btest( state%val(i+1), 0 ) ) state%val(i) = ieor( state%val(i), matrix_a )
    end do
    mld = ibits( state%val(1), 0, 31 )
    call mvbits( state%val(n), 31, 1, mld, 31 )
    state%val(n) = ieor( state%val(m), ishft( mld, -1 ) )
    if ( btest( state%val(1), 0 ) ) state%val(n) = ieor( state%val(n), matrix_a )
    state%cnt = 1_wi
    return

  end subroutine next_state

!  elemental subroutine genrand_encode( chr, val )
!    
!    intrinsic :: len
!
!    character(len=*), intent(out) :: chr
!    integer(kind=wi), intent(in ) :: val
!    
!    integer(kind=wi)  :: i, m, d
!
!    d = val
!    chr = ""
!    do i = 1, len( chr ), 1
!      m = uimod( d, alps ) + 1
!      chr(i:i) = alph(m:m)
!      d = uidiv( d, alps )
!      if ( d == 0 ) exit
!    end do
!    return
!
!  end subroutine genrand_encode
!
!  elemental subroutine genrand_decode( val, chr )
!    
!    intrinsic :: len, len_trim, trim, adjustl, scan
!
!    integer(kind=wi), intent(out) :: val
!    character(len=*), intent(in ) :: chr
!    
!    integer(kind=wi)        :: i, e, p
!    character(len=len(chr)) :: c
!
!    e = 1
!    c = trim( adjustl( chr ) )
!    val = 0
!    do i = 1, len_trim( c ), 1
!      p = scan( alph, c(i:i) ) - 1
!      if( p >= 0 ) then
!        val = uiadd( val, uimlt( p, e ) )
!        e = uimlt( e, alps )
!      end if
!    end do
!    return
!
!  end subroutine genrand_decode
!
!  elemental subroutine genrand_load_state( stt, rpr )
!
!    intrinsic :: scan
!
!    type(genrand_state), intent(out)  :: stt
!    type(genrand_srepr), intent(in )  :: rpr
!
!    integer(kind=wi)    :: i, j
!    character(len=clen) :: c
!
!    i = 1
!    c = rpr%repr
!    do
!      j = scan( c, sepr )
!      if ( j /= 0 ) then
!        call genrand_decode( stt%val(i), c(:j-1) )
!        i = i + 1
!        c = c(j+1:)
!      else
!        exit
!      end if
!    end do
!    call genrand_decode( stt%cnt, c )
!    stt%ini = .true._wi
!    return
!
!  end subroutine genrand_load_state
!
!  elemental subroutine genrand_dump_state( rpr, stt )
!
!    intrinsic :: len_trim
!
!    type(genrand_srepr), intent(out) :: rpr
!    type(genrand_state), intent(in ) :: stt
!
!    integer(kind=wi)  :: i, j
!
!    j = 1
!    rpr%repr = ""
!    do i = 1, n, 1
!      call genrand_encode( rpr%repr(j:), stt%val(i) )
!      j = len_trim( rpr%repr ) + 1
!      rpr%repr(j:j) = sepr
!      j = j + 1
!    end do
!    call genrand_encode( rpr%repr(j:), stt%cnt )
!    return
!
!  end subroutine genrand_dump_state

  ! generates a random number on [0,0xffffffff]-interval
  subroutine genrand_int32_0d( y )

!    intrinsic :: ieor, iand, ishft

    integer(kind=wi), parameter :: temper_a = -1658038656_wi !z'9D2C5680'
    integer(kind=wi), parameter :: temper_b =  -272236544_wi !z'EFC60000'

    integer(kind=wi), intent(out) :: y
    
    if ( state%cnt > n ) call next_state( )
    y = state%val(state%cnt)
    state%cnt = state%cnt + 1_wi
    ! Tempering 
    y = ieor( y, ishft( y, -11 ) )
    y = ieor( y, iand( ishft( y,  7 ), temper_a ) )
    y = ieor( y, iand( ishft( y, 15 ), temper_b ) )
    y = ieor( y, ishft( y, -18 ) )
    return

  end subroutine genrand_int32_0d

!  subroutine genrand_int32_1d( y )
!
!    intrinsic :: size
!
!    integer(kind=wi), dimension(:), intent(out) :: y
!
!    integer(kind=wi)  :: i
!
!    do i = 1, size( y, 1 ), 1
!      call genrand_int32_0d( y(i) )
!    end do
!    return
!
!  end subroutine genrand_int32_1d
!
!  subroutine genrand_int32_2d( y )
!
!    intrinsic :: size
!
!    integer(kind=wi), dimension(:,:), intent(out) :: y
!    
!    integer(kind=wi)  :: i
!
!    do i = 1, size( y, 2 ), 1
!      call genrand_int32_1d( y(:,i) )
!    end do
!    return
!
!  end subroutine genrand_int32_2d
!
!  subroutine genrand_int32_3d( y )
!
!    intrinsic :: size
!
!    integer(kind=wi), dimension(:,:,:), intent(out) :: y
!    
!    integer(kind=wi)  :: i
!
!    do i = 1, size( y, 3 ), 1
!      call genrand_int32_2d( y(:,:,i) )
!    end do
!    return
!
!  end subroutine genrand_int32_3d
!
!  subroutine genrand_int32_4d( y )
!
!    intrinsic :: size
!
!    integer(kind=wi), dimension(:,:,:,:), intent(out) :: y
!    
!    integer(kind=wi)  :: i
!
!    do i = 1, size( y, 4 ), 1
!      call genrand_int32_3d( y(:,:,:,i) )
!    end do
!    return
!
!  end subroutine genrand_int32_4d
!
!  subroutine genrand_int32_5d( y )
!
!    intrinsic :: size
!
!    integer(kind=wi), dimension(:,:,:,:,:), intent(out) :: y
!    
!    integer(kind=wi)  :: i
!
!    do i = 1, size( y, 5 ), 1
!      call genrand_int32_4d( y(:,:,:,:,i) )
!    end do
!    return
!
!  end subroutine genrand_int32_5d
!
!  subroutine genrand_int32_6d( y )
!
!    intrinsic :: size
!
!    integer(kind=wi), dimension(:,:,:,:,:,:), intent(out) :: y
!    
!    integer(kind=wi)  :: i
!
!    do i = 1, size( y, 6 ), 1
!      call genrand_int32_5d( y(:,:,:,:,:,i) )
!    end do
!    return
!
!  end subroutine genrand_int32_6d
!
!  subroutine genrand_int32_7d( y )
!
!    intrinsic :: size
!
!    integer(kind=wi), dimension(:,:,:,:,:,:,:), intent(out) :: y
!    
!    integer(kind=wi)  :: i
!
!    do i = 1, size( y, 7 ), 1
!      call genrand_int32_6d( y(:,:,:,:,:,:,i) )
!    end do
!    return
!
!  end subroutine genrand_int32_7d
!
!  ! generates a random number on [0,0x7fffffff]-interval
!  subroutine genrand_int31_0d( y )
!
!    intrinsic :: ishft
!
!    integer(kind=wi), intent(out) :: y
!
!    call genrand_int32_0d( y )
!    y = ishft( y, -1 )
!    return
!
!  end subroutine genrand_int31_0d
!
!  subroutine genrand_int31_1d( y )
!
!    intrinsic :: size
!
!    integer(kind=wi), dimension(:), intent(out) :: y
!
!    integer(kind=wi)  :: i
!
!    do i = 1, size( y, 1 ), 1
!      call genrand_int31_0d( y(i) )
!    end do
!    return
!
!  end subroutine genrand_int31_1d
!
!  subroutine genrand_int31_2d( y )
!
!    intrinsic :: size
!
!    integer(kind=wi), dimension(:,:), intent(out) :: y
!
!    integer(kind=wi)  :: i
!
!    do i = 1, size( y, 2 ), 1
!      call genrand_int31_1d( y(:,i) )
!    end do
!    return
!
!  end subroutine genrand_int31_2d
!
!  subroutine genrand_int31_3d( y )
!
!    intrinsic :: size
!
!    integer(kind=wi), dimension(:,:,:), intent(out) :: y
!
!    integer(kind=wi)  :: i
!
!    do i = 1, size( y, 3 ), 1
!      call genrand_int31_2d( y(:,:,i) )
!    end do
!    return
!
!  end subroutine genrand_int31_3d
!
!  subroutine genrand_int31_4d( y )
!
!    intrinsic :: size
!
!    integer(kind=wi), dimension(:,:,:,:), intent(out) :: y
!
!    integer(kind=wi)  :: i
!
!    do i = 1, size( y, 4 ), 1
!      call genrand_int31_3d( y(:,:,:,i) )
!    end do
!    return
!
!  end subroutine genrand_int31_4d
!
!  subroutine genrand_int31_5d( y )
!
!    intrinsic :: size
!
!    integer(kind=wi), dimension(:,:,:,:,:), intent(out) :: y
!
!    integer(kind=wi)  :: i
!
!    do i = 1, size( y, 5 ), 1
!      call genrand_int31_4d( y(:,:,:,:,i) )
!    end do
!    return
!
!  end subroutine genrand_int31_5d
!
!  subroutine genrand_int31_6d( y )
!
!    intrinsic :: size
!
!    integer(kind=wi), dimension(:,:,:,:,:,:), intent(out) :: y
!
!    integer(kind=wi)  :: i
!
!    do i = 1, size( y, 6 ), 1
!      call genrand_int31_5d( y(:,:,:,:,:,i) )
!    end do
!    return
!
!  end subroutine genrand_int31_6d
!
!  subroutine genrand_int31_7d( y )
!
!    intrinsic :: size
!
!    integer(kind=wi), dimension(:,:,:,:,:,:,:), intent(out) :: y
!
!    integer(kind=wi)  :: i
!
!    do i = 1, size( y, 7 ), 1
!      call genrand_int31_6d( y(:,:,:,:,:,:,i) )
!    end do
!    return
!
!  end subroutine genrand_int31_7d
!
!  ! generates a random number on [0,1]-real-interval
!  subroutine genrand_real1_0d( r )
!
!    intrinsic :: real
!
!    real(kind=wr), intent(out)  :: r
!
!    integer(kind=wi)  :: a
!
!    call genrand_int32_0d( a )
!    r = real( a, kind=wr ) * pi232_1 + p231d232_1
!    ! divided by 2^32-1
!    return
!
!  end subroutine genrand_real1_0d
!
!  subroutine genrand_real1_1d( r )
!
!    intrinsic :: size
!
!    real(kind=wr), dimension(:), intent(out)  :: r
!
!    integer(kind=wi)  :: i
!
!    do i = 1, size( r, 1 ), 1
!      call genrand_real1_0d( r(i) )
!    end do
!    return
!
!  end subroutine genrand_real1_1d
!
!  subroutine genrand_real1_2d( r )
!
!    intrinsic :: size
!
!    real(kind=wr), dimension(:,:), intent(out)  :: r
!
!    integer(kind=wi)  :: i
!
!    do i = 1, size( r, 2 ), 1
!      call genrand_real1_1d( r(:,i) )
!    end do
!    return
!
!  end subroutine genrand_real1_2d
!
!  subroutine genrand_real1_3d( r )
!
!    intrinsic :: size
!
!    real(kind=wr), dimension(:,:,:), intent(out)  :: r
!
!    integer(kind=wi)  :: i
!
!    do i = 1, size( r, 3 ), 1
!      call genrand_real1_2d( r(:,:,i) )
!    end do
!    return
!
!  end subroutine genrand_real1_3d
!
!  subroutine genrand_real1_4d( r )
!
!    intrinsic :: size
!
!    real(kind=wr), dimension(:,:,:,:), intent(out)  :: r
!
!    integer(kind=wi)  :: i
!
!    do i = 1, size( r, 4 ), 1
!      call genrand_real1_3d( r(:,:,:,i) )
!    end do
!    return
!
!  end subroutine genrand_real1_4d
!
!  subroutine genrand_real1_5d( r )
!
!    intrinsic :: size
!
!    real(kind=wr), dimension(:,:,:,:,:), intent(out)  :: r
!
!    integer(kind=wi)  :: i
!
!    do i = 1, size( r, 5 ), 1
!      call genrand_real1_4d( r(:,:,:,:,i) )
!    end do
!    return
!
!  end subroutine genrand_real1_5d
!
!  subroutine genrand_real1_6d( r )
!
!    intrinsic :: size
!
!    real(kind=wr), dimension(:,:,:,:,:,:), intent(out)  :: r
!
!    integer(kind=wi)  :: i
!
!    do i = 1, size( r, 6 ), 1
!      call genrand_real1_5d( r(:,:,:,:,:,i) )
!    end do
!    return
!
!  end subroutine genrand_real1_6d
!
!  subroutine genrand_real1_7d( r )
!
!    intrinsic :: size
!
!    real(kind=wr), dimension(:,:,:,:,:,:,:), intent(out)  :: r
!
!    integer(kind=wi)  :: i
!
!    do i = 1, size( r, 7 ), 1
!      call genrand_real1_6d( r(:,:,:,:,:,:,i) )
!    end do
!    return
!
!  end subroutine genrand_real1_7d
!
!  ! generates a random number on [0,1)-real-interval
!  subroutine genrand_real2_0d( r )
!
!    intrinsic :: real
!
!    real(kind=wr), intent(out)  :: r
!
!    integer(kind=wi)  :: a
!
!    call genrand_int32_0d( a )
!    r = real( a, kind=wr ) * pi232 + 0.5_wr
!    ! divided by 2^32
!    return
!
!  end subroutine genrand_real2_0d
!
!  subroutine genrand_real2_1d( r )
!
!    intrinsic :: size
!
!    real(kind=wr), dimension(:), intent(out)  :: r
!
!    integer(kind=wi)  :: i
!
!    do i = 1, size( r, 1 ), 1
!      call genrand_real2_0d( r(i) )
!    end do
!    return
!
!  end subroutine genrand_real2_1d
!
!  subroutine genrand_real2_2d( r )
!
!    intrinsic :: size
!
!    real(kind=wr), dimension(:,:), intent(out)  :: r
!
!    integer(kind=wi)  :: i
!
!    do i = 1, size( r, 2 ), 1
!      call genrand_real2_1d( r(:,i) )
!    end do
!    return
!
!  end subroutine genrand_real2_2d
!
!  subroutine genrand_real2_3d( r )
!
!    intrinsic :: size
!
!    real(kind=wr), dimension(:,:,:), intent(out)  :: r
!
!    integer(kind=wi)  :: i
!
!    do i = 1, size( r, 3 ), 1
!      call genrand_real2_2d( r(:,:,i) )
!    end do
!    return
!
!  end subroutine genrand_real2_3d
!
!  subroutine genrand_real2_4d( r )
!
!    intrinsic :: size
!
!    real(kind=wr), dimension(:,:,:,:), intent(out)  :: r
!
!    integer(kind=wi)  :: i
!
!    do i = 1, size( r, 4 ), 1
!      call genrand_real2_3d( r(:,:,:,i) )
!    end do
!    return
!
!  end subroutine genrand_real2_4d
!
!  subroutine genrand_real2_5d( r )
!
!    intrinsic :: size
!
!    real(kind=wr), dimension(:,:,:,:,:), intent(out)  :: r
!
!    integer(kind=wi)  :: i
!
!    do i = 1, size( r, 5 ), 1
!      call genrand_real2_4d( r(:,:,:,:,i) )
!    end do
!    return
!
!  end subroutine genrand_real2_5d
!
!  subroutine genrand_real2_6d( r )
!
!    intrinsic :: size
!
!    real(kind=wr), dimension(:,:,:,:,:,:), intent(out)  :: r
!
!    integer(kind=wi)  :: i
!
!    do i = 1, size( r, 6 ), 1
!      call genrand_real2_5d( r(:,:,:,:,:,i) )
!    end do
!    return
!
!  end subroutine genrand_real2_6d
!
!  subroutine genrand_real2_7d( r )
!
!    intrinsic :: size
!
!    real(kind=wr), dimension(:,:,:,:,:,:,:), intent(out)  :: r
!
!    integer(kind=wi)  :: i
!
!    do i = 1, size( r, 7 ), 1
!      call genrand_real2_6d( r(:,:,:,:,:,:,i) )
!    end do
!    return
!
!  end subroutine genrand_real2_7d
!
!  ! generates a random number on (0,1)-real-interval
!  subroutine genrand_real3_0d( r )
!
!    intrinsic :: real
!
!    real(kind=wr), intent(out)  :: r
!
!    integer(kind=wi)  :: a
!
!    call genrand_int32_0d( a )
!    r = real( a, kind=wr ) * pi232 + p231_5d232
!    ! divided by 2^32 
!    return
!
!  end subroutine genrand_real3_0d
!
!  subroutine genrand_real3_1d( r )
!
!    intrinsic :: size
!
!    real(kind=wr), dimension(:), intent(out)  :: r
!
!    integer(kind=wi)  :: i
!
!    do i = 1, size( r, 1 ), 1
!      call genrand_real3_0d( r(i) )
!    end do
!    return
!
!  end subroutine genrand_real3_1d
!
!  subroutine genrand_real3_2d( r )
!
!    intrinsic :: size
!
!    real(kind=wr), dimension(:,:), intent(out)  :: r
!
!    integer(kind=wi)  :: i
!
!    do i = 1, size( r, 2 ), 1
!      call genrand_real3_1d( r(:,i) )
!    end do
!    return
!
!  end subroutine genrand_real3_2d
!
!  subroutine genrand_real3_3d( r )
!
!    intrinsic :: size
!
!    real(kind=wr), dimension(:,:,:), intent(out)  :: r
!
!    integer(kind=wi)  :: i
!
!    do i = 1, size( r, 3 ), 1
!      call genrand_real3_2d( r(:,:,i) )
!    end do
!    return
!
!  end subroutine genrand_real3_3d
!
!  subroutine genrand_real3_4d( r )
!
!    intrinsic :: size
!
!    real(kind=wr), dimension(:,:,:,:), intent(out)  :: r
!
!    integer(kind=wi)  :: i
!
!    do i = 1, size( r, 4 ), 1
!      call genrand_real3_3d( r(:,:,:,i) )
!    end do
!    return
!
!  end subroutine genrand_real3_4d
!
!  subroutine genrand_real3_5d( r )
!
!    intrinsic :: size
!
!    real(kind=wr), dimension(:,:,:,:,:), intent(out)  :: r
!
!    integer(kind=wi)  :: i
!
!    do i = 1, size( r, 5 ), 1
!      call genrand_real3_4d( r(:,:,:,:,i) )
!    end do
!    return
!
!  end subroutine genrand_real3_5d
!
!  subroutine genrand_real3_6d( r )
!
!    intrinsic :: size
!
!    real(kind=wr), dimension(:,:,:,:,:,:), intent(out)  :: r
!
!    integer(kind=wi)  :: i
!
!    do i = 1, size( r, 6 ), 1
!      call genrand_real3_5d( r(:,:,:,:,:,i) )
!    end do
!    return
!
!  end subroutine genrand_real3_6d
!
!  subroutine genrand_real3_7d( r )
!
!    intrinsic :: size
!
!    real(kind=wr), dimension(:,:,:,:,:,:,:), intent(out)  :: r
!
!    integer(kind=wi)  :: i
!
!    do i = 1, size( r, 7 ), 1
!      call genrand_real3_6d( r(:,:,:,:,:,:,i) )
!    end do
!    return
!
!  end subroutine genrand_real3_7d
!
!  ! generates a random number on [0,1) with 53-bit resolution
!  subroutine genrand_res53_0d( r )
!
!    intrinsic :: ishft, real
!
!    real(kind=wr), intent(out)  :: r
!
!    integer(kind=wi)  :: a, b
!
!    call genrand_int32_0d( a )
!    call genrand_int32_0d( b )
!    a = ishft( a, -5 )
!    b = ishft( b, -6 )
!    r = real( a, kind=wr ) * pi227 + real( b, kind=wr ) * pi253
!    return
!
!  end subroutine genrand_res53_0d
!
!  subroutine genrand_res53_1d( r )
!
!    intrinsic :: size
!
!    real(kind=wr), dimension(:), intent(out)  :: r
!
!    integer(kind=wi)  :: i
!
!    do i = 1, size( r, 1 ), 1
!      call genrand_res53_0d( r(i) )
!    end do
!    return
!
!  end subroutine genrand_res53_1d
!
!  subroutine genrand_res53_2d( r )
!
!    intrinsic :: size
!
!    real(kind=wr), dimension(:,:), intent(out)  :: r
!
!    integer(kind=wi)  :: i
!
!    do i = 1, size( r, 2 ), 1
!      call genrand_res53_1d( r(:,i) )
!    end do
!    return
!
!  end subroutine genrand_res53_2d
!
!  subroutine genrand_res53_3d( r )
!
!    intrinsic :: size
!
!    real(kind=wr), dimension(:,:,:), intent(out)  :: r
!
!    integer(kind=wi)  :: i
!
!    do i = 1, size( r, 3 ), 1
!      call genrand_res53_2d( r(:,:,i) )
!    end do
!    return
!
!  end subroutine genrand_res53_3d
!
!  subroutine genrand_res53_4d( r )
!
!    intrinsic :: size
!
!    real(kind=wr), dimension(:,:,:,:), intent(out)  :: r
!
!    integer(kind=wi)  :: i
!
!    do i = 1, size( r, 4 ), 1
!      call genrand_res53_3d( r(:,:,:,i) )
!    end do
!    return
!
!  end subroutine genrand_res53_4d
!
!  subroutine genrand_res53_5d( r )
!
!    intrinsic :: size
!
!    real(kind=wr), dimension(:,:,:,:,:), intent(out)  :: r
!
!    integer(kind=wi)  :: i
!
!    do i = 1, size( r, 5 ), 1
!      call genrand_res53_4d( r(:,:,:,:,i) )
!    end do
!    return
!
!  end subroutine genrand_res53_5d
!
!  subroutine genrand_res53_6d( r )
!
!    intrinsic :: size
!
!    real(kind=wr), dimension(:,:,:,:,:,:), intent(out)  :: r
!
!    integer(kind=wi)  :: i
!
!    do i = 1, size( r, 6 ), 1
!      call genrand_res53_5d( r(:,:,:,:,:,i) )
!    end do
!    return
!
!  end subroutine genrand_res53_6d
!
!  subroutine genrand_res53_7d( r )
!
!    intrinsic :: size
!
!    real(kind=wr), dimension(:,:,:,:,:,:,:), intent(out)  :: r
!
!    integer(kind=wi)  :: i
!
!    do i = 1, size( r, 7 ), 1
!      call genrand_res53_6d( r(:,:,:,:,:,:,i) )
!    end do
!    return
!
!  end subroutine genrand_res53_7d
  ! These real versions are due to Isaku Wada, 2002/01/09 added 
  ! Altered by José Sousa genrand_real[1-3] will not return exactely
  ! the same values but should have the same properties and are faster

  subroutine genrand_real4( r )

!    intrinsic :: real

    real(kind=wr), intent(out)  :: r

    integer(kind=wi)  :: a

    call genrand_int32_0d( a )
    
    if (a < 0) then
       r = (real( a, kind=wr ) + p232) * pi232_1
       ! divided by 2^32-1
    else
       r =  real( a, kind=wr ) * pi232_1
    endif
    return

  end subroutine genrand_real4

!end module mt95
end module random_m

