!   LUXURY LEVELS.
!  level 0  (p=24): equivalent to the original RCARRY of Marsaglia
!           and Zaman, very long period, but fails many tests.
!  level 1  (p=48): considerable improvement in quality over level 0,
!           now passes the gap test, but still fails spectral test.
!  level 2  (p=97): passes all known tests, but theoretically still
!           defective.
!  level 3  (p=223): DEFAULT VALUE.  Any theoretically possible
!           correlations have very small chance of being observed.
!  level 4  (p=389): highest possible luxury, all 24 bits chaotic.
c---------------------------------------------
      SUBROUTINE ranlux(rvec, lenv)
c                    returns a vector RVEC of LEN   
c                   32-bit random floating point numbers between 
c                   zero (not included) and one (also not incl.).
c           Next call to ranlux gives next LEN of random numbers
c---------------------------------------------
      INTEGER  lenv
      REAL        rvec(lenv)
      INTEGER  iseeds(24)
      INCLUDE 'luxury.h'
      DATA ndskip/ 0, 24, 73, 199, 365 /
      DATA i24,j24,luxlev/24,10,lxdflt/
      DATA notyet/.true./
      DATA in24,kount,mkount,carry/0,0,0,0./


!  NOTYET is .TRUE. if no initialization has been performed yet.
!              Default Initialization by Multiplicative Congruential

      IF (notyet) THEN
        notyet = .false.
        jseed = jsdflt
        inseed = jseed
c        WRITE (6,'(A,I12)') ' RANLUX DEFAULT INITIALIZATION: ', jseed
        luxlev = lxdflt
        nskip = ndskip(luxlev)
        lp = nskip + 24
        in24 = 0
        kount = 0
        mkount = 0
c      WRITE (6,'(A,I2,A,I4)') ' RANLUX DEFAULT LUXURY LEVEL= ', luxlev,   
c     &                            '    p =', lp
      twom24 = 1.
        DO i = 1, 24
          twom24 = twom24 * 0.5
          k = jseed / 53668
          jseed = 40014 * (jseed-k*53668) - k * 12211
          IF (jseed.LT.0) jseed = jseed + icons
          iseeds(i) = MOD(jseed,itwo24)
        END DO
        twom12 = twom24 * 4096.
        DO i = 1, 24
          seeds(i) = REAL(iseeds(i)) * twom24
          next(i) = i - 1
        END DO
        next(1) = 24
        i24 = 24
        j24 = 10
        carry = 0.
        IF (seeds(24).EQ.0.) carry = twom24
      END IF

!          The Generator proper: "Subtract-with-borrow",
!          as proposed by Marsaglia and Zaman,
!          Florida State University, March, 1989

      DO ivec = 1, lenv
        uni = seeds(j24) - seeds(i24) - carry
        IF (uni.LT.0.) THEN
          uni = uni + 1.0
          carry = twom24
        ELSE
          carry = 0.
        END IF
        seeds(i24) = uni
        i24 = next(i24)
        j24 = next(j24)
        rvec(ivec) = uni
      !  small numbers (with less than 12 "significant" bits) are "padded".
        IF (uni.LT.twom12) THEN
          rvec(ivec) = rvec(ivec) + twom24 * seeds(j24)
      !        and zero is forbidden in case someone takes a logarithm
          IF (rvec(ivec).EQ.0.) rvec(ivec) = twom24 * twom24
        END IF
      !        Skipping to luxury.  As proposed by Martin Luscher.
        in24 = in24 + 1
        IF (in24.EQ.24) THEN
          in24 = 0
          kount = kount + nskip
          DO isk = 1, nskip
            uni = seeds(j24) - seeds(i24) - carry
            IF (uni.LT.0.) THEN
              uni = uni + 1.0
              carry = twom24
            ELSE
              carry = 0.
            END IF
            seeds(i24) = uni
            i24 = next(i24)
            j24 = next(j24)
          END DO
        END IF
      END DO
      kount = kount + lenv
      IF (kount.GE.igiga) THEN
        mkount = mkount + 1
        kount = kount - igiga
      END IF
      RETURN

      END ! SUBROUTINE ranlux

c---------------------------------------------
c           Subroutine to input and float integer seeds from previous run
      SUBROUTINE rluxin(isdext)
