- GAMS Data eXchange (GDX)
- Basic information on GDX file format
- Setting up and building GDX
- Reference documentation
- Introduction into using GDX API
- Writing data to a GDX file
- Writing data using strings
- Writing data using integers (raw)
- Writing data using integers (mapped)
- Reading data from a GDX file
- Reading data using strings
- Reading data using integers (raw)
- Reading data using integers (Mapped)
- Reading data using a filter
- Dealing with acronyms
- Functions by Category
- Transition diagram
- Example programs
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:
- Sets,
- parameters,
- scalars,
- decision variables,
- and equations.
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.
- 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)
- with their attributes...
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.
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.
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.
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:
- GAMS API generator (language binding/wrapper tool)
- CMake (build system)
- C++17 compiler (e.g. GCC, clang, MSVC, Intel C++)
A full detailed Doxygen-generated API reference is available here.
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.
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);
}
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.
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();
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.
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 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 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 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 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
.
// We wish to only read the values of A when the first label is either "New-York" or "Chicago"
// For this, we assign a unique value to each one of the label, here we choose 1000 and 2000
// Then, we register a filter with a unique ID, here 123.
// Note that a filter ID cannot be reused. The filter is immutable after its creation
gdx.gdxUELRegisterMapStart();
gdx.gdxUELRegisterMap( 1000, "New-York" );
gdx.gdxUELRegisterMap( 2000, "Chicago" );
gdx.gdxUELRegisterDone();
// Register the filter for set I; reference this filter with integer 123 (filter number)
if(!gdx.gdxFilterRegisterStart(123))
ReportGDXError();
gdx.gdxFilterRegister(1000);
gdx.gdxFilterRegister(2000);
if(!gdx.gdxFilterRegisterDone())
ReportGDXError();
// set the filter actions
std::array filterAction {
123, //filter for I
gdx::DOMC_EXPAND // expand (=-1)
};
// Remember highest mapped value in variable LastMapped
int NrUnMapped, LastMapped;
gdx.gdxUMUelInfo(NrUnMapped, LastMapped);
// Read parameter A as a 2 dimensional parameter
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)) {
// do something to process the record read (index, values)
}
}
if(!gdx.gdxDataReadDone()
ReportGDXError();
// see if there are new unique elements
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".
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;
//Check the library
if(!gdxGetReadyX(ErrMsg)) {
std::cout << "Error loading GDX library, msg = " << ErrMsg << std::endl;
exit(1);
}
//Create GDX object and open file for writing
gdx.gdxCreateX( ErrMsg);
gdx.gdxOpenWriteEx( "test.gdx", "testing", 0, ErrNr);
//register some unique elements
gdx.gdxUELRegisterRawStart();
for(int N{}; N<5; N++)
gdx.gdxUELRegisterRaw( "uel" + std::to_string(N));
gdx.gdxUELRegisterDone();
//write a parameter with two acronyms
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();
//provide the names for the acronyms used
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)
}
//final check for errors before we close the file
N = gdx.gdxClose();
if(N) {
gdxErrorStr(Nil, N, ErrMsg);
std::cout << "Error writing file = " << ErrMsg << std::endl;
exit(1);
}
gdx.gdxFree();
//open the file we just created
gdx.gdxCreateX( ErrMsg);
gdx.gdxOpenRead( "test.gdx", ErrNr);
if(ErrNr) {
std::cout << "Error opening file, nr = " << ErrNr << std::endl;
exit(1);
}
//give acronym indices using the name of the acronym
gdx.gdxAcronymSetInfo( 1, "acro1", "", 1000);
gdx.gdxAcronymSetInfo( 2, "acro2", "", 1001);
//read the parameter
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();
//final error check before closing the file
if(ErrNr) {
gdxErrorStr(nil, ErrNr, ErrMsg);
std::cout << "Error reading file = ", ErrMsg);
exit(1);
}
gdx.gdxFree();
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 |
Some GDX operations only make sense after running other routines for preparation beforehand. For example, writing records to a symbol in raw mode can only be done after the symbol has been "opened" for writing in raw mode. Hence, the GDX operations follow a state machine like logic that prevents the user from executing operations that are not sensible in the current state of the GDX object. The routines documented below follow certain input / output state transitions. Routines not documented below have no special state requirements.
graph TD
f_notopen -->|gdxOpenRead| fr_init
f_notopen -->|gdxOpenWrite| fr_init
f_notopen -->|gdxOpenWriteEx| fr_init
f_init -->|gdxClose| f_notopen
fw_init -->|gdxClose| f_notopen
fr_init -->|gdxSymbMaxLength| fr_init
fr_init -->|gdxUELMaxLength| fr_init
fr_init -->|gdxSymbIndxMaxLength| fr_init
fr_init -->|gdxAcronymSetInfo| fr_init
fw_init -->|gdxAcronymSetInfo| fw_init
graph TD
fr_init -->|gdxDataReadRawStart*| fr_raw_data
fr_init -->|gdxDataReadMapStart*| fr_map_data
fr_init -->|gdxDataReadStrStart*| fr_str_data
fr_init -->|gdxDataReadFilteredStart*| fr_map_data
fr_raw_data -->|gdxDataReadRaw**| fr_raw_data
fr_raw_data -->|gdxDataReadRaw**| fr_init
fr_map_data -->|gdxDataReadMap**| fr_map_data
fr_map_data -->|gdxDataReadMap**| fr_init
fr_str_data -->|gdxDataReadStr**| fr_str_data
fr_str_data -->|gdxDataReadStr**| fr_init
fr_raw_data -->|gdxDataReadDone| fr_init
fr_map_data -->|gdxDataReadDone| fr_init
fr_str_data -->|gdxDataReadDone| fr_init
fr_init -->|gdxFilterRegisterStart| fr_filter
fr_filter -->|gdxFilterRegister| fr_filter
fr_filter -->|gdxFilterRegisterDone| fr_init
fr_init -->|gdxFilterExists| fr_init
*
denotes symbol having data. Transition tofr_init
if the symbol is empty.**
stay infr_{raw,map,str}_data
iff. there are more records to read, move tofr_init
otherwise.
graph TD
fw_init -->|gdxDataWriteRawStart| fw_raw_data
fw_init -->|gdxDataWriteMapStart| fw_map_data
fw_init -->|gdxDataWriteStrStart| fw_str_data
fw_raw_data -->|gdxDataWriteRaw| fw_raw_data
fw_map_data -->|gdxDataWriteMap| fw_map_data
fw_str_data -->|gdxDataWriteStr| fw_str_data
fw_raw_data -->|gdxDataWriteDone| fw_init
fw_map_data -->|gdxDataWriteDone| fw_init
fw_str_data -->|gdxDataWriteDone| fw_init
graph TD
fr_init -->|gdxUELRegisterRawStart| f_raw_elem
f_raw_elem -->|gdxUELRegisterRaw| f_raw_elem
fr_init -->|gdxUELRegisterRawStart| f_map_elem
f_map_elem -->|gdxUELRegisterRaw| f_map_elem
fr_init -->|gdxUELRegisterRawStart| f_str_elem
f_str_elem -->|gdxUELRegisterRaw| f_str_elem
f_raw_elem -->|gdxUELRegisterDone| fr_init
f_map_elem -->|gdxUELRegisterDone| fr_init
f_str_elem -->|gdxUELRegisterDone| fr_init
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
/*
Use this command to compile the example:
cl gdxdumpc.c ../../gmstest/apifiles/C/api/gdxcc.c ../../gmstest/apifiles/C/api/gclgms.c -I../../gmstest/apifiles/C/api/
*/
#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);
/* Acroynms */
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");
}
/* Symbolinfo */
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) /* Scalar */
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) /* Scalar */
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))) /* all default records */
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);
}
/*
Use this command to compile the example:
cl xp_example1.cpp ../C/api/gdxcc.c -I../C/api
*/
#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) {
/* Write demand data */
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; /* skip level 0.0 is default */
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;
}
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
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")
///////////////////////////////////////////////////////////////
// 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 //
///////////////////////////////////////////////////////////////
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)
{
//write demand data
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);
//read x variable back (non-default level values only)
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) //skip level = 0.0 is default
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;
}
}
}
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) {
/* Write demand data */
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; /* skip level 0.0 is default */
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);
}
}
}