Understanding User Exit Subroutines

Overview of User Exits

The Optimization Library provides two informational, seven MIP, and one interior point solver related user exit subroutines that enable you to regain control of execution while selected library routines are actually running. User exit routines can be used to: record statistics, report progress, intercept messages, call some, but not all, library routines to do various things, evaluate the progress of the solution process and alter or stop execution or allow execution to continue without change, and so on. Stub routines that are called from within various library modules are distributed with the library. Most of these stubs are dummies that simply return to the calling routine.

You need do nothing to avoid gaining control at one of the user exit calls. If you do wish to gain control at one of these points, you must write your own user exit subroutine and link it with your application code so that at execution time your user exit subroutine will gain control in place of the stub routine provided. If you are running with an static version of the Optimization Library, and you give your user exit code the same name as the corresponding stub, then all you need do is link your user exit before the library.

If you are running in a PC environment, with the DLL version of the library, or if you want to call your user exit subroutine by a different name than that of the stub provided, or if you want to provide several different versions of a user exit routine various ones of which may be called under different conditions to be determined at run time, then it will be necessary to "register" your routine before it is called. This is accomplished by a call to EKKRGCB. This subroutine "makes known" a user exit subroutine by associating its name with a number that identifies one of the stub routines. The correspondence between the number identifiers and the user exit names is as follows.
 
  1 corresponds to MIP User Exit EKKBRNU,
  2 corresponds to MIP User Exit EKKCHNU,
  3 corresponds to MIP User Exit EKKCUTU,
  4 corresponds to MIP User Exit EKKEVNU,
  5 corresponds to MIP User Exit EKKHEUU,
  6 corresponds to Iteration User Exit EKKITRU,
  7 corresponds to Message User Exit EKKMSGU,
  8 corresponds to MIP User Exit EKKNODU,
  9 corresponds to Row Ordering User Exit EKKORDU, and
10 corresponds to MIP User Exit EKKSLVU.

A companion subroutine, EKKCLCB, is provided to "clear" the registration of user exit subroutines. Since registering a new user exit overrides a previous registration, in most cases a call to EKKCLCB would be unnecessary. However, in a large or complicate application program it is advisable to use EKKCLCB as an aid to good housekeeping.

User exit subroutines may be coded in C or FORTRAN, but since the current library code is not re-entrant, these subroutines should not make calls that could result in recursion.


Informational User Exit Subroutines:

The informational user exit subroutines allow your application program to gain information and control, if desired, at the following times:

Iteration User Exit Subroutine (EKKITRU)

The following are two sample iteration user exit subroutines. The first limits the amount of time spent in EKKSSLV before stopping, and the second is for use with the parametric analyzer EKKSPAR.
C***********************************************************************
C
C                            EXITRU
C
C   By setting the user return code to 3, this user exit routine
C   causes EKKSSLV to stop after the accumulated CPU time exceeds
C   1000 microseconds.  The CPU clock is started after the first
C   primal iteration and it is checked after each primal iteration.
C   NOTE:  CPUTIME subroutine is available only in VS FORTRAN.
C   On AIX platforms, the times() system call may be used to get process
C   and child process times.
C
C***********************************************************************
C
      SUBROUTINE EKKITRU(DSPACE,MSPACE,IMODE,ISTAT)
C
      INTEGER*4  IMODE,ISTAT,MSPACE(*),RTCOD
      REAL*8     DSPACE(*),START,CURRENT,ELAPSED
      SAVE       START
C
C   Include file with integer control variable definitions.
      INCLUDE (OSLI)
C
C   IMODE=1: called after a primal iteration of EKKSSLV.
      IF(IMODE.NE.1) GOTO 100
      CALL EKKIGET(RTCOD,DSPACE,OSLI,OSLILN)
C
C   CPUTIME subroutine is available only with VS FORTRAN.
C   User should check RTCOD here to make sure the timing is correct.
      IF (IITERNUM.EQ.1) THEN
        CALL CPUTIME(START,RTCOD)
      ELSE
        CALL CPUTIME(CURRENT,RTCOD)
        ELAPSED = CURRENT - START
        IF (ELAPSED.GT.1000.0) THEN
          CALL EKKPRTS(RTCOD,DSPACE)
          CALL EKKBASO(RTCOD,DSPACE,35,1)
          ISTAT=3
        ENDIF
      ENDIF
 100  RETURN
      END
The following sample EKKITRU user exit subroutine is used when EKKSPAR is called.
C***********************************************************************
C
C                            EXSPARIT
C
C  This is a sample EKKITRU to use with EKKSPAR. EKKSPAR calls
C  EKKITRU at every solution point found, as follows:
C
C  IMODE = 10  means that this is a solution at an increment point.
C  IMODE = 11  means that this is a solution at a basis change
C              between increment points.
C
C***********************************************************************
C
      SUBROUTINE EKKITRU(DSPACE,MSPACE,IMODE,ISTAT)
      INTEGER*4 MSPACE(*),IMODE,ISTAT,IRTCOD
      REAL*8 DSPACE(*)