c                   restarts the generator from vector  
c                   ISDEXT of 25 32-bit integers 
c---------------------------------------------
      INCLUDE 'luxury.h'
      INTEGER isdext(25)
      IF (notyet) THEN
        WRITE (6,'(A)')' Proper results ONLY with ',
     &        'initialisation from 25 integers obtained with RLUXUT'
        notyet = .false.
      END IF
      
      twom24 = 1.
      DO i = 1, 24
        next(i) = i - 1
        twom24 = twom24 * 0.5
      END DO
      next(1) = 24
      twom12 = twom24 * 4096.
c      WRITE (6,'(A)') ' FULL INITIALIZATION OF RANLUX WITH 25 INTEGERS:'
c      WRITE (6,'(5X,5I12)') isdext
      DO i = 1, 24
        seeds(i) = REAL(isdext(i)) * twom24
      END DO
      carry = 0.
      IF (isdext(25).LT.0) carry = twom24
      isd = ABS(isdext(25))
      i24 = MOD(isd,100)
      isd = isd / 100
      j24 = MOD(isd,100)
      isd = isd / 100
      in24 = MOD(isd,100)
      isd = isd / 100
      luxlev = isd
      IF (luxlev.LE.maxlev) THEN
        nskip = ndskip(luxlev)
c        WRITE (6,'(A,I2)') ' RANLUX LUXURY LEVEL SET BY RLUXIN TO: ',
c     &                       luxlev
      ELSE IF (luxlev.GE.24) THEN
        nskip = luxlev - 24
c        WRITE (6,'(A,I5)') ' RANLUX P-VALUE SET BY RLUXIN TO:', luxlev
      ELSE
        nskip = ndskip(maxlev)
c        WRITE (6,'(A,I5)') ' RANLUX ILLEGAL LUXURY RLUXIN: ', luxlev
        luxlev = maxlev
      END IF
      inseed = -1
      RETURN
      
      END ! SUBROUTINE rluxin

c---------------------------------------------
c                    Subroutine to ouput seeds as integers
      SUBROUTINE rluxut(isdext)
c      outputs the current values of the 25
c                 32-bit integer seeds, to be used for restarting
c      ISDEXT must be dimensioned 25 in the calling program 
c---------------------------------------------
      INCLUDE 'luxury.h' 
      INTEGER isdext(25)
      DO i = 1, 24
        isdext(i) = INT(seeds(i)*twop12*twop12)
      END DO
      isdext(25) = i24 + 100 * j24 + 10000 * in24 + 1000000 * luxlev
      IF (carry.GT.0.) isdext(25) = -isdext(25)
      RETURN
      
      END ! SUBROUTINE rluxut

c---------------------------------------------
!                    Subroutine to output the "convenient" restart point
      SUBROUTINE rluxat(lout, inout, k1, k2)
c---------------------------------------------
      INCLUDE 'luxury.h'
      
      lout = luxlev
      inout = inseed
      k1 = kount
      k2 = mkount
      RETURN
      
      END ! SUBROUTINE rluxat

c---------------------------------------------
c                    Subroutine to initialize from one or three integers
      SUBROUTINE rluxgo(lux, ins, k1, k2)
