don't panic - uw computer sciences user...
TRANSCRIPT
Linking your Solver to GAMSTHE COMPLETE NOTES
Don't Panic !!
GAMSGAMS Development Corporation1217 Potomac Street, N.W.Washington, DC 20007
Tel: (202) 342-0180Internet: [email protected]
2
TABLE OF CONTENTS1 Connecting your solver to GAMS2 An Introduction to the GAMS I/O library2.1 Introduction2.2 GAMS - The Operating Procedure2.3 Restarts with GAMS2.4 The Objective Function2.5 Data Types2.6 Dynamic Memory vs Fixed Arrays2.7 Passing Algorithm Options to the solver2,8 Overview of GAMS Input - Output Subroutines2,9 Error Handling2.10 The Status file2.11 The Dictionary file3 GAMS I/O Subroutines4 Implementation Notes5 Examples for linear systems6 Nonlinear section of GAMS I/O library7 GAMS Nonlinear I/O Subroutines8 Examples for Nonlinear systems
4
1 CONNECTING YOUR SOLVERWITH GAMS
To make GAMS aware of your solver, you have to add your solver to the list in the filegamscomp.txt. This is the 'solver capability' file - it contains information about eachsolver: it's name, the model types that it can solve (LPs, MIPs etc.), how to run the solverand the list of default solvers for all model types. An entry in a typical gamscomp.txtfile for the PC is listed below:
bdmlp 2 0 1 LP RMIPgamsbdm3gams3bdm.exe
The first digit contains the file type or file format in which the matrix and solutionfiles are read and written. The file type is described below:
File type Description0 Coded files (ASCII or EBCDIC)1 Binary Stream I/O2 Fortran Unformatted I/O3 Salford Fortran Unformatted I/O4 VMS G_FLOATING
This file format is written by GAMS and expected on the way back if you specify a 1 asfile type. Pick a file type which is supported by your compiler.
Coded (text) files are the slowest, and the most disk space consuming. It should only beused when running GAMS in a distributed environment, where the solver and GAMS arerunning on two different machines of a different architecture. Coded files are normalASCII (EBCDIC) files.
The other file types are all for binary files, which are written in blocks, currently of 800bytes. The floating point numbers are written in full precision (i.e. 8 bytes), so the matricespassed on via coded files and binary files are slightly different. Some tricks areimplemented to reduce the size of the files (removal of redundant information andcompression).
File type 1 reads and writes the files as a stream of bytes. Some Fortran compilers canhandle this, and all C and Pascal compilers use this method. File type 2 is for most Fortrancompilers. Writing unformatted files normally results in a 4 bytes header containing the
length of the record n , then n data bytes, and then a footer which is a copy of the header.File type 3 is a special format for the Salford 386 Fortran compiler. There the header andthe footer are 5 bytes long, with the first byte a -1, following by a 4 byte integer containingthe length n.
The second number gives information about the dictionary file that is used to pass on theGAMS symbol table where the names of the equations and variables are stored. Thisdictionary file is written optionally depending on the value of this number. The Dictionaryfile types are as follows:
File type Description0 No dictionary file1 Standard dictionary file2 Dictionary file with quoted strings
The third number is used to make the system read the name of the executable that ispresent on the third line. This is usually needed only inside embedded systems likeDICOPT that use other solvers to solve various sub-problems.
The second line lists the batch file that is called when your solver is used. The accessstring contains the name (and optionally the path) of the shell script (batch file or exec)that call the solver. A typical batch file is GAMSBDM3.BAT which is listed below:
@echo offgams3bdm %4gamscmex %3gamsnext %3
The first line calls the solver, with the control file specified on the command line. Thesecond line calls GAMS, so that it can read the solution, and proceed executing. Theparameter on this call is the parameter files GAMS uses for internal control. GAMSproduces a GAMSNEXT batch file, which contains instructions what to do next, and the callto it is specified on the third line. For your specific machine, it is probably a good adviceto have a look at the scripts we provide for MINOS, BDMLP and ZOOM, and alter one ofthem to suit your needs.
In order to add your solver to GAMS, use a text editor to add your solver to theGAMSCOMP.TXT file. If desired, you can also change the defaults, so that your solver isused by default. Then create the batch file that is similar to the one described above byreplacing the gams3bdm on the second line by the name of your executable.
6
2 THE GAMS INPUT-OUTPUTLIBRARY
2.1. INTRODUCTION
This document describes the GAMS I/O library, available for developers, who want tointegrate their own solvers with GAMS. Currently we have C and Fortran versions of thislibrary available on a variety of platforms. The entire list of platforms and compilers isgiven in Appendix A.
There are a number of advantages when a solver is using this library, instead of its owninput/output routines. First, these routines have been heavily tested and as a result arevirtually bug-free (lets hope so!). Second the library is ported to a large number ofplatforms. A solver using this library will contain only a few machine dependent parts, soporting a solver is now almost reduced to linking with the appropriate version of thelibrary. For instance, using this library we are now capable of doing a complete port ofour solvers within a few hours, a task that earlier often required a few days. Third, thelibrary is optimized for different machine architectures. We have put lots of effort ininvestigating how we can exploit the features of a given machine architecture. As a resultwe can achieve performance gains compared to reading and writing MPS files up to afactor of 100.
2.2. GAMS - THE OPERATING PROCEDURE
GAMS first compiles the input file which is specified in the GAMS source language. Thenthe GAMS execution system takes control. As soon as a SOLVE statement is encountered,the corresponding model will be generated, and stored in two files called the control fileand the data (or matrix) file. For nonlinear models, an additional file called the instructionfile is also generated by GAMS. Before terminating, GAMS will also write its completestate to the disk in the form of temporary work files. Then GAMS terminates, and a shellscript (or batch file) will give control to the solver. After the solver has completed its joband terminated, it has to pass on the solution information to GAMS through two files - thesolution file and the status file. The shell script now gives control back to GAMS, whichfirst reads the work files and restores its state a it was before terminating. Then thesolution and status file as written by the solver are read. GAMS generates its listing filefor the problems and then continues with executing the statements after the SOLVEstatement. GAMS, therefore, communicates with its solvers through the set of filessummarized in Table 1.
From among the files generated by GAMS, the solver should first read the control file.This file contains all kind of statistics on the problem, like the number of variables, the
number of constraints, the type of the model etc. Then the data/matrix file, containing thecoefficients of the matrix and the bounds on the variables, should be read. For NLP's thenon-linear instruction file should also be read. This contains information how to evaluatethe non-linear functions specified in the model, and their derivatives, in a compiled format.These instructions are interpreted by an interpreter, whose use is explained in the non-linear section of this document.
GAMS ÄÄÄÄÄ> solvercontrol filedata fileinstruction file
statistics of the problemproblem matrixnonlinear instructions for NLP's
(gamscntr.scr)(gamsmatr.scr)(gamsinst.scr)
solver ÄÄÄÄÄ> GAMSstatus filesolution file
messages from solversolution returned by the solver
(gamsstat.scr)(gamssolu.scr)
Table 1. Files used for communication(The names in parentheses are typical file names)
The subroutines in the I/O library hide the actual format of the various files from the user.In fact on some platforms the data and solution file may be using a complicatedcompressed binary format. Data files, non-linear instruction files and solution files arereduced in size by a factor of two when using binary files, and the I/O speed improvementfactor is approximately 10. The handling of the files is completely done inside the library,and the actual file format is transparent to the user of the library.
In this document, we will start with concepts applicable to linear or mixed-integerprogramming. (The individual routines are described in roughly the order in which theyare used.) The details needed for nonlinear work are mostly collected in the section onnonlinear programming, near the end. Many of the general purpose routines haveparameters that are only used for nonlinear problems. These are discussed with thegeneral description of those routines. Other routines are only used in nonlinearprogramming. Their description can be found in the nonlinear section.
RESTARTS WITH GAMS
If your solver support hot restarts, it is very desirable to give GAMS the opportunity to usethis feature. In many practical situations several solve statements appear in a row, withrelatively minor changes in the data. Allowing restarts will speed up solution times for thesolves following the first one, by a considerable amount.
GAMS itself does not have the notion of a basis. The only thing it knows about are levelsand marginals. However this is enough information for the solver to reconstruct anoptimal basis. You should try to run a small LP with BDMLP, with 2 solves in a row. Thesecond solve will need 0 (or 1, depending how one is counting) iterations to reach an
8
optimal solution. This paragraph will give you some advice on how such a basis can beconstructed.
We will use the marginal to determine whether a variable (either a structural or a logicalvariable) goes into the basis or not. If the marginal is zero, it can go into the basis. Youmay want to count the number of variables that are declared basic until now, so that youare sure there are no more basic variables than there are rows. If the marginal is non-zero,the variable is non-basic. You can use the levels and the bounds to determine whether weshould set the status to lower, to upper, or that it is a free variable. Note that a non-basicfree variable is possible in GAMS: consider the example where a variable is returned non-basic at one of its bounds (i.e. with a non-zero marginal), and that the user resets thebounds before the subsequent solve. If you want to declare free variables basic make surethere are no more than m basics (that is if your solver can not handle this).
On the way back, the routine that writes a solution record will ask you for the basis status(nonbasic lower, nonbasic upper, basic, or super-basic). GAMS itself is not using thisinformation, it will only save the level values and the marginals. But when using binaryfiles we may not want to write the level if the status is nonbasic upper or nonbasic lower.So be sure if you say that a variable is nonbasic, it is really at one of its bounds, becauseGAMS will set it to the corresponding bound. In case of doubt, declare the variable assuperbasic: this will force the routine to write the level and marginal. Especially whenlinking GAMS to (mixed) integer solvers you should pay attention to this point: often thestatus of integer variables is reported wrong by the solvers (that is they correspond to themost recent subproblem instead of the original problem). Again, if a variable is non-basicbut you are not sure at which bound it is sitting (or even if it is at a bound at all), report itto GAMS as a superbasic.
THE OBJECTIVE FUNCTION
The files written for the solver contain an objective variable index, which corresponds tothe variable the user has specified in the GAMS solve statement. Your solver probablyneeds to optimize the value of a row (or nonlinear function). There are two ways toarrange for this.
The most straight forward approach is to add an extra row to the problem. This shouldhave one coefficient, value 1.0, in the column corresponding to the GAMS objectivevariable, iobvar, and be non-binding. The row activity of this added row will then equalthat of the variable the user has specified. This extra row is probably most convenientlyadded after the other rows have been read. Notice that now the problem has numrow + 1rows, and one more non-zero. When writing solution records remember to ignore the lastrow.
For nonlinear or network problems, it may be preferable to reformulate the row in whichthe objective variable occurs. This is especially desirable if the only nonlinearities in theproblem are in the definition of the objective variable. In the nonlinear programming
section we describe how this reformulation is be done. For linear problems see thediscussion above before KGV(14).
DATA TYPES
We have only used logical (boolean), integer, real and character data types. Our genericreal type in this text is DOUBLE PRECISION, although the implementation notes forparticular machine (e.g Crays) may indicate that the binaries are actually single precision.The integer is the generic integer on the particular machine/compiler combination. Onsome machines we may use INTEGER*2 and INTEGER*4.
DYNAMIC MEMORY vs. FIXED ARRAYS
This paragraph is mainly important for solvers written in Fortran. Most fortran basedsolvers are have fixed array sizes. Always spaces is allocated for say n columns, m rowsand nz non-zeroes. If the model is much smaller than these numbers, lots of memory iswasted. If the model exceeds these limits, the solver will not be able to handle it. Somecommercial solvers (LAMPS, SCICONIC) allow the user to reconfigure the maximum sizeby recompiling parts of the system, and then link it together. SCICONIC provides eventwo versions of their executables: a small one and a bigger one. The problem with fixedsize arrays is that they are always too small or too big.
In BDMLP, GAMS/MINOS, GAMS/OSL, GAMS/CONOPT and GAMS/ZOOM weadopted another approach. The solver does an estimation of the workspace needed basedon the statistics of the model (number or rows, columns, nonzeroes etc.), and then requestsa contiguous chunk of memory of that size. When the request is granted arrays are mappedinto this workspace and the algorithm can start reading the matrix. If the availableworkspace is smaller than the estimate then one can decide to give up, or still to try tosolve it, because the fill-in may be less than estimated. Notice that this set up is relativelyeasy in GAMS because the counts (number of rows etc.) are known in advance. Whenreading an MPS file this is not the case.
The GAMS user has the possibility to override the estimate done by the solver. If there is astatement OPTION WORK=8000 or MODEL.WORKSPACE = 2 in the GAMS model,the user wants to allocate 8000 double words (8 byte quantities) or 2 megabyte for hismodel. This value is passed on to the solver, and if non-zero it should override theestimate.
PASSING ALGORITHM OPTIONS TO SOLVER
GAMS uses a separate option file in order to pass algorithm specific options on to thesolver. Each line in the option file specifies a single option, using one or both items asfollows:
• A keyword - Required for all options.
10
• A number or character string that represents the value for the option specified by thekeyword.
Any line starting with a '*' in column 1 is a comment. The following two examples ofoption files for OSL and CPLEX illustrate its use.
* OSL Option file * CPLEX option filemethod dsimplex dualpresolve -1 presolve 0
Both option files cause the problem to be solved by the dual simplex method without usingthe presolve features of the algorithms.
The user can specify the list of keywords that are the names of the various options that canbe passed on through GAMS. The GAMS I/O library provides subroutines that can beused to read the option file and pass the values of the various options to be passed on tothe solver.
OVERVIEW OF GAMS INPUT-OUTPUT SUBROUTINES
The linear part of the library consists of the subroutines listed in tables 2,3, and 4. All theuser-callable routines are presented (some internal routines are not listed). The routines aresplit up in three parts: input, output and resident. For machines with no virtual memoryand tight memory (the PC is an example), the input and output part may be overlaid, whilethe resident part should remain in core if possible.
subroutine short description
GFINITGFMACHGFRCNTGFSTATGFOPSTGFPGSZGFOPTIGFRDOPGFTIMEGFWDIRGFSDIRGFCDIRGFRROWXGFRCOLXGFRCOF
InitializationReturn machine constantsRead GAMS control fileReturn status file nameOpen the status fileReturn page size of status fileReturn option file nameRead option fileReturn GAMS timeReturn GAMS working directoryReturn GAMS system directoryReturn GAMS scratch directoryRead a row recordRead a col recordRead a matrix coefficient
Table 2. Overview of the input library routines
subroutine short description
GFERR
GFWSTAGFWROWGFWCOLGFWBNDGFWRTIGFWCTIGFWWTIGFWNODGFCLOS
Write error message and terminate(should not be called by the user)Write model and solution statusWrite now (solution)Write column (solution)Write best integer boundWrite reading timeWrite calculation timeWrite writing timeWrite nodes usedClose down the I/O library
Table 3. Overview of the output library routines
There is a certain order in which the routines should be called. For instance the GFINITroutine should be called first, and you should read the row records before the columnrecords. The next diagram gives a rough idea in what order the routines should be called.You may also want to take a look at the examples presented a few pages further.
subroutine short description
GFCLCKGFSTCTGFRWERGFCLERGFRCERGFMSGGFGETMGFFREMMEMINFGETPARGFUOPNGFUOPUGFFRSTGFINDXGFFRMTGFXARGGFSGET
ClockStatus file controlReport row errorReport column errorReport element errorWrite a messageRequest a memory blockRelease a memory blockPrints memory statisticsInterrogate GAMS Parameter fileOpen a fileOpen an unformatted filePosition first non-blank in stringLength string excluding trailing blanksReturns "good" formatting string for printing a realFind i'th parameter from command lineFind i'th token in a string
Table 4. Overview of the resident library routines
12
1. CALL GFINIT ! initialize the system2. CALL GFRCNT ! read control file
extract nrows,ncols,etc.3. CALL GFOPST ! open status file
orCALL GFSTAT ! get status file name and open it by yourself
4. CALL GFGETM ! allocate enough memoryneeded for fortran codes only
5. for i:=1 to nrows doCALL GFRROWXAdd additional row for the objective (optional)
6.if needed add one non-zero in objective row
7. solve the problem8. CALL GFWSTA ! write status9. for i:=1 to nrows do
CALL GFWROW10.for i:=1 to ncols do
CALL GFWCOL
Table 6. Outline of subroutine calling order
ERROR HANDLING
Most of the errors that can occur while executing the library routines are the result ofprogramming mistakes or incompatibilities. If any such errors are detected, an errormessage is written, and execution terminated. Two files are being used to report errors.First the status file. This file is used to write information that GAMS can copy to thelisting (.LST) file once it takes over control again. The log file is the file where the solverwrites information about the progress of the algorithm etc. The log file will normally bethe screen. If neither files are opened, error messages are written to standard output (i.e. infortran WRITE (*,*) is used).
THE STATUS FILE
The status file is a text file written by the solver. Parts of the status file will be copied byGAMS to the listing file. The status file contains certain control characters that areprocessed by GAMS. Inserting these control characters is normally done by calls toGFSTCT. These control sequences look like "=n" where n is a digit. For instance a "=1"means start copying and "=2" means stop copying. All these control sequences start incolumn 1. So a solver may produce the next file:
=1 ************************************* * H Y P E R L P, By Solvers Inc. * ************************************* Version 0.001 Release A
=2
Problem is read in. Scaling: min row scale = 0.01 max row scale = 100.0 min col scale = 0.001 max col scale = 1e3 Start of SIMPLEX algorithm. Problems in iteration 2764748: basis nearly singular. Switching to COMPLEX algorithm. Too difficult... going back to SIMPLEX Solved, accuracy check : 1.0e-5
The part between the "=1" and the "=2" is echoed to the GAMS listing file. The otherpart becomes only visible for the user if he or she has a statement option sysout=onin the GAMS model, or if the solver had added a "=4" to the status file (normally by usingCALL GFSTCT('SYSOUT'). It is good practice to include the sysout control sequence tothe status file if something is going wrong in the solver, so that extra debugginginformation is copied to the listing file.
In case you want to use a different control character than the "=", because one of yourstring start with an equal sign in column 1, you can reset the control character by callingCALL GFSTCT('CHRSW&'), where the '&' may be any (printable) character.
THE DICTIONARY FILE
The Dictionary file is used to pass on the GAMS symbol table where the names of theequations and variables are stored. This dictionary file is written optionally depending onan entry in the GAMSCOMP.TXT file as explained in Chapter 1. The user can generatethe GAMS names of the various set elements, sets, variables and equations by using thefollowing subroutines that access the dictionary file:
subroutine short description
14
GFDICTFDICTMEMREADDICTGETROWINFOGETCOLINFOGETROWNAMEGETCOLNAMEGETDECLARGETSETSIZEGETSETDECL
Returns name of dictionary fileAllocates memory for dictionary file informationRead dictionary fileReturns name of equation and indices for given rowReturns name of variable and indices for given columnReturn name of equation for given rowReturn name of variable for given columnReturn domains of equation or variableReturn number of elements in a given setReturn all the elements in a given set
Table 4. Overview of the dictionary file library routines
CHAPTER 3
GAMS INPUT/OUTPUTSUBROUTINES
List of Subroutines:
DICTMEMGETCOLINFOGETCOLNAMEGETDECLARGETPARGETROWINFOGETROWNAMEGETSETDECLGETSETSIZEGFCDIRGFCLCKGFCLERGFCLOSGFDATEGFDICTFGFERRGFFREMGFFRMT
GFFRSTGFGETMGFINDXGFINITGFMACHGFMSGGFOPOKGFOPSTGFOPTIGFPGSZGFRCERGFRCNTGFRCOFGFRCOLXGFRDOPGFRROWXGFRWERGFSDIR
GFSGETGFSTATGFSTCTGFTIMEGFUOPNGFUOPUGFWBNDGFWCOLGFWCTIGFWDIRGFWNODGFWROWGFWRTIGFWSTAGFWWTIGFXARGMEMINFREADDICT
16
SUBROUTINE DICTMEM
Allocates memory for information in dictionary file.
Fortran SUBROUTINE DICTMEM(IUNIT,DWNEEDED)INTEGER IUNIT, DWNEEDED
Pascal n.a.
C dictmem(void)
Description of the parameters
IUNIT (input)
Unit number that can be used to read header info in dictionary file.
DWNEEDED (output)
Number of double words needed to store data structure. This has to be called beforeGFGETM.
SUBROUTINE GETCOLINFO
This subroutine gets the name of the variable block and individual indices of acolumn.
Fortran SUBROUTINE GETCOLINFO(I,NAME,INDEX,NIND,ARRAY)INTEGER I, NINDDOUBLE PRECISION ARRAY(*)CHARACTER*10 NAME, INDEX(10)
Pascal n.a.
C getcolinfo(i,name,index,nind)int ichar* namechar** indexint* nind
Description of the parameters
I (input)
Column number
NAME (output)
Stem name of variable
INDEX (output)
List of indices of variable. Empty if the variable has no indices.
NIND (output)
Number of indices
ARRAY (input/output)
A double precision vector, used for accessing the allocated memory.
18
SUBROUTINE GETCOLNAME
Gets GAMS equation name of a column
Fortran SUBROUTINE GETCOLNAME(I,NAME,ARRAY)INTEGER IDOUBLE PRECISION ARRAY(*)CHARACTER*10 NAME
Pascal n.a.
C getcolname(i,name,namelen)int ichar* nameint namelen
Description of the parameters
I (input)
Column number
NAME (output)
Name of corresponding variable
ARRAY (input/output)
A double precision vector, used for accessing the allocated memory.
SUBROUTINE GETDECLAR
Gets domains of variable or equation
Fortran SUBROUTINE GETDECLAR(NAME,NIND,DOM,ARRAY)CHARACTER*10 NAMEINTEGER NINDCHARACTER*10 DOM(10)DOUBLE PRECISION ARRAY(*)
Pascal n.a.
C getdeclar(name,nind, dom)char* nameint nindchar **dom
Description of the parameters
NAME (Input)
Name of variable or equation
NIND (Output)
Number of indices for variable or equation
DOM (Output)
Domains of variable or equation
ARRAY (Input/Output)
A double precision vector, used for accessing the allocated memory.
20
FUNCTION GETPAR
Interrogate the GAMS parameter file.
Fortran SUBROUTINE GETPAR(N,KEY,PAR,UNIT)INTEGER NCHARACTER*10 KEY(N)CHARACTER*80 PAR(N)INTEGER UNIT
Pascal n.a.
C n.a.
Description of the parameters
N (input)
The number of parameters you are requesting.
KEY (input)
The parameter names. For an overview of the available parameters see thedocument "The GAMS parameter file".
PAR (output)
Strings containing the values of the parameters specified in KEY. Empty strings ' ')will be returned for non-existing ones.
UNIT (input)
Unit number to be used by this routine. Afterwards you can re-use the unit for otherpurposes.
SUBROUTINE GETROWINFO
This subroutine gets the name of the row block and individual indices of a row.
Fortran SUBROUTINE GETROWINFO(I,NAME,INDEX,NIND,ARRAY)INTEGER I, NINDDOUBLE PRECISION ARRAY(*)CHARACTER*10 NAME, INDEX(10)
Pascal n.a.
C getrowinfo(i,name,index,nind)int ichar* namechar** indexint* nind
Description of the parameters
I (input)
Row number
NAME (output)
Stem name of equation
INDEX (output)
List of indices of equation row. Empty if the equation has no indices.
NIND (output)
Number of indices
ARRAY (input/output)
A double precision vector, used for accessing the allocated memory.
22
SUBROUTINE GETROWNAME
Gets GAMS equation name of a row
Fortran SUBROUTINE GETROWNAME(I,NAME,ARRAY)INTEGER IDOUBLE PRECISION ARRAY(*)CHARACTER*10 NAME
Pascal n.a.
C getrowname(i,name,namelen)int ichar* nameint namelen
Description of the parameters
I (input)
Row number
NAME (output)
Name of corresponding equation
ARRAY (input/output)
A double precision vector, used for accessing the allocated memory.
SUBROUTINE GETSETDECL
This subroutines returns all the elements (labels) that belong to a set
Fortran SUBROUTINE GETSETDECL(NAME,RC, SIZE,ALIAS,N,. CLIST, ARRAY) CHARACTER*10 NAME, ALIAS INTEGER NIND DOUBLE PRECISION ARRAY(*)
Pascal n.a.
C n.a.
Description of the parameters
NAME (Input)
Name of the set
N (Input)
Declared number of elements in set
SIZE (Output)
Actual number of elements in the set. Should be less than N
CLIST (Output)
List of elements (labels) corresponding to set
RC (output)
Return Code. It's value can be interpreted as follows:
RC Explanation0 Success1 NAME is not a set2 NAME is an alias3 Not enough space in CLIST
ALIAS (Output)
24
Set aliased with NAME. Returned only if RC = 2
ARRAY (Input/Output)
A double precision vector, used for accessing the allocated memory.
SUBROUTINE GETSETSIZE
Returns number of elements in a set
Fortran SUBROUTINE GETSETSIZE(NAME,SIZE,ALIAS,ARRAY)CHARACTER*10 NAME, ALIASINTEGER NINDDOUBLE PRECISION ARRAY(*)
Pascal n.a.
C n.a.
Description of the parameters
NAME (Input)
Name of set
SIZE (Output)
The interpretations for the values of SIZE are as follows
SIZE Explanation>0 NAME is a proper set with SIZE entries0 NAME is not a set-1 NAME is an alias
ALIAS (Output)
Set aliased with NAME. Returned only if SIZE = -1
ARRAY (Input/Output)
A double precision vector, used for accessing the allocated memory.
26
SUBROUTINE GFCDIR
Subroutine GFCDIR returns the scratch directory, i.e. the directory where the matrixfile etc. are sitting. This is the right place to to put (large) scratch files that are usedby the solver.
Fortran SUBROUTINE GFCDIR(SCRDIR)CHARACTER*80 SCRDIR
Pascal procedure gfcdir(var scrdir : pathname);
C gfcdir(scrdir)char **scrdir;
Description of the parameters
SCRDIR (output)
SCRDIR is a character string that contains on exit the scratch directory.
FUNCTION GFCLCK
Clock, returns used CPU time since start of the solver, or since the call to GFINIT.
Fortran DOUBLE PRECISION FUNCTION GFCLCK()
Pascal n.a.
C double gfclck()
On some systems there are problems with the clock. CMS for instance resets thetime at 12.00 midnight. Other clocks have a short range, and start counting at zeroagain after the job is running for some time. We have protected us as much aspossible against these problems. The best thing is to call GFCLCK at regular,sufficiently small, intervals. In order to obey the GAMS RESLIM option, you need tokeep track of the used up CPU time anyway. Calling GFCLCK each iteration tocheck against the RESLIM value, is a good approach, and provides our clock routinewith enough information to recover from most problems pictured above.
28
SUBROUTINE GFCLER
Subroutine GFCLER passes on an error message concerning column ICOL to GAMS.GAMS will translate this column number into the correct GAMS name.
Fortran SUBROUTINE GFCLER(ICOL,MSGNO,MESS)INTEGER ICOL, MSGNOCHARACTER*(*) MESS
Pascal procedure gfcler(icol, msgno: integer, mess : messt);
C gfcler(icol,msgno,mess)int icol, msgno;char *mess;
Description of the parameters
ICOL (input)
ICOL is the column number of the variable corresponding to this error.
MSGNO (input)
MSGNO is the number of the error message. This number is used for look up. Onlyone instance of the message string is stored inside GAMS, where message stringsare considered to be the same if the message number is the same. Note that nocheck on the string itself is done, so it is your responsibility to make sure that themessage numbers are different for different messages. The allowed range forMSGNO is from 1 to 100.
MESS (input)
MESS is the string containing the message. GAMS will store and report only thefirst 50 characters of this string (ignoring the leading blanks).
SUBROUTINE GFCLOS
This is used to close down the library routines. Checks are done that all calls havebeen made the correct number of times.
Fortran SUBROUTINE GFCLOS
Pascal procedure gfclos;
C gfclos()
This is used to close down execution of the I/O library. Systems that use binary fileswill not work unless this call is made. No parameters are passed. No further callscan be made to any library routines that do file input or output.
30
SUBROUTINE GFDATE
Subroutine GFDATE returns the date when the current GAMS job started.
Fortran SUBROUTINE GFDATE(GMSDAT)CHARACTER*10 GMSDAT
Pascal procedure gfdate(var gmsdat: char10);
C gfdate(gmsdat)char **gmsdat;
Description of the parameters
GMSDAT (output)
GMSDAT is a character string that contains on exit the date.
SUBROUTINE GFDICTF
Subroutine GFDICTF returns the name of the dictionary file. This is neededbecause the user has to open it.
Fortran SUBROUTINE GFDICTF(FLN)CHARACTER*80 FLN
Pascal procedure gfstct(cmd : cmdstring);
C gfdictf(fln)char *fln;
Description of the parameters
FLN (output)
Name of dictionary file
32
SUBROUTINE GFERR
Error handling. The errors are reported in both the log file and the status file. Foruse in embedded systems, you may want to use your own error recovery routine.You can replace the default GFERR routine by your own one. The header of thisroutine should look as below. NUM is the error number, SUBROU is the name of theroutine where the error was detected.
All the error codes that are used by the library and the corresponding errormessages are listed in Table 5. In the chapter Error Messages you will find a moredetailed description of the errors, when they can occur, and what to do about it. Allerrors we have listed are the result of programming errorrs and serious hardwarefailures (disk full etc.), and should not occur during normal operation by the enduser.
Fortran SUBROUTINE GFERR(NUM,SUBROU)INTEGER NUMCHARACTER*(*) SUBROU
Pascal n.a.
C n.a.
Error Number Description
1 Illegal status code in opnfil (internal error)2 Illegal format code in opnfil (internal error)3 Could not open file4 MIP solver need to solve the problem5 NLP solver needed to solve the problem6 Control file version is incompatible7 Calling order of routines is wrong8 Too many calls to GFRROWX
9 Too many calls to GFRCOLX
10 Binary file error while reading row11 Binary file error while reading column12 Binary file error while reading buffer13 Binary file error while writing buffer14 Too many calls to GFRCOF
15 Not read all the coefficients yet16 Too many calls to GFWROW or GFWCOL
17 Error while reading instruction file18 Not enough storage for nl instructions19 Binary file type for other machine
20 Illegal command string for status control21 Binary file buffer already occupied22-24 Not used25 Illegal address field in nonlinear instruction26 Illegal opcode for nonlinear instruction27 Illegal nonlinear instruction start index28 Consecutive calls to GFGETM
Table 5. Error number and Messages
Errors marked by internal error are probably problems in the library itself. ContactGAMS Development to discuss how to solve them. Other errors are likely to beprogramming errors in your code. Please inspect your code carefully before callingGAMS Development.
34
SUBROUTINE GFFREM
Free the memory space allocated by the call to GFGETM.
Fortran SUBROUTINE GFFREM(ARRAY)DOUBLE PRECISION ARRAY(*)
Pascal n.a.
C n.a.
Description of the parameters
ARRAY (input)
The double precision vector, used for accessing the allocated memory.
Hints for using GFGETM and GFRETM
To be able to run a fortran program using the dynamic memory routines on allplatforms, for which we provide this facility, you have to set up your program in acertain way. The dynamic array Z should be in a labelled common block in the mainprogram. This array should then be passed as an assumed dimension array to asubroutine. This is necessary for DOS-Microsoft to ensure that (a) the array originis on a paragraph boundary, and (b) huge mode addressing is enforced for allreferences to Z. This arrangement is illustrated in the example in appendix LP-4.After the problem size is determined, GFGETM is called to allocate memory, andthen this memory is partitioned before the problem is read in. The example in theappendices show how to use GFGETM to allocate dynamic memory. Notice how,inside the routine SUB2, components of Z are treated as separate arrays.
FUNCTION GFFRMT
Calculates a good format string for printing a double precision number with valueVALUE. The string returned is of the form Fw.d or Ew.d. The G format in Fortrandoes not work very well: it switches to E format too quickly.
Fortran SUBROUTINE GFFRMT(VALUE,WIDTH,DECS,FRMTST)DOUBLE PRECISION VALUEINTEGER WIDTH,DECSCHARACTER*(*) FRMTST
Pascal n.a.
C n.a.
Description of the parameters
VALUE (input)
Value of the number to be printed.
WIDTH (input)
Width of the field.
DECS (input)
Number of decimals required.
FRMTST (output)
Format string. Normaly a string of length 10 should be sufficient to handle allcases.
Example of use
36
C 1 2C 12345678901234567890 FRM14 = '(1X,A,1X, )' CALL GFFRMT(Z,14,4,FRM14(10:19)) WRITE(IOLOG,FRM14) 'GAMS provided cutoff of ',Z
FUNCTION GFFRST
Returns position of first non-blank character in string. Returns 0 if not found: i.e. ifall characters in string are blanks.
Fortran INTEGER FUNCTION GFFRST(ST)CHARACTER*(*) ST
Pascal n.a.
C n.a.
38
SUBROUTINE GFGETM
Memory management. On many machines it has proven possible to request memoryat execution time in a Fortran program. The normal way to use this routine is toestimate how much is needed after the problem characteristics have been obtainedfrom GFRCNT but before any data is read. It is a fatal error to call GFGETM twicewithout an intervening call to GFFREM.
This subroutine is not available for Pascal and C. Pascal prohibits the use of asimilar mechanism, because of the strong type checking. Some Pascal systemsallow allocation of dynamic arrays, consult the compiler documentation. Whenusing Turbo Pascal one can use getmem and freemem to simulate dynamic arrays. Itis important that array bound checking is turned off when using this trick. For anexample see the implementation notes on Turbo Pascal. C allows dynamicallocation of arrays by malloc. See the C example in the appendix how this can beimplemented.
Fortran SUBROUTINE GFGETM(ARRAY,FIRST,MEMREQ,& MEMGOT,MAXMEM)DOUBLE PRECISION ARRAY(*)INTEGER FIRST,MEMREQ,MEMGOT,MAXMEM
Pascal n.a.
C n.a.
Description of the parameters
GFGETM tries to allocate space for MEMREQ double precision reals. It returns theamount of memory it could grab MEMGOT, where it is located: FIRST is the firstuseable position in the array, and on some machines, how much there is available:MAXMEM. The result is that when MEMGOT>0 the following memory locations areavailable for the user: ARRAY(FIRST)..ARRAY(FIRST+MEMGOT-1). Note that ingeneral MEMGOT can be smaller or larger than MEMREQ. The caller should decide,based on the value of MEMGOT whether it is worthwile to start solving the problemor not. In any case GFGETM should be followed by a GFFREM. In case you want touse the memory, you can partition the array and pass on the partition boundaries toa subroutine. In this way the subroutine can operate on ``normal'' arrays, while stillhaving the advantage of dynamic memory. For an example see appendix LP-4.
ARRAY (input)
A double precision vector, used for accessing the allocated memory.
FIRST (output)
The first useable position in the array.
40
MEMREQ (input)
The amount of memory to be requested, in units of double precision reals (normally8 bytes).
MEMGOT (output)
The amount of memory allocated. Your program should check that this is ≥MEMREQ and terminate if not.
MAXMEM (output)
The maximum amount of memory that can be allocated (again in units of doubleprecision reals), or 0. Some operating systems allow us to give back the maximumsize we can allocate. For those systems we return it. Others cannot do it, there wereturn 0.
Example of use
See appendix LP-4.
Machine specific behavior
DOS (real mode)
On DOS (Microsoft Fortran) GFGETM always allocate all memory that is available,regardless the value of REQMEM. DOS is a single tasking operating system, and thememory that is not used, can not be used for anything. This is the rationale toallocate everything.
UNIX,386
On all UNIX systems and on the 386 (NDP Fortran) we allocate exactly what isasked for. If this is not available nothing is allocated (in which case we do a binarysearch to find out the maximum that could be allocated).
FUNCTION GFINDX
Returns the length of the string ST minus the number of trailing blanks.
Fortran INTEGER FUNCTION GFINDX(ST)CHARACTER*(*) ST
Pascal n.a.
C n.a.
Example of use
c read option file
CALL GFOPTI(OPTFLN) ! get option file name OPTLEN = GFINDX(OPTFLN) ! calc length of filename IF (USEOPT) THEN IF (GFOPOK(IOOPT)) THEN ! if true, that start reading WRITE(IOLOG,13) OPTFLN(1:OPTLEN) ! write message to log CALL RDSPEC(IOOPT,IOSTA,IOLOG) ! read option file CLOSE(IOOPT) ELSE ! write message to log and status file WRITE(IOLOG,11) OPTFLN(1:OPTLEN) CALL GFSTCT('START') WRITE(IOSTA,11) CALL GFSTCT('STOPC') ENDIF ENDIF
11 FORMAT(' Cannot find option file ',A,/ & ' Using defaults instead.') 13 FORMAT(' Reading option file ',A)
42
SUBROUTINE GFINIT
Subroutine GFINIT is used to initialize the library routines. It must be called beforeany of the other routines. It initializes the clock and various internal variables.
Fortran SUBROUTINE GFINIT(IOUNIT, IOSTA, SCREEN)INTEGER IOUNIT, IOSTA, SCREEN
Pascal procedure gfinit;
C gfinit()
Description of the parameters
Note that the Pascal and the C versions do not have the i/o units as parameters. Thisis because in Fortran one has to reserve i/o units for files, and those i/o units areglobal. I.e. the library cannot pick any i/o unit number, because this may already bein use by the user.
In the case of Pascal, the files iolog, iosta and ioscrn are declared as global data. Aninclude file containing the declarations should be included immediately after theprogram or module header. All these files are of type text.
IOUNIT (input)
This is the Fortran file unit that will be used to read and write the potentially largedata files. These are the data (matrix) file, the nonlinear instruction file (if there arenonlinearities), the solution file, and the matrix output file (normally only withspecial iterative solvers such as DICOPT). Note (a) you should not use this unit foryour own files, and (b) only one of the above named files can be opensimultaneously. Termination will occur if you intermingle operations on these files.The library routines will open each one on the first call that uses it, and close it afterthe last.
IOSTA (input)
This is the unit for the status file. The user should open the status file, after callingGFINIT, GFRCNT, and GFSTAT but before any other library routine. This file shouldbe opened for writing, and it should be an ordinary text file. Note that the libraryalso provides a routine for this purpose: GFOPST. You can write your ownmessages to the status file so that they will appear in the GAMS listing (.LST) file.For the exact format of the status file see the paragraph about the status file.
SCREEN (input/output)
This unit is connected to the screen. If necesary it will be opened by GFINIT.Depending on the user's program, this unit may be used to write summaryinformation to an interactive user. This argument should be a variable and not aconstant!
There are two units which can be used to pass information to the user: the screen(unit SCREEN) and the log file (unit IOLOG, available after calling GFRCNT). All theinformation written to the screen is directly written to the console, withoutinterference of the library. The information written to the log file however, canappear either on the screen, or on a disk file or may vanish. This depends on howGAMS is called. A GAMS call with the options1 LOGOPTION=2 andLOGFILE=SCREEN.DMP, will redirect all the output you will normally see on thescreen to the file SCREEN.DMP. A GAMS invocation with LOGOPTION=0 will causeGAMS to run in silent mode. The default is LOGOPTION=1: output to the console.If you want the output of your solver to behave accordingly, you should write to theIOLOG unit instead of the SCREEN unit or *. This option is useful in differentsituations: users run both gams and the solver in silent mode, which is nice whenyou have slow communication lines, or more important, when GAMS is embeddedin a larger system. The complete screen output of a session can be written to a diskfile, which may be helpful in case something is going wrong.
If you want to prevent the user from redirecting a message (say you want to haveyour copyright message always to appear on the screen) then use the SCREEN unit.Note: on UNIX systems the GFINIT may reset the SCREEN unit to 0 (stderr) or 6(stdout), because writing directly to /dev/tty can cause problems when the programis executed on a network under control of a remote shell. Therefore SCREEN shouldbe variable and not a constant!
1 For an exact description of the GAMS options see the GAMS documentation.
44
SUBROUTINE GFMACH
Subroutine GFMACH returns a set of machine constants, like EPS, HUGE, etc. Wehave listed here the values that are returned when the machine is using doubleprecision (8 byte) IEEE floating point.
Fortran SUBROUTINE GFMACH(RMACH, IMACH)DOUBLE PRECISION RMACH(6)INTEGER IMACH(4)
Pascal procedure gfmach(var mach: machrec);
C gfmach(mach)machrec *mach;
Description of the parameters
RMACH (output)
RMACH(1) Epsilon, the smallest value ∈ > 0, such that 1.0 + ∈ ≠ 1.0. Sometimes an approximation of thisvalue is returned with RMACH(1) > ∈. Fordouble precision IEEE floating point arithmeticthis value is 2.220446049250313E-16.
RMACH(2) Huge, largest positive real number that can berepresented by the machine. Any expressionreturning a value larger than Huge may triggeran overflow exception. IEEE double precisionvalue: 1.797693134862316E+308.
RMACH(3) MinExponent, largest negative decimal exponentthat can be respresented by the machine. Doubleprecision IEEE value: -307.
RMACH(4) MaxExponent, largest positive decimal exponentthat can be respresented by the machine. Doubleprecision IEEE value: 308.
RMACH(5) Precision, the number of significant decimaldigits. Double precision IEEE value: 15.
RMACH(6) Tiny, smallest positive number that can berepresented by the machine. Double precisionIEEE value: 2.225073858507201E-308.
Notice that on VAX/VMS there are two REAL*8 floating point formats:D_floating (the default) and G_floating. If your solvers require G_floating, the IOlibrary has to be translated from generic fortran into VMS by fortrans with gfloatdefined. The DEC AXP running OpenVMS has G_floating as default (which iscurrently the only one we support). G_floating is represented by a file type of 4 inthe gamscomp.txt file.
IMACH (output)
This integer array returns the sizes of different data types in terms of the allocationunits ("words") that are being used by the dynamic memory allocation routinesGFGETM.
IMACH(1) intw, the number of (long) integers that fit in aword.
IMACH(2) shortw, the number of short integers that fit in aword. If no short integers exist on a certainmachine, intw is returned.
IMACH(3) llogw, the number of long logicals (LOGICAL*4)that fit in a word.
IMACH(4) slogw, the number of short logicals (LOGICAL*1
or LOGICAL*2 depending on the machine) that fitin a word.
C version
The C version only returns the RMACH parameters. For interrogating sizes usesizeof(). The machrec type is defined as:
typedef struct { double rmach[6+1]; } machrec; .
Notice that we start at [1]. rmach[0] is undefined.
46
SUBROUTINE GFMSG
Writes a message to the log file and the status file. It checks is both files are alreadyopened. In case log file is not available yet it writes the message to standard outputusing WRITE(*,*).
Fortran SUBROUTINE GFMSG(MSG)CHARACTER*(*) MSG
Pascal n.a.
C n.a.
Description of the parameters
MSG (input)
Message to be printed.
FUNCTION GFOPOK
Function GFOPOK returns true if opening of the option file was successful, and itreturns false otherwise. It uses GFOPTI for this purpose. For the C version a NULL
pointer is returned if opening the file was unsuccessful.
Fortran LOGICAL FUNCTION GFOPOK(IUNUT)INTEGER IUNIT
Pascal function gfopok(var f : text) : boolean;
C FILE* gfopok();
Example of use
c read option file
CALL GFOPTI(OPTFLN) ! get option file name OPTLEN = GFINDX(OPTFLN) ! calc length of filename IF (USEOPT) THEN IF (GFOPOK(IOOPT)) THEN ! if true, that start reading WRITE(IOLOG,13) OPTFLN(1:OPTLEN) ! write message to log CALL RDSPEC(IOOPT,IOSTA,IOLOG) ! read option file CLOSE(IOOPT) ELSE ! write message to log and status file WRITE(IOLOG,11) OPTFLN(1:OPTLEN) CALL GFSTCT('START') WRITE(IOSTA,11) CALL GFSTCT('STOPC') ENDIF ENDIF
11 FORMAT(' Cannot find option file ',A,/ & ' Using defaults instead.') 13 FORMAT(' Reading option file ',A)
NB. The function GFINDX returns the length of a string minus the number of trailingblanks.
48
SUBROUTINE GFOPST
Subroutine GFOPST opens the status file. It calls GFSTAT to find out the name of thefile.
Fortran SUBROUTINE GFOPST()
Pascal procedure gfopst;
C gfopst()
SUBROUTINE GFOPTI
Subroutine GFOPTI returns the option file name so that you can open the option fileand parse it. This is only done if useopt, returned by GFRCNT, is true. Beware thatthe option file may not exist (GAMS is not checking on that): you should checkwith an INQUIRE statement before you attempt to read it. If it does not exist, just usedefault values for all settings. This routine should not be called before callingGFRCNT, because otherwise the filename is not known yet.
It is advised to use the routine GFOPOK for this purpose. Opening the option fileturns out to be a machine specific piece of code: some systems, notably CMS, toinclude code that is different from other platforms. GFOPOK will hide this for you.
Fortran SUBROUTINE GFOPTI(FLN)CHARACTER*80 FLN
Pascal procedure gfopti(var fln : filename)
C gfopti(fln)char **fln;
Example of use
CHARACTER*80 FLNOPT LOGICAL EXISTS. USEOPT : CALL DEFAULT ! set default values IF (USEOPT) THEN ! this comes from CALL GFOPTI(FLNOPT) ! get option file name INQUIRE(FILE=FLNOPT,EXIST=EXISTS) ! test for existance IF (EXISTS) CALL RDOPTS(FLNOPT) ! if ok read option file ENDIF :
50
SUBROUTINE GFPGSZ
Subroutine GFPGSZ returns the page width and the page size of the listing file thatGAMS will produce. This information can be used for writing a status file thatmatches these sizes. This routine should not be called before GFRCNT.
Fortran SUBROUTINE GFPGSZ(PAGWID,PAGSIZ)INTEGER PAGWID, PAGSIZ
Pascal procedure gfpgsz(var pagwid, pagsiz : integer)
C gfpgsz(pagwid, pagsiz)int *pagwid, *pagsiz;
SUBROUTINE GFRCER
Subroutine GFRCER passes on an error message concerning row IROW and columnICOL to GAMS. GAMS will translate these numbers into the correct GAMS name.Typical use for this routine is to report a jacobian element that looks suspicious in anon-linear programming algorithm.
Fortran SUBROUTINE GFRWER(IROW,ICOL, MSGNO,MESS)INTEGER IROW. MSGNOCHARACTER*(*) MESS
Pascal procedure gfrwer(irow, icol, msgno: integer, mess : messt);
C gfrwer(irow,icol,msgno,mess)int irow, icol, msgno;char *mess;
Description of the parameters
IROW (input)
IROW is the row number of the equation corresponding to this error.
ICOL (input)
ICOL is the column number of the variable corresponding to this error.
MSGNO (input)
MSGNO is the number of the error message. This number is used for look up. Onlyone instance of the message string is stored inside GAMS, where message stringsare considered to be the same if the message number is the same. Note that nocheck on the string itself is done, so it is your responsibility to make sure that themessage numbers are different for different messages. The allowed range forMSGNO is from 1 to 100.
MESS (input)
MESS is the string containing the message. GAMS will store and report only thefirst 50 characters of this string (ignoring the leading blanks).
52
SUBROUTINE GFRCNT
Subroutine GFRCNT is used to read and return control information. Values arereturned in vectors to avoid an overwhelmingly long parameter list. However,many of the returned values are given acronyms in the explanation so they can beeasily referred to later.
Fortran SUBROUTINE GFRCNT(IOCNTR, IOLOG,& MIPOK, NLPOK,& XGV, KGV, LGV, KNV, KMV) INTEGER IOCNTR, IOLOG LOGICAL MIPOK, NLPOK INTEGER KGV(30), KNV(30), KMV(30) LOGICAL LGV(30) DOUBLE PRECISION XGV(30)
Pascal procedure gfrcnt(mipok, nlpok : boolean; var cntinfo : cntrec);
C gfrcnt(mipok, nlpok, cntinfo, argi)BOOLE mipok, nlpok;cntrec* cntinfo;char *arg1;
Description of the parameters
IOCNTR (input)
IOCNTR is the unit number to be used for reading the control file. Normally thecontrol file name is passed through the command line (see the section Connectingyour solver with GAMS), or through redirection. On some machines you shouldprovide a correct environment for opening this file (see the implementation notes).The file will be opened and closed by GFRCNT.
IOLOG (input, output)
This is the unit for the log file. Normally the log file is connected to the screen, butit can also be a disk file or a scratch file. The user can write information about theprogress of the algorithm to this unit. The log file is opened by GFRCNT. Theoutput value of IOLOG is either the input value (i.e. it is not changed), or it is thevalue you specified for SCREEN in the GFINIT call. See the discussion on GFINIT.
MIPOK (input)
Set this variable to .TRUE. if discrete variables can be handled, to .FALSE. value ifnot. If not, but they appear in this problem, the program will be terminated.
NLPOK (input)
Set this variable to .TRUE. if nonlinearities can be handled, to .FALSE. value if not.If not, but they appear in this problem, the program will be terminated.
XGV (output)
The vector XGV is a general real (double precision) vector. The meaning of theelements is shown in the table below.
XGV(1) Resource limit in seconds, reslim. Thesolver should terminate if more than reslimCPU seconds have been elapsed. See theparagraph about GFCLCK for moreinformation about timings.
XGV(2)-XGV(6) A set of 5 real user cells that can be set by the user'sGAMS program. This should only be used in thedevelopment phase of the solver.
XGV(7) The value of the MIP absolute optimality criterion. Thisis the OPTCA option in the GAMS model. Only appliesto integer problems, i.e. if ismip (see further) is true.The MIP solver should stop, as soon as the best solutionpossible is within OPTCA of the best integer solutionfound so far.
XGV(8) The value of the MIP relative optimalitycriterion. This is the OPTCR option in the GAMSmodel. Only applies to mixed integer problems,i.e. if ismip is true. The MIP solver should stop,as soon as the best solution possible is within100 X OPTCR percent of the best integer solutionfound so far.
XGV(9) The value of the WORK option in GAMS. Thisvalue can be used to override core estimations.This value is normally used in Fortran basedsolvers who want to use dynamic memory.
54
XGV(10) The value GAMS uses for + ∞: plinfy.
XGV(11) The value GAMS uses for - ∞: minfy.
XGV(12) The value GAMS uses for ``undefined'': undef.
XGV(13) The value GAMS uses for ``not available'': na.
XGV(14) The value GAMS uses for ``epsilon'': eps.
XGV(15) Cutoff value, cutoff. If icutof=1 (see the KMV
array) this value can be used to ignore parts ofthe branch and bound tree that have a bestpossible value worse than this one. Also knownas incumbent. In case of maximization any partof the tree with an upperbound lower than thisvalue can be ignored. This cell is only set if themodel is a MIP model.
XGV(16) Cheating parameter, cheat. If icheat=1 (see theKMV array), this value can be used to explore thebranch-and-bound tree is a quicker fashion.Every new node should be at least |cheat| betterthan the current node. In other words, once aninteger solution is found, the cutoff valuemaintained by the algorithm may be updated byadding (or subtracting in case of minimization)the absolute value of this parameter to (from) thecurrent cutoff. If icheat=0 don't use cheating.This cell is only set if the model is a MIP model.
XGV(17)..XGV(30) Reserved for future use.
KGV (output)
The vector KGV is a general integer vector.
KGV(1) The number of row records in the matrix, numrow.There is no objective row in this matrix -- one may needto be added (see below).
KGV(2) The number of column records in the matrix, numcol.
KGV(3) The number of nonzeroes in the matrix, numnnz. It maybe necessary to add one for the objective row. Thenumber of nonzeroes in the rhs-vector are not includedin this figure.
KGV(4) The number of the numrow right-hand-side values thatare nonzero, numrhs.
KGV(5) The number of the numcol columns that are fixed,numfxv.
KGV(6) The largest number of nonzeroes in a column, maxcol.
KGV(7) The sequence number in the matrix of the objectivevariable, iobvar.
KGV(8) Iteration limit, itnlim. After the solver has performeditnlim iterations it should terminate, and write a solutionfile with an indication that the maximum number ofiterations is exceeded.
KGV(9)-KGV(13) A set of 5 integer user cells that can be set by the user'sGAMS program. These can be used a rudimentary formof an option file. Of course, if the solver is in generaluse it should have a well-designed option file.
The next few cells are useful to find out if the model can be "reformulated"by substituting out the GAMS objective variable. In many cases users havea free objective variable that really defines an objective function, eg:
OBJ.. Z =E= ....;
In some cases it is needed or advantageous for the solver to consider the rhsof OBJ as the objective function. Of course in general the expression is:
a*z + f(x) = b;
We can reformulate and use
56
( b - f(x) ) / a
as objective if the following conditions hold:
(1) The objective variable is a free variable (user may have specifiedbounds on it).
(2) The objective variable should appear only in this row.
(3) This row is an equality.
(4) and z is a linear variable.
Notice that we have the constant b/a in the objective. In many cases one hasto take this constant out of the objective, remember it and compensate theobjective before reporting the solution. When reporting the solution z has tobe reconstructed as well as the equation OBJ (i.e. level and marginal). As zis a free variable the marginal (reduced cost) can be made 0 (basis status:BASIC). The OBJ row is binding and the dual should be made -1 or +1depending on whether we are minimizing or maximizing.
In case reformulation is not possible one should add a dummy row to themodel with only one nonzero element: a +1 or -1 in the GAMS ObjectiveVariable position. This increases the number of rows by 1 and the numberof nonzeroes also by 1.
KGV(14) Number of nonzeroes in the objective. If > 1 theobjective variable appears in more than one row andreformulation is not possible.
KGV(15) Last row index in the objective column. If KGV(9)=1 thenthis points to the objective row.
KGV(16) 0 if there are no bounds on the objective variable, 1 ifthe objective variable has bounds.
KGV(17) Number of =E= constraints in the model.
KGV(18) Number of =G= constraints in the model.
KGV(19) Number of =L= constraints in the model.
KGV(20) Number of =N= constraints in the model.
KGV(21)..KGV(30) Reserved for future use.
LGV (output)
The vector LGV is a general logical vector.
LGV(1) If .TRUE. use basis information implicit in the matrix, if.FALSE., do not, usebas.
LGV(2) If .TRUE., attempt to read user's option file at theappropriate time. If .FALSE, do not, useopt. The formatand syntax of the option file are the responsibility of thealgorithm builder. Also reading and parsing the optionfile is left to the solver. For an example how toimplement an option file parser, see the section on theoption file.
LGV(3) If .TRUE., the sense of optimization is to minimize,otherwise maximize, ismin.
LGV(4) If .TRUE., the problem contains discrete (binary orinteger) variables. Otherwise not, ismip.
LGV(5) If .TRUE., the problem contains nonlinearities.Otherwise not, isnlp.
LGV(6) The SYSOUT option in GAMS. If .TRUE., GAMS willcopy the complete status file to the listing file. (You canalso force this from within the solver by the subroutine call:
CALL GFSTCT('SYSOUT').
LGV(7)..LGV(30) Reserved for future use.
KNV (output)
58
KNV is a general integer vector. It is used in accomodating nonlinearities.Assignments are made to this vector only if you said you could handlenonlinearities, i.e. if nlpok is true.
KNV(1) Count of rows that contain nonlinear terms, numnnr.
KNV(2) Count of the variables that appear nonlinearly in theproblem, numnnv. This will never be set to zero if theproblem is nonlinear, i.e. it is a good indicator to testwhether a model is non-linear.
KNV(3) Count of nonzero elements in the incidence matrix thatcorrespond to nonlinear terms. Again this will never bezero if the problem is nonlinear.
KNV(4) The length of the array needed to store the nonlinearinstructions, lenins. This will be a general integer array.
KNV(5) Workspace needed by the non-linear instructioninterpreter nlwork.
KNV(6) Number of domain errors allowed while evaluatingnonlinearities, maxerr.
KNV(7) The maximum address that can be stored in the addressfield of a non-linear instruction. When movinginstruction you should not exceed this limit.
KNV(8)..KNV(30) Reserved for future use.
KMV (output)
KMV is a general integer vector. The values are used in accomodating mixedinteger programs. Assignments are made to this vector only if you specified thatyou can handle discrete variables, i.e. if mipok is true.
KMV(1) Count of binary variables in the problem, binvar.
KMV(2) Count of integer variables in the problem, intvar. Thetotal number of discrete variables is binvar + intvar +SOS1var + SOS2var.
KMV(3) Number of binary variables needed to represent all theinteger variables int the in the problem, bin2var. If thesolver can only handle binary variables, a generalinteger variable Xk ∈ {1,...,M} can be converted to asum of binary variables bi using the expansion:
χk=ΣL
i=12i-1bi
where L = Llog2MO. KMV(3) reports the sum of allvalues of L for each integer variable. The total numberof zero-one variables required is then binvar + bin2var+ SOS1var + SOS2var. If your solver can handlegeneral integer variables you should not use thisexpansion.
KMV(4) Count of variables of SOS type I in the problem,SOS1var.
KMV(5) Count of variables of SOS type II in the problem,SOS2var.
KMV(6) User specified node limit. If this value is zero, thenignore it, otherwise stop as soon as number of nodesstored in the node table exceeds this number. nodlim.
KMV(7) icutof, indicator whether or not the user has specified acutoff value or incumbent. icutof =0 means no value isspecified, icutof=1 means: user specified a cutoff valueof cutoff. This value can be found in the XGV array.This value can then be used to ignore parts of the branchand bound tree (i.e. parts that exceed this cutoff).
KMV(8) icheat, indicator whether or not the user has specified acheat parameter. The value of the cheat parameter canbe found in the XGV array. If user wants to cheat, he iswilling to risk missing integer solutions in order toexplore the tree faster. icheat=0 indicates that the userdoes not want to cheat, icheat=1 indicates that cheatingis requested.
60
KMV(9) priots, indicator whether priorities are specified by theuser. priots=0 means no priorities and priots=1 meanspriorities are present. If this value is 1 then for eachdiscrete variable a priority is passed on by GAMS.
KMV(10)..KMV(30) Reserved for future use.
SUBROUTINE GFRCOF
Subroutine GFRCOF is used to read a nonzero record from the data file. There mustbe nnzcol calls to GFRCOF between each call to GFRCOLX (above). The data file willbe closed after the very last call to GFRCOF.
Fortran SUBROUTINE GFRCOF(COEFF, IROSEQ, NLTYP)DOUBLE PRECISION COEFFINTEGER IROSEQ, NLTYP
Pascal procedure gfrcof(var coeff : float; var iroseq, nltyp :integer);
C gfrcof(coeff, iroseq, nltyp)double *coeff;int iroseq, nltyp;
Description of the parameters
COEFF (output)
The value of the coefficient.
IROSEQ (output)
The sequence number of the row in which this coefficient occurs.
NLTYP (output)
Only useful if there are nonlinearities (isnlp). Value 0 is returned if this is aconstant (linear) coefficient, 1 otherwise.
In appendix 1 Fortan code is presented that shows how to read a problem into afixed size array system. The same program but using dynamic arrays is shown later.Also a Turbo Pascal and a C version is shown.
62
SUBROUTINE GFRCOLX
Subroutine GFRCOLX is used to read a column record from the data file. The firstcall to this routine must be preceded by exactly numrow calls to GFRROWX. Theremust be nnzcol calls to GFRCOF between successive calls to GFRCOLX, to return thenonzero elements of each column in sequence.
Fortran SUBROUTINE GFRCOLX(CDATA,IDATA)DOUBLE PRECISION CDATA(5)INTEGER IDATA(4)
Pascal procedure gfrcolx(var coldata : colrec);
C gfrcolx(coldata)colrec *coldata;
Description of the parameters
CDATA (output)
This double precision vector contains the level and the bounds of the variables.
CDATA(1) The lower bound on the column. Note that you shouldcheck whether this is the special value corresponding to-INF. (See GFSPVL)
CDATA(2) The level value for the column. It will not be one of thespecial values.
CDATA(3) The upper bound on the column. Note that you shouldcheck whether this is the special value corresponding toINF. (See GFSPVL).
CDATA(4) If this is a discrete row (IDATA(3) <> 0) and (priots = 1)(see KMV(9) in GFRCNT), then this value is the priority ofthe current variable. Priorities are real numbers andlower numbers mean higher priorities. You have to scalethe numbers that are provided here to your own prioritynumbers (often integers between 1 and 255). This can bedone once all the numbers have been read. For instanceif your range is 1..255, and you have stored the realpriorities provided by gams in xprior[i] and you wantyour integer priorities in iprior[i] iprior[i] := int(
(xprior[i]-lo+d)/d + 0.001) where lo := min(xprior[i])and hi := max(xprior(i)) and d = (hi-lo)/255.
CDATA(5) dual value (reduced cost) for column. Can be used forwarm restarts.
64
IDATA (output)
The vector IDATA is a general integer vector.
IDATA(1) The number of nonzero coefficient in this column, (alsothe number of coefficient records following), nnzcol.
IDATA(2) The marginal value for the column. This will be either$+1$ (not basic) or 0 (basic). This information is used ifa basis has to be constructed, as indicated by usebas.
IDATA(3) The variable type. A nonzero value means that thevariable is discrete. The following map shows therelationships.
IDATA(3) Variable type0 Continuous variable1 Binary variable2 Integer variable3 SOS type 1 variable4 SOS type 2 variable
IDATA(4) The new SOS set indicator. This variable is only usefulif the problem contains discrete variables, and thevariable type is SOS I or SOS II. If the current column isthe first member of an SOS set, IDATA(4) will be setnonzero, else to zero.
SUBROUTINE GFRDOP
This is the option file reader for Fortran. It is a little bit complex due to "sparse"storage of strings. If you only have integer and real options things are easy. Forstring options a little bit more work is required,
Fortran SUBROUTINE GFRDOP(U,IOSTA,IOLOG,& N, MAXS, IVAL, RVAL,& MAXSTR, NSTR, FLAG,& KW, TYPE, SVAL)INTEGER U, IOSTA, IOLOGINTEGER N, MAXSCHARACTER*10 KW(N)CHARACTER*1 TYPE(N)CHARACTER*80 SVAL(MAXS)INTEGER IVAL(N)DOUBLE PRECISION RVAL(N)INTEGER MAXSTR(MAXS), NSTR(MAXS)LOGICAL FLAG(N)
Pascal n.a.
C n.a.
Description of the parameters
U (input)
Unit to be used by the option file reader
IOSTA (input)
Unit of status file (content of the option file will be echoed to the status file).
IOLOG (input)
Unit of the log file (content of the option file will be echoed to the log file).
N (input)
Number of different options
KW (input)
66
Keyword of each option. Must be unique (this is not checked). Keywords should bespecified in uppercase.
TYPE (input)
Array of types:
type description'I' Integer'R' Real (i.e. double precision)'S' String (i.e. CHARACTER*80)'T' String or empty'N' No argument
IVAL (input/output)
For integer options K, IVAL(K) may be set by the user. For a string option K, thecaller has to specify in IVAL(K) the position L in the array SVAL where the stringhas to be stored.
RVAL (output)
For real options K, RVAL(K) may be set by the user.
SVAL (output)
For a string option K, SVAL(IVAL(K)).... will contain user specified strings.
FLAG (output)
If FLAG(K) = .TRUE. then the user has set option K.
MAXSTR (input)
String option K can have up to MAXSTR(IVAL(K)) string arguments
NSTR (output)
String option K has NSTR(IVAL(K)) string arguments (NSTR(IVAL(K)). LE.
MAXSTR(IVAL(K))).
SUBROUTINE GFRROWX
Subroutine GFRROWX is used to read a row record from the data (matrix) file. Thisfile will be opened on the first call to this routine, so you don't have to worry aboutthat. If you call this routine more times than there are rows in the problem, an errormessage will be issued and the program will be terminated.
Fortran SUBROUTINE GFRROWX(RDATA, IDATA)DOUBLE PRECISION RDATA(3)INTEGER IDATA(2)
Pascal procedure gfrrowx(var rowdata : rowrec);
C gfrrowx(rowdata)rowrec *rowdata;
Description of the parameters
RDATA (output)
The vector RDATA is a general real (double precision) vector.
RDATA(1) An indication that a variable is superbasic. If nonzero, itis the row activity level: SUM(J,A(I,J)*X(J)). If themarginal is zero, RDATA(1) will also be zero. It is only tobe used by some NLP solvers, like MINOS.
RDATA(2) The right-hand-side value, bj.
RDATA(3) Dual value (marginal) for row. This can be used towarm restarts.
IDATA (output)
The vector IDATA is a general integer vector.
IDATA(1) The type of the equation. The values are in the rangeIDATA(1) in {0,1,2,3}, with the following meaning:
constraint type GAMS syntax IDATA(1)equality =E= 0greater-than constraint =G= 1
68
less-than constraint =L= 2free row =N= 3
IDATA(2) The marginal value indicator for the row or slack. Thiswill be either +1 (not basic) or 0 (basic). Thisinformation is used if a basis has to be constructed, asindicated by usebas. Some hints on how to set up a basisbased on these marginal indicators is given in theparagraph
SUBROUTINE GFRWER
Subroutine GFRWER passes on an error message concerning row IROW to GAMS.GAMS will translate this row number into the correct GAMS name.
Fortran SUBROUTINE GFRWER(IROW,MSGNO,MESS)INTEGER IROW. MSGNOCHARACTER*(*) MESS
Pascal procedure gfrwer(irow, msgno: integer, mess : messt);
C gfrwer(irow,msgno,mess)int irow, msgno;char *mess;
Description of the parameters
IROW (input)
IROW is the row number of the equation corresponding to this error.
MSGNO (input)
MSGNO is the number of the error message. This number is used for look up. Onlyone instance of the message string is stored inside GAMS, where message stringsare considered to be the same if the message number is the same. Note that nocheck on the string itself is done, so it is your responsibility to make sure that themessage numbers are different for different messages. The allowed range forMSGNO is from 1 to 100.
MESS (input)
MESS is the string containing the message. GAMS will store and report only thefirst 50 characters of this string (ignoring the leading blanks).
70
SUBROUTINE GFSDIR
Subroutine GFSDIR returns the system directory, i.e. the directory where the gamssystem files are residing. Note that you can only assume that the user has readpermission to this directory.
Fortran SUBROUTINE GFSDIR(SYSDIR)CHARACTER*80 SYSDIR
Pascal procedure gfsdir(var sysdir : pathname);
C gfsdir(sysdir)char **sysdir;
Description of the parameters
SYSDIR (output)
SYSDIR is a character string that contains on exit the system directory.
FUNCTION GFSGET
Extracts the i-th token from a string. Tokens are series of non-blank characters, andare separated by (one or more) blanks.
Fortran SUBROUTINE GFSGET(I,LINE,TOKEN)INTEGER ICHARACTER*(*) LINE,TOKEN
Pascal n.a.
C n.a.
Description of the parameters
I (input)
The sequence number of the token you are interested in.
LINE (input)
Input string. Is not altered by this routine.
TOKEN (output)
String containing the result. Will be ``empty'' for non-existing parameters, i.e. if i<1or i>maxtok TOKEN will get assigned the string ' '.
72
SUBROUTINE GFSTAT
Subroutine GFSTAT returns the status file name so that you can open the status file.This routine should be called after GFRCNT. Normally you would use GFOPST forthis: GFOPST calls GFSTAT and opens the file for you.
Fortran SUBROUTINE GFSTAT(FLN)CHARACTER*80 FLN
Pascal procedure gfstat(var fln : filename);
C gfstat(fln)char** fln;
In Fortran you should open the status file with the same unit number you passed onto GFINIT. The file format should be a flat text file. The next code fragmentillustrates this
PROGRAM EXAMPLE1
INTEGER IOSTA ! unit number of the status file INTEGER GFUNIT ! unit number for internal lib routines INTEGER IOLOG ! unit number log file INTEGER SCREEN ! unit number screen INTEGER IOCNTR ! unit number control file DOUBLE PRECISION XGV(30) ! storage control info INTEGER KGV(30) LOGICAL LGV(30) INTEGER DUMMY
C define the unit numbers
IOSTA = 10 IOLOG = 11 GFUNIT = 12 SCREEN = 3 IOCNTR = 2
C initialize and read control file
CALL GFINIT(GFUNIT, IOSTA, SCREEN) CALL GFRCNT(IOCNTR, IOLOG, .FALSE., .FALSE., & XGV,KGV,LGV,DUMMY,DUMMY)
C open status file, next two statements can be replaced by
CALL GFOPST()
C write a message to the satus file
CALL GFSTCT('STARTC') WRITE(IOSTA,*) ' ********************************' WRITE(IOSTA,*) ' * SUPERLP, BY SOLVERS INC. *' WRITE(IOSTA,*) ' ********************************' CALL GFSTCT('STOPC')
END
Some of the routines in this example are explained in the next few pages.
74
SUBROUTINE GFSTCT
Subroutine GFSTCT controls the status file. Using this routine you can give thefollowing commands to GAMS while it is reading the status file: start copying, stopcopying, page eject, character switch and sysout.
A page eject will tell GAMS to insert a page eject at this place when it is insertingthe status file into the GAMS listing file. The page size for the listing file can beinterrogated by a call to GFPGSZ.
A character switch tells GAMS not longer to consider a "=" in column 1 as acontrol character, but to use another character for that purpose. For example CALL
GFSTCT('CHRSW#') will switch the control character to "#". Normally one shouldnot use an alphanumeric character for this purpose, but if you do, you should kownthat the character you pass on, will be uppercased.
A sysout results in copying the complete status file into the GAMS listing file. Thismay be useful in case of an error. Note that this can also be forced in other ways:first through a GAMS option OPTION SYSOUT), and second by certain values of thesolver status and the model status (see GFWSTA).
Fortran SUBROUTINE GFSTCT(CMD)CHARACTER*(*) CMD
Pascal procedure gfstct(cmd : cmdstring);
C gfopst(cmd)char *cmd;
Description of the parameters
CMD (input)
CMD is a character string containing one of the following commands: 'STARTC','STOPC', 'EJECT', 'CHRSW.' or 'SYSOUT'.
Example of use
CALL GFSTCT('SYSOUT')
SUBROUTINE GFTIME
Subroutine GFTIME returns the time when the current GAMS job started.
Fortran SUBROUTINE GFTIME(GMSTIM)CHARACTER*10 GMSTIM
Pascal procedure gftime(var gmstim : char10);
C gftime(gmstim)char **gmstim;
Description of the parameters
GMSTIM (output)
GMSTIM is a character string that contains on exit the time.
76
SUBROUTINE GFUOPN
Opens a file, for which the user provides a filename. The file to be opened is a flatsequential text file.
Fortran SUBROUTINE GFUOPN(FLN, IUNIT, CMODE)CHARACTER*(*) FLNINTEGER IUNITCHARACTER CMODE
Pascal n.a.
C n.a.
Description of the parameters
FLN (input)
Filename of the file to be opened.
IUNIT (input)
Unit number to be used.
CMODE (input)
Character code that determines how the file should be opened. 'R' means forreading, 'W' for writing and 'A' for appending.
SUBROUTINE GFUOPU
As GFUOPN but now for unformatted files. Notice that unformatted files areincompatible over different machines and over different compilers. You may useunformatted files for scratch files. Notice we do not provide any support for directaccess files, i.e. the organization is sequential.
Fortran SUBROUTINE GFUOPU(FLN, IUNIT, CMODE)CHARACTER*(*) FLNINTEGER IUNITCHARACTER CMODE
Pascal n.a.
C n.a.
Description of the parameters
FLN (input)
Filename of the file to be opened.
IUNIT (input)
Unit number to be used.
CMODE (input)
Characater code that determines how the file should be opened. 'R' means forreading, 'W' for writing.
BUGS:
This routine cannot be used while the matrix is being read or while the solution fileis being written.
78
SUBROUTINE GFWBND
For MIP problems report the best possible integer solution, bstbnd. The user wantsto stop when either |objval-bstbnd| ≤ optca or |objval-bstbnd| ≤ optcr * |bstbnd|.The values for optca and optcr can be found in the arrays returned by GFRCNT.
Fortran SUBROUTINE GFWBND(BSTBND)DOUBLE PRECISION BSTBND
Pascal procedure gfwbnd(bstbnd : float);
C gfwbnd(bstbnd)double bstbnd;
Description of the parameters
BSTBND (input)
Use BSTBND to pass the best possible value for an integer solution.
SUBROUTINE GFWCOL
Subroutine GFWCOL is used to write column records to the solution file. Exactlynumcol calls are required.
Fortran SUBROUTINE GFWCOL(LEVEL,MARGIN,& BASIND,VARSTA)DOUBLE PRECISION LEVEL,MARGININTEGER BASIND,VARSTA
Pascal procedure gfwcol(level, margin : float; basind, varsta :integer);
C gfwrow(level, margin, basind, varsta)double level, margin;int basind, varsta;
The same range considerations apply as to GFWROW. The parameters passed havethe same purpose as in GFWROW.
Description of the parameters
LEVEL (input)
The activity level for the column.
MARGIN (input)
The marginal value for the column. The following sign convention should be usedfor nonbasic columns in an optimal solution to be consistent with other solvers:
Minimization Maximizationat lowerbound positive negativeat upperbound negative positive
BASIND (input)
The basis indicator. Mapping is as below.
BASIND Basis status0 nonbasic at lower bound1 nonbasic at upper bound2 basic3 superbasic or non-basic but not at one of its
bounds
80
The third option can be used for variables in an NLP which are superbasic,or in the case of a MIP, where a variable is non-basic and fixed by thealgorithm between its bounds. NOTE: The internal I/O routines may packthe solution by not passing back the level if it is at one of its bounds. So onlyuse option 0 or 1 if the levels are really at their original bounds.
In general this means that you have to be very careful with integer variables:in many cases they will have a status of lets say upper, but this is the state inthe last subproblem, which does not have the same bounds as the originalproblem ! In SCICONIC there is another problem: when using dynamicpresolve during the branch and bound even the bounds of the linearvariables may be changed. In case you want to be sure that the level value ispassed back without packing, declare it superbasic!
GAMS uses only the marginals to give a subsequent solve a hint how to setup the basis.
VARSTA (input)
The variable status indicator. Mapping is as below.
VARSTA Status0 normal (OK)1 non-optimal2 infeasible3 unbounded
To prevent conversion problems and system failure, this subroutine filters thevalues of LEVEL and MARGIN. All numbers closer to zero than dwarf = 1.0E-20 willbe set to zero. All numbers with magnitude equal to or larger than huge = 1.0E31$will be set to undefined when returned to GAMS. You can use the values epsilon,undefined, plinfy, and minfy (see GFRCNT) to return special values.
SUBROUTINE GFWCTI
Optional routine for giving GAMS more fine-grained timing info.
Fortran SUBROUTINE GFWCTI(CALTIM)DOUBLE PRECISION CALTIM
Pascal procedure gfwcti(caltim : float);
C gfwrti(caltim)double caltim;
Description of the parameters
CALTIM (input)
Use CALTIM to pass the time the solver needed to solve the problem. This valueshould correspond to the pure calculation time, i.e. no input or output.
82
SUBROUTINE GFWDIR
Subroutine GFWDIR returns the working directory, i.e. the directory where thelisting file is written to. Normally this is the users current directory. It can beassumed that the user has read and write permission to this directory.
Fortran SUBROUTINE GFWDIR(WRKDIR)CHARACTER*80 WRKDIR
Pascal procedure gfwdir(var wrkdir : pathname);
C gfwdir(wrkdir)char **wrkdir;
Description of the parameters
WRKDIR (output)
WRKDIR is a character string that contains on exit the working directory.
SUBROUTINE GFWNOD
Optional routine to inform GAMS how many nodes were traversed in the branch-and-bound search.
Fortran SUBROUTINE GFWNOD(NODUSD)INTEGER NODUSD
Pascal procedure gfwnod(nodusd : integer);
C gfwnod(nodusd)integer nodusd;
Description of the parameters
NODUSD (input)
Use NODUSD to pass the number of nodes visited during the branch-and-boundsearch.
84
SUBROUTINE GFWROW
Subroutine GFWROW is used to write row records to the solution file. Exactlynumrow calls are required.
Fortran SUBROUTINE GFWROW(LEVEL,MARGIN,& BASIND,EQSTAT)DOUBLE PRECISION LEVEL,MARGININTEGER BASIND,EQSTAT
Pascal procedure gfwrow(level, margin : float; basind, eqstat :integer);
C gfwrow(level, margin, basind, eqstat)double level, margin;int basind, eqstat;
Description of the parameters
LEVEL (input)
LEVEL is the activity level of the row: SUM(J, A(I,J)*X(J)).
MARGIN (input)
The marginal value for the row. The following sign conventions should be used forthe nonbasic rows in an optimal solution if you want to be consistent with othersolvers:
Minimization Maximization=L= constraint negative positive=G= constraint positive negative
BASIND (input)
The basis indicator. Mapping is as below. Note that this indicator is about theequation level, and not the slack (if the slack is non-basic at lowerbound, then thelevel is non-basic at upperbound).
BASIND Basis status0 nonbasic at lower bound
1 nonbasic at upper bound2 basic3 superbasic or non-basic but not at one of its
bounds
EQSTAT (input)
The equation status indicator. Mapping is as below.
EQSTAT Status0 normal (OK)1 non-optimal2 infeasible3 unbounded
To prevent conversion problems and system failure, this subroutine filters thevalues of LEVEL and MARGIN. All numbers closer to zero than dwarf = 1.0E-20will be set to zero. All numbers with magnitude equal to or larger than huge =1.0E31 will be set to undefined when returned to GAMS. You can use the valuesepsilon, undefined, plinfy, and minfy (see GFRCNT) to return special values.
86
SUBROUTINE GFWRTI
Optional routine for giving GAMS more fine-grained timing info.
Fortran SUBROUTINE GFWRTI(RDTIME)DOUBLE PRECISION RDTIME
Pascal procedure gfwrti(rdtime : float);
C gfwrti(rdtime)double rdtime;
Description of the parameters
RDTIME (input)
Use RDTIME to pass the time the solver needed to read the problem.
SUBROUTINE GFWSTA
Subroutine GFWSTA opens the solution file, and writes the model and solver statusto it.
Fortran SUBROUTINE GFWSTA(MODSTA,SOLSTA,& ITSUSD,RESUSD,OBJVAL,DOMERR)INTEGER MODSTA,SOLSTA,ITSUSD,DOMERRDOUBLE PRECISION RESUSD,OBJVAL
Pascal procedure gfwsta(modsta, solsta, itsusd : integer;resusd, objval : float; domerr : integer);
C gfwsta(modsta, solsta, itsusd, resusd, objval, domerr)int modsta, solsta, itsusd, domerr;double resusd, objval;
Description of the parameters
MODSTA (input)
This is the model status, an integer value drawn from the following list which mostaccurately describes the solution to be returned, if any.
modsta Message produced by GAMS1 OPTIMAL2 LOCALLY OPTIMAL3 UNBOUNDED4 INFEASIBLE5 LOCALLY INFEASIBLE6 INTERMEDIATE INFEASIBLE7 INTERMEDIATE NONOPTIMAL8 INTEGER SOLUTION9 INTERMEDIATE NON-INTEGER
10 INTEGER INFEASIBLE11 NO SOLUTION12 * ERROR UNKNOWN13 * ERROR NO SOLUTION
An asterix in the table indicates that GAMS will trigger a SYSOUT.
SOLSTA (input)
This is the solver status. The mapping is below.
88
solsta Message produced by GAMS1 NORMAL COMPLETION2 ITERATION INTERRUPT
3 RESOURCE INTERRUPT4 * TERMINATED BY SOLVER5 EVALUATION ERROR LIMIT6 UNKNOWN7 (free for future use)8 ERROR PREPROCESSOR ERROR(S)9 ERROR SETUP FAILURE10 * ERROR SOLVER FAILURE11 * ERROR INTERNAL ERROR12 ERROR POST-PROCESSOR ERROR13 * ERROR SYSTEM FAILURE
If the solver does not write a solution (for instance because is terminated due to afatal error), GAMS will notice this and will use a default solution that says:modsta=13 and solsta=13. For an explanation of the exact meaning of the messagessee page 117 of the GAMS User's Guide.
ITSUSD (input)
Use ITSUSD to pass the number of iterations used.
RESUSD (input)
Use RESUSD to pass the value of the used up CPU seconds.
OBJVAL (input)
OBJVAL must be set to the value of the user's objective variable. If the problem isreformulated, pass the value the variable would assume in the orginal problem.
DOMERR (input)
This is only used for NLP's, return 0 for LP's or MIP's. The number of evaluationerrors occured. If the NLP algorithm tries to evaluate SQRT(X), X<0 the system doesnot terminate immediately. Instead a ``reasonable'' number is returned, and thenumber of errors nlerrs is incremented by one. As soon as nlerrs >= maxerr, oneshould terminate the algorithm. Use this routine to report nlerrs to GAMS.
SUBROUTINE GFWWTI
Optional routine for giving GAMS more fine-grained timing info.
Fortran SUBROUTINE GFWWTI(WRITIM)DOUBLE PRECISION WRITIM
Pascal procedure gfwwti(writim : float);
C gfwrti(writim)double writim;
Description of the parameters
WRITIM (input)
Use WRITIM to pass the time the solver needed to write the solution.
90
FUNCTION GFXARG
Extracts the i-th parameter from the command line.
Fortran SUBROUTINE GFXARG(I,ARG)INTEGER ICHARACTER*(*) ARG
Pascal n.a.
C n.a.
Description of the parameters
I (input)
The sequence number of the command line parameter you are interested in.
ARG (output)
String containing the result. Will be ``empty'' for non-existing parameters, i.e. if i<1or i>maxarg ARG will get assigned the string ' '.
SUBROUTINE MEMINF
Writes memory statistics in the same way as BDMLP, MINOS, ZOOM and OSL.On all machines except the PC the units in which info is printed is Megabytes. Onthe PC we use KB.
Fortran SUBROUTINE MEMINF(IOSTA, CON,& ESTIM, LUCORE, MAXZ, MAXBLK)INTEGER IOSTA,CONINTEGER ESTIM, LUCORE, MAXZ, MAXBLK
Pascal n.a.
C n.a.
Description of the parameters
IOSTA (input)
Unit number of the status file.
CON (input)
Unit number of the log file.
ESTIM (input)
Estimated memory requirements in 8-byte words.
LUCORE (input)
User provided memory request. 0 if not applicable. See GFRCNT.
MAXZ (input)
Size of obtained memory by GFGETM. Again in 8-byte words.
MAXBLK (input)
Maximum memory size that can be requested. 0 if not applicable. Returned byGFGETM.
92
SUBROUTINE READDICT
Read the dictionary file
Fortran SUBROUTINE READDICT(IUNIT,ARRAY,CRMAX,CRUSED)INTEGER IUNITDOUBLE PRECISION ARRAY(*)INTEGER CRMAX, CRUSED
Pascal n.a.
C readdict()
Description of the parameters
IUNIT (input)
Unit number to read dictionary file
ARRAY (input)
A double precision vector, used for accessing the allocated memory.
CRMAX (input)
Maximum memory available in double words for dictionary file
CRUSED (output)
Memory used in double word reals
CHAPTER 4
IMPLEMENTATION NOTES
Microsoft Fortran for 286 DOSNDP 4.4 Fortran for Extended DOS (386 and above)Unix: Sun OS 4.1.xIBM VM CMS
94
MICROSOFT FORTRAN
For the 286 DOS environment, we use the Microsoft Fortran compiler, version 5.We compile the I/O library programs using the following makefile example:
#----------------------------------------#--- Microsoft fortran version 5.0 ------#----------------------------------------## because has to go into overlays# no library possible#F77 = flF77OPTS = /c /FPi /AH /Ox
OBJS = allmem.obj iolib1.obj iolib2.obj iolib3.objiolib4.obj \
iolib5.obj iolib6.obj
.for.obj: $(F77) $(F77OPTS) $<
iolib.lib: $(OBJS) echo all done
iolib1.$(OBJEXT) : iolib1.$(FOREXT) defines.inc gmscom.incnlcon1.inc
iolib2.$(OBJEXT) : iolib2.$(FOREXT) defines.inc gmscom.incnlcon1.inc
iolib3.$(OBJEXT) : iolib3.$(FOREXT) defines.inc gmscom.incnlcon1.inc
iolib4.$(OBJEXT) : iolib4.$(FOREXT) defines.inc gmscom.incnlcon1.inc
iolib5.$(OBJEXT) : iolib5.$(FOREXT) defines.inc gmscom.incnlcon1.inc
iolib6.$(OBJEXT) : iolib6.$(FOREXT) defines.inc gmscom.inc
allmem.obj : allmem.ob copy allmem.ob allmem.obj
The /c flag tells the compiler only to compile (no linking). The /AH flag says wewant to use the HUGE memory model. This is needed when you want to use arrays >64K. Also our dynamic memory routines require that the huge memory model isused. /FPi instructs the compiler to generate inline floating point code, and the /Oxoption tells the compiler to do its best on optimization. When using this libraryalways use the huge memory model.
allmem.obj is a little assembly routine for the memory allocation.
96
To link this into your program you could use something like:
#----------------------------------------#--- Microsoft fortran version 5.0 ------#----------------------------------------F77 = flF77OPTS = /c /FPi /AHF77NOPTS = /c /FPi /AH /OdLD = linkLDOPTS = @dolnkFOREXT = forOBJEXT = objEXENAME = gams2bdm.exeSPECOBJS = allmem.objIOLIBDIR = \gams225\iolib\# comment needed for \COPY = copy
.$(FOREXT).$(OBJEXT):$(F77) $(F77OPTS) $<
OBJS = block1.$(OBJEXT) block2.$(OBJEXT)block3.$(OBJEXT) \
block4.$(OBJEXT) block5.$(OBJEXT)iolib1.$(OBJEXT) \
iolib2.$(OBJEXT) iolib3.$(OBJEXT)iolib4.$(OBJEXT) \
$(SPECOBJS)
$(EXENAME): $(OBJS) $(LD) $(LDOPTS)
del *.obj
block1.$(OBJEXT): block1.$(FOREXT) bdmlpcb.inc defines.incblock2.$(OBJEXT): block2.$(FOREXT) bdmlpcb.inc defines.incblock3.$(OBJEXT): block3.$(FOREXT) bdmlpcb.inc defines.incblock4.$(OBJEXT): block4.$(FOREXT) bdmlpcb.inc defines.incblock5.$(OBJEXT): block5.$(FOREXT) bdmlpcb.inc defines.inc
iolib1.$(OBJEXT): $(IOLIBDIR)iolib1.$(OBJEXT)$(COPY) $(IOLIBDIR)iolib1.$(OBJEXT) .
iolib2.$(OBJEXT): $(IOLIBDIR)iolib2.$(OBJEXT)$(COPY) $(IOLIBDIR)iolib2.$(OBJEXT) .
iolib3.$(OBJEXT): $(IOLIBDIR)iolib3.$(OBJEXT)$(COPY) $(IOLIBDIR)iolib3.$(OBJEXT) .
iolib4.$(OBJEXT): $(IOLIBDIR)iolib4.$(OBJEXT)$(COPY) $(IOLIBDIR)iolib4.$(OBJEXT) .
defines.inc: $(IOLIBDIR)defines.inc$(COPY) $(IOLIBDIR)defines.inc .
allmem.$(OBJEXT): allmem.obcopy allmem.ob allmem.$(OBJEXT)
98
The linker response file looks like:
block1+iolib3+(block2+block3+block4+block5)+(iolib1+iolib4)+(iolib2)
+allmemgams2BDM.exe/E/INF/F/PACKC
c:\lib\,
The input routines (GFRCNT, GFRROWX etc) are located in IOLIB1, the outputroutines (GFWSTA, GFWROW etc) in IOLIB2 and the "resident" parts (GFCLCK etc) inIOLIB3. IOLIB4 contains the license checker.
NDP 386 FORTRAN
The NDP 386 compiler allows you to use the protected mode of the 386 CPU. Thisgives you (a) more speed and (b) more memory than having it running in the (8086compatible) real mode. The switching software to and from protected mode isprovided by Phar Lap. We use NDP version 4.4.1 and Phar Lap tools version 7.0.
The makefile we used to generate I/O library is as follows:
#### Make File for iolib# generates IOLIB.LIB###
OBJS = iolib1.obj iolib2.obj iolib3.obj iolib4.obj iolib5.objiolib6.obj
fpu287 = -n1fpu387 = -n3fpuW = -n4
f77opt = -c $(fpu387) -OML -on -phar1
iolib.lib : $(OBJS) 386lib iolib -replace $(OBJS)
.f.obj: mf386 $(f77opt) $<
A makefile for a user application can look like:
OBJS = main.obj miles.obj lusol.obj cplib.obj \ cpmain.obj gfdict.obj mpsge.obj nlio.obj \ ..\iolib\iolib.lib
fpu287 = -n1fpu387 = -n3fpuW = -n4
f77opt = $(fpu387) -OLM -on -phar1
.f.obj: mf386 -c $(f77opt) $<
gams3mls.exe: $(OBJS) 386link @miles.lnk bind386 \phar386\bin\run386b gams3mls cfig386 gams3mls -vdisk -maxi 64
100
del gams3mls.exp
main.obj: main.fslcp.obj: slcp.flusol.obj: lusol.fcpmain.obj: cpmain.fcplib.obj: cplib.fnlio.obj: nlio.fmpsge.obj: mpsge.f
where the linker response file is:
c:\ndp386\lib\dos386.objc:\ndp386\lib\__co387.objc:\ndp386\lib\profdumy.objmain.objmiles.objlusol.objcplib.objcpmain.objgfdict.objmpsge.objnlio.obj-twocase-exegams3mls-nomap-lib ..\iolib\iolib-lib c:\ndp386\lib\libf3h-lib c:\ndp386\lib\libc3h-lib c:\ndp386\lib\libm3h-lib c:\ndp386\lib\libg3h-pack
UNIX FORTRAN
Sun Fortran for the SUN OS 4.1.x Operating System is used to illustrate themakefiles for the various flavours of Unix.
The makefile we used to generate the library iolib.a is as follows:
#### Make File for iolib# generates iolib.a###
F77 = f77F77OPTS = -c -OFOREXT = fOBJEXT = o
.$(FOREXT).$(OBJEXT):$(F77) $(F77OPTS) $<
iolib.a: iolib1.$(OBJEXT) \iolib2.$(OBJEXT) \iolib3.$(OBJEXT) \iolib4.$(OBJEXT) \iolib5.$(OBJEXT) \iolib6.$(OBJEXT) \falloc.oar r iolib.a *.oranlib iolib.a
iolib1.$(OBJEXT): iolib1.$(FOREXT) defines.inc gmscom.inciolib2.$(OBJEXT): iolib2.$(FOREXT) defines.inc gmscom.inciolib3.$(OBJEXT): iolib3.$(FOREXT) defines.inc gmscom.inciolib4.$(OBJEXT): iolib4.$(FOREXT) defines.inc gmscom.inciolib5.$(OBJEXT): iolib5.$(FOREXT) defines.inc gmscom.inciolib6.$(OBJEXT): iolib6.$(FOREXT) defines.inc gmscom.inc
falloc.o: falloc.ccc -c -DPOSTUC falloc.c
A makefile for a user application can look like:
F77 = f77F77OPTS = -c -OLD = f77LDOPTS = -o gamsmiles.out -BstaticFOREXT = fOBJEXT = oLIBEXT = a
102
EXENAME = gamsmiles.out
SRCS = main.$(FOREXT) miles.$(FOREXT) lusol.$(FOREXT) \ cplib.$(FOREXT) cpmain.$(FOREXT)
gfdict.$(FOREXT) \mpsge.$(FOREXT) nlio.$(FOREXT)
OBJS = main.$(OBJEXT) miles.$(OBJEXT) lusol.$(OBJEXT) \cplib.$(OBJEXT) cpmain.$(OBJEXT) gfdict.$(OBJEXT)
\mpsge.$(OBJEXT) nlio.$(OBJEXT) ../iolib/iolib.a
.SUFFIXES: .$(FOREXT) .$(OBJEXT)
.$(FOREXT).$(OBJEXT):$(F77) $(F77OPTS) $<
$(EXENAME): $(OBJS)$(LD) $(LDOPTS) $(OBJS)
main.$(OBJEXT): main.$(FOREXT)miles.$(OBJEXT): miles.$(FOREXT)lusol.$(OBJEXT): lusol.$(FOREXT)cplib.$OBJEXT): cplib.$(FOREXT)cpmain.$(OBJEXT): cpmain.$(FOREXT)gfdict.$(OBJEXT): gfdict.$(FOREXT)mpsge.$(OBJEXT) : mpsge.$(FOREXT)nlio.$(OBJEXT): nlio.$(FOREXT)
IBM VM CMS
The standard implementation is for the VS FORTRAN compiler, Release 2.(Timing is done with the library function CPUTIME.) For VM systems wenormally supply a TXTLIB which is compatible with VM/CMS or VM/XA, butdoes not exploit the 31-bit addressing of VM/XA. An "XA exploitive" library isalso available, but it will not run under VM/CMS. Similarly with MVS systems.
The GAMS control file and the screen output file must be equivalenced with thecorresponding Fortran file units outside your program. The following Rexxskeleton shows an example of this. (On MVS an exactly similar scheme is neededusing TSO ALLOCATE statements. The name of the control file in this case is ....)
/* Rexx solver EXEC */ /* We assign 90 to SCREEN in the solver (subroutineGFINIT) */
'FILEDEF 90 TERM' /* We assign 91 to IOSNTR in the solver (subroutineGFRCNT) */ /* The name of the control file is GAMSCNTR DATA */
'FILEDEF 91 DISK GAMSCNTR DATA' /* The solver program name is MYSOLVER (module) */
address COMMAND 'MYSOLVER''FILEDEF 90 CLEAR''FILEDEF 91 CLEAR'
/* Control is returned to GAMS automatically */
104
CHAPTER 5
EXAMPLES FOR LINEARSYSTEMS
LP-1 Fixed Array type of LP problem in FortranLP-2 Fixed Array type of LP problem in PascalLP-3 Dynamic Array type of LP problem in CLP-4 Dynamic Array type of LP problem in FortranLP-5 Example of MPS file generation of GAMS model
EXAMPLE LP-1
This example shows how to read an LP problem into a fixed size array type of LPsystem. The matrix is stored column wise, and an extra dummy objrective row isadded at the bottom.
C-------------------------------------------------------------------- PROGRAM EXAMPLEC--------------------------------------------------------------------CC Example how to read an LP into a fixed array LP systemC Data is stored in common block LPMODC
C-- common data
INTEGER MAXN, MAXN1, MAXM, MAXNZ PARAMETER (MAXN=100,MAXN1=101,MAXM=100,MAXNZ=1000) COMMON /LPMOD/ AA, IROW, JCOL, & LB, X, UB, RHS, & ISIGN, & N,M,NZ,OBJVAR, & GINF, GMINF ! gams values for + and - inf DOUBLE PRECISION GINF, GMINF DOUBLE PRECISIONAA(MAXNZ),LB(MAXN),UB(MAXN),RHS(MAXN),X(MAXN) INTEGER IROW(MAXNZ),JCOL(MAXN1),ISIGN(MAXM) INTEGER N,M,NZ,OBJVAR
C-- local vars
INTEGER IOSTA ! unit number of the status file INTEGER GFUNIT ! unit number for internal lib routines INTEGER IOLOG ! unit number log file INTEGER SCREEN ! unit number screen INTEGER IOCNTR ! unit number control file DOUBLE PRECISION XGV(30) ! storage control info INTEGER KGV(30) LOGICAL LGV(30) INTEGER DUMMY
C define the unit numbers
IOSTA = 10 IOLOG = 11 GFUNIT = 12 SCREEN = 13 IOCNTR = 14
106
C initialize and read control file
CALL GFINIT(GFUNIT, IOSTA, SCREEN) CALL GFRCNT(IOCNTR,IOLOG,.FALSE.,.FALSE., & XGV,KGV,LGV,DUMMY,DUMMY)
C open status file
CALL GFOPST()
C write a message to the status file
CALL GFSTCT('STARTC') WRITE(IOSTA,*) ' ******************************' WRITE(IOSTA,*) ' * SUPERLP, BY SOLVERS INC. *' WRITE(IOSTA,*) ' ******************************' WRITE(IOSTA,*) CALL GFSTCT('STOPC')
C store info in common block
M = KGV(1)+1 ! one extra contraint: objective row N = KGV(2) NZ = KGV(3)+1 ! and in that row 1 extra non-zero OBJVAR= KGV(7) GINF = XGV(10) GMINF = XGV(11)
IF (N.GT.MAXN) CALL LPERR(IOLOG,IOSTA,'TOO MANY VARIABLES') IF (M.GT.MAXM) CALL LPERR(IOLOG,IOSTA,'TOO MANY CONTRAINTS') IF (NZ.GT.MAXNZ) CALL LPERR(IOLOG,IOSTA,'TOO MANYNON-ZEROES')
CALL READAT(IOLOG,IOSTA)
END
C-------------------------------------------------------------------- SUBROUTINE READAT(IOLOG,IOSTA)C--------------------------------------------------------------------C READ DATA FILE
INTEGER IOLOG, IOSTA
C-- common data
INTEGER MAXN, MAXN1, MAXM, MAXNZ PARAMETER (MAXN=100,MAXN1=101,MAXM=100,MAXNZ=1000) COMMON /LPMOD/ AA, IROW, JCOL, & LB, X, UB, RHS, & ISIGN, & N,M,NZ,OBJVAR,
& GINF, GMINF ! gams values for + and - inf DOUBLE PRECISION GINF, GMINF DOUBLE PRECISIONAA(MAXNZ),LB(MAXN),UB(MAXN),RHS(MAXN),X(MAXN) INTEGER IROW(MAXNZ),JCOL(MAXN1),ISIGN(MAXM) INTEGER N,M,NZ,OBJVAR
C-- local vars
PARAMETER(DWARF=1.0D-10,HUGE=1.0D10) DOUBLE PRECISION X5VEC(5) INTEGER I4VEC(4) INTEGER I, J, NZCOL, IDUMMY, NNZ
WRITE(IOLOG,901)
DO 10, I=1,M-1 CALL GFRROWX(X5VEC,I4VEC) RHS(I) = X5VEC(2) ISIGN(I) = I4VEC(1) 10 CONTINUE
C add objective row
RHS(M) = 0.0D0 ISIGN(M) = 3 ! a free row
WRITE(IOLOG,902)
NNZ = 1
DO 20, J=1,N CALL GFRCOLX(X5VEC,I4VEC) LB(J) = X5VEC(1) IF (LB(J).EQ.GMINF) LB(J) = -HUGE X(J) = X5VEC(2) UB(J) = X5VEC(3) IF (UB(J).EQ.GINF) UB(J) = HUGE NZCOL = I4VEC(1) JCOL(J) = NNZ DO 30, I=1,NZCOL CALL GFRCOF(AA(NNZ),IROW(NNZ),IDUMMY) NNZ = NNZ + 1 30 CONTINUE IF (J.EQ.OBJVAR) THEN AA(NNZ) = 1.0D0 IROW(NNZ) = M
NNZ = NNZ+1 ENDIF 20 CONTINUE JCOL(NNZ) = N+1
WRITE(IOLOG,903)
108
901 FORMAT(' READING ROWS...') 902 FORMAT(' READING COLUMNS...') 903 FORMAT(' PROBLEM IS LOADED')
END
C-------------------------------------------------------------------- SUBROUTINE LPERR(IOSTA, IOLOG, MESS)C--------------------------------------------------------------------C write message to status file and log file and terminate
IMPLICIT NONE INTEGER IOSTA, IOLOG CHARACTER*(*) MESS
CALL GFSTCT('SYSOUT')
WRITE(IOSTA,100) MESS WRITE(IOLOG,100) MESS
100 FORMAT(' *** ERROR: ',A80)
STOP
END
EXAMPLE LP-2
The Turbo-pascal version of example LP-1 is:
program test;{$N+,E+}
uses iolib, typedef;
const maxn = 100; maxn1 = 101; maxm = 100; maxnz = 1000;
type mess = packed array[1..20] of char;
var aa : array[1..maxnz] of double; lb, ub, x : array[1..maxn] of double; rhs : array[1..maxm] of double; irow : array[1..maxnz] of integer; jcol : array[1..maxn1] of integer; isign : array[1..maxm] of integer;
m : integer; n : integer; nz : integer; objvar : integer; ginf : double; gminf : double;
cntinfo : cntrec;
procedure lperr(var statusfile : text; var logfile : text; message : mess); begin gfstct('sysou'); writeln(statusfile,' *** Error: ',message); writeln(logfile ,' *** Error: ',message); halt; end;
procedure readat(var logfile : text;
110
var statusfile : text); const dwarf = 1.0e-10; huge = 1.0e10; var row : rowrec; col : colrec; nzcol : inte ger; idummy : integer; nnz : integer; i, j : integer;
begin writeln(logfile,'Reading rows ...'); for i := 1 to m-1 do begin gfrrowx(row); rhs[i] := row.rdata[2]; isign[i] := row.idata[1]; end;
rhs[m] := 0.0; isign[m] := 3;
writeln(logfile,'Reading columns ...'); nnz := 1; for j := 1 to n do begin gfrcolx(col); lb[j] := col.cdata[1]; if (lb[j]=gminf) then lb[j] := -huge; x[j] := col.cdata[2]; ub[j] := col.cdata[3]; if (ub[j]=ginf) then ub[j] := huge; nzcol := col.idata[1]; jcol[j] := nnz; for i := 1 to nzcol do begin gfrcof(aa[nnz], irow[nnz], idummy); nnz := succ(nnz); end; if (j=objvar) then begin aa[nnz] := 1.0; irow[nnz] := m;
nnz := nnz + 1; end; end;
jcol[nnz] := n+1; writeln(logfile,'Problem is loaded');
end;
begin gfinit; gfrcnt(false, false,cntinfo); gfopst;
gfstct('start'); writeln(iosta,' ****************************** '); writeln(iosta,' * SUPERLP, BY SOLVERS INC. * '); writeln(iosta,' ****************************** '); writeln(iosta); gfstct('stopc');
m := cntinfo.kgv[1]+1; n := cntinfo.kgv[2]; nz := cntinfo.kgv[3]+1; objvar := cntinfo.kgv[7]; ginf := cntinfo.xgv[10]; gminf := cntinfo.xgv[11];
if (n>maxn) then lperr(iolog, iosta, 'Too many variables '); if (m>maxm) then lperr(iolog, iosta, 'Too many constraints'); if (nz> maxnz) then lperr(iolog, iosta, 'Too many non-zeroes ');
readat(iolog, iosta);
end.
112
EXAMPLE LP-3
C provides good facilities for dynamic memory allocation and variable lengtharrays. The next example shows how to exploit these features.
/* * example.c * * run as "example gamscntr.scr" * */#include <stdio.h>#include <stdlib.h>#include "iolib.h"
#define HUGE 1.0E31#define DWARF 1.0E-20
int m,n,nz,objvar;double ginf, gminf;double *aa;double *lb,*x,*ub;double *rhs;int *irow;int *jcol;int *isign;
void readat(logfile, statusfile)FILE *logfile, *statusfile;{ rowrec row; colrec col; int nzcol; int idummy; int nnz; int i,j;
fprintf(logfile,"Reading rows ...\n"); for (i=0;i<m-1;++i) { gfrrowx(&row); rhs[i] = row.rdata[2]; isign[i] = row.idata[1]; }
/* objective row at the end */ rhs[m-1] = 0.0; isign[m-1] = 3;
fprintf(logfile,"Reading columns ...\n"); nnz = 0; for (j=0;j<n;++j) { gfrcolx(&col);
lb[j] = col.cdata[1]; if (lb[j] == gminf) lb[j] = -HUGE; x[j] = col.cdata[2]; ub[j] = col.cdata[3]; if (ub[j] == ginf) ub[j] = HUGE; nzcol = col.idata[1]; jcol[j] = nnz; for (i=0;i<nzcol;++i) { gfrcof(&aa[nnz],&irow[nnz],&idummy); --irow[nnz]; ++nnz; } if (j==objvar) { aa[nnz] = 1.0; irow[nnz] = m-1; /* objective row */ ++nnz; } }
jcol[n] = nnz;
fprintf(logfile,"Problem is loaded\n"); gfstct("START"); fprintf(statusfile,"Problem is loaded\n"); gfstct("STOPC");}
char *mymalloc(size)int size;{ char *p;
p = (char *) malloc(size); if (p==NULL) { fprintf(gfiolog,"ERROR: not enough memory"); exit(1); } return ( p );}
main(argc, argv)int argc;char *argv[];{
cntrec cntinfo; char *statfile;
gfinit(); gfrcnt(FALSE,FALSE,&cntinfo,argv[1]); gfopst();
114
gfstct("start"); fprintf(gfiosta," ********************************\n"); fprintf(gfiosta," * super_lp, by solvers inc. *\n"); fprintf(gfiosta," ********************************\n\n"); gfstct("stopc");
m = cntinfo.kgv[1]+1; /* one extra for dummy objective row */ n = cntinfo.kgv[2]; nz = cntinfo.kgv[3]+1; /* one extra element in objective */ objvar = cntinfo.kgv[7]; /* no need to subtract one: already done by gfrcnt */ ginf = cntinfo.xgv[10]; gminf = cntinfo.xgv[11];
aa = (double *) mymalloc(nz*sizeof(double)); lb = (double *) mymalloc(n*sizeof(double)); ub = (double *) mymalloc(n*sizeof(double)); x = (double *) mymalloc(n*sizeof(double)); rhs = (double *) mymalloc(m*sizeof(double)); irow = (int *) mymalloc(nz*sizeof(int)); jcol = (int *) mymalloc((n+1)*sizeof(int)); isign = (int *) mymalloc(m*sizeof(int));
readat(gfiolog, gfiosta);
}
EXAMPLE LP-4
This example shows how to setup a dynamic memory Fortran system. Notice thatafter a nesting two subroutine calls we can code as if it is a fixed size array type ofsystem. So all the dirty code concering the dynamic memory can be isolated in onefile, that contains the few outermost subroutines and the program.
C-------------------------------------------------------------------- PROGRAM EXAMPLEC--------------------------------------------------------------------CC Example how to read an LP into a dynamic array LP systemCC
IMPLICIT NONE
COMMON /DYNARR/ Z DOUBLE PRECISION Z(1) INTEGER CORESZ
CORESZ = 2
CALL SUB1(Z,CORESZ)
END
C-------------------------------------------------------------------- SUBROUTINE SUB1(Z, CORESZ)C--------------------------------------------------------------------
IMPLICIT NONE
INTEGER CORESZ DOUBLE PRECISION Z(CORESZ)
INTEGER INTSIZ PARAMETER(INTSIZ=2) ! 2 integers fit in a real*8 (on manymachines)
COMMON /LPMOD/ N,M,NZ, ! #cols, #rows, #non-zeroes & MA,MIROW,MJCOL,MLB,MUB,MRHS,MISIGN,MX, ! sizes & PA,PIROW,PJCOL,PLB,PUB,PRHS,PISIGN,PX !position INTEGER N,M,NZ,MA,MIROW,MJCOL,MLB,MUB,MRHS,MISIGN,MX
116
INTEGER PA,PIROW,PJCOL,PLB,PUB,PRHS,PISIGN,PX
C-- local vars
INTEGER IOSTA ! unit number of the status file INTEGER GFUNIT ! unit number for internal lib routines INTEGER IOLOG ! unit number log file INTEGER SCREEN ! unit number screen INTEGER IOCNTR ! unit number control file DOUBLE PRECISION XGV(30) ! storage control info INTEGER KGV(30) LOGICAL LGV(30) INTEGER DUMMY INTEGER NEEDED ! memory needed INTEGER MEMGOT, MAXMEM ! allocated, available INTEGER ISTART ! first useable position in z INTEGER OBJVAR DOUBLE PRECISION GMINF, GINF
C define the unit numbers
IOSTA = 10 IOLOG = 11 GFUNIT = 12 SCREEN = 13 IOCNTR = 14
C initialize and read control file
CALL GFINIT(GFUNIT, IOSTA, SCREEN) CALL GFRCNT(IOCNTR, IOLOG, .FALSE., & .FALSE., XGV, KGV, LGV, DUMMY, DUMMY)
C open status file
CALL GFOPST()
C write a message to the status file
CALL GFSTCT('STARTC') WRITE(IOSTA,*) ' ******************************' WRITE(IOSTA,*) ' * SUPERLP, BY SOLVERS INC. *' WRITE(IOSTA,*) ' ******************************' WRITE(IOSTA,*) CALL GFSTCT('STOPC')
C extract info
M = KGV(1)+1 ! one extra contraint: objective row N = KGV(2) NZ = KGV(3)+1 ! and in that row 1 extra non-zero OBJVAR= KGV(7) GINF = XGV(10)
GMINF = XGV(11)
C Do a memory estimationC In "real life" add space for basis, lu-factors, eta-vectors,C workspace, etc. All arrays of which the size depends on theC size of the problem should be accomodated within this array.
MA = NZ ! NZ reals are needed to store A MIROW = 1 + (NZ/INTSIZ) ! space needed to store IROW MJCOL = 1 + ((N+1)/INTSIZ) ! etc. MLB = N MUB = N MX = N MRHS = M MISIGN = 1 + (M/INTSIZ)
CALL MPART(1,NEEDED) ! calculate size of memory needed
WRITE(IOLOG,900) NEEDED*8
CALL GFGETM(Z, ISTART, NEEDED, MEMGOT, MAXMEM)
WRITE(IOLOG,901) MEMGOT*8 WRITE(IOLOG,902) MAXMEM*8 IF (MEMGET.LT.NEEDED) & CALL LPERR(IOLOG,IOSTA,' NOT ENOUGH MEMORY')
CALL MPART(ISTART,DUMMY) ! calculate partitioning
CALL SUB2(IOLOG, IOSTA, M, N, N+1, NZ, OBJVAR, GMINF, GINF, & Z(PA),Z(PIROW),Z(PJCOL),Z(PLB), & Z(PUB),Z(PRHS),Z(PISIGN),Z(PX))
900 FORMAT(' MEMORY NEEDED :',I8,' BYTES') 901 FORMAT(' MEMORY USED :',I8,' BYTES') 902 FORMAT(' MAX. AVAILABLE :',I8,' BYTES')
END
C-------------------------------------------------------------------- SUBROUTINE SUB2(IOLOG, IOSTA, M, N, N1, NZ, OBJVAR, GMINF,GINF, & AA, IROW, JCOL, LB, UB, RHS, ISIGN, X)C--------------------------------------------------------------------
IMPLICIT NONE
C now we can work with "normal" arrays
118
INTEGER IOLOG, IOSTA, M, N, N1, NZ DOUBLE PRECISION AA(NZ), LB(N), UB(N), X(N), RHS(M) DOUBLE PRECISION GMINF, GINF INTEGER IROW(NZ), JCOL(N1), ISIGN(M), OBJVAR
C now read the data file
CALL READAT(IOLOG, IOSTA, ! in case we want to writesomething & M, N, N1, NZ, OBJVAR, GMINF, GINF, & AA, IROW, JCOL, LB, UB, RHS, ISIGN, X)
C place here the call to the solver
C Here come calls to write the solution
CALL GFCLOS() ! close down the I/O library END
C-------------------------------------------------------------------- SUBROUTINE READAT(IOLOG, IOSTA, M, N, N1, NZ, OBJVAR, GMINF, & GINF, AA, IROW, JCOL, LB, UB, RHS, ISIGN,X)C--------------------------------------------------------------------C READ DATA FILE
IMPLICIT NONE
C-- PARAMETERS
INTEGER IOLOG, IOSTA, M, N, N1, NZ DOUBLE PRECISION AA(NZ), LB(N), UB(N), X(N), RHS(M) DOUBLE PRECISION AA(NZ), GMINF, GINF INTEGER IROW(NZ), JCOL(N1), ISIGN(M), OBJVAR
C-- LOCALS DOUBLE PRECISION X5VEC(5) INTEGER I4VEC(4) INTEGER I, J, NZCOL, IDUMMY, NNZ
WRITE(IOLOG,901)
DO 10, I=1,M-1 CALL GFRROWX(X5VEC,I4VEC) RHS(I) = X5VEC(2) ISIGN(I) = I4VEC(1) 10 CONTINUE
C add objective row
RHS(M) = 0.0D0 ISIGN(M) = 3 ! a free row
WRITE(IOLOG,902)
NNZ = 1
DO 20, J=1,N CALL GFRCOLX(X5VEC,I4VEC) LB(J) = X5VEC(1) IF (LB(J).EQ.GMINF) LB(J) = -HUGE X(J) = X5VEC(2) UB(J) = X5VEC(3) IF (UB(J).EQ.GINF) UB(J) = HUGE NZCOL = I4VEC(1) JCOL(J) = NNZ DO 30, I=1,NZCOL CALL GFRCOF(AA(NNZ),IROW(NNZ),IDUMMY) NNZ = NNZ + 1 30 CONTINUE IF (J.EQ.OBJVAR) THEN AA(NNZ) = 1.0D0 IROW(NNZ) = M NNZ = NNZ + 1 ENDIF 20 CONTINUE
JCOL(N+1) = NNZ
WRITE(IOLOG,903)
901 FORMAT(' READING ROWS...') 902 FORMAT(' READING COLUMNS...') 903 FORMAT(' PROBLEM IS LOADED')
END
C-------------------------------------------------------------------- SUBROUTINE LPERR(IOSTA, IOLOG, MESS)C--------------------------------------------------------------------C write message to status file and log file and terminate
IMPLICIT NONE INTEGER IOSTA, IOLOG CHARACTER*(*) MESS
CALL GFSTCT('SYSOUT')
WRITE(IOSTA,100) MESS WRITE(IOLOG,100) MESS
100 FORMAT(' *** ERROR: ',A80)
120
STOP
END
C-------------------------------------------------------------------- SUBROUTINE MPART(ISTART,IEND)C--------------------------------------------------------------------C this subroutine partitions the memory whereC ISTART is the first available REAL*8 slot.C It returns IEND, the last occupied slot.C Use also to esimate memory requirements by callingC it with ISTART=1;
IMPLICIT NONE INTEGER ISTART,IEND
COMMON /LPMOD/ N,M,NZ, ! #cols, #rows, #non-zeroes & MA,MIROW,MJCOL,MLB,MUB,MRHS,MISIGN,MX, ! sizes & PA,PIROW,PJCOL,PLB,PUB,PRHS,PISIGN,PX !position INTEGER N,M,NZ,MA,MIROW,MJCOL,MLB,MUB,MRHS,MISIGN,MX INTEGER PA,PIROW,PJCOL,PLB,PUB,PRHS,PISIGN,PX
INTEGER INTSIZ
INTSIZ = 2 ! two 4 byte integers fit in one real*8
PA = ISTART PIROW = PA + MA PJCOL = PIROW + MIROW PLB = PJCOL + MJCOL PUB = PLB + MLB PX = PUB + MUB PRHS = PX + MX PISIGN = PRHS + MRHS IEND = PISIGN + MISIGN - 1
END
EXAMPLE LP-5
The next example shows how an MPS file can be generated for a linear model.
C-------------------------------------------------------------------- PROGRAM GAMSMPSC--------------------------------------------------------------------CC Example how to read an LP, and to produce an MPS fileCC
IMPLICIT NONE
COMMON /DYNARR/ Z DOUBLE PRECISION Z(1) INTEGER CORESZ
CORESZ = 2
CALL SUB1(Z,CORESZ)
END
C-------------------------------------------------------------------- SUBROUTINE SUB1(Z, CORESZ)C--------------------------------------------------------------------
IMPLICIT NONE
INTEGER CORESZ DOUBLE PRECISION Z(CORESZ)
INTEGER INTSIZ PARAMETER(INTSIZ=2) ! 2 integers fit in a real*8
COMMON /LPMOD/ N,M,NZ, ! #cols, #rows, #non-zeroes & MLB, MUB, MRHS, ! #lb, #ub, #rhs slots & PLB, PUB, PRHS ! positions INTEGER N,M,NZ,MLB,MUB, MRHS INTEGER PLB, PUB, PRHS
C-- local vars
INTEGER IOSTA ! unit number of the status file INTEGER GFUNIT ! unit number for internal lib routines INTEGER IOLOG ! unit number log file
122
INTEGER IOMPS ! unit number mps file INTEGER SCREEN ! unit number screen INTEGER IOCNTR ! unit number control file DOUBLE PRECISION XGV(30) ! storage control info INTEGER KGV(30) LOGICAL LGV(30) INTEGER DUMMY INTEGER NEEDED ! memory needed INTEGER MEMGOT, MAXMEM ! allocated, available INTEGER ISTART ! first useable position in z INTEGER OBJVAR DOUBLE PRECISION GMINF, GINF
C define the unit numbers
IOSTA = 10 IOLOG = 11 GFUNIT = 12 SCREEN = 13 IOCNTR = 14 IOMPS = 15
C initialize and read control file
CALL GFINIT(GFUNIT, IOSTA, SCREEN) CALL GFRCNT(IOCNTR, IOLOG, .FALSE., & .FALSE., XGV, KGV, LGV, DUMMY, DUMMY)
C open status file
CALL GFOPST()
C write a message to the status file
CALL GFSTCT('STARTC') WRITE(IOSTA,*) ' **********************************' WRITE(IOSTA,*) ' * GAMSMPS, BY GAMS DEVELOPMENT *' WRITE(IOSTA,*) ' **********************************' WRITE(IOSTA,*) WRITE(IOSTA,*) ' This solver will generate an MPS file ofyour' WRITE(IOSTA,*) ' current model. The file is called GAMS.MPS' WRITE(IOSTA,*) ' and should be in your current directory.' WRITE(IOSTA,*) CALL GFSTCT('STOPC')
C extract info
M = KGV(1)+1 ! one extra contraint: objective row N = KGV(2) NZ = KGV(3)+1 ! and in that row 1 extra non-zero OBJVAR= KGV(7)
GINF = XGV(10) GMINF = XGV(11)
C Do a memory estimationC we need to store the bounds, and the right hand sidec so that is 2*n+m slots.
MLB = N MUB = N MRHS = M
CALL MPART(1,NEEDED) ! calculate size of memory needed
WRITE(IOLOG,900) NEEDED*8
CALL GFGETM(Z, ISTART, NEEDED, MEMGOT, MAXMEM)
WRITE(IOLOG,901) MEMGOT*8 WRITE(IOLOG,902) MAXMEM*8 IF (MEMGOT.LT.NEEDED) & CALL LPERR(IOLOG,IOSTA,' NOT ENOUGH MEMORY')
CALL MPART(ISTART,DUMMY) ! calculate partitioning
CALL SUB2(IOLOG, IOSTA, IOMPS, & M, N, N+1, NZ, OBJVAR, GMINF, GINF, & Z(PLB), Z(PUB), Z(PRHS))
900 FORMAT(' MEMORY NEEDED :',I8,' BYTES') 901 FORMAT(' MEMORY USED :',I8,' BYTES') 902 FORMAT(' MAX. AVAILABLE :',I8,' BYTES')
END
C-------------------------------------------------------------------- SUBROUTINE WRTMPS(IOMPS, FIELD1, FIELD2, FIELD3, FIELD4)C--------------------------------------------------------------------CC Write a single line to the mps fileCC Fields start at columns 2, 5, 15 and 25
c --- arguments INTEGER IOMPS ! io unit mps file CHARACTER*(*) FIELD1, FIELD2, FIELD3, FIELD4
c --- locals CHARACTER*36 LINE INTEGER LAST, I
124
LINE = ' ' LAST = 0
IF (LEN(FIELD1).GT.0) THEN LAST = 1 + LEN(FIELD1) LINE(2:LAST) = FIELD1 ENDIF
IF (LEN(FIELD2).GT.0) THEN LAST = 4 + LEN(FIELD2) LINE(5:LAST) = FIELD2 ENDIF
IF (LEN(FIELD3).GT.0) THEN LAST = 14 + LEN(FIELD3) LINE(15:LAST) = FIELD3 ENDIF
IF (LEN(FIELD4).GT.0) THEN LAST = 24 + LEN(FIELD4) LINE(25:LAST) = FIELD4 ENDIF
WRITE(IOMPS,100) LINE(1:LAST)
100 FORMAT (A)
RETURN END
C-------------------------------------------------------------------- CHARACTER*8 FUNCTION ROWNAM(K)C--------------------------------------------------------------------
C --- arguments INTEGER K
c --- locals CHARACTER*8 NAME
NAME = ' ' WRITE(NAME,100) K ROWNAM = NAME
100 FORMAT('R',I7.7)
RETURN END
C--------------------------------------------------------------------
CHARACTER*8 FUNCTION COLNAM(K)C--------------------------------------------------------------------
C --- arguments INTEGER K
c --- locals CHARACTER*8 NAME
NAME = ' ' WRITE(NAME,100) K COLNAM = NAME
100 FORMAT('C',I7.7)
RETURN END
C-------------------------------------------------------------------- CHARACTER*12 FUNCTION VALUE(X)C--------------------------------------------------------------------
C --- arguments DOUBLE PRECISION X
c --- locals CHARACTER*12 NAME CHARACTER*7 FRMT DOUBLE PRECISION ABSX INTEGER SIZE, DECS
NAME = ' ' FRMT = '(F12.9)' ABSX = ABS(X)
IF (ABSX.GE.1.0D0) THEN SIZE = NINT(LOG10(ABSX)+0.5D0) IF (SIZE.GT.10) & WRITE(*,*) 'Overflow in MPS file, ****** written' DECS = MAX(0,10-SIZE) WRITE(FRMT(6:6),'(I1)') DECS ENDIF
WRITE(NAME,FRMT) X VALUE = NAME
RETURN END
126
C-------------------------------------------------------------------- SUBROUTINE SUB2(IOLOG, IOSTA, IOMPS, & M, N, N1, NZ, OBJVAR, GMINF, GINF, & LB, UB, RHS)C--------------------------------------------------------------------
IMPLICIT NONE
C now we can work with "normal" arrays
INTEGER IOLOG, IOSTA, IOMPS, M, N, N1, NZ DOUBLE PRECISION LB(N), UB(N), RHS(M) DOUBLE PRECISION GMINF, GINF INTEGER OBJVAR
DOUBLE PRECISION X5VEC(5) INTEGER I4VEC(4) DOUBLE PRECISION AA, ABSX INTEGER I, J, NZCOL, IDUMMY, IROW
CHARACTER*8 ROWNAM, COLNAM CHARACTER*12 VALUE
DOUBLE PRECISION DWARF PARAMETER(DWARF=1.0D-8)
CHARACTER RTYP(4) DATA RTYP/'E','G','L','N'/
OPEN(UNIT=IOMPS, FILE='GAMS.MPS') ! ????????????????????? WRITE(IOMPS,950) 'GAMSMOD' WRITE(IOMPS,951)
WRITE(IOLOG,901)
DO 10, I=1,M-1 CALL GFRROWX(X5VEC,I4VEC) RHS(I) = X5VEC(2) ! store rhs for rhs-section CALL WRTMPS(IOMPS, RTYP(I4VEC(1)+1),ROWNAM(I),' ',' ') 10 CONTINUE
C add objective row
RHS(M) = 0.0D0 CALL WRTMPS(IOMPS, 'N',ROWNAM(M),' ',' ')
WRITE(IOLOG,902) WRITE(IOMPS,953)
DO 20, J=1,N CALL GFRCOLX(X5VEC,I4VEC) LB(J) = X5VEC(1) UB(J) = X5VEC(3) NZCOL = I4VEC(1) DO 30, I=1,NZCOL CALL GFRCOF(AA,IROW,IDUMMY) CALL WRTMPS(IOMPS,'',COLNAM(J),ROWNAM(IROW),VALUE(AA)) 30 CONTINUE IF (J.EQ.OBJVAR) THEN CALL WRTMPS(IOMPS,'',COLNAM(J),ROWNAM(M),VALUE(1.0D0)) ENDIF 20 CONTINUE
WRITE(IOLOG,903) WRITE(IOMPS,957)
DO 40,I=1,M ABSX = ABS(RHS(I)) IF (ABSX.GT.DWARF) THEN CALL WRTMPS(IOMPS,' ','RHS',ROWNAM(I),VALUE(RHS(I))) ENDIF 40 CONTINUE
WRITE(IOLOG,904) WRITE(IOMPS,961)
DO 50,I=1,N IF (LB(I).EQ.UB(I)) THEN CALL WRTMPS(IOMPS,'FX','BOUND',COLNAM(I),VALUE(LB(I))) ELSE IF (LB(I).EQ.GMINF) THEN IF (UB(I).EQ.GINF) THEN CALL WRTMPS(IOMPS,'FR','BOUND',COLNAM(I),' ') ELSE CALL WRTMPS(IOMPS,'MI','BOUND',COLNAM(I),' ') IF (UB(I).NE.0.0D0) THEN CALLWRTMPS(IOMPS,'UP','BOUND',COLNAM(I),VALUE(UB(I))) ENDIF ENDIF ELSE IF (UB(I).NE.GINF) THEN CALLWRTMPS(IOMPS,'UP','BOUND',COLNAM(I),VALUE(UB(I))) ENDIF IF (LB(I).NE.0.0D0) THEN CALLWRTMPS(IOMPS,'LO','BOUND',COLNAM(I),VALUE(LB(I))) ENDIF ENDIF 50 CONTINUE
128
WRITE(IOMPS,966) WRITE(IOLOG,905)
CALL GFCLOS() ! close down the I/O library CLOSE(IOMPS)
901 FORMAT(' READING ROWS AND WRITING ROW SECTION') 902 FORMAT(' READING COLUMNS AND WRITING COLUMN SECTION') 903 FORMAT(' WRITING RHS SECTION') 904 FORMAT(' WRITING BOUND SECTION') 905 FORMAT(' DONE')
950 FORMAT('NAME',10X,A) 951 FORMAT('ROWS') 953 FORMAT('COLUMNS') 957 FORMAT('RHS') 961 FORMAT('BOUNDS') 966 FORMAT('ENDATA')
END
C-------------------------------------------------------------------- SUBROUTINE LPERR(IOSTA, IOLOG, MESS)C--------------------------------------------------------------------C write message to status file and log file and terminate
IMPLICIT NONE INTEGER IOSTA, IOLOG CHARACTER*(*) MESS
CALL GFSTCT('SYSOUT')
WRITE(IOSTA,100) MESS WRITE(IOLOG,100) MESS
100 FORMAT(' *** ERROR: ',A)
STOP
END
C-------------------------------------------------------------------- SUBROUTINE MPART(ISTART,IEND)C--------------------------------------------------------------------C this subroutine partitions the memory whereC ISTART is the first available REAL*8 slot.C It returns IEND, the last occupied slot.
C Use also to esimate memory requirements by callingC it with ISTART=1;
IMPLICIT NONE INTEGER ISTART,IEND
COMMON /LPMOD/ N,M,NZ, ! #cols, #rows, #non-zeroes & MLB, MUB, MRHS, ! #lb, #ub, #rhs slots & PLB, PUB, PRHS ! positions INTEGER N,M,NZ,MLB,MUB, MRHS INTEGER PLB, PUB, PRHS
PLB = ISTART PUB = PLB + MLB PRHS = PUB + MUB IEND = PRHS+ MRHS
END
130
CHAPTER 6
NON-LINEAR SECTION OF GAMSINPUT-OUTPUT LIBRARY
ll Introductionll Storagell How the Interpreter worksll Storing gradients
INTRODUCTION
This document describes how algorithms for solving non-linear programmingproblems can be hooked up to GAMS. A prerequisite is a thorough understandingof the linear I/O library. We advise first to set up your code so that it can solvesimple LP's.
The core of this library is the non-linear interpreter. This interpreter executes codethat is produced by GAMS. It calculates based on the current level values X newvalues for thefunctions, and for the gradients. The gradients are plugged back into the matrix (i.e.it updates the non-linear non-zeroes in the matrix). The function values are returnedin an array.
The interpreter works only on the non-linear part of the problem, i.e. the linear partof the function values are not calculated. These parts can be added later on.
The interpreter works on an equation by equation basis. It calculates both thegradients and the function values. If only function values are needed, it is possibleto strip out the instructionsthat involve the gradients. Notice however, that the gain in execution speed is notvery high, because GAMS produces quite efficient code, in which lots ofintermediate results are shared between the function and derivative calculations.
For most users the library consists of only two high-level components: a routine toread in the non-linear instructions and set up the datastructures, and a routine theevaluates the non-linear functions and gradients (this one executes the interpreter).An example of such a generic is included in the appendix. That code executes thefollowing steps:
1. Initialize IO library and read control file.2. Allocate memory and partition it.3. Read the matrix file.4. Read non-linear instructions and set-up data structures.5. Evaluate function values and gradients at current point.
132
Note that evaluating the gradients at the original point is not very useful: GAMSalready did this for you, and the matrix already contains the correct gradients for thenon-linear non-zeroes.
In addition we provide a large amount of source code that shows how to load theinstructions, how to patch them and how to run the interpreter. More advancedapplications may require access to other low-level routines.
Currently the non-linear IO library is only available in Fortran and C.
STORAGE
There are two objects to store for non-linear models: the non-linear instructionsthemselves, and some non-linear workspace, which is used for storing constantsand the stack.
The instructions can be stored in an INTEGER*4 array of length lenins which isreturned in KNV(4) by GFRCNT. It is possible to scatter individual equationsaround, butno statistics are available on the length of the non-linear code for each equation, sothis can only be done after reading (part of) the non-linear code.
The constants and reserved space for the stack should be stored in an doubleprecision array of length nlwork, which is returned in the parameter KNV(5) byGFRCNT.
HOW THE INTERPRETER WORKS
The interpreter executes the non-linear instructions. These instructions are stored in{INTEGER*4} array's, in an equation by equation fashion. The interpretercalculates the level of the nonlinear part of a single equation and the gradients, andplugs those gradients back into the matrix. There is no easy way to ask theinterpreter to update the gradientsfor a certain column. Each instruction has the following format:
opcode address
The precise format (2 byte opcode, 2 byte address field versus 1 byte opcode, 3 byteaddress field) is machine dependent: we optimize here for machine architecture.Examples of instructions are "add variable X(address) to value on top of the stack",and "store row level in user parameter G, by assigning it the value on top of thestack" (in this case the address field is irrelevant). For a large extend the interpretercan be considered as a black box. A few instructions need more attention however.
STORING GRADIENTS
The most important one is the "store derivative" instruction. This instruction putsthe gradient of equation i and variable j, i.e. δfi(x)/δxj back into the matrix. The
134
location within the matrix is contained in the address field of the instruction. Thislocation has to be stored there before running the interpreter, by some initializationroutine, typically in step 4 of the algorithm outlined above.
The example routine that performs step 4 is shown in in Appendix 2. First we readthe non-linear code, then we compute an array with pointers to the store derivativeinstructions, and then we update the address field of these instructions. The pointersare stored in an integer array of size nz (the same size as the matrix), which shouldcontain before calling the non-linear set up routine the non-linearity pattern of thematrix:
jtyp[k] = 0 if corresponding nonzero element A[k] is linear 1 otherwise.
This array can be set up this way while reading the matrix: parameterNLTYP of subroutine GFRCOF (read non-zero coefficient) is 0 for a linearnon-zero, and 1 for a non-linear non-zero.
The subroutine GFRINS reads the instructions and the constants. Then we callGFJTYP to set up an array with pointers to the store derivative instructions, andfinally we use thisarray to update them.
CHAPTER 7
GAMS NONLINEARINPUT/OUTPUT SUBROUTINES
GFDMPAGFDMPEGFINSFGFJTYPGFNSTOGFNTRPGFRINS
Dump instructions pertaining to one equation in ASCII formatDump all instructions in ASCII formatReturn Instruction file nameFinds the Store Derivative instructionsStores Nonlinear instructionsCalculates nonlinear function value and gradientsRead Nonlinear instructions
136
SUBROUTINE GFDMPA
Subroutine GFDMPA dumps all the instructions. It assumes that they are sitting in acontiguous array. The routine GFRINS delivers them this way, and if you did notscatter them around you can use this routine to dump all the non-linear instructionsto the status file.
Fortran SUBROUTINE GFDMPA(MESS,INSTR,LINS)CHARACTER*(*) MESSINTEGER LINSINTEGER INSTR(LINS)
Pascal n.a.
C n.a.
Description of the parameters
MESS (input)
Character string containing a message that is printed to the status file.
INSTR (input)
Instruction array containing the non-linear instructions.
LINS (input)
Length of the instruction array. Is returned by GFCNTR in KNV(4).
SUBROUTINE GFDMPE
Subroutine GFDMPE dumps the instructions belonging to one equation in humanreadible format to the status file. This routine is for debugging. You may need it ifyou try to patch the instructions for a particular purpose.
Fortran SUBROUTINE GFDMPE(MESS,INSTR,LINS)CHARACTER*(*) MESSINTEGER LINSINTEGER INSTR(LINS)
Pascal n.a.
C n.a.
Description of the parameters
MESS (input)
Character string containing a message that is printed to the status file.
INSTR (input)
Instruction array containing non-linear instructions for a particular equation.
LINS (input)
Number of instructions for this equation.
138
SUBROUTINE GFINSF
Subroutine GFINSF returns the instruction file name so that you can open theinstruction file. This routine should be called after GFRCNT. It is called by thehigh-level subroutine GFRINS.
Fortran SUBROUTINE GFINSF(FLN)CHARACTER*80 FLN
Pascal n.a.
C n.a.
SUBROUTINE GFJTYP
Subroutine GFJTYP finds the Store Derivative instructions.All instructions aresupposed to be contiguous. It returns the pointers to the store derivative instructionsin the integer array JTYP(LJAC) which should contain a 0 for a linear non-zero and a1 for a non-linear non-zero on input. On output JTYP(K) is still 0 if AA[k] is a linearnon-zero element, but if it is a non-linear element, it contains the relative positionof the store derivative instruction with respect to the start of the row to wich AA[k]
belongs. That means on output linear elements have a JTYP[k] of 0, and non-linearelements have a positive JTYP[k].
Fortran SUBROUTINE GFJTYP(INSTR, LINS, IROW, JCOL, JLEN,& JTYP, LJAC, ISCR, LSCR)INTEGER LINS, LJAC, LCOL, LSCRINTEGER IROW(LJAC), JTYP(LJAC), JCOL(LCOL)INTEGER JLEN(LCOL), ISCR(LSCR)INTEGER INSTR(LINS)
Pascal n.a.
C n.a.
Description of the parameters
INSTR (input)
The array that holds the non-linear instructions.
LINS (input)
Length of the instruction array. Is returned by GFCNTR in KNV(4).
IROW (input)
Integer array holding the row indices of the non-zero elements.
JROW (input)
Integer array holding the column pointers.
JLEN (input)
140
Integer array holding the length of each column.
JLEN (input)
Integer array holding the length of each column.
JTYP (input/output)
Integer array holding on input the non-linearity pattern of thenon-zeroes:
jtyp[k] = 0 if corresponding nonzero element A[k] is linear1 otherwise.
On output JTYP[k] for non-linear non-zero elements, points to the store derivativeinstructions (relative to the beginning of each equation). The value of JTYP[k] forthe linear non-zero elements remains 0.
LJAC (input)
Length of the array holding the matrix (jacobian). If there are no holes in the matix(i.e. if jcol[j]+jlen[j]=jcol[j+1]) then this is equal to the number of non-zeroelements.
LCOL (input)
Length of the array JCOL. Should be equal to the number of variables n.
ISCR (scratch)
Integer scratch array. Length should be at least equal to the number of variables n.
LSCR (input)
Length of integer scratch array. Should be at least equal to the number of variablesn.
SUBROUTINE GFNSTO
Subroutine GFNSTO stores a non linear instruction with opcode IOPCOD andaddress field IADDR in INSTR(ISEQ). This is a low-level routine, only to be used ifyou do advanced things like patching instructions.
Fortran SUBROUTINE GFNSTO(INSTR, ISEQ, IOPCOD, AIIDR& ESTIM, LUCORE, MAXZ, MAXBLK)INTEGER IOSTA,CONINTEGER ESTIM, LUCORE, MAXZ, MAXBLK
Pascal n.a.
C n.a.
Description of the parameters
INSTR (input)
Instruction array.
ISEQ (input)
Position within the instruction array, i.e. the instruction (iopcod,iaddr) will bestored at location INSTR(ISEQ).
IOPCOD (input)
Opcode. This is a positive integer between 1 and 74.
IADDR (input)
Address field. This is an integer that should be between -32768 and 32767 for thePC and between -8388607 and +8388607 for larger machines. This implies thatmodels with more than 32767 (8388607) non-zero elements can not be solved usingthe current setup.
142
SUBROUTINE GFNTRP
Subroutine GFNTRP calculates the non-linear function value and the gradients,based on the current levels X for one equation.
Fortran SUBROUTINE GFNTRP(X, F, A, INSTR, NLWORK,& NUMERR, Z, REFRM, N, NZ, NCON,& LINS)INTEGER NUMERR, REFRMINTEGER N,NZ,NCON,LINSINTEGER INSTR(LINS)DOUBLE PRECISION X(N), F, A(NZ), NLWORK(NCON), Z(*)
Pascal n.a.
C n.a.
Description of the parameters
X (input)
The double precision array with the current level values.
F (output)
The function value of the current row. This is a scalar.
A (output)
The double precision array of the Jacobian (the A matrix).
INSTR (input)
The array that holds the non-linear instructions.
NLWORK (input)
The non-linear work array as was set up by GFRINS.
NUMERR (input/output)
This variable should accumulate the number of "domain violations" encountered inthe interpreter. It should be set to 0 before calling the interpreter for the first time.After each call the the interpreter the user should compare this value with KNV(6) asprovided by GFRCNT. If numerr > knv(6) then terminate with a solution status of 5.See the documentation on GFWSTA.
Z (input)
Start of the Z array. See example 1 and the description of GFENLE for moreinformation.
REFRM (input)
Reformulation level. Currently only used for MINOS. Other users should pass on a0.
N (input)
Number of structural variables n. Dimension of X.
NZ (input)
Number of nonzero elements nz. Dimension of the array A holding the matrix.
NCON (input)
Size of non-linear workspace array. Is returned by GFCNTR in KNV(5).
LINS (input)
Length of the instruction array. Is returned by GFCNTR in KNV(4).
144
SUBROUTINE GFRINS
Subroutine GFRINS is used to read the non-linear instructions. In case the model islinear it returns control to the caller immediately.
Fortran SUBROUTINE GFRINS(INSTR, LENINS, NLWORK,& LENWRK)INTEGER LENINS,LENWRKINTEGER INSTR(LENINS)DOUBLE PRECISION NLWORK(LENWRK)
Pascal n.a.
C n.a.
Description of the parameters
INSTR (output)
The array that will hold on output the non-linear instructions. It's length is LENINS.It should be an INTEGER*4 array.
LENINS (input)
The length of the integer array that will hold the instructions. This length is reportedby GFRCNT as KNV(4). It may be longer than KN(4) but not smaller.
NLWORK (output)
This is a non-linear work array. After this array is initialized by GFRINS it shouldnot be touched by the user. The interpreter will need this array to find someinformation and for scratch space.
LENWRK (input)
Length of the non-linear work array. Should be at least KNV(5), as reported byGFRCNT.
Remarks
After reading the instructions in to memory, one should patch them up so that theStore Derivative instructions point to the right place in the the A matrix. In order toevaluate all instructions you have to loop on the non-linear equations.
146
CHAPTER 8
EXAMPLES FOR NONLINEARSYSTEMS
NLP-1 NLP problem in Fortran where instructions are loaded andevaluated
EXAMPLE NLP1 - LOAD NONLINEAR INSTRUCTIONS ANDEVALUATE
The next listings show you how to set up data structures for a non-linear model.The file NLEX1.FOR is a slightly modified version of the one that is presented in thelinear documentation in Example LP-4. It allocates more memory to make sure wecan load the non-linear instructions.Two subroutines NLINIT and NLEVAL are shown that act as wrappers around thelower level routines in the I/O library. NLINIT should be called after reading thematrix, and NLEVAL to evaluate the function and the gradients.
C-------------------------------------------------------------------- PROGRAM NLEXAM1C--------------------------------------------------------------------CC Example how to read an NLP into a dynamic array LP systemCC
IMPLICIT NONE
COMMON /DYNARR/ Z DOUBLE PRECISION Z(1) INTEGER CORESZ
CORESZ = 2
CALL SUB1(Z,CORESZ)
END
C-------------------------------------------------------------------- SUBROUTINE SUB1(Z, CORESZ)C--------------------------------------------------------------------
IMPLICIT NONE
INTEGER CORESZ DOUBLE PRECISION Z(CORESZ)
INTEGER INTSIZ PARAMETER(INTSIZ=2) ! 2 integers fit in a real*8
COMMON/NLPMOD/ N,M,NZ,
148
& MA,MIROW,MJCOL,MJLEN,MLB,MUB,MRHS,MISIGN,MX, & MINS,MNLW,MSCR,MJTYP,MF, & PA,PIROW,PJCOL,PJLEN,PLB,PUB,PRHS,PISIGN,PX, & PINS,PNLW,PSCR,PJTYP,PF INTEGER N,M,NZ,MA,MIROW,MJCOL,MJLEN,MLB,MUB,MRHS,MISIGN,MX INTEGER MINS,MNLW,MSCR,MJTYP,MF INTEGER PA,PIROW,PJCOL,PJLEN,PLB,PUB,PRHS,PISIGN,PX INTEGER PINS,PNLW,PSCR,PJTYP,PF
C-- local vars
INTEGER IOSTA ! unit number of the status file INTEGER GFUNIT ! unit number for internal lib routines INTEGER IOLOG ! unit number log file INTEGER SCREEN ! unit number screen INTEGER IOCNTR ! unit number control file DOUBLE PRECISION XGV(30) ! storage control info INTEGER KGV(30) LOGICAL LGV(30) INTEGER KNV(30) INTEGER DUMMY INTEGER NEEDED ! memory needed INTEGER MEMGOT, MAXMEM ! allocated, available INTEGER ISTART ! first useable position in z INTEGER OBJVAR DOUBLE PRECISION GMINF, GINF INTEGER NLCLEN, NLWLEN LOGICAL CANMIP, CANNLP PARAMETER (CANNLP=.TRUE.,CANMIP=.FALSE.)
C define the unit numbers
IOSTA = 10 IOLOG = 11 GFUNIT = 12 SCREEN = 13 IOCNTR = 14
C initialize and read control file
CALL GFINIT(GFUNIT, IOSTA, SCREEN) CALL GFRCNT(IOCNTR, IOLOG, CANMIP, & CANNLP, XGV, KGV, LGV, KNV, DUMMY)
C open status file
CALL GFOPST()
C write a message to the status file
CALL GFSTCT('STARTC') WRITE(IOSTA,*) ' ******************************' WRITE(IOSTA,*) ' * SUPERNLP, BY SOLVERS INC. *'
WRITE(IOSTA,*) ' ******************************' WRITE(IOSTA,*) CALL GFSTCT('STOPC')
C extract info
M = KGV(1)+1 ! one extra contraint: objective row N = KGV(2) ! number of columns NZ = KGV(3)+1 ! 1 extra non-zero OBJVAR= KGV(7) ! objective variable GINF = XGV(10) ! GAMS bit pattern for +infinity GMINF = XGV(11) ! GAMS bit patters for -infinity NLCLEN= KNV(4) ! length non-linear code NLWLEN= KNV(5) ! length non-linear work space
C Do a memory estimationC In "real life" add space for basis, lu-factors, eta-vectors,C workspace, etc. All arrays of which the size depends on theC size of the problem should be accomodated within this array.
MA = NZ ! NZ reals are needed to store A MIROW = 1 + (NZ/INTSIZ) ! space needed to store IROW MJCOL = 1 + (N/INTSIZ) ! etc. MJLEN = 1 + (N/INTSIZ) ! etc. MLB = N MUB = N MX = N MRHS = M MISIGN = 1 + (M/INTSIZ) MINS = 1 + (NLCLEN/INTSIZ) ! instructions are stored asinteger*4 MNLW = NLWLEN MSCR = 1 + (N/INTSIZ) ! scratch array MJTYP = 1 + (NZ/INTSIZ) MF = M
CALL MPART(1,NEEDED) ! calculate size of memory needed
CALL GFGETM(Z, ISTART, NEEDED, MEMGOT, MAXMEM) CALL MEMINF(IOSTA,IOLOG,NEEDED,0,MEMGOT,MAXMEM)
IF (MEMGOT.LT.NEEDED) & CALL LPERR(IOLOG,IOSTA,' NOT ENOUGH MEMORY')
CALL MPART(ISTART,DUMMY) ! calculate partitioning
CALL SUB2(IOLOG, IOSTA, M, N, NZ, OBJVAR, GMINF, GINF, & Z(PA),Z(PIROW),Z(PJCOL),Z(PJLEN),Z(PLB), & Z(PUB),Z(PRHS),Z(PISIGN),Z(PX),Z(PF),Z(PJTYP), & Z(PINS),NLCLEN,Z(PNLW),NLWLEN,Z(PSCR),MSCR,Z)
END
150
C-------------------------------------------------------------------- SUBROUTINE SUB2(IOLOG, IOSTA, M, N, NZ, OBJVAR, GMINF, GINF, & AA, IROW, JCOL, JLEN, LB, UB, RHS, ISIGN, X, & F, JTYP, & INS, LENINS, NLWORK, NLWLEN, SCR, SCRLEN, Z)C--------------------------------------------------------------------
IMPLICIT NONE
C now we can work with "normal" arrays
c-- parms INTEGER IOLOG, IOSTA, M, N, NZ DOUBLE PRECISION AA(NZ), LB(N), UB(N), X(N), RHS(M), F(M) DOUBLE PRECISION GMINF, GINF INTEGER IROW(NZ), JCOL(N), JLEN(N), ISIGN(M), OBJVAR INTEGER JTYP(NZ) INTEGER LENINS, NLWLEN, SCRLEN INTEGER INS(LENINS) DOUBLE PRECISION NLWORK(NLWLEN), SCR(SCRLEN) DOUBLE PRECISION Z(1)c-- locals INTEGER NUMERR ! domain errors in the interpreter
C now read the data file
CALL READAT(IOLOG, IOSTA, ! in case we want to writesomething & M, N, NZ, OBJVAR, GMINF, GINF, & AA, IROW, JCOL, JLEN, LB, UB, RHS, ISIGN, X,JTYP)
c read nl instructions, and set up pointers in JTYP array.
WRITE(IOLOG,900) CALLNLINIT(INS,LENINS,NLWORK,NLWLEN,AA,IROW,JCOL,JLEN,NZ,M,N, & JTYP,SCR,SCRLEN) NUMERR = 0
WRITE(IOLOG,901)
CALL NLEVAL(Z,INS,LENINS,NLWORK,NLWLEN,AA,IROW,JCOL,JLEN, & JTYP,X,F,NZ,M,N,NUMERR)
WRITE(IOLOG,902)
CALL GFCLOS() ! close down the I/O library
RETURN
900 FORMAT (' READING NON-LINEAR INSTRUCTIONS...') 901 FORMAT (' EVALUATING FUNCTION AND GRADIENTS AT CURRENTPOINT...') 902 FORMAT (' DONE') END
C-------------------------------------------------------------------- SUBROUTINE READAT(IOLOG, IOSTA, M, N, NZ, OBJVAR, GMINF, & GINF, AA, IROW, JCOL, JLEN, LB, UB, RHS, & ISIGN, X, JTYP)C--------------------------------------------------------------------C READ DATA FILE
IMPLICIT NONE
C-- PARAMETERS
INTEGER IOLOG, IOSTA, M, N, NZ DOUBLE PRECISION AA(NZ), LB(N), UB(N), X(N), RHS(M) DOUBLE PRECISION GMINF, GINF INTEGER IROW(NZ), JCOL(N), JLEN(N), ISIGN(M), OBJVAR INTEGER JTYP(NZ)
C-- LOCALS DOUBLE PRECISION X5VEC(5) INTEGER I4VEC(4) INTEGER I, J, NZCOL, NNZ DOUBLE PRECISION HUGE PARAMETER (HUGE=1.0D10)
WRITE(IOLOG,901)
DO 10, I=1,M-1 CALL GFRROWX(X5VEC,I4VEC) RHS(I) = X5VEC(2) ISIGN(I) = I4VEC(1) 10 CONTINUE
C add objective row
RHS(M) = 0.0D0 ISIGN(M) = 3 ! a free row
WRITE(IOLOG,902)
NNZ = 1
DO 20, J=1,N CALL GFRCOLX(X5VEC,I4VEC) LB(J) = X5VEC(1)
152
IF (LB(J).EQ.GMINF) LB(J) = -HUGE X(J) = X5VEC(2) UB(J) = X5VEC(3) IF (UB(J).EQ.GINF) UB(J) = HUGE NZCOL = I4VEC(1) JCOL(J) = NNZ JLEN(J) = NZCOL DO 30, I=1,NZCOL CALL GFRCOF(AA(NNZ),IROW(NNZ),JTYP(NNZ)) NNZ = NNZ + 1 30 CONTINUE IF (J.EQ.OBJVAR) THEN AA(NNZ) = 1.0D0 IROW(NNZ) = M JTYP(NNZ) = 0 NNZ = NNZ + 1 ENDIF 20 CONTINUE
901 FORMAT(' READING ROWS...') 902 FORMAT(' READING COLUMNS...')
END
C-------------------------------------------------------------------- SUBROUTINE LPERR(IOSTA, IOLOG, MESS)C--------------------------------------------------------------------C write message to status file and log file and terminate
IMPLICIT NONE INTEGER IOSTA, IOLOG CHARACTER*(*) MESS
CALL GFSTCT('SYSOUT')
WRITE(IOSTA,100) MESS WRITE(IOLOG,100) MESS
100 FORMAT(' *** ERROR: ',A80)
STOP
END
C-------------------------------------------------------------------- SUBROUTINE MPART(ISTART,IEND)C--------------------------------------------------------------------C this subroutine partitions the memory where
C ISTART is the first available REAL*8 slot.C It returns IEND, the last occupied slot.C Use also to esimate memory requirements by callingC it with ISTART=1;
IMPLICIT NONE INTEGER ISTART,IEND
COMMON/NLPMOD/ N,M,NZ, & MA,MIROW,MJCOL,MJLEN,MLB,MUB,MRHS,MISIGN,MX, & MINS,MNLW,MSCR,MJTYP,MF, & PA,PIROW,PJCOL,PJLEN,PLB,PUB,PRHS,PISIGN,PX, & PINS,PNLW,PSCR,PJTYP,PF INTEGER N,M,NZ,MA,MIROW,MJCOL,MJLEN,MLB,MUB,MRHS,MISIGN,MX INTEGER MINS,MNLW,MSCR,MJTYP,MF INTEGER PA,PIROW,PJCOL,PJLEN,PLB,PUB,PRHS,PISIGN,PX INTEGER PINS,PNLW,PSCR,PJTYP,PF
INTEGER INTSIZ
INTSIZ = 2 ! two 4 byte integers fit in one real*8
PA = ISTART PIROW = PA + MA PJCOL = PIROW + MIROW PJLEN = PJCOL + MJCOL PLB = PJLEN + MJLEN PUB = PLB + MLB PX = PUB + MUB PRHS = PX + MX PISIGN = PRHS + MRHS PINS = PISIGN + MISIGN PNLW = PINS + MINS PSCR = PNLW + MNLW PJTYP = PSCR + MSCR PF = PJTYP + MJTYP IEND = PF + MF - 1
END
c-------------------------------------------------------------------- SUBROUTINENLINIT(INSTR,LENGIN,XNLWRK,NLWORK,A,IROW,JCOL,JLEN, & NZ,M,N,NZTYPE,SCRARR,SCRLEN)c--------------------------------------------------------------------cc NLINIT reads the instruction file, patches up the instructionsc such that STORE DERIVATIVE and the STORE (function value)c instructions point to the right places. It also producesc an array that contains the pattern of the non-linearities inc the matrix, which is later on used by NLEVAL.
154
cc INSTR(LENGIN) is the INTEGER*4 array where the instructionsc are stored. LENGIN can be found in KNV(4) afterc calling GFRCNT. This array should not be altered.c XNLWRK(NLWORK) is a DOUBLE PRECISION array where some non-linearc constants are stored, and space needed by thec interpreter. This array should not be altered.c A(NZ),IROW(NZ),JCOL(N),JLEN(N) describe the matrix. Thestoragec technique is "row index, column pointer", i.e.c columnwise.A contains the non-zero elements. The rowc index of A(K) is IROW(K). JCOL(J) points to theplacec where column J starts, and JLEN(J) contains thelength ofc this column.c NZ,M,N are the counts (non-zeroes, rows, columns).c NZTYPE(NZ) is an INTEGER array containing the nl non-zeropattern.c On input should contain NZTYPE(K) = 0 if A(K) is alinearc nonzero and ZNTYPE(K) = 1 if A(K) is a non-linearc nonzero. On output contains pointers to STOREDERIVATIVEc instructions.c Should not be altered by the user after this call.c This info is provided by GFRCOF.c SCRARR(SCRLEN) is a REAL*8 scratch array. Space can be reusedafterc calling this routine.cc IMPLICIT NONE
c-- params INTEGER N,M,NZ ! counts INTEGER LENGIN ! length instruction array INTEGER INSTR(LENGIN) ! instructions INTEGER NLWORK ! length nl work array DOUBLE PRECISION XNLWRK(NLWORK) ! nl work array DOUBLE PRECISION A(NZ) ! matrix INTEGER IROW(NZ) ! row indices INTEGER JCOL(N) ! column pointers INTEGER JLEN(N) ! length of the columns INTEGER NZTYPE(NZ) ! 0 : linear, >0 : non-linear INTEGER SCRLEN ! length scratch array DOUBLE PRECISION SCRARR(SCRLEN) ! scratch arrayc-- locals INTEGER ISCRLN ! # integer scratch locations INTEGER IMACH(4) ! arguments for GFMACH DOUBLE PRECISION RMACH(6)
c we need to know how much (long) integer we can store in a
c double precision array of length SCRLEN (see linear IOLIBc docs for information about GFMACH). CALL GFMACH(RMACH,IMACH) ISCRLN = SCRLEN*IMACH(1)
c first read instructions CALL GFRINS(INSTR,LENGIN,XNLWRK,NLWORK)
c set up nztype, so that it points to the STORE DERIVATIVEc instructions CALL GFJTYP(INSTR, LENGIN, IROW, JCOL, JLEN, NZTYPE, & NZ, N, SCRARR, ISCRLN)
c update addresses of STORE DERIVATIVE instructions CALL GFPMJJ(INSTR, LENGIN, IROW, NZTYPE, SCRARR, ISCRLN, NZ )
RETURN END
c-------------------------------------------------------------------- SUBROUTINENLEVAL(Z,INSTR,LENGIN,XNLWRK,NLWORK,A,IROW,JCOL,JLEN, & NZTYPE,X,F,NZ,M,N,NUMERR)c--------------------------------------------------------------------cc NLEVAL evaluates the functions and the gradients in thec current point X.cc Z(1) is the start of the Z array (see the Fortran examplesc in the IOLIB documentation about dynamic memory).c INSTR(LENGIN) is the INTEGER*4 array where the instructionsc are stored. LENGIN can be found in KNV(4) afterc calling GFRCNT. This array should not be altered.c XNLWRK(NLWORK) is a DOUBLE PRECISION array where some non-linearc constants are stored, and space needed by thec interpreter. This array should not be altered.c A(NZ) is the double precision arraywhere the non-zero elementsc are stored.c NZTYPE(NZ) is the integer*4 array with pointers to the STOREc GRADIENT instructions.c F(M) is on output the double precision array that holds thec function values. Both linear and non-linear rowsc are evaluated.C X(N) should on input contain the current values.c NZ,M,N are the counts.c NUMERR should accumulate the number of evaluation errorsc encountered by the interpreter. User shouldc set it to zero before calling this routine forc the first time, and after each call compare
156
c it with KNV(7) (max. allowed domain errors).c If it exceeds this value, write out solutionc and stop with solution status of 5 (seec documentation on GFWSTA).
IMPLICIT NONE
$include:'gmscom.inc'
C-- PARAMS INTEGER NZ,M,N,NLWORK,LENGIN,NUMERR INTEGER INSTR(LENGIN),NZTYPE(NZ) DOUBLE PRECISION F(M),XNLWRK(NLWORK),X(N),A(NZ),Z(*) ! no problems with bound checking here INTEGER IROW(NZ),JCOL(N),JLEN(N)C-- LOCALS INTEGER I,J,K INTEGER ISEQ ! sequence number of instruction at beginning ! of current equation INTEGER INEXT ! sequence number of instruction at beginningof ! next INTEGER IROSEQ ! number of the non-linear equation ! evaluated by the interpreter
c.tfr INTEGER LINS ! location of next instruction - tfr patch
c.tfr if (gfdbug.gt.0) then call gfdmpa(6,INSTR,LENGIN)
call gfprr8('LEVELS:',X,N,GFSTA) endif
DO 10, I=1, M F(I) = 0.0D0 10 CONTINUE
ISEQ = 1
100 CONTINUE ! ------- LOOP OVER ALL NON-LINEAR EQUATIONS CALL GFNINT(INSTR, ISEQ, INEXT, IROSEQ, LENGIN)c.tfr
IF (INEXT.GT.0) THEN LINS = INEXT ELSE LINS = LENGIN ENDIF
c.tfr Use LINS instead of INEXT in the call:
CALL GFNTRP(X,F(IROSEQ),A,INSTR(ISEQ),XNLWRK, & NUMERR,Z,REFORM,N,NZ,NLWORK,LINS)
IF (INEXT.EQ.0) GOTO 200 ISEQ = INEXT GOTO 100
200 CONTINUE
if (gfdbug.gt.0) CALL GFPRR8('NON LINEAR PART OFF:',F,M,GFSTA)
c now add linear terms
DO 300, J=1,N DO 310, K=JCOL(J), JCOL(J)+JLEN(J)-1 IF (NZTYPE(K).EQ.0) THEN ! LINEAR NON-ZERO I = IROW(K) F(I) = F(I) + A(K)*X(J) ENDIF 310 CONTINUE 300 CONTINUE
c if (gfdbug.gt.0) CALL GFPRR8('TOTAL F:',F,M,GFSTA)
RETURN END