Basic information on GDX file format
The GAMS modeling language is a domain specific language tailored towards mathematical optimization. The language reflects the basic building blocks (symbols) of an algebraic optimization model:
While declaring the symbols in the GAMS language is rather straightforward and concise, defining their values (which must be done prior to running the optimization for exogenous symbols like sets, parameters and scalars) might be comparatively cumbersome. In many applications, the actual data for the symbols is also already stored in some other location like a file or database. In order to have an efficient way to load data into a model, store the solution results and in general exchange information with other applications, the GDX file format was conceived.
Information contained inside a GDX file
- Unique elements (strings used to identify set elements)
- Acronyms as shorthand names for specific numeric values
- Symbols
- with their attributes...
- Type: Set, Alias, Parameter, Scalar, Variable, Equation
- Dimensionality
- User info
- Explanatory text
- ...and data (records)
Records are mapping from the domain of the symbol to the value space with up to 5 fields (level, marginal, lower bound, upper bound, scale)
The actual data might be stored verbatim or compressed (using zlib).
Please note: a GDX file does not store a model formulation or executable statements.
Features of the GDX API
For efficiency reasons (both read/write-speeds and disk usage) the GDX format is a binary format that cannot be easily processed using a text editor. Hence, looking at the contents of a GDX file is ideally done via a graphical user interface like the GDX viewer included in GAMS Studio or the gdxdump
console utility included in the GAMS distribution. In order to write conversion utilities between GDX and various other data file formats, an API is needed. This API has the following features:
- Reading list of symbols and UELs
- Reading data from a symbol (metadata, records)
- Writing a new symbol (metadata, records)
- Bindings to multiple languages
The GDX API is very powerful with fine-grained control and is also used at GAMS internally.
Setting up and building GDX
Accessing GDX from a custom application
The GDX API can be directly accessed from C/C++ via the library contained in this repository. Although there is a main GDX object for representing a file in this interface, it is mostly procedural and offers many functions operating on elementary data types instead of a sophisticated class hierarchy.
For an easier to use object-oriented interface GAMS offers wrappers for multiple programming languages including:
Even more abstraction is offered by the GAMS Transfer libraries for Python and R.
Building GDX from source
The GDX library is written in C++17 and built via CMake.
The fastest way to build the GDX library (static and dynamic) locally is by running the following spells:
git clone https://github.com/GAMS-dev/gdx.git
cd gdx
git clone https://github.com/madler/zlib zlib
cmake -DNO_TESTS=ON -DNO_EXAMPLES=ON -DNO_TOOLS=ON .
cmake --build .
Running this on Linux creates the dynamic library libgdxcclib64.so
and the static library libgdx-static.a
.
This repository contains a GitLab CI YAML that describes a pipeline which
- builds GDX for all supported platforms (Windows, macOS, Linux) with Doxygen documentation, libraries, and examples,
- runs its unit test suite,
- checks for memory leaks with valgrind memcheck,
- and checks for performance regressions against GAMS 43 legacy Delphi GDX library.
Please run
git clone https://github.com/madler/zlib zlib
inside the root-directory of the gdx
-repository to make the zlib compression library available.
doctest and apigenerator are included in this repo (as file and submodule respectively).
Dependencies:
Build tools:
Reference documentation
A full detailed Doxygen-generated API reference is available here.
Introduction into using GDX API
This document describes the Application Programmers Interface (API) for the GDX library. The GDX library is used to read or write GDX files. A GDX file is a file that stores the values of one or more GAMS symbols such as sets, parameters, variables, and equations. GDX files can be used to prepare data for a GAMS model, present results of a GAMS model, store results of the same model using different parameters etc. A GDX file does not store a model formulation or executable statements.
GDX files are binary files that are portable between different platforms. They are written using the byte ordering native to the hardware platform they are created on, but can be read on a platform using a different byte ordering.
To read or write data, we need to be able to reference the set elements used to represent the index space for symbols with one or more dimensions. The API provides three interface models for this purpose:
- The String based interface. An
n
dimensional element is represented as an array of strings.
- The Raw integer interface. An
n
dimensional element is represented as an array of integers. The integer used for each index position is obtained from the API after registering the string representation with the API.
- The Mapped integer interface. An
n
dimensional element is represented as an array of integers. The integer used for each index position is defined by the user. Before such an element can be used, its value and string has to be registered.
Writing data to a GDX file
Creating a GDX file and writing one or more symbols to the file requires a number of steps:
- Make sure the GDX library is available
- Open a file for writing
- Register unique elements
- Start writing a symbol
- Write the data
- Finish writing for the symbol
- Optional: share acronyms
- Close the file
- Unload the GDX library
Steps 3 - 6 can be repeated to write any number of symbols to the file. Once a symbol has been written to the file, it cannot be replaced. Currently, there are no facilities to overwrite a symbol or append data to an existing file.
The following sections illustrate the basic steps for each type of interface. The method of writing (string, raw, or mapped) can be selected for each symbol; it cannot be changed while writing a symbol.
Most code samples reference the following auxiliary function ReportGDXError
to report the latest GDX error when the most recent call to the GDX API has reported a problem (usually by returning false
).
void ReportGDXError(TGXFileObj &gdx) {
std::array<char, GMS_SSSIZE> S;
std::cout << "**** Fatal GDX Error" << std::endl;
gdx.gdxErrorStr(gdx.gdxGetLastError(), S.data());
std::cout << "**** " << S.data() << std::endl;
exit(1);
}
Writing data using strings
The String based interface is suitable when we want to use a string based index and do not want to maintain a mapping from strings to integers.
Before writing data using a string based interface we can register strings for the unique elements, but this step is optional. The only reason to register the strings beforehand is to enter the strings in a given order which may have advantages later in the modelling stage.
if(!gdx.gdxDataWriteStrStart("Demand","Demand data",1,dt_par,0))
ReportGDXError();
IndxS[0] = "New-York";
Values[0] = 324.0;
gdx.gdxDataWriteStr(IndxS,Values);
IndxS[0] = "Chicago";
Values[0] = 299.0;
gdx.gdxDataWriteStr(IndxS,Values);
if(!gdx.gdxDataWriteDone())
ReportGDXError();
In this example we write two records for a parameter that has a dimension of one.
Writing data using integers (raw)
The Raw interface is suitable when we want to manage our own list of unique elements, and use an integer based index. The Raw interface assumes that the integers assigned to the strings range from one to the number of strings registered.
Before we can write data using the Raw interface, we have to register the strings for the unique elements. The GDX routines will assign an integer to the string that increases by one for every string registered.
if(!gdx.gdxUELRegisterRawStart())
ReportGDXError();
gdx.gdxUELRegisterRaw("New-York");
gdx.gdxUELRegisterRaw("Chicago");
if(!gdx.gdxUELRegisterDone())
ReportGDXError();
if(!gdx.gdxDataWriteRawStart("Demand","Demand data",1,dt_par,0))
ReportGDXError();
IndxI[0] = 1;
Values[0] = 324.0;
gdx.gdxDataWriteRaw(IndxI,Values);
IndxI[0] = 2;
Values[0] = 299.0;
gdx.gdxDataWriteRaw(IndxI,Values);
if(!gdx.gdxDataWriteDone())
ReportGDXError();
Writing data using integers (mapped)
The Mapped interface is suitable when we want to manage our own list of unique elements, and use an integer based index. The mapped interface lets us select our own mapping between strings for the unique elements and their integer equivalent. The integers assigned to the unique elements should be greater equal one, and be unique for each element.
Before we can write data using the Mapped interface, we have to register the strings for the unique elements.
if(!gdx.gdxUELRegisterMapStart())
ReportGDXError();
gdx.gdxUELRegisterMap(1000,"New-York");
gdx.gdxUELRegisterMap(2000,"Chicago");
if(!gdx.gdxUELRegisterDone())
ReportGDXError();
if(!gdx.gdxDataWriteMapStart("Demand","Demand data",1,dt_par,0))
ReportGDXError();
IndxI[0] = 1000;
Values[0] = 324.0;
gdx.gdxDataWriteRaw(IndxI,Values);
IndxI[0] = 2000;
Values[0] = 299.0;
gdx.gdxDataWriteRaw(IndxS,Values);
if(!gdx.gdxDataWriteDone())
ReportGDXError();
In this example we register two unique elements, and write a parameter of dimension one.
Reading data from a GDX file
Opening an existing GDX file and reading one or more symbols from the file requires a number of steps:
- Make sure the GDX library is available
- Open a file for reading
- Optional: share acronyms
- Register unique elements
- Start reading a symbol
- Read the data
- Finish reading for the symbol
- Close the file
- Unload the GDX library
Steps 3 - 6 can be repeated to read any number of symbols from the file.
The following sections illustrate the basic steps for each type of interface. The method of writing (string, raw or mapped) can be selected for each symbol; it cannot be changed while writing a symbol.
Reading data using strings
Reading data using strings does not require any unique element registration.
if(!gdx.gdxFindSymbol("x",SyNr)) {
std::cout << "**** Could not find symbol X" << std::endl;
exit(1);
}
gdx.gdxSymbolInfo(SyNr,SyName,SyDim,SyTyp);
if(SyDim != 1 || SyTyp != dt_par) {
std::cout << "**** X is not a one dimensional parameter" << std::endl;
exit(1);
}
if(!gdx.gdxDataReadStrStart(SyNr,NrRecs))
ReportGDXError();
std::cout << "Parameter X has " << NrRecs << " records" << std::endl;
while(gdx.gdxDataReadStr(IndxS,Values,N))
std::cout << "Record = " << IndxS[0] << " " << Values[0] << '\n';
if(!gdx.gdxDataReadDone())
ReportGDXError();
In this example we find the symbol by its name, and before reading the data we verify that the symbol represents a one dimensional parameter.
Reading data using integers (raw)
Reading data using integers in Raw mode does not require the registration of unique elements. The read routine returns an integer for which we can find the string representation.
if(!gdx.gdxFindSymbol("x",SyNr) {
std::cout << "**** Could not find symbol X" << std::endl;
exit(1);
}
gdx.gdxSymbolInfo(SyNr,SyName,SyDim,SyTyp);
if(SyDim != 1 || SyTyp != dt_par) {
std::cout << "**** X is not a one dimensional parameter" << std::endl;
exit(1);
}
if(!gdx.gdxDataReadRawStart(SyNr,NrRecs))
ReportGDXError();
std::cout << "Parameter X has ",NrRecs," records");
while(gdx.gdxDataReadRaw(IndxI,Values,N)) {
std::cout << "Record = " << IndxI[0] << " = " << Values[0];
gdx.gdxUMUelGet(IndxI[0],S,UsrMap);
std::cout << " with string = " << S << '\n';
}
if(!gdx.gdxDataReadDone())
ReportGDXError();
In this example we find the symbol by its name, and before reading the data we verify that the symbol represents a one dimensional parameter. When reading the data, we get a unique element as an integer. The integer value is used to get the corresponding string for the unique element.
Reading data using integers (Mapped)
Reading data using integers in Mapped mode requires the registration of unique elements. The read routine returns an integer for which we can find the string representation.
When the gdx file contains data elements that we never registered, the read function will not return these elements, they will be added to an internal list of error records instead.
if(!gdx.gdxUELRegisterMapStart())
ReportGDXError();
gdx.gdxUELRegisterMap(1000,"New-York");
gdx.gdxUELRegisterMap(2000,"Chicago");
if(!gdx.gdxUELRegisterDone())
ReportGDXError();
if(!gdx.gdxFindSymbol("x",SyNr)) {
std::cout << "**** Could not find symbol X" << std::endl;
exit(1);
}
gdx.gdxSymbolInfo(SyNr,SyName,SyDim,SyTyp);
if(SyDim != 1 || SyTyp != dt_par) {
std::cout << "**** X is not a one dimensional parameter" << std::endl;
exit(1);
}
if(!gdx.gdxDataReadMapStart(SyNr,NrRecs))
ReportGDXError();
std::cout << "Parameter X has " << NrRecs << " records" << std::endl;
for(int N{}; N<NrRecs; N++) {
if(gdx.gdxDataReadMap(N,IndxI,Values,N)) {
std::cout << "Record = " << N << " " << IndxI[0] << " = " << Values[0];
GetUEL(gdx,IndxI[0],S);
std::cout << " with string = " << S << '\n';
}
}
if(!gdx.gdxDataReadDone())
ReportGDXError();
NrRecs = gdx.gdxDataErrorCount();
if(NrRecs > 0)
std::cout << NrRecs << " records were skipped" << std::endl;
In this example we register a few unique elements using our \own integer values. After verifying that we can find the symbol and that the symbol represents a one dimensional parameter we can read the data. The index for the parameter is returned using the integers we used when registering our elements. When we read the records in sequence, the index returned will be sorted with the first index position the most significant.
After reading the data, we print the number of records that were skipped in the read routine.
Reading data using a filter
Reading data using a filter allows us to control the action for every index position. The type of action is specified using action codes and needs to be specified for every index position. The actual reading of the records is done with the gdxDataReadMap function.
Action code | Description |
UnMapped (-2) | No mapping is performed; the value of the unique element is the value as stored in the GDX file. Use gdxUMUelGet to get the string representation. |
Checked (0) | Map the unique element value to the user defined value. Use gdxGetUEL to get the string representation. If a user mapping was not defined for this element,
the record is flagged as an error record and the record will be skipped. |
Expand (-1) | Map the unique element value to the user defined value. Use gdxGetUEL to get the string representation. If a user mapping was not defined for this element, define a user mapping automatically using the next higher user map value. |
Filter number (>0) | Map the unique element value to the user defined value. Use gdxGetUEL to get the string representation. If the element is not enabled in the filter for this index position, the record is flagged as an error record and it will be skipped. The filter number is specified using the gdxFilterRegisterStart function. |
Referring to the following GAMS fragment, we want to read the parameter A
. The set I
is the domain for the first index; there is no domain for the second index position:
Set I /.../;
Parameter A(I,*);
Assuming we have read set I
already, the following code snapshot illustrates how to read parameter A
.
gdx.gdxUELRegisterMapStart();
gdx.gdxUELRegisterMap( 1000, "New-York" );
gdx.gdxUELRegisterMap( 2000, "Chicago" );
gdx.gdxUELRegisterDone();
if(!gdx.gdxFilterRegisterStart(123))
ReportGDXError();
gdx.gdxFilterRegister(1000);
gdx.gdxFilterRegister(2000);
if(!gdx.gdxFilterRegisterDone())
ReportGDXError();
std::array filterAction {
123,
gdx::DOMC_EXPAND
};
int NrUnMapped, LastMapped;
gdx.gdxUMUelInfo(NrUnMapped, LastMapped);
int SyNr;
if(!gdx.gdxFindSymbol("A", SyNr) {
std::cout << "**** Could not find symbol A" << std::endl;
exit(1);
}
std::array<char, GMS_SSSIZE> SyName;
int SyDim, SyTyp;
gdx.gdxSymbolInfo(SyNr, SyName.data(), SyDim, SyTyp);
if(SyDim != 2 || SyTyp != dt_par) {
std::cout << "**** A is not a two dimensional parameter" << std::endl;
exit(1);
}
int NrRecs;
if(!gdx.gdxDataReadFilteredStart(SyNr, filterAction.data(), NrRecs));
ReportGDXError();
int DimFrst;
for(int N{1}; N<=NrRecs; N++) {
if(gdx.gdxDataReadMap(N, IndxI, Values, DimFrst)) {
}
}
if(!gdx.gdxDataReadDone()
ReportGDXError();
int NewLastMapped;
gdx.gdxUMUelInfo(NrUnMapped, NewLastMapped);
if(NewLastMapped > LastMapped) {
for(int N{LastMapped + 1}; N<=NewLastMapped; N++) {
std::array<char, GMS_SSSIZE> S {};
gdx.gdxGetUel(N,S.data());
std::cout << "New element " << N << " = " << S.data() << '\n';
}
}
A runnable version of this example can be found in the unit test suite under /src/tests/gdxtests.cpp
as test case with the name "Test filter example from README".
Dealing with acronyms
In GAMS we can use acronyms in places where we can use a floating point number as in the following example:
set i /i1*i5/;
acronym acro1, acro2;
parameter A(i) /i1=1, i2=acro1, i3=3, i4=acro2, i5=5/;
display A;
The result of the display statement looks like:
---- 4 PARAMETER A
i1 1.000, i2 acro1, i3 3.000, i4 acro2, i5 5.000
As we write data to a GDX file, the system keeps track which acronyms were used in the data written. Before we close the GDX file, we share the identifiers used for each acronym used. When reading a GDX file, we share all acronym identifiers and their corresponding index before reading any data. Doing so will replace the acronym indices stored in the GDX file by the one we provide.
The example below illustrates these steps.
TGXFileObj gdx;
TgdxUELIndex UELS;
TgdxValues Vals;
int FDim, N, NrRecs, ErrNr, acrindx;
std::array<char, GMS_SSIZE> ErrMsg, acrtext, acrname;
if(!gdxGetReadyX(ErrMsg)) {
std::cout << "Error loading GDX library, msg = " << ErrMsg << std::endl;
exit(1);
}
gdx.gdxCreateX( ErrMsg);
gdx.gdxOpenWriteEx( "test.gdx", "testing", 0, ErrNr);
gdx.gdxUELRegisterRawStart();
for(int N{}; N<5; N++)
gdx.gdxUELRegisterRaw( "uel" + std::to_string(N));
gdx.gdxUELRegisterDone();
gdx.gdxDataWriteRawStart( "symb1", "text for symb1", 1, dt_par, 0);
for(int N{}; N<5; N++) {
UELS[0] = N;
Vals[vallevel] = (N == 1 || N == 3) ? gdx.gdxAcronymValue( N) : N;
gdx.gdxDataWriteRaw( UELS, Vals);
}
gdx.gdxDataWriteDone();
for(int N{}; N<gdx.gdxAcronymCount(); N++) {
gdx.gdxAcronymGetInfo( N, acrname, acrtext, acrindx);
if(acrindx == 2)
gdx.gdxAcronymSetInfo( N, "acro1", "Some text for acro1", acrindx)
else if(acrindx == 4)
gdx.gdxAcronymSetInfo( N, "acro2", "Some text for acro2", acrindx)
}
N = gdx.gdxClose();
if(N) {
gdxErrorStr(Nil, N, ErrMsg);
std::cout << "Error writing file = " << ErrMsg << std::endl;
exit(1);
}
gdx.gdxFree();
gdx.gdxCreateX( ErrMsg);
gdx.gdxOpenRead( "test.gdx", ErrNr);
if(ErrNr) {
std::cout << "Error opening file, nr = " << ErrNr << std::endl;
exit(1);
}
gdx.gdxAcronymSetInfo( 1, "acro1", "", 1000);
gdx.gdxAcronymSetInfo( 2, "acro2", "", 1001);
gdx.gdxDataReadRawStart( 1, NrRecs);
while(gdx.gdxDataReadRaw( UELs, Vals, FDim)) {
N = gdx.gdxAcronymIndex( Vals[vallevel]);
if(!N) std::cout << Vals[vallevel])
else std::cout << "Acronym: index = " << N << '\n';
}
gdx.gdxDataReadDone();
ErrNr = gdx.gdxClose();
if(ErrNr) {
gdxErrorStr(nil, ErrNr, ErrMsg);
std::cout << "Error reading file = ", ErrMsg);
exit(1);
}
gdx.gdxFree();
Functions by Category
The following table organizes the functions by category:
Category | Functions |
File (Open/Close) | gdxOpenRead gdxOpenWrite gdxClose |
System/Symbol | gdxSystemInfo gdxSymbolInfo gdxSymbolInfoX |
Information | gdxFindSymbol gdxGetUEL |
Unique elements | gdxUELRegisterRawStart gdxUELRegisterMapStart gdxUELRegisterStrStart gdxUELRegisterRaw gdxUELRegisterMap gdxUELRegisterStr gdxUELRegisterDone gdxGetUEL gdxUMUelInfo gdxUMUelGet gdxUMFindUEL |
Write Data | gdxDataWriteRawStart gdxDataWriteMapStart gdxDataWriteStrStart gdxDataWriteRaw gdxDataWriteMap gdxDataWriteStr gdxDataWriteDone |
Read Data | gdxDataReadRawStart gdxDataReadMapStart gdxDataReadStrStart gdxDataReadRaw gdxDataReadMap gdxDataReadStr gdxDataReadFilteredStart gdxDataReadDone gdxDataErrorCount gdxDataErrorRecord |
Text for UELs | gdxAddSetText gdxSetTextNodeNr gdxGetElemText gdxSetHasText |
Filters | gdxFilterRegisterStart gdxFilterRegister gdxFilterRegisterDone gdxFilterExists |
Special values | gdxResetSpecialValues gdxSetSpecialValues gdxGetSpecialValues gdxMapValue |
Errors | gdxGetLastError gdxErrorCount gdxErrorStr |
Version/Information | gdxSetTraceLevel gdxFileVersion gdxGetDLLVersion |
Longest symbol UEL | gdxSymbMaxLength gdxUELMaxLength gdxSymbIndxMaxLength |
Acronyms | gdxAcronymIndex gdxAcronymValue gdxAcronymCount gdxAcronymGetInfo gdxAcronymSetInfo |
Example programs
Example 1 (GAMS)
In this modified version of the trnsport.gms model, we use an external program to generate data for the demand parameter. After we solve the model, we write the solution to a GDX file, and call the external program again to read the variable from the GDX file.
$Title trnsport model using gdx files
$EOLCOM //
Sets
i canning plants / seattle, san-diego /
j markets / new-york, chicago, topeka / ;
Parameter
a(i) capacity of plant i in cases
/ seattle 350
san-diego 600 /
b(j) demand at market j in cases ;
Table d(i,j) distance in thousands of miles
new-york chicago topeka
seattle 2.5 1.7 1.8
san-diego 2.5 1.8 1.4 ;
Scalar f freight in dollars per case per thousand miles /90/ ;
Parameter c(i,j) transport cost in thousands of dollars per case ;
c(i,j) = f * d(i,j) / 1000 ;
Variables
x(i,j) shipment quantities in cases
z total transportation costs in thousands of dollars ;
Positive Variable x ;
Equations
cost define objective function
supply(i) observe supply limit at plant i
demand(j) satisfy demand at market j ;
// These lines execute during the compilation phase
// The GAMS system directory is passed the the program so it knows where
// to look for the gdxcclib library
$call 'gdxexdp.exe %gams.sysdir%' // create demand data
$GDXIN demanddata.gdx // open data file
$LOAD b=demand // load parameter b (named 'demand' in file)
$GDXIN // close data file
cost .. z =e= sum((i,j), c(i,j)*x(i,j)) ;
supply(i) .. sum(j, x(i,j)) =l= a(i) ;
demand(j) .. sum(i, x(i,j)) =g= b(j) ;
Model transport /all/ ;
Solve transport using lp minimizing z ;
Display b,x.l, x.m ;
// These lines execute during the execution phase
execute_unload 'results.gdx',x; // write variable x to the gdx file
execute 'gdxexdp.exe %gams.sysdir% results.gdx'; // do something with the solution
Example 2 (C)
#include <stdio.h>
#include <string.h>
#include "gdxcc.h"
#include "gclgms.h"
char *val2str(gdxHandle_t Tptr, double val, char *s) {
int sv;
if (gdxAcronymName(Tptr, val, s)) {
return s;
} else {
gdxMapValue(Tptr, val, &sv);
if (sv_normal != sv)
sprintf(s,"%s", gmsSVText[sv]);
else
sprintf(s,"%g", val);
return s;
}
}
int main (int argc, char *argv[]) {
int rc,i,j,NrSy,NrUel,ADim,ACount,AUser,AUser2,NRec,FDim,IDum, BadUels=0;
int ATyp, ATyp2;
char
msg[GMS_SSSIZE],
FileVersion[GMS_SSSIZE], FileProducer[GMS_SSSIZE],
sName[GMS_SSSIZE], sName2[GMS_SSSIZE], sText[GMS_SSSIZE], UelName[GMS_SSSIZE];
gdxHandle_t Tptr=NULL;
char DomainIDs[GMS_MAX_INDEX_DIM][GMS_SSSIZE];
char *DP[GMS_MAX_INDEX_DIM];
double
Vals[GMS_VAL_MAX],
dv[GMS_VAL_MAX];
int
Keys[GMS_MAX_INDEX_DIM];
char *dn, c;
GDXSTRINDEXPTRS_INIT(DomainIDs,DP);
if (argc != 2) {
printf("Usage: gdxdumpc gdxfile\n");
exit(1);
}
gdxCreate (&Tptr,msg,sizeof(msg));
if (NULL==Tptr) {
printf("Could not create GDX object:\n%s\n",msg);
exit(1);
}
rc = gdxOpenRead(Tptr, argv[1], &i);
if (0==rc) {
gdxErrorStr(Tptr,i,msg);
printf("Could not read GDX file %s:\n%s (rc=%d)\n",argv[1],msg,rc);
exit(1);
}
rc = gdxGetLastError(Tptr);
if (rc) {
gdxErrorStr(Tptr,rc,msg);
printf("Problems processing GDX file %s:\n%s (rc=%d)\n",argv[1],msg,rc);
exit(1);
}
gdxFileVersion(Tptr, FileVersion, FileProducer);
gdxSystemInfo(Tptr,&NrSy,&NrUel);
printf("* File version : %s\n",FileVersion);
printf("* Producer : %s\n",FileProducer);
printf("* Symbols : %d\n",NrSy);
printf("* Unique Elements: %d\n",NrUel);
for (i=1; i<=gdxAcronymCount(Tptr); i++) {
gdxAcronymGetInfo(Tptr, i, sName, sText, &rc);
printf("Acronym %s", sName);
if (strlen(sText)) printf(" '%s'", sText);
printf(";\n");
}
printf("$ontext\n");
for (i=1; i<=NrSy; i++) {
gdxSymbolInfo(Tptr, i, sName, &ADim, &ATyp);
gdxSymbolInfoX(Tptr, i, &ACount, &rc, sText);
printf("%-15s %3d %-12s %s\n", sName, ADim, gmsGdxTypeText[ATyp],sText);
}
printf("$offtext\n");
printf("$onempty onembedded \n");
for (i=1; i<=NrSy; i++) {
gdxSymbolInfo(Tptr, i, sName, &ADim, &ATyp);
gdxSymbolInfoX(Tptr, i, &ACount, &AUser, sText);
if (GMS_DT_VAR == ATyp || GMS_DT_EQU == ATyp) printf("$ontext\n");
if (GMS_DT_VAR == ATyp) {
if (AUser < 0 || AUser>=GMS_VARTYPE_MAX) AUser = GMS_VARTYPE_FREE;
memcpy(dv,gmsDefRecVar[AUser],GMS_VAL_MAX*sizeof(double));
dn = (char *) gmsVarTypeText[AUser];
} else if (GMS_DT_EQU == ATyp) {
if (AUser < 0 || AUser>=GMS_EQUTYPE_MAX) AUser = GMS_EQUTYPE_E;
memcpy(dv,gmsDefRecEqu[AUser],GMS_VAL_MAX*sizeof(double));
} else dv[GMS_VAL_LEVEL] = 0.0;
if (0 == ADim && GMS_DT_PAR == ATyp)
printf("Scalar");
else {
if (GMS_DT_VAR == ATyp) printf("%s ",dn);
printf("%s",gmsGdxTypeText[ATyp]);
}
if (GMS_DT_ALIAS == ATyp) {
gdxSymbolInfo(Tptr, AUser, sName2, &j, &ATyp2);
printf(" (%s, %s);\n", sName, sName2);
} else {
printf(" %s", sName);
if (ADim > 0) {
gdxSymbolGetDomain(Tptr, i, Keys);
printf("("); for (j=0; j<ADim; j++) {
if (Keys[j]==0) strcpy(sName,"*");
else
gdxSymbolInfo(Tptr, Keys[j], sName, &AUser2, &ATyp2);
if (j < ADim-1) printf("%s,",sName);
else printf("%s)",sName);
}
}
if (strlen(sText)) printf(" '%s'", sText);
}
if (0 == ACount) {
if (0 == ADim && GMS_DT_PAR == ATyp)
printf(" / 0.0 /;\n");
else if (GMS_DT_ALIAS != ATyp)
printf(" / /;\n");
} else {
printf(" /\n");
gdxDataReadRawStart (Tptr, i, &NRec);
while (gdxDataReadRaw(Tptr,Keys,Vals,&FDim)) {
if ((GMS_DT_VAR == ATyp || GMS_DT_EQU == ATyp) && 0 == memcmp(Vals,dv,GMS_VAL_MAX*sizeof(double)))
continue;
if (GMS_DT_PAR == ATyp && 0.0 == Vals[GMS_VAL_LEVEL])
continue;
for (j=1; j<=ADim; j++) {
if (1==gdxUMUelGet(Tptr, Keys[j-1], UelName, &IDum))
printf("'%s'", UelName);
else {
printf("L__",Keys[j-1]); BadUels++;
}
if (j < ADim) printf (".");
}
if (GMS_DT_PAR == ATyp)
printf(" %s\n", val2str(Tptr, Vals[GMS_VAL_LEVEL], msg));
else if (GMS_DT_SET == ATyp)
if (Vals[GMS_VAL_LEVEL]) {
j = (int) Vals[GMS_VAL_LEVEL];
gdxGetElemText(Tptr, j, msg, &IDum);
printf(" '%s'\n", msg);
} else printf("\n");
else if (GMS_DT_VAR == ATyp || GMS_DT_EQU == ATyp) {
printf(" ."); c='(';
for (j=GMS_VAL_LEVEL; j<GMS_VAL_MAX; j++) {
if (Vals[j] != dv[j]) {
if (GMS_VAL_SCALE == j && GMS_DT_VAR == ATyp &&
AUser != GMS_VARTYPE_POSITIVE && AUser != GMS_VARTYPE_NEGATIVE && AUser != GMS_VARTYPE_FREE)
printf("%c prior %s", c, val2str(Tptr, Vals[GMS_VAL_SCALE], msg));
else
printf("%c %s %s", c, gmsValTypeText[j]+1, val2str(Tptr, Vals[j], msg));
if ( '(' == c) c = ',';
}
}
printf(" )\n");
}
}
}
printf("/;\n");
j=1; while (gdxSymbolGetComment(Tptr, i, j++, msg)) printf("* %s\n", msg);
if (GMS_DT_VAR == ATyp || GMS_DT_EQU == ATyp) printf("$offtext\n");
printf("\n");
}
printf("$offempty offembedded \n");
if (BadUels > 0)
printf("**** %d reference(s) to unique elements without a string representation\n", BadUels);
gdxFree(&Tptr);
}
Example 3 (C++)
#include <string>
#include <cstring>
#include <cstdlib>
#include <iostream>
#include "gdxcc.h"
using namespace std;
static gdxStrIndexPtrs_t Indx;
static gdxStrIndex_t IndxXXX;
static gdxValues_t Values;
void ReportGDXError(gdxHandle_t PGX) {
char S[GMS_SSSIZE];
cout << "**** Fatal GDX Error" << endl;
gdxErrorStr(PGX, gdxGetLastError(PGX), S);
cout << "**** " << S << endl;
exit(1);
}
void ReportIOError(int N, const string &msg) {
cout << "**** Fatal I/O Error = " << N << " when calling " << msg << endl;
exit(1);
}
void WriteData(gdxHandle_t PGX, const char *s, const double V) {
strcpy(Indx[0], s);
Values[GMS_VAL_LEVEL] = V;
gdxDataWriteStr(PGX, (const char **)Indx, Values);
}
int main(int argc, char *argv[]) {
gdxHandle_t PGX = NULL;
char Msg[GMS_SSSIZE], Producer[GMS_SSSIZE], Sysdir[GMS_SSSIZE], VarName[GMS_SSSIZE];
int ErrNr;
int VarNr;
int NrRecs;
int N;
int Dim;
int VarTyp;
int D;
if (argc < 2 || argc > 3) {
cout << "**** xp_Example1: incorrect number of parameters" << endl;
exit(1);
}
strcpy(Sysdir, argv[1]);
cout << "xp_Example1 using GAMS system directory: " << Sysdir << endl;
if (!gdxCreateD(&PGX, Sysdir, Msg, sizeof(Msg))) {
cout << "**** Could not load GDX library" << endl << "**** " << Msg << endl;
exit(1);
}
gdxGetDLLVersion(PGX, Msg);
cout << "Using GDX DLL version: " << Msg << endl;
GDXSTRINDEXPTRS_INIT(IndxXXX, Indx);
if (2 == argc) {
gdxOpenWrite(PGX, "demanddata.gdx", "xp_example1", &ErrNr);
if (ErrNr) ReportIOError(ErrNr, "gdxOpenWrite");
if (!gdxDataWriteStrStart(PGX, "Demand", "Demand data", 1, GMS_DT_PAR, 0))
ReportGDXError(PGX);
WriteData(PGX, "New-York", 324.0);
WriteData(PGX, "Chicago", 299.0);
WriteData(PGX, "Topeka", 274.0);
if (!gdxDataWriteDone(PGX)) ReportGDXError(PGX);
cout << "Demand data written by example1" << endl;
}
else {
gdxOpenRead(PGX, argv[2], &ErrNr);
if (ErrNr) ReportIOError(ErrNr, "gdxOpenRead");
gdxFileVersion(PGX, Msg, Producer);
cout << "GDX file written using version: " << Msg << endl;
cout << "GDX file written by: " << Producer << endl;
if (!gdxFindSymbol(PGX, "x", &VarNr)) {
cout << "**** Could not find variable X" << endl;
exit(1);
}
gdxSymbolInfo(PGX, VarNr, VarName, &Dim, &VarTyp);
if (Dim != 2 || GMS_DT_VAR != VarTyp) {
cout << "**** X is not a two dimensional variable: "
<< Dim << ":" << VarTyp << endl;
exit(1);
}
if (!gdxDataReadStrStart(PGX, VarNr, &NrRecs)) ReportGDXError(PGX);
cout << "Variable X has " << NrRecs << " records" << endl;
while (gdxDataReadStr(PGX, Indx, Values, &N)) {
if (0 == Values[GMS_VAL_LEVEL]) continue;
for (D = 0; D < Dim; D++) cout << (D ? '.' : ' ') << Indx[D];
cout << " = " << Values[GMS_VAL_LEVEL] << endl;
}
cout << "All solution values shown" << endl;
gdxDataReadDone(PGX);
}
if (ErrNr = gdxClose(PGX)) ReportIOError(ErrNr, "gdxClose");
return 0;
}
Example 4 (VB.NET)
Module xp_example1
'///////////////////////////////////////////////////////////////
'// This program generates demand data for a modified version //
'// of the trnsport model or reads the solution back from a //
'// gdx file. //
'// //
'// Calling convention: //
'// Case 1: //
'// Parameter 1: GAMS system directory //
'// The program creates a GDX file with demand data //
'// Case 2: //
'// Parameter 1: GAMS system directory //
'// Parameter 2: gdxfile //
'// The program reads the solution from the GDX file //
'// Paul van der Eijk Jun-12, 2002 //
'///////////////////////////////////////////////////////////////
Dim PGX As IntPtr
Sub ReportGDXError(ByVal PGX As IntPtr)
Dim S As String = String.Empty
Console.WriteLine("**** Fatal GDX Error")
gdxErrorStr(0, gdxGetLastError(PGX), S)
Console.WriteLine("**** " & S)
End
End Sub
Sub ReportIOError(ByVal N As Integer)
Console.WriteLine("**** Fatal I/O Error = " & N)
End
End Sub
Sub WriteData(ByVal s As String, ByVal V As Double)
Dim Indx(maxdim) As String 'TgdxStrIndex
Dim Values(val_max) As Double 'TgdxValues
Indx(0) = s
Values(val_level) = V
gdxDataWriteStr(PGX, Indx, Values)
End Sub
Dim Msg As String
Dim Sysdir As String
Dim Producer As String
Dim ErrNr, rc As Integer
Dim Indx(maxdim) As String 'TgdxStrIndex
Dim Values(val_max) As Double 'TgdxValues
Dim VarNr As Integer
Dim NrRecs As Integer
Dim N As Integer
Dim Dimen As Integer
Dim VarName As String
Dim VarTyp As Integer
Sub Main()
If Environment.GetCommandLineArgs().Length <> 2 And Environment.GetCommandLineArgs().Length <> 3 Then
Console.WriteLine("**** XP_Example1: incorrect number of parameters")
End
End If
Sysdir = Environment.GetCommandLineArgs(1)
Console.WriteLine("XP_Example1 using GAMS system directory: " & Sysdir)
If Not gdxCreateD(PGX, Sysdir, Msg) Then
Console.WriteLine("**** Could not load GDX library")
Console.WriteLine("**** " & Msg)
Exit Sub
End If
gdxGetDLLVersion(PGX, Msg)
Console.WriteLine("Using GDX DLL version: " & Msg)
If Environment.GetCommandLineArgs().Length = 2 Then
'write demand data
gdxOpenWrite(PGX, "demanddata.gdx", "xp_example1", ErrNr)
If ErrNr <> 0 Then
ReportIOError(ErrNr)
End If
If gdxDataWriteStrStart(PGX, "Demand", "Demand data", 1, dt_par, 0) = 0 Then
ReportGDXError(PGX)
End If
WriteData("New-York", 324.0)
WriteData("Chicago", 299.0)
WriteData("Topeka", 274.0)
If gdxDataWriteDone(PGX) = 0 Then
ReportGDXError(PGX)
End If
Console.WriteLine("Demand data written by xp_example1")
Else
rc = gdxOpenRead(PGX, Environment.GetCommandLineArgs(2), ErrNr) 'Environment.GetCommandLineArgs(1) "trnsport.gdx"
If ErrNr <> 0 Then
ReportIOError(ErrNr)
End If
'read x variable back (non-default level values only)
gdxFileVersion(PGX, Msg, Producer)
Console.WriteLine("GDX file written using version: " & Msg)
Console.WriteLine("GDX file written by: " & Producer)
If gdxFindSymbol(PGX, "x", VarNr) = 0 Then
Console.WriteLine("**** Could not find variable X")
Exit Sub
End If
gdxSymbolInfo(PGX, VarNr, VarName, Dimen, VarTyp)
If (Dimen <> 2) Or (VarTyp <> dt_var) Then
Console.WriteLine("**** X is not a two dimensional variable")
Exit Sub
End If
If gdxDataReadStrStart(PGX, VarNr, NrRecs) = 0 Then
ReportGDXError(PGX)
End If
Console.WriteLine("Variable X has " & NrRecs & " records")
While gdxDataReadStr(PGX, Indx, Values, N) <> 0
If Values(val_level) = 0.0 Then 'skip level = 0.0 is default
Continue While
End If
For D = 1 To Dimen
Console.Write(Indx(D - 1))
If D < Dimen Then
Console.Write(".")
End If
Next
Console.WriteLine(" = " & Values(val_level))
End While
Console.WriteLine("All solution values shown")
gdxDataReadDone(PGX)
End If
ErrNr = gdxClose(PGX)
If ErrNr <> 0 Then
ReportIOError(ErrNr)
End If
End Sub
End Module
Example 6 (Python)
import argparse
import sys
from gams.core import gdx
if __name__ == "__main__":
parser = argparse.ArgumentParser()
parser.add_argument("sysDir")
parser.add_argument("gdxFile", nargs="?", default=None)
args = parser.parse_args()
print(f"Using GAMS system directory: {args.sysDir}")
gdx_h = gdx.new_gdxHandle_tp()
rc = gdx.gdxCreateD(gdx_h, args.sysDir, gdx.GMS_SSSIZE)
if not rc[0]:
raise Exception(rc[1])
print(f"Using GDX DLL version: {gdx.gdxGetDLLVersion(gdx_h)[1]}")
if args.gdxFile is None:
if not gdx.gdxOpenWrite(gdx_h, "demanddata.gdx", "xp_example1")[0]:
raise Exception("Error gdxOpenWrite")
if not gdx.gdxDataWriteStrStart(
gdx_h, "Demand", "Demand data", 1, gdx.GMS_DT_PAR, 0
):
raise Exception("Error gdxDataWriteStrStart")
values = gdx.doubleArray(gdx.GMS_VAL_MAX)
values[gdx.GMS_VAL_LEVEL] = 324.0
gdx.gdxDataWriteStr(gdx_h, ["New-York"], values)
values[gdx.GMS_VAL_LEVEL] = 299.0
gdx.gdxDataWriteStr(gdx_h, ["Chicago"], values)
values[gdx.GMS_VAL_LEVEL] = 274.0
gdx.gdxDataWriteStr(gdx_h, ["Topeka"], values)
if not gdx.gdxDataWriteDone(gdx_h):
raise Exception("Error gdxDataWriteDone")
print("Demand data written")
else:
if not gdx.gdxOpenRead(gdx_h, sys.argv[2])[0]:
raise Exception("Error gdxOpenRead")
file_version, producer = gdx.gdxFileVersion(gdx_h)[1:]
print(f"GDX file written using version: {file_version}")
print(f"GDX file written by: {producer}")
rc, sym_nr = gdx.gdxFindSymbol(gdx_h, "x")
if not rc:
raise Exception("Symbol x not found")
dim, sym_type = gdx.gdxSymbolInfo(gdx_h, sym_nr)[2:]
if dim != 2 or sym_type != gdx.GMS_DT_VAR:
raise Exception(
f"x is not a two dimensional variable:\ndim = {dim}\ntype = {sym_type}"
)
rc, nr_recs = gdx.gdxDataReadStrStart(gdx_h, sym_nr)
if not rc:
raise Exception(
f"Error in gdxDataReadStrStart: {gdx.gdxErrorStr(gdx_h, gdx.gdxGetLastError(gdx_h))[1]}"
)
print(f"Variable x has {nr_recs} records")
for i in range(nr_recs):
rc, elements, values, afdim = gdx.gdxDataReadStr(gdx_h)
if not rc:
raise Exception(
f"Error in gdxDataReadStr: {gdx.gdxErrorStr(gdx_h, gdx.gdxGetLastError(gdx_h))[1]}"
)
level = values[gdx.GMS_VAL_LEVEL]
if level != 0:
elements = [elements[d] for d in range(dim)]
print(f"{'.'.join(elements)} = {level}")
print("All solution values shown")
gdx.gdxDataReadDone(gdx_h)
if gdx.gdxClose(gdx_h):
raise Exception("Error in gdxClose")
if not gdx.gdxFree(gdx_h):
raise Exception("Error in gdxFree")
print("All done")
Example 7 (C#)
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace xp_example1
{
class xp_example1
{
static gdxcs gdx;
static void ReportGDXError()
{
string S = string.Empty;
Console.WriteLine("**** Fatal GDX Error");
gdx.gdxErrorStr(gdx.gdxGetLastError(), ref S);
Console.WriteLine("**** " + S);
Environment.Exit(1);
}
static void ReportIOError(int N)
{
Console.WriteLine("**** Fatal I/O Error = " + N);
Environment.Exit(1);
}
static void WriteData(string s, double V)
{
string[] Indx = new string[gamsglobals.maxdim];
double[] Values = new double[gamsglobals.val_max];
Indx[0] = s;
Values[gamsglobals.val_level] = V;
gdx.gdxDataWriteStr(Indx, Values);
}
static int Main(string[] args)
{
string Msg = string.Empty;
string Sysdir;
string Producer = string.Empty;
int ErrNr = 0;
int rc;
string[] Indx = new string[gamsglobals.maxdim];
double[] Values = new double[gamsglobals.val_max];
int VarNr = 0;
int NrRecs = 0;
int N = 0;
int Dimen = 0;
string VarName = string.Empty;
int VarTyp = 0;
int D;
if (Environment.GetCommandLineArgs().Length != 2 && Environment.GetCommandLineArgs().Length != 3)
{
Console.WriteLine("**** XP_Example1: incorrect number of parameters");
return 1;
}
String[] arguments = Environment.GetCommandLineArgs();
Sysdir = arguments[1];
Console.WriteLine("XP_Example1 using GAMS system directory: " + Sysdir);
gdx = new gdxcs(Sysdir, ref Msg);
if (Msg != string.Empty)
{
Console.WriteLine("**** Could not load GDX library");
Console.WriteLine("**** " + Msg);
return 1;
}
gdx.gdxGetDLLVersion(ref Msg);
Console.WriteLine("Using GDX DLL version: " + Msg);
if (Environment.GetCommandLineArgs().Length == 2)
{
gdx.gdxOpenWrite("demanddata.gdx", "xp_example1", ref ErrNr);
if (ErrNr != 0) xp_example1.ReportIOError(ErrNr);
if (gdx.gdxDataWriteStrStart("Demand", "Demand data", 1, gamsglobals.dt_par, 0) == 0) ReportGDXError();
WriteData("New-York", 324.0);
WriteData("Chicago", 299.0);
WriteData("Topeka", 274.0);
if (gdx.gdxDataWriteDone() == 0) ReportGDXError();
Console.WriteLine("Demand data written by xp_example1");
}
else
{
rc = gdx.gdxOpenRead(arguments[2], ref ErrNr);
if (ErrNr != 0) ReportIOError(ErrNr);
gdx.gdxFileVersion(ref Msg, ref Producer);
Console.WriteLine("GDX file written using version: " + Msg);
Console.WriteLine("GDX file written by: " + Producer);
if (gdx.gdxFindSymbol("x", ref VarNr) == 0)
{
Console.WriteLine("**** Could not find variable X");
return 1;
}
gdx.gdxSymbolInfo(VarNr, ref VarName, ref Dimen, ref VarTyp);
if (Dimen != 2 || VarTyp != gamsglobals.dt_var)
{
Console.WriteLine("**** X is not a two dimensional variable");
return 1;
}
if (gdx.gdxDataReadStrStart(VarNr, ref NrRecs) == 0) ReportGDXError();
Console.WriteLine("Variable X has " + NrRecs + " records");
while (gdx.gdxDataReadStr(ref Indx, ref Values, ref N) != 0)
{
if(Values[gamsglobals.val_level] == 0.0)
continue;
for (D=0; D<Dimen; D++)
{
Console.Write(Indx[D]);
if (D < Dimen-1) Console.Write(".");
}
Console.WriteLine(" = " + Values[gamsglobals.val_level]);
}
Console.WriteLine("All solution values shown");
gdx.gdxDataReadDone();
}
ErrNr = gdx.gdxClose();
if (ErrNr != 0) ReportIOError(ErrNr);
return 0;
}
}
}
Example 8 (Java)
package com.gams.xp_examples;
import com.gams.api.*;
public class xp_example1 {
static final int maxdim = 20;
static final int val_level = 0;
static final int val_marginal = 1;
static final int val_lower = 2;
static final int val_upper = 3;
static final int val_scale = 4;
static final int val_max = 5;
static final int dt_set = 0;
static final int dt_par = 1;
static final int dt_var = 2;
static final int dt_equ = 3;
static final int dt_alias = 4;
static final int dt_max = 5;
static gdx gdxio = new gdx();
static String[] Indx = new String[maxdim];
static double[] Values = new double[val_max];
static void ReportGDXError() {
String[] S = new String[1];
System.out.println("**** Fatal GDX Error");
gdxio.ErrorStr(gdxio.GetLastError(), S);
System.out.println("**** " + S[0]);
System.exit(1);
}
static void ReportIOError(int N, String msg ) {
System.out.println("**** Fatal I/O Error = " + N + " when calling " + msg);
System.exit(1);
}
static void WriteData(String s, double V) {
Indx[0] = s;
Values[val_level] = V;
gdxio.DataWriteStr(Indx,Values);
}
public static void main (String[] args) {
String[] Msg = new String[1];
String[] Producer = new String[1];
String Sysdir;
int[] ErrNr = new int[1];
int[] VarNr = new int[1];
int[] NrRecs = new int[1];
int[] N = new int[1];
int[] Dim = new int[1];
String[] VarName = new String[1];
int[] VarTyp = new int[1];
int D;
if (args.length < 1 || args.length > 2) {
System.out.println("**** Example1: incorrect number of parameters");
System.exit(1);
}
Sysdir = args[0];
System.out.println("Example1 using GAMS system directory: " + Sysdir);
if (gdxio.CreateD(Sysdir, Msg) != 1) {
System.out.println("**** Could not load GDX library");
System.out.println("**** " + Msg[0]);
System.exit(1);
}
gdxio.GetDLLVersion(Msg);
System.out.println("Using GDX DLL version: " + Msg[0]);
if (1 == args.length) {
gdxio.OpenWrite("demanddata.gdx", "example1", ErrNr);
if (ErrNr[0] != 0) ReportIOError(ErrNr[0],"gdxOpenWrite");
if (gdxio.DataWriteStrStart("Demand","Demand data",1,dt_par,0) != 1)
ReportGDXError();
WriteData("New-York",324.0);
WriteData("Chicago" ,299.0);
WriteData("Topeka" ,274.0);
if (gdxio.DataWriteDone() != 1) ReportGDXError();
System.out.println("Demand data written by example1\n");
} else {
gdxio.OpenRead(args[1], ErrNr);
if (ErrNr[0] != 0) ReportIOError(ErrNr[0],"gdxOpenRead");
gdxio.FileVersion(Msg,Producer);
System.out.println("GDX file written using version: " + Msg[0]);
System.out.println("GDX file written by: " + Producer[0]);
if (gdxio.FindSymbol("x",VarNr) != 1) {
System.out.println("**** Could not find variable X");
System.exit(1);
}
gdxio.SymbolInfo(VarNr[0],VarName,Dim,VarTyp);
if (Dim[0] != 2 || dt_var != VarTyp[0]) {
System.out.println("**** X is not a two dimensional variable: " + Dim[0] + ":" + VarTyp[0]);
System.exit(1);
}
if (gdxio.DataReadStrStart(VarNr[0],NrRecs) != 1) ReportGDXError();
System.out.println("Variable X has " + NrRecs[0] + " records");
while (gdxio.DataReadStr(Indx,Values,N) != 0) {
if (0 == Values[val_level]) continue;
for (D=0; D<Dim[0]; D++) {
System.out.print(Indx[D]);
if (D<Dim[0]-1) System.out.print(".");
}
System.out.println(" = " + Values[val_level]);
}
System.out.println("All solution values shown");
gdxio.DataReadDone();
}
ErrNr[0] = gdxio.Close();
if (ErrNr[0] != 0) ReportIOError(ErrNr[0],"gdxClose");
if (gdxio.Free() != 1) {
System.out.println("Problems unloading the GDX DLL");
System.exit(1);
}
}
}