c                initializes the generator from  
c               one 32-bit integer INT and sets Luxury Level LUX
c               which is integer between zero and MAXLEV, or if
c               LUX .GT. 24, it sets p=LUX directly.  K1 and K2
c               should be set to zero unless restarting at a break
c               point given by output of RLUXAT
c---------------------------------------------
      INCLUDE 'luxury.h'
      INTEGER  iseeds(24)
      
      IF (lux.LT.0) THEN
        luxlev = lxdflt
      ELSE IF (lux.LE.maxlev) THEN
        luxlev = lux
      ELSE IF (lux.LT.24.OR.lux.GT.2000) THEN
        luxlev = maxlev
        WRITE (6,'(A,I7)') ' RANLUX ILLEGAL LUXURY RLUXGO: ', lux
      ELSE
        luxlev = lux
        DO ilx = 0, maxlev
          IF (lux.EQ.ndskip(ilx)+24) luxlev = ilx
        END DO
      END IF
      IF (luxlev.LE.maxlev) THEN
        nskip = ndskip(luxlev)
        WRITE (6,'(A,I2,A,I4)') ' RANLUX LUXURY LEVEL SET BY RLUXGO :',
     &              luxlev,'     P=', nskip + 24
      ELSE
        nskip = luxlev - 24
        WRITE (6,'(A,I5)') ' RANLUX P-VALUE SET BY RLUXGO TO:', luxlev
      END IF
      in24 = 0
      IF (ins.LT.0) WRITE (6,'(A)')
     &        ' Illegal initialization by RLUXGO, negative input seed'
      IF (ins.GT.0) THEN
        jseed = ins
        WRITE (6,'(A,3I12)')' RANLUX INITIALIZED BY RLUXGO FROM SEEDS',
     &                                    jseed, k1, k2
      ELSE
        jseed = jsdflt
       WRITE (6,'(A)')' RANLUX INITIALIZED BY RLUXGO FROM DEFAULT SEED'
      END IF
      inseed = jseed
      notyet = .false.
      twom24 = 1.
      DO i = 1, 24
        twom24 = twom24 * 0.5
        k = jseed / 53668
        jseed = 40014 * (jseed-k*53668) - k * 12211
        IF (jseed.LT.0) jseed = jseed + icons
        iseeds(i) = MOD(jseed,itwo24)
      END DO
      twom12 = twom24 * 4096.
      DO i = 1, 24
        seeds(i) = REAL(iseeds(i)) * twom24
        next(i) = i - 1
      END DO
      next(1) = 24
      i24 = 24
      j24 = 10
      carry = 0.
      IF (seeds(24).EQ.0.) carry = twom24
      !        If restarting at a break point, skip K1 + IGIGA*K2
      !        Note that this is the number of numbers delivered to
      !        the user PLUS the number skipped (if luxury .GT. 0).
      kount = k1
      mkount = k2
      IF (k1+k2.NE.0) THEN
        DO iouter = 1, k2 + 1
          inner = igiga
          IF (iouter.EQ.k2+1) inner = k1
          DO isk = 1, inner
            uni = seeds(j24) - seeds(i24) - carry
            IF (uni.LT.0.) THEN
              uni = uni + 1.0
              carry = twom24
            ELSE
              carry = 0.
            END IF
            seeds(i24) = uni
            i24 = next(i24)
            j24 = next(j24)
          END DO
        END DO
      !         Get the right value of IN24 by direct calculation
        in24 = MOD(kount,nskip+24)
        IF (mkount.GT.0) THEN
          izip = MOD(igiga, nskip+24)
          izip2 = mkount * izip + in24
          in24 = MOD(izip2, nskip+24)
        END IF
      !       Now IN24 had better be between zero and 23 inclusive
        IF (in24.GT.23) THEN
          WRITE (6,'(A/A,3I11,A,I5)') 
     &       '  Error in RESTARTING with RLUXGO:', '  The values', ins, 
     &                k1, k2, ' cannot occur at luxury level', luxlev
          in24 = 0
        END IF
      END IF
      RETURN
      
      END ! SUBROUTINE rluxgo


!************************************************************************
      PROGRAM luxtst
!         Exercise for the RANLUX Pseudorandom number generator.
!    USE luxury
      PARAMETER (Nnumbers = 10000)
      INCLUDE 'luxury.h'
      REAL    rvec(Nnumbers)
      INTEGER restart(25)

      CALL rluxgo(3,0,0,0)
      WRITE (6,'(/A)') '  CALL RANLUX(RVEC,Nnumbers)'
      CALL ranlux(rvec,Nnumbers)
      WRITE (6,'(A/9X,5F12.8)') ' RANLUX default numbers   1-  5:', 
     &     (rvec(i),i=1,5)            
      CALL ranlux(rvec,Nnumbers)
      WRITE (6,'(A/9X,5F12.8)') ' RANLUX default numbers:', 
     &     (rvec(i),i=1,5)      

      
      WRITE (6,'(/A)') '  test restarting from the full vector'
      CALL rluxut(restart)
      WRITE (6,'(/A/(1X,5I14))') '  current RANLUX status saved:', 
     &     (restart(i),i=1,25)
      CALL ranlux(rvec,Nnumbers)
      WRITE (6,'(A/9X,5F12.8)') ' RANLUX numbers 1- 5:',
     &     (rvec(i),i=1,5)
      CALL ranlux(rvec,Nnumbers)
      WRITE (6,'(A/9X,5F12.8)') ' RANLUX numbers:',
     &     (rvec(i),i=1,5)
      
      WRITE (6,'(/A)') '   previous RANLUX status will be restored'
      CALL rluxin(restart)
      CALL ranlux(rvec,Nnumbers)
      WRITE (6,'(A/9X,5F12.8)') ' RANLUX numbers 1- 5:',
     &     (rvec(i),i=1,5)
      CALL ranlux(rvec,Nnumbers)
      WRITE (6,'(A/9X,5F12.8)') ' RANLUX numbers:', 
     &     (rvec(i),i=1,5)
      
      STOP

      END  !PROGRAM luxtst

