ex2.gms : External Equation - Example 2

Description

This is the second in a sequence of examples that show how to
use the external equations (=X=) facility with GAMS/CONOPT.
The second model is also simple unconstrained quadratic model
and the quadratic function is defined in an external equation.

But this time we communicate the data from GAMS via a put file
including information on the size of the model. We can now change
the data in GAMS without reprogramming the Fortran or C routine.

The model is slightly convoluted. We want to be able to solve
it for different subsets I of the Domain D.


Small Model of Type : GAMS


Category : GAMS Test library


Main file : ex2.gms

$title  External Equation - Example 2 (EX2,SEQ=565)

$offSymList offsymxref
$onText

 This is the second in a sequence of examples that show how to
 use the external equations (=X=) facility with GAMS/CONOPT.
 The second model is also simple unconstrained quadratic model
 and the quadratic function is defined in an external equation.

 But this time we communicate the data from GAMS via a put file
 including information on the size of the model. We can now change
 the data in GAMS without reprogramming the Fortran or C routine.

 The model is slightly convoluted. We want to be able to solve
 it for different subsets I of the Domain D.

$offText


set D    Domain for the variables / i1*i14 /;
set I(D) Subset for actual optimization;
alias (D,E), (i,j);

Parameter Q(D,D) Covariance Matrix
          X0(D)  Targets;
Q(D,E) = power(0.5, abs(ord(D)-ord(E)) );
X0(D)  = ord(D) / card(D);
display Q, x0;

variable x(D), z;
equation zdef, zdefX;

*  Define I for the first solve to hold 7 elements

I(D) = yes$(ord(D) le 7);

*  The desired equation, implemented in GAMS, is

zdef..  sum {(i,j),
             (x(i)-x0(i)) * Q(i,j) * (x(j)-x0(j)) }
        =e= z;

*   It is implemented as an external equation as:

zdefX.. sum {D$I(D), ord(D)*x(D) } + (card(I)+1)* z =X= 1;

$onText
 See the comments in ex1.gms for further details.
 We use D instead of I in the equation since I is now a dynamic
 set and we cannot use ord(I).

 The size of the set I and the model data is now written to
 the file ex2.put using PUT statements.  Note that we end with
 a putclose statement so the file is closed when we read it
 in the external module.
$offText

file f / ex2.put /; f.nw = 0; f.nd = 13;

f.nr = 0; put f card(i):0:0 /; f.nr = 2;
loop {i,
   put x0(i) /;
   loop {j,
      put q(i,j) /;
   };
};
putclose f;

$                             set pre
$ifI %system.filesys%==unix  $set pre 'lib'
$                             set suf '64'

$set N     ex2
$set c_cbN %pre%%N%c_cb%suf%
$set d_cbN %pre%%N%d_cb%suf%
$set f_cbN %pre%%N%f_cb%suf%

model %N%      'GAMS implementation'                         / zdef /;
model %c_cbN%  'External equations in C, with callbacks'     / zdefX /;
model %d_cbN%  'External equations in Delphi with callbacks' / zdefX /;
model %f_cbN%  'External equations in F77, with callbacks'   / zdefX /;

option limcol = 0;
$onText
 Create a summary table where we compare the expected results,
 x0 with the actual results, x.l, to ensure that data have been
 communicated correctly to the external equation.
$offText

parameter report(*,*,*) 'Solution Summary';
option report:5;
scalar totdist /0/;

*  reuse the same code several times
$onEchoV > runme.gms
z.l = 0;
z.m = 0;
x.l(i) = 0;
x.m(i) = 0;
zdef.l = 0;
zdef.m = 0;
solve %1 using nlp minimizing z;
abort$(%1.solvestat %2) 'problems running model %1';
execerror = 0;
report('Solve ','Stat',  '%1') = %1.solvestat;
report('Model ','Stat',  '%1') = %1.modelstat;
report(i,'Target',  '%1') = x0(i);
report(i,'Value',   '%1') = x.l(i);
report(i,'Distance','%1') = abs(x.l(i) - x0(i));
totdist = totdist + sum(i,abs(x.l(i) - x0(i)));
$offEcho

$                             set ext '.dll'
$ifI %system.filesys%==unix  $set ext '.so'
$ifI %system.platform%==dex  $set ext '.dylib'
$ifI %system.platform%==dax  $set ext '.dylib'

$                             set eq
$ifI %system.filesys%==unix  $set eq "'"

$if set runall  $set runC_cb '1' set runD_cb '1' set runF_cb '1'

$ifThen not set nocomp
$  ifI set runC_cb $call gams complink lo=%gams.lo% --lang=c         --files=ex2c_cb.c                                     --libname=%c_cbN%%ext%
$  if errorlevel 1 $abort Error compiling C Library
$  ifI set runD_cb $call gams complink lo=%gams.lo% --lang=Delphi    --files=ex2d_cb.dpr
$  if errorlevel 1 $abort Error compiling Delphi Library
$  ifI set runF_cb $call gams complink lo=%gams.lo% --lang=fortran90 --files=%eq%"gehelper.f90 msg2_f.f90 ex2f_cb.f90"%eq% --libname=%f_cbN%%ext%
$  if errorlevel 1 $abort Error compiling Fortran90 Library
$endIf

$                batInclude runme %N%     '<> 1'
$if set runC_cb $batInclude runme %c_cbN% '<> 1'
$if set runD_cb $batInclude runme %d_cbN% '<> 1'
$if set runF_cb $batInclude runme %f_cbN% '<> 1'

display report;

if ((totdist < 1.0E-6),
  display "@@@@ #Test passed.";
else
  abort totdist, "@@@@ #Test not passed. Inspect ex2.lst for details.";
);

$onText
 Now define I to hold all 14 elements. This should give rise to an
 error since we have only allocated space for 10 elements in the
 Fortran and Delphi routine.
 The C-version allocates memory dynamically and will work correctly.
$offText

I(D) = yes;

$onText
 When we open the PUT file again for writing it will by default
 be overwritten, which is what we need:
$offText

* start over with new data and empty report

f.nr = 0; put f card(i):0:0 /; f.nr = 2;
loop {i,
   put x0(i) /;
   loop {j,
      put q(i,j) /;
   };
};
putclose f;

option clear = report;
totdist = 0;

$                batInclude runme %N%     '<> 1'
$if set runC_cb $batInclude runme %c_cbN% '<> 1'
$if set runD_cb $batInclude runme %d_cbN% ' = 1'
$if set runF_cb $batInclude runme %f_cbN% ' = 1'

display report;