C     Print out every EKKSPAR solution
      IF(IMODE.EQ.10.OR.IMODE.EQ.11) CALL EKKPRTS(IRTCOD,DSPACE)
      RETURN
      END

Message User Exit Subroutine (EKKMSGU)

Optimization Library messages have the following format: EKKnnnnx message-text. The message text consists of a fixed template and variable components that may contain integer, real, or character values. (See Appendix A. "Optimization Library Messages".) The user exit subroutine EKKMSGU can be used to access these values.

The full message text of each message, including the message number, is available in the array cvec. For example, the following code can be used to extract this text from cvec and and build the message into an array msg_text.

      SUBROUTINE EKKMSGU(DSPACE,MSPACE,STRTNUM,NREAL,RVEC,NINT,IVEC,NCHAR,CVEC)
      REAL*8    RVEC(*),DSPACE(*)
      INTEGER*4 IVEC(*),MSPACE(*),STRTNUM
      CHARACTER*128 CVEC(*)
      PARAMETER (MAX_CHUNCK=5)
      PARAMETER (MAX_LEN=128*MAX_CHUNK)
      CHARACTER*(MAX_LEN) MSG_TEXT
        .
        .
        .
C
C     Extract the message text from CVEC
C
      MSG_TEXT = ' '
      N = NCHAR + 1
      DO 100 I = 1, MAX_LEN, 128
         MSG_TEXT(I:I+127) = CVEC(N)
         N = N + 1
         IF ( CVEC(N) .EQ. ' ' )  GO TO 110
  100 CONTINUE
      PRINT *,'Warning: Message truncated to length',MAX_LEN
  110 CONTINUE
C
C     MSG_TXT now contains the text for message number STRTNUM
C
        .
        .
        .
The sample EKKMSGU routine shown below maintains a FIFO queue of information associated with the messages. The subroutine DSPMSG is used to display this queue. Note that to activate EKKMSGU, the main program must first call EKKMSET with the usrexit argument set to 2.
C***********************************************************************
C
C                            EXMSGU
C
C   This example uses the message user exit routine to maintain a fifo
C   queue of the last MSGQLEN messages that occurred.
C
C***********************************************************************
      PROGRAM MAIN
C
C   Allocate dspace.
      PARAMETER (MAXSPC=200000)
      REAL*8    DSPACE(MAXSPC)
      COMMON/BIG/DSPACE
C
C   Queue of message numbers.
      PARAMETER (MSGQLEN=4)
      INTEGER*4 MSGQNUM(MSGQLEN)
C
C   Arrays to hold real, integer, and character values that are
C   printed in the message.
      REAL*8        MSGQRL(25,MSGQLEN)
      INTEGER*4     MSGQIN(25,MSGQLEN)
      CHARACTER*128 MSGQCH(25,MSGQLEN)
C
C   Vectors to hold number of elements in each column of
C   msgqrl, msgqin, msgqch.
      INTEGER*4 MSGQNRL(MSGQLEN),MSGQNIN(MSGQLEN),MSGQNCH(MSGQLEN)
C
C   Common containing message queue data.
      COMMON /MSGQUE/ MSGQRL,MSGQNUM,MSGQIN,MSGQNRL,MSGQNIN,MSGQNCH,
     +                MSGQPTR,MSGQCH
      INTEGER*4 RTCOD
C
C
C   Call EKKMSET so message user exit routine gets called after
C   each message, and initialize message queue pointer.
      MSGQPTR=1
      CALL EKKMSET(RTCOD,DSPACE,1,0,0,0,2,9999,0)
        IF(RTCOD.GT.0) CALL DSPMSGS
C
C   Describe application and specify that there is 1 model.
      CALL EKKDSCA(RTCOD,DSPACE,MAXSPC,1)
        IF(RTCOD.GT.0) CALL DSPMSGS
C
C   Describe the model as having 1 block.
      CALL EKKDSCM(RTCOD,DSPACE,1,1)
        IF(RTCOD.GT.0) CALL DSPMSGS
C
C   Read model data from MPS file on unit 98
      CALL EKKMPS(RTCOD,DSPACE,98,2,0)
        IF(RTCOD.GT.0) CALL DSPMSGS
C
C   Scale the problem.
      CALL EKKSCAL(RTCOD,DSPACE)
        IF(RTCOD.GT.0) CALL DSPMSGS
C
C   Create a vector copy of the matrix.
      CALL EKKNWMT(RTCOD,DSPACE,3)
        IF(RTCOD.GT.0) CALL DSPMSGS
C
C   Solve the problem using primal barrier method.
      CALL EKKBSLV(RTCOD,DSPACE,1,3)
C
C   Display the message queue.
      CALL DSPMSGS
C
C   Print the solution.
      CALL EKKPRTS(RTCOD,DSPACE)
        IF(RTCOD.GT.0) CALL DSPMSGS
C
      STOP
      END
C
C***********************************************************************
C   This routine displays previous MSGQLEN message conditions that
C   occurred.
C***********************************************************************
C
      SUBROUTINE DSPMSGS
C
C   Queue of message numbers
      PARAMETER (MSGQLEN=4)
      INTEGER*4 MSGQNUM(MSGQLEN)
C
C   Array to hold real, integer, and character values that are
C   printed in the message.
      REAL*8        MSGQRL(25,MSGQLEN)
      INTEGER*4     MSGQIN(25,MSGQLEN)
      CHARACTER*128 MSGQCH(25,MSGQLEN)
C
C   Vectors to hold number of elements in each column of
C   msgqrl, msgqin, msgqch.
      INTEGER*4 MSGQNRL(MSGQLEN),MSGQNIN(MSGQLEN),MSGQNCH(MSGQLEN)
C
C   Common containing message queue data.
      COMMON /MSGQUE/ MSGQRL,MSGQNUM,MSGQIN,MSGQNRL,MSGQNIN,MSGQNCH,
     +                MSGQPTR,MSGQCH
C
C
      WRITE(6,*)' '
      WRITE(6,*)'Writing FIFO queue of previous',MSGQLEN,'messages.'
      DO 1000 I=1,MSGQLEN
         WRITE(6,*)' '
         WRITE(6,*)'Message number is:',MSGQNUM(MSGQPTR)
C   Write real numbers written with this message.
         DO 100 J=1,MSGQNRL(MSGQPTR)
            WRITE(6,*)'  real printed on message:',MSGQRL(J,MSGQPTR)
100      CONTINUE
C   Write integers written with this message.
         DO 200 J=1,MSGQNIN(MSGQPTR)
            WRITE(6,*)'  integers printed on message:',MSGQIN(J,MSGQPTR)
200      CONTINUE
C   Write characters written with this message.
         DO 300 J=1,MSGQNCH(MSGQPTR)
            WRITE(6,*)'  Char. printed on message:',MSGQCH(J,MSGQPTR)
300      CONTINUE
C   Update queue pointer.
         MSGQPTR=MOD(MSGQPTR,MSGQLEN)+1
1000  CONTINUE
      RETURN
      END
C
C***********************************************************************
C   This user exit routine will maintain a queue of messages.
C***********************************************************************
C
      SUBROUTINE EKKMSGU(DSPACE,MSPACE,
     +                   STRTNUM,NREAL,RVEC,NINT,IVEC,NCHAR,CVEC)
      REAL*8        RVEC(*),DSPACE(*)
      INTEGER*4     IVEC(*),MSPACE(*),STRTNUM
      CHARACTER*128 CVEC(*)
C
C   Queue of message numbers
      PARAMETER (MSGQLEN=4)
      INTEGER*4 MSGQNUM(MSGQLEN)
C
C   Array to hold real, integer, and character values that are
C   printed in the message.
      REAL*8        MSGQRL(25,MSGQLEN)
      INTEGER*4     MSGQIN(25,MSGQLEN)
      CHARACTER*128 MSGQCH(25,MSGQLEN)
C
C   Vectors to hold number of elements in each column of
C   msgqrl, msgqin, msgqch.
      INTEGER*4 MSGQNRL(MSGQLEN),MSGQNIN(MSGQLEN),MSGQNCH(MSGQLEN)
C
C   Common containing message queue data.
      COMMON /MSGQUE/ MSGQRL,MSGQNUM,MSGQIN,MSGQNRL,MSGQNIN,MSGQNCH,
     1                MSGQPTR,MSGQCH
C
C
C   Save message number.
      MSGQNUM(MSGQPTR)=STRTNUM
C
C   Save real values.
      MSGQNRL(MSGQPTR)=NREAL
      DO 100 J=1,NREAL
         MSGQRL(J,MSGQPTR)=RVEC(J)
100   CONTINUE
C
C   Save integer values.
      MSGQNIN(MSGQPTR)=NINT
      DO 200 J=1,NINT
         MSGQIN(J,MSGQPTR)=IVEC(J)
200   CONTINUE
C
C   Save character values.
      MSGQNCH(MSGQPTR)=NCHAR
      DO 300 J=1,NCHAR
         MSGQCH(J,MSGQPTR)=CVEC(J)
300   CONTINUE
C
C   Update queue pointer.
      MSGQPTR=MOD(MSGQPTR,MSGQLEN)+1
C
      RETURN
      END

[ Top of Page | Previous Page | Next Page | Table of Contents ]