quality.gms : Driver for quality tests of all sorts

Description


Small Model of Type : GAMS


Category : GAMS Test library


Main file : quality.gms   includes :   testmod.inc [html]

$TITLE 'Driver for quality tests of all sorts' (QUALITY,SEQ=2)


$version 142

$eolcom //
$escape &
$if not set TRACE    $set TRACE    testlib.trc    // gtrace file trace=%TRACE%
$if not set TRACEREP $set TRACEREP testlib.rep    // Gtrace report file
$set TL       6
$if NOT %gams.tl%==0 $set TL %gams.tl%
// the default TL of 6 is just for starters - just trying it on for size

$set SLASH     \
$if %system.filesys% == UNIX $set SLASH /
$if not set PREFIX $set PREFIX %system.buildcode%

$if not set FAIL $set ALL alltests.gms
$if     set FAIL $set ALL alltests.tmp
$if not set FAIL $set FAIL failures_qa.gms

$include testmod.inc

SET mdl(m);
SET ignore(m) models which are not supposed to be tested here /
  BADPT4                   'is that test correct?'
  BADPT5                   'is that test correct?'
  CTRLC                    'interactive test'
  CONVERT1                 'tests convert option coinfml, which does not exist (anymore), can be deleted?'
 (fnacos,fnacosx,fnasin,fnasinx,fnatan,fnatan2,fnatan2n,fnatan2x,fncentr
  fncentr2*fncentr6,fncentrx,fncentry,fncos,fncosh,fnedist,fnentro,fnentro2
  fnerrf,fnerrf2,fnexp,fnfact,fngamma,fngamma2,fnlog,fnlog10,fnlog2,fnncpcm
  fnncpcm2,fnncpf,fnncpf2,fnncpvup,fnncpvus,fnncpvux,fnpi,fnpower,fnrpow
  fnrpow2,fnrpow3,fnsigmo,fnsigmo2,fnsin,fnsinh,fnsqr,fnsqrt,fntan,fntanh
  fnvcpow,fnvcpow2,fnspowx,fnspown,fnsincosintrv
  fnsllog10,fnsllog102,fnslexp,fnslexp2,fnslrec,fnslrec2
  fnsqlog10,fnsqlog102,fnsqexp,fnsqexp2,fnsqrec,fnsqrec2
  fnloggamma,fnbinomial,fnbeta,fnlogbeta
 )               '(supposed to be) tested in funcs5'
 (COMPLINK
  EX1,    EX1X,   EX2, EX3, EX4, EX4X, EX5
  ER1,    ER2,    ER3
  EXMCP1, EXMCP2, EXMCP3, EXMCP4, EXMCP5, EXMCP6) 'used by testexeq'
  ENPRO56                  'Used by CTRLC'
  FNCVPOW
  FNCVPOW2
  FNCVPOW3
  FNEDIST2
  FNEDIST3
  FUZZY                    'Used by CTRLC'
$if %DEMOSIZE% == 1 (kestrel1*kestrel4)  'these talk to the NEOS server, so do not run so often'
  gamsbas1                 'gamsbas no longer shipped'
 (gdxmrw01 * gdxmrw06)     'Matlab required to test GDXMRW'
 (genw2,genw3,genw4)       'part of gdxmrw01'
 (genr2,genr3,genr4,genr5) 'part of gdxmrw02'
 (gen_r1,gen_r2,gen_rbig)  'part of gdxmrw03'
  GFT                      'Used by CTRLC'
 ('testinst', 'gversion')  'part of gdxmrw05'
 (lp05*lp07)               'depends on reported iterations which does not work reliably for a lot of solvers'
  lp09                     'same as lp03'
  math1                    'an example, not a test'
  mcp07                    'an example, not a test'
  mcp09                    'Trac #1809 - outstanding'
  MOD011                   'Used by CTRLC'
  MPSWRIT1                 'mpswrite is gone'
 (N3707,
  NUCLEAR49B)              'Used by CTRLC'
  pgams01                  'part of pgams02'
 (POPDYNMMCP25,
  POPDYNMMCP250,
  POPDYNMMCP1000)          'Used by CTRLC'
  quality                  'obvious'
 (rest2,save2)             'part of restart2'
  testhtm                  'obvious'
  testutil                 'obvious'
  tramp01                  'tramp is gone'
  mip06                    'longer-running test'
/;

mdl(m) = not (letters(m) or ignore(m));

SET suite /
  baron, bench, cmex01, cmex02, cmex03, conopt, convert, cplex,
  emp, examiner, gamschk, gurobi, guss,
  kestrel, knitro, lgo, lindoglobal, lp, mip, minlp, miqcp, nlp, miles, minos, mosek, mpsge, cns,
  mpec, mpecdump, qcp, mcp, oqnlp, nlpec, path, pathnlp, refact, sbb, tramp
  xa, xpress
/;
SET type       model types /
  CNS, DNLP, DECIS, EMP, GAMS, LP, MCP, MIP, MINLP, MIQCP
  MPEC, MPSGE, NLP, QCP, RMINLP, RMIP, RMIQCP
/;
SET solver 'master set of solvers' / system.solverNames /;
SET solverPlatformMap(solver,*) / system.SolverPlatformMap /;
SET avail(solver)  'Solvers available for this platform';
avail(solver) = sum(solverPlatformMap(solver,'%system.platform%'),1)
   and solvers(solver);

SET filter(solver) 'solvers to filter out' /      //can be overwritten by '--solver' flag, but GAMSCHK and some additional solvers are totally switched off later in the SKIP set
* this first bunch includes the more obvious choices
  AMPL,         PYOMO
  BARON2,
  BENCH,        CONVERT,      CONVERTD,
  DE,           DECIS,        DECISC,       DECISM,
  EXAMINER,     EXAMINER2,    GAMSCHK,      KESTREL
  LINGO,        LS,
  MPECDUMP,     SCENSOLVER,
* these are not so obvious
  DICOPTD
  OS                              'only works with option service'
$if %sysenv.SOLVEENGINE_APIKEY% == %&sysenv.SOLVEENGINE_APIKEY% SOLVEENGINE   'only works with SolveEngine API Key'
$if %system.buildcode% == AIX SBB 'has problems writing a status file, #2762'
$if %system.buildcode% == AIX MILES 'has problems writing a status file, #2762'
$if %system.buildcode% == AIX PATH 'has problems writing a status file, #2762'
/;

set globalSolver(solver) Solvers with global demo limit /
  ANTIGONE, BARON, LGO, LINDOGLOBAL, MSNLP, OQNLP
/;

alias (solver,solvera);

SET ASM(solvera,solver) 'Alias Solver Map' /
  CONOPT.     CONOPTD
  CONOPT3.    CONOPTD
  COINBONMIN. BONMIN
  COINCBC.    CBC
  COINCOUENNE.COUENNE
  COINIPOPT.  IPOPT
  COINOS.     OS
  COINSCIP.   SCIP
  GLOMIQO.    ANTIGONE
  LGO.        LGOD
  LOGMIP.     JAMS
  MILESE.     MILES
  MINOS.      MINOS55
  MINOS5.     MINOS55
  PATH.       PATHC
  OSISOPLEX.  SOPLEX
/;

SET solverAlias(solvera) 'Aliases of Solvers';
option solverAlias < ASM;

$set GAMSlo %GAMS.lo%
$if %GAMS.ide% == 1 $set GAMSlo 2

$set FLAGS lo=%GAMSlo%
$if %DEMOSIZE% == 1 $set FLAGS --DEMOSIZE=1 %FLAGS%
$if set before      $set FLAGS --before=%before% %FLAGS%
$if %runAsTester% == 1 $set FLAGS --noComp=1 %FLAGS%
SET modelFlags(m) /
  assign1  'pw=79'
/;
* set --QCPMCHECKS=0 if marginals are OK  for QP and bad for QCP in general
* set  --QPMCHECKS=0 if marginals are bad for QP and bad for QCP in general
SET solverFlags(solver) /
  alphaecp '--QPMCHECKS=0'
  (antigone,baron,lgo) '--GLOBALSIZE=1'
  bonmin   '--QPMCHECKS=0'
  bonminH  '--QPMCHECKS=0'
  cplex    '--QCPMCHECKS=0 --TESTTOL=2e-6'  // hack since it does not get marginals for QCP
  knitro   '--TESTTOL=3e-4'  // temporary?
* actually lindo and lindoglobal behave the same with respect to globalsize, but by setting
* the flag for one but not the other we test both, the global and the local solver in demo mode
  lindo    '--TESTTOL=1e-5'
  lindoglobal '--GLOBALSIZE=1 --TESTTOL=1e-5'
  localsolver 'iterlim=1000000 reslim=10 --MIPMCHECKS=0 --QPMCHECKS=0'
  mosek    'workfactor=2'
  msnlp    '--GLOBALSIZE=1 --TESTTOL=1.9e-3'  // marginals are not so accurate
  oqnlp    '--GLOBALSIZE=1 --TESTTOL=1.9e-3'  // marginals are not so accurate
  snopt    '--TESTTOL=1e-4'  // marginals are not so accurate
  nlpec    '--MCPMCHECKS=0 --NONSTRICT=0'   // hack for bad marginals for MCP
  couenne  '--TESTTOL=1e-2 --MCHECKS=0 --QPMCHECKS=0' //Couenne knows about primal solution only
  scip     '--MIPMCHECKS=0 --QPMCHECKS=0 --TESTTOL=1e-3 optcr=0'
  solveengine '--MIPMCHECKS=0'
  xpress   '--TESTTOL=2e-5'
/;
SET modelSolverFlags(m,solver) /
  (lp03,sl4lp03).(snopt,conoptd,conopt4,minos55,mosek,quadminos)  '--SKIPITER=1'
$if %system.buildcode% == AIX  sl4lp03.cplexd             '--SKIPITER=1'
  (lp01,sl4lp01,lp12).knitro                              'optdir=.. optfile=500 --SKIPUNBND=1'
  (lp04,lp11,sl4lp11,lp14).knitro                         '--SKIPUNBND=1'
   lp15.(ipopt,ipopth)                                    '--TESTTOL=1e-4'
   mip02 .(OsiCplex,OsiGurobi,OsiMosek,OsiXpress)         'integer1=1' //OSI links do not return marginals for MIPs otherwise
   mip03 . bdmlp                                          'nodlim=1e9' //BDMLP does not converge fast enough
   mip03 .(xpress)                                        '--CZ_VAL=10' //a bit weaker than the default, #3207
  (qcp05).knitro                                          'optdir=.. optfile=501'
  (qcp01,nlpqcp01,sl4qcp01).scip                          '--TESTTOL=1e-2'
  (qcp01,sl4qcp01).xpress                                 'optdir=.. optfile=500'
  (qcp02,sl4qcp02).xpress                                 '--TESTTOL=5e-3'
   qcp04.xpress                                           'optdir=.. optfile=500 --TESTTOL=3e-5'
   qcp09.(cplex,cplexd)                                   '--TESTTOL=1e-4'
  (qcp02,sl4qcp02).cplexd                                 '--TESTTOL=1e-2'
   qcp04.cplexd                                           '--TESTTOL=1e-4'
  (qcp02,sl4qcp02,qcp09).gurobi                           '--TESTTOL=1e-2'
  (qcp04,miqcp03).gurobi                                  '--TESTTOL=1e-3'
   qcp09.xpress                                           'optdir=.. optfile=500'
   sos2a.xpress                                           '--MIPMCHECKS=0' // for Optimizer 27.01: not clear the duals are unique anyway
   semicon1.gurobi                                        '--MIPMCHECKS=0'
  (semicon1,sl4scon1).(lindo,lindoglobal)                 '--MIPMCHECKS=0'
  (miqcp01).(lindo,lindoglobal, mosek,oqnlp)              '--QPMCHECKS=0'
  (qcp01,qcp02,qcp10,nlpqcp01,nlpqcp02,
   sl4qcp01,sl4qcp02,miqcp01,cns11,cns12,sl4cns11,sl4cns12).baron '--TESTTOL=1e-5'
   miqcp03.(baron,lindo,lindoglobal,mosek)                '--TESTTOL=1e-4'
   qcp04.(lindo,lindoglobal,mosek)                        '--TESTTOL=1e-4'
  (qcp04).baron                                           '--TESTTOL=1e-5 --QCPMCHECKS=0'   // #3022
   qcp09.(lindo,lindoglobal,mosek)                        '--TESTTOL=1e-3'
  (qcp01,sl4qcp01).mosek                                  '--TESTTOL=1e-5'
/;
SET ms(m,suite) /

  (
  baron01 * baron03
  ).baron
  (
  bench01,bench02,bench03,bench04
  ).bench
  (
  conopt01,condtwin
  ).conopt
  (
  convert2*convert12
  ).convert
  (
  cplex01*cplex03
  ).cplex
  (
  emp01*emp26
  empadj01
  empbp01*empbp06
  empdisj1*empdisj7
  empecs01*empecs02
  emplog1*emplog2
  emplp01*emplp03, emplp10*emplp13
  empvi01*empvi05
  ).emp
  (
  examin01*examin04
  ).examiner
  (
  gamschk1
  ).gamschk
  (
  gurobi01*gurobi04, lazy01
  ).gurobi
  (
  kestrel1*kestrel4
  ).kestrel
  (
  knitro01
  ).knitro
  (
  lgo01
  ).lgo
  (
  lindgl01*lindgl04,lindorng,lindorg2
  ).lindoglobal
  (
  lolp,lp01*lp04,lp08,lp10*lp15,sl4lp01,sl4lp02,sl4lp03,sl4lp10,sl4lp11
  ).lp
  (
  mip01*mip06,sos1a,sos2a,semicon1,semiint1,sl4mip01,sl4sos1a,sl4scon1,
  indic01*indic04,dumpsol,pf4mip
  ).mip
  (
  pf4minlp
  ).minlp
  (
  miles01
  ).miles
  (
  minos01
  ).minos
  (
  mosek01,sdp01
  ).mosek
  (
  circlen,lonlp,nlp01,nlplp02,nlpqcp01,nlpqcp02
  ).nlp
  (
  mpsge01*mpsge14
  ).mpsge
  (
  cns01*cns13,sl4cns01*sl4cns13
  ).cns
  (
  mpec01,mpec03,mpec04*mpec08
  ).mpec
  (
  mpecdu01
  ).mpecdump
  (
  lomcp,mcp01*mcp06,mcp08,mcp11,sl4mcp01*sl4mcp04,sl4mcp06
  ).mcp
  (
  miqcp01*miqcp03
  ).miqcp
  (
  qcp01*qcp10,sl4qcp01*sl4qcp03
  ).qcp
  (
  alias01, assign1 * assign2, asynexec, asynntrp
  binary1 * binary3,  blank,  breakcont1*breakcont2
  call1   * call6
  card01  * card02
  choles01 * choles02
  clear1,   clear2,   clear3,   clear4,   clear5
  clear6,   clear7
  compile1 * compile8
  cpplib00 * cpplib05
  data1
  dattim1 * dattim6
  ddlist1
  decis01 * decis03,  decla1,   decla2,   delim1,   delim2,   delim3,   delim4,
  dump01,
  echo1,    edcrypt1,
  eigval01, eigvec01 *eigvec02
  embed1  * embed3
  eval01  * eval07,   execerr1
  fitlib01, funcs3,   funcs4,   funcs5,   funcback
  gdx1    * gdx9
  gdxcomp1* gdxcomp2
  gdxconv1
  gdxcopy1* gdxcopy5
  gdxdiff1, gdxdump1, gdxmerg1 *gdxmerg2, gdxrank1
  gdxxrw1 * gdxxrw7
  gzip01
  har1
  idxoper1, idxperm1* idxperm4
  ifnot1,   ifstat1 * ifstat7
  ifthen1 * ifthen6
  interval
  invert01 *invert02
  lagd1,    lags1,
  ldidx01 * ldidx05
  libdepend
  load1   * load11
  local01
  loop1,    loop2,     loop3 *  loop9
  lsalib01
  ls01    * ls04
  macro01 * macro02,   map1,    match01,
  mdb2gms1, mtxlib, nonneg
  onelab1,  onelab2
  onmulti1 * onmulti7
  parlib01
  pfmaptst
  pgams02
  phantom1, phantom2,
  pipe1,    pipe2,    pipe3,    pipe4,    pipe5,    pipe6,    pipe7,    pipe8
  pipe9,    pipe10
  point1,   point2
  power1,   power2
  privat01
  pwplib01
  put1    * put10
  restart1, restart2, sameas1
  scale01*scale02,  scnred01 *scnred02
  set1    * set11
  sl601
  slx01
  sort1
  sql2gms1
  stolib01
  single01* single05, suffix01
  symxref1, syschk1*syschk2,    sysenv01*sysenv02
  tabsubst, tester,   title1
  trilib01* trilib04
  trylin01
  uldidx01 * uldidx03
  unary1,   unary2,   undf1,    univ1
  unload1 * unload11
  utils01 * utils03
  warning1* warning2
  ).cmex01
  (
  dict1,    embpy01,  embpy02,  empty1,   eps1,     execmode01,
  forceerr
  funcs1,   funcs2,   gbin1,
  gdxsqlite1,
  handle01, handle02, mps2gms1
  nest1,    nest2
  nlcode1 * nlcode7,  obfusc01, perm1, procdir1, savep1
  traceuc
  vardat01 *vardat05
  veda1
  ).cmex02
  (
  badpt1,   badpt2,   badpt3
  cerr1,    cmexrc01, dbg01,    maxima,   mcp10,    merr1,
  model2tex1,mrw01,
  rs01 *    rs02,     refact00, testexeq, shuffle1, ssuffix,
  xerr1,    xerr2,
  doc01, buildwarnings, csv2gdx1
  ).cmex03
  (
  msnlp01,  oqnlp01
  ).oqnlp
  (mpec01,mpec02,mpec04*mpec08,nlpec01,nlpec02).nlpec
  (
  path01
  ).path
  (
  pathnlp1, pathnlp2
  ).pathnlp
  (
  refact01*refact05
  ).refact
  (
  sbb01, sbb02
  ).sbb
  (
  gussskip
  scen01 * scen03
  scenempty
  scensol1* scensol6
  ).guss
  (
  tramp01
  ).tramp
  (
  xa01
  ).xa
  (
  xpress01 * xpress06
  ).xpress
/;
SET st(suite,type) 'default type of models unless set below' /
  baron.GAMS
  bench.GAMS
  cmex01.GAMS
  cmex02.GAMS
  cmex03.GAMS
  conopt.NLP
  convert.GAMS
  cplex.LP
  emp.EMP
  examiner.GAMS
  gamschk.GAMS
  gurobi.LP
  guss.LP
  kestrel.GAMS
  knitro.GAMS
  lgo.GAMS
  lindoglobal.GAMS
  lp.LP
  mip.MIP
  minlp.MINLP
  miles.GAMS
  minos.GAMS
  mosek.GAMS
  nlp.NLP
  mpsge.MCP
  cns.CNS
  mpec.MPEC
  mpecdump.GAMS
  miqcp.MIQCP
  qcp.QCP
  mcp.MCP
  oqnlp.NLP
  nlpec.MPEC
  path.GAMS
  pathnlp.GAMS
  refact.GAMS
  sbb.GAMS
  tramp.GAMS
  xa.GAMS
  xpress.GAMS
/;
* mt can be computed based on suite for now - if we have other models that
* don't have a suite membership, we can bang them in.
SET mt(m,type);
mt(mdl,type) = sum{ms(mdl,suite), st(suite,type)};

parameter typecount(m);
typecount(mdl) = sum{mt(mdl,type),1} - 1;
abort$[smax{mdl,abs(typecount(mdl))} ne 0] typecount;

$onempty
SET notQuick(m) / nlpec01 /;
SET gskip(m) 'CMEX tests we know will fail' /
$if %system.buildcode% == AIX cerr1     'we do not have Mosek here'
$ifThenI not x%sysenv.GBUILDMODE%==xalpha
$if %system.buildcode% == VS8 cmexrc01  'creates a pop-up if not alpha'
$if %system.buildcode% == WEI cmexrc01  'creates a pop-up if not alpha'
$endif
$if %system.buildcode% == AIX decis01   'we do not have DECIS here'
$if %system.buildcode% == BGP decis01   'we do not have DECIS here'
$if %system.buildcode% == DEG decis01   'we do not have DECIS here'
$if %system.buildcode% == SIG decis01   'we do not have DECIS here'
$if %system.buildcode% == BGP decis02   'we do not have DECIS here'
$if %system.buildcode% == BGP decis03   'we do not have DECIS here'
  minos01                               'Minos cycling problem, it is just luck if this test does not fail, Trac #1700'
$if %system.buildcode% == BGP pfmaptst  'we do not have the gmspfmap.gdx on idle platforms'
$if not %system.buildcode% == VS8 xerr1 'work in progress'
$if not %system.buildcode% == VS8 xerr2 'work in progress'
 (kestrel1*kestrel3)                    'some issues on the server side (probably the same for kestrel4 but this is skipped below already), #2930'
  kestrel4                              'Unexpected solver status 6 from solver KESTREL, trac #2655'
 (rs01,rs02)                            'Gurobi compute server not reachable or license expired, #3016'
 (xpress05,xpress06)                    'different with XPRESS 31.01, #3208 #3209'
  /;
$if set NOSKIP gskip(mdl) = no;
$if set QUICK  gskip(mdl)$notquick(mdl) = yes;

SET suiteskip(solver,m) 'skips for tests in solver-specific suites' /
$if %system.buildcode% == BGP bench.bench02     'expects CPLEX to exist'
$if %system.buildcode% == BGP bench.bench03     'expects CPLEX to exist'
$if %system.buildcode% == AIX sbb.(sbb01,sbb02) 'has problems writing a status file, #2762'
 gurobi.gurobi01                                'with Gurobi 5.6 the default options perform so well that we cannot get a reliable improvement with tuning for this model'
/;
SET skip(solver,m) 'we know these will fail' /
* put permanent skips first
 baron.(sl4lp10,lp10)                              'baron does not handle unbounded models well'
 (knitro,pathnlp).(lp03,sl4lp03)                   'issue with nonbasic free vars : simplex-only test'
 miles.(mcp01*mcp04,sl4mcp01*sl4mcp04)             'cannot solve models with all variables fixed'
 mosek.(lonlp,circlen)                             'Model is nonconvex'
 (Bonmin,bonminH,CBC).(lp03,sl4lp03)               'Doubt if the test is correct'
 (Ipopt,IpoptH).(lp03,sl4lp03)                     'Ipopt does not compute a basis'
 lgo.(lp01,lp10*lp12,lp14,sl4lp01,sl4lp10,sl4lp11) 'declares solution as local optimal'
 gurobi.lp04                                       'Gurobi does not set inf/unb marker with (dual) infeasible models (uses Farkas certificate)'
 lgo.lp04                                          'this will go way when gmosetsolutionfixer is implicit'
 mosek.lp04                                        'mosek does not do infeasibilities right'
 scip.nlplp02                                      'scip does not return marginals for nlps'
 lindo.(qcp02,nlpqcp02,sl4qcp02)                   'precission issue'
 msnlp.(qcp01,sl4qcp01,nlpqcp01)                   'exceeds reslim from time to time'
 (ipopt,ipopth).(cns12,sl4cns12)                   'infeasibility too small to be reported in infeasibility markers'
 (knitro,minos,snopt).(cns01,sl4cns01)             'cannot handle instances without variables'
 cpoptimizer.(mip01,mip02,mip04,miqcp01,miqcp02,miqcp03,semicon1,semiint1,sl4mip01,sl4scon1,sl4sos1a,sos1a,sos2a)  'cannot handle continuous variables'
 cpoptimizer.(mip03,mip05)                         'exceeds reslim'
 cpoptimizer.dumpsol                               'may exceed available memory before hitting reslim; also does not implement solution pool yet'
 localsolver.(cns01*cns05,cns07,cns12,cns13,sl4cns01*sl4cns05,sl4cns07,sl4cns12,sl4cns13,miqcp01*miqcp03,lonlp,nlp01,nlplp02,qcp01*qcp05,sl4qcp01*sl4qcp03,circlen,nlpqcp01,nlpqcp02,qcp07*qcp10,semicon1,sl4scon1) "hits iterlim before finding any or good solution or test doesn't expect stop on iterlim"
 localsolver.(mip02*mip05)                         'test expects proof of optimality or unboundedness'
 solveengine.(lp01*lp04,lp08,lp10*lp15,sl4lp01*sl4lp03,sl4lp10,sl4lp11) 'solveengine does not report enough results (e.g., duals) for LP checks'
 solveengine.mip05                                 'takes a while to solve a long sequence of tiny MIPs remotely'

* put temporary skips here
 baron.(lp03,sl4lp03)     'fix is in progress'
 knitro.(lp10,sl4lp10)    'scaling or unboundedness issue : being investigated'
 msnlp.(qcp03,sl4qcp03)   'bad marginals - under investigation'
 oqnlp.(qcp03,sl4qcp03)   'bad marginals - under investigation'
 oqnlp.qcp04              'system failure - under investigation'
 snopt.(qcp02,nlpqcp02,sl4qcp02) 'reports optimal in log, but NONOPTs in listing - modelstat=2 in lst'
 xa.(lp03,sl4lp03)        'under investigation'
 (IpoptH,Ipopt).(lp10,sl4lp10) 'classification required'
* cplexd.cplex02           'cplexd cannot handle tuning yet - normal completion'
 cplexd.cplex03           'cplexd cannot handle tuning and indicators yet'
 couenne.(qcp02,nlpqcp02,sl4qcp02) 'exceeds reslim'
 scip.(qcp02,sl4qcp02)    'does not find solution in time'
 nlpec.nlpec01            'does not terminate (on lx3)'
 (baron,lindoglobal,lindo).(qcp07) 'BARON and Lindo do not handle poly function'
 cplexd.mip04             'cplexd will not be fixed anymore'
* xpress.(xpress05,xpress06) 'different with XPRESS 31.01, #3208 #3209'
 xpress.miqcp03           'segmentation fault, #2314'
 knitro.lp15              'knitro is far off the optimal value, #2346 and #2335'
$if %system.buildcode% == SIG lgod.scenempty 'unexpected/wrong results, #2658'
 localsolver.(mip01,sl4mip01) 'gets stuck on windows, #3182'
/;
* if a model is skipped for a solver alias it is automatically skipped for the solver itself
skip(solver,'indic01')$[(not sameas(solver,'cplex')) and (not sameas(solver,'xpress')) and (not sameas(solver,'scip')) and (not sameas(solver,'coinscip'))] = yes;
skip(solver,'indic02')$[(not sameas(solver,'cplex')) and (not sameas(solver,'xpress')) and (not sameas(solver,'scip')) and (not sameas(solver,'coinscip'))] = yes;
skip(solver,'indic03')$[(not sameas(solver,'cplex')) and (not sameas(solver,'xpress')) and (not sameas(solver,'scip')) and (not sameas(solver,'coinscip'))] = yes;
skip(solver,'indic04')$[(not sameas(solver,'cplex')) and (not sameas(solver,'xpress')) and (not sameas(solver,'scip')) and (not sameas(solver,'coinscip'))] = yes;

skip('nlpec',mdl)$[sum{ms(mdl,'mpsge'),1}] = yes;
* has problems writing a status file, #2762
$if %system.buildcode% == AIX skip('pathc',mdl)$[sum{ms(mdl,'mpsge'),1}] = yes;

$if set NOSKIP skip(solver,mdl) = no;

set mdlstdoutskip(m) 'skips for stdout check' /
$if not %system.filesys% == UNIX asynexec 'when killing a process, taskkill writes to stdout'
   asynntrp      'sometimes a process to be killed does not exist anymore, which results in a message to stdOut'
   call1,call2   'tests handling of wrong parameters, error is written to stdout'
   call3         'tests output conflicts, so we know it writes to sterr and stdout'
   cmexrc01      'we are forcing a CMEX error resulting in a message to stdout'
   cpplib00      'compilers write to both stderr and stdout by default'
   decis01*decis03 'decis writes to stdout'
   maxima        'creates a wanted Cmex error writing to stdout'
   pgams02       'writes message when deleting directory below 225'
   testexeq      'compiler write to both stderr and stdout by default'
   trilib01*trilib04,parlib01 'unzip and compiler write to stdout and stderr by default'
   veda1         'tests gdx2veda which writes to stdout'
   kestrel1*kestrel4 'the kestreltest script writes its log to stdout'
   scensol6      'deletion of grid files is reported to stdout'
   rs02          'gurobi distributed mip writes to stdout, #2748'
   doc01         'documentation tests write to stdout'
   procdir1      'model uses keep option, which writes to stdout'
/;
set mdlstderrskip(m) 'skips for stderr check' /
   call3         'tests output conflicts, so we know it writes to sterr and stdout'
   cpplib00      'compilers write to both stderr and stdout by default'
   decis01*decis03 'decis writes to stderr'
   testexeq      'compiler write to both stderr and stdout by default'
   trilib01*trilib04,parlib01 'unzip and compiler write to stdout and stderr by default'
   doc01         'documentation tests may write to stderr'
/;

set slvstdoutskip(solver) 'solvers which are skipped for stdout check' /
   OS
/;
set slvstderrskip(solver) 'solvers which are skipped for stderr check' /
/;
set stdoutskip(solver,m) 'model - solver combinations which are skipped for stdout check' /
/;
set stderrskip(solver,m) 'model - solver combinations which are skipped for stderr check' /
/;
$offempty

stdoutskip(slvstdoutskip,mdl)$(not mt(mdl,'GAMS'))              = yes;
stdoutskip(solver,mdlstdoutskip)$(not mt(mdlstdoutskip,'GAMS')) = yes;
stderrskip(slvstderrskip,mdl)$(not mt(mdl,'GAMS'))              = yes;
stderrskip(solver,mdlstderrskip)$(not mt(mdlstderrskip,'GAMS')) = yes;

$onempty
set mdltraceskip(m) 'skips for trace file check' /
    badpt2,badpt3  '9/14 is expected outcome of this test'
    qcp06          '2nd solve is supposed to fail'
    scensol3       '%solvestat.TerminatedBySolver% is expected'
/;

set slvtraceskip(solver) 'solvers which are skipped for trace file check' /
/;

set traceskip(solver,m) 'model - solver combinations which are skipped for trace file check' /
/;
$offempty

$if exist %sysenv.USRQUALITYSKIPS% $include %sysenv.USRQUALITYSKIPS%

traceskip(slvtraceskip,mdl)$(not mt(mdl,'GAMS'))             = yes;
traceskip(solver,mdltraceskip)$(not mt(mdltraceskip,'GAMS')) = yes;

* Solver test suites
set slvtest(solver,suite) /
   (oqnlp,msnlp).oqnlp
   baron.baron
   bench.bench
   (conoptd,conopt4).conopt
   convert.convert
   (cplex,cplexd).cplex
   jams.emp
   examiner.examiner
   gamschk.gamschk
   gurobi.gurobi
   knitro.knitro
   lgo.lgo
   (lindo,lindoglobal).lindoglobal
   miles.miles
   minos.minos
   mosek.mosek
   nlpec.nlpec
   path.path
   pathnlp.pathnlp
   sbb.sbb
   (bdmlpd,cbc,conopt4,conoptd,couenne,cplex,cplexd,gurobi,ipopt,ipopth,lgo,lindo,lindoglobal,minos,mosek,osicplex,osigurobi,osimosek,soplex,osixpress,pathc,scip,snopt,xpress).guss
   xa.xa
   xpress.xpress
/;

loop(ASM(solverAlias,solver),
  slvtest(solver,suite) $= slvtest(solverAlias,suite);
  slvtest(solverAlias,suite) $= slvtest(solver,suite);
);

alias(solver,solverp);
set slvsuite(suite); option slvsuite < slvtest;
SET moreskip(solver,m) 'more skips, based on solver suites to use';

* start by skipping all models in the solver suites
moreskip(solver,mdl)$sum(ms(mdl,slvsuite),1) = yes;
* but include the models in solver suites chosen to run,
* if the solver is available
moreskip(solver,mdl)$sum((slvtest(avail(solver),slvsuite),ms(mdl,slvsuite)),1) = no;
* display moreskip;
skip(moreskip(solver,mdl)) = yes;
skip(suiteskip(solver,mdl)) = yes;
$if %DEMOSIZE% == 1 skip(solver,      mdl)$sum(sm(s,mdl)$(big(s)),      1) = yes;
$if %DEMOSIZE% == 1 skip(globalSolver,mdl)$sum(sm(s,mdl)$(bigGlobal(s)),1) = yes;

gskip(mdl)$[sum{suiteskip(solver,mdl),1}] = yes;
gskip(mdl)$[sum((slvtest(solver,slvsuite),ms(mdl,slvsuite)),
                not avail(solver)) ] = yes;
$if %DEMOSIZE% == 1 gskip(mdl)$sum(sm(s,mdl)$(big(s)),1) = yes;

$if set QUICK  skip(solver,mdl)$notquick(mdl) = yes;
* display gskip, skip;

file log /''/;

$if not set HELP $goto nohelp
put log
 / 'This model is used to run the quality tests and report on the results'
 / 'You can run all tests for all solvers by running the model with no parameters:'
 / ' '
 / '  gams quality'
 / ' '
 / 'You can choose specific tests by using the --TEST parameter:'
 / ' '
 / '  gams quality --TEST "binary1,binary2"'
 / ' '
 / 'Instead of choosing specific tests, you can choose'
 / 'specific test suites by using the --SUITE parameter:'
 / ' '
 / '  gams quality --SUITE "cmex01,lp"'
 / ' '
 / 'Independently from the parameters above, you can make'
 / 'a choice of solvers using the --SOLVER parameter:'
 / ' '
 / '  gams quality --SUITE lp --SOLVER "bdmlp,xa"'
 / ' '
 / 'By default, a skip list is used to skip tests that are known to fail.'
 / 'To turn off the skip list and really run all the tests,'
 / 'set the --NOSKIP parameter to anything:'
 / ' '
 / '  gams quality --NOSKIP=1'
 / ' '
 / 'By default, a solver with one or more aliases is only tested once. To run the'
 / 'tests with the aliased names as well set the --RUNALIAS parameter to anything:'
 / ' '
 / '  gams quality --RUNALIAS=1'
 / ' '
 / 'You can knock out the slower tests (see the set notQuick)'
 / 'using the --QUICK parameter:'
 / ' '
 / '  gams quality --QUICK=1'
 / ' '
 / 'To run only those tests that fit within the demo size limits, do:'
 / ' '
 / '  gams quality --DEMOSIZE=1'
 / ' ';
$exit

$label nohelp

SET tmdl(m)          'set of tests to run';
SET tsuite(suite)    'set of suites to run';
SET tsolver(solver)  'set of solvers to test';

$if not errorfree $abort Compilation errors before processing -- options

$if not set TEST $goto checksuite
SET tmdl(m) / %TEST% /;
$if errorfree $goto TEST_OK
$clearerror
$log The test model(s) specified (--TEST=%TEST%) are not all valid
$abort
$label TEST_OK
tsuite(suite) = no;
$goto havetestlist

$label checksuite
$if not set SUITE $goto alltests
SET tsuite(suite) / %SUITE% /;
$if errorfree $goto SUITE_OK
$clearerror
$log The suite(s) specified (--SUITE=%SUITE%) are not all valid
$abort
$label SUITE_OK

tmdl(mdl) = sum{ms(mdl,tsuite),yes};
$goto havetestlist

$label alltests
tsuite(suite) = no;
tmdl(mdl) = yes;

$label havetestlist
display tmdl;

$if not set SOLVER $goto allsolvers
SET tsolver(solver) / %SOLVER% /;
gskip(mdl) = yes;
gskip(mdl)$[sum((slvtest(tsolver,slvsuite),ms(mdl,slvsuite)),avail(tsolver)) ] = no;
$if errorfree $goto SOLVER_OK
$clearerror
$log The solver(s) specified (--SOLVER=%SOLVER%) are not all valid
$abort
$label SOLVER_OK
$goto havesolvers
$label allsolvers
tsolver(solver) = yes;
tsolver(filter(solver)) = no;
$if set RUNALIAS $goto havesolvers
tsolver(solverAlias(solver)) = no;

$label havesolvers

loop(ASM(solverAlias,solver),
  solverFlags(solver)               $= solverFlags(solverAlias);
  modelSolverFlags(mdl,solver)      $= modelSolverFlags(mdl,solverAlias);
  stdoutskip(solver,mdl)            $= stdoutskip(solverAlias,mdl);
  stderrskip(solver,mdl)            $= stderrskip(solverAlias,mdl);
  skip(solver,mdl)                  $= skip(solverAlias,mdl);
  solverFlags(solverAlias)          $= solverFlags(solver);
  modelSolverFlags(mdl,solverAlias) $= modelSolverFlags(mdl,solver);
  stdoutskip(solverAlias,mdl)       $= stdoutskip(solver,mdl);
  stderrskip(solverAlias,mdl)       $= stderrskip(solver,mdl);
  skip(solverAlias,mdl)             $= skip(solver,mdl);
);

scalar
  rc     / 0 /,
  tot    / 0 /,
  err    / 0 /,
  stderr / 0 /,
  stdout / 0 /,
  cnt    / 0 /;

file oneTest  / 'onetest.gms' /     //Getting test from testlib and executing test
     stdTest  / 'stdtest.gms' /     //Checking if stderr and stdout are empty
     allTests / '%ALL%'  /
     failures / '%FAIL%' /
     rmme     / 'rmme.gms' /
     fx;

oneTest.tf    = 0;
oneTest.lcase = 1;

$if %ALL% == alltests.gms putclose allTests '* These are the tests we ran' /;
$if %FAIL% == failures_qa.gms putclose failures '* These are the tests that failed' / '*Total tests: 0 Failed tests: 0' /;

putclose rmme '* Delete all directories of tests without problems' /;
allTests.ap = 1;
failures.ap = 1;
rmme.ap     = 1;
$if exist %TRACE% $call rm -f %TRACE%

$set DIRNAMEGAMS "'%PREFIX%_qa_' tmdl.tl:0 '_gams'"
loop {mt(tmdl,'GAMS')$[not (gskip(tmdl) or ms(tmdl,'refact'))],
  cnt = cnt + 1;
  tot = tot + 1;
  put_utility fx 'shell' / 'rm -rf ' %DIRNAMEGAMS%;
  put_utility fx 'shell' / 'mkdir ' %DIRNAMEGAMS%;
  put oneTest
     '$call testlib -q ' tmdl.tl:0
   / '$if errorlevel 1 $abort'
   / '$echo JobStart ' tmdl.tl:0 ' >> %TRACE%'
   / '$call =gams ' tmdl.tl:0 ' jt=' tmdl.tl:0 ' trace=%TRACE% ' modelFlags.te(tmdl):0 ' %gams.user1% %FLAGS%';
  put$(not mdltraceskip(tmdl))
   / '$call gams %TRACE% a=gt ps=0 pw=255 tl=0 lo=0';
  putclose
   / '$if errorlevel 1 $set err 1'
   / '$if set err scalar err /%err%/'
   / '$call cat %TRACE% >> ..%SLASH%%TRACE%'
   / "$if %err% == 1 $abort 'Problem'";
  put_utility fx 'shell' / 'mv -f onetest.gms ' %DIRNAMEGAMS% ' && cd ' %DIRNAMEGAMS% ' && gams onetest lo=%GAMSlo% --err=0 gdx=..%SLASH%err > stdout.txt 2>stderr.txt'; rc=1; execute_load 'err' rc=err;
  putclose stdTest                                                                                          //Checking if stderr and stdout are empty
     '$call =test -s ' %DIRNAMEGAMS% '%SLASH%stderr.txt'
   / '$if errorlevel 1 $set stderr 0'
   / '$if set stderr scalar stderr /%stderr%/'
   / '$call =test -s ' %DIRNAMEGAMS% '%SLASH%stdout.txt'
   / '$if errorlevel 1 $set stdout 0'
   / '$if set stdout scalar stdout /%stdout%/'
  execute 'gams stdtest.gms lo=2 --stderr=1 --stdout=1 gdx=std'; stderr=1; stdout=1; execute_load 'std' stderr,stdout;
  put allTests;
  put '$call =gams quality %FLAGS% --prefix=%PREFIX% --fail=failures_qa.tmp --test=' tmdl.tl:0 ' ';
  if {rc,                                 put '--ftrace=1 '};
  if {stderr and not mdlstderrskip(tmdl), put '--fstderr=1 '};
  if {stdout and not mdlstdoutskip(tmdl), put '--fstdout=1 '};
  putclose allTests '--dir='%DIRNAMEGAMS% /;
  if {rc or (stderr and not mdlstderrskip(tmdl)) or (stdout and not mdlstdoutskip(tmdl)),
    err = err + 1;
    put failures;                                                                                         // failure_qa.gms
    put '$call =gams quality %FLAGS% --prefix=%PREFIX% --fail=failures_qa.tmp --test=' tmdl.tl:0 ' ';     // --fail defines alternative failures file
    if {rc,     put '--ftrace=1 '};                                                                       // execution error
    if {stderr and not mdlstderrskip(tmdl), put '--fstderr=1 '};                                          // writing to standard error
    if {stdout and not mdlstdoutskip(tmdl), put '--fstdout=1 '};                                          // writing to standard output
    putclose failures '--dir='%DIRNAMEGAMS% /;                                                            // name of kept directory
  else
    putclose rmme '$call rm -rf ' %DIRNAMEGAMS% /;
  };
  if(cnt=5,
    execute "=gams rmme lo=0";
    cnt = 0;
    execute "echo '* Delete all directories of tests without problems' > rmme.gms";
  );
};

$set DIRNAMEREFACT "'%PREFIX%_qa_refact'"
if(tsuite('refact'),
  put_utility fx 'shell' / 'if not exist ' %DIRNAMEREFACT% ' mkdir ' %DIRNAMEREFACT%;
)
loop {ms(tmdl,'refact')$tsuite('refact'),
  cnt = cnt + 1;
  tot = tot + 1;
  put oneTest
     '$if exist %TRACE% $call rm -f %TRACE%'
   / '$call testlib -q ' tmdl.tl:0
   / '$if errorlevel 1 $abort'
   / '$echo JobStart ' tmdl.tl:0 ' >> %TRACE%'
   / '$call =gams ' tmdl.tl:0 ' jt=' tmdl.tl:0 ' trace=%TRACE% ' modelFlags.te(tmdl):0 ' %gams.user1% %FLAGS%';
  put$(not mdltraceskip(tmdl))
   / '$call gams %TRACE% a=gt ps=0 pw=255 tl=0 lo=0';
  putclose
   / '$if errorlevel 1 $set err 1'
   / '$if set err scalar err /%err%/'
   / '$call cat %TRACE% >> ..%SLASH%%TRACE%'
   / "$if %err% == 1 $abort 'Problem'";
  put_utility fx 'shell' / 'mv -f onetest.gms ' %DIRNAMEREFACT% ' && cd ' %DIRNAMEREFACT% ' && gams onetest lo=%GAMSlo% --err=0 gdx=..%SLASH%err > stdout.txt 2>stderr.txt'; rc=1; execute_load 'err' rc=err;
  putclose stdTest                                                                                          //Checking if stderr and stdout are empty
     '$call =test -s ' %DIRNAMEREFACT% '%SLASH%stderr.txt'
   / '$if errorlevel 1 $set stderr 0'
   / '$if set stderr scalar stderr /%stderr%/'
   / '$call =test -s ' %DIRNAMEREFACT% '%SLASH%stdout.txt'
   / '$if errorlevel 1 $set stdout 0'
   / '$if set stdout scalar stdout /%stdout%/'
  execute 'gams stdtest.gms lo=2 --stderr=1 --stdout=1 gdx=std'; stderr=1; stdout=1; execute_load 'std' stderr,stdout;
  put allTests;
  put '$call =gams quality %FLAGS% --prefix=%PREFIX% --fail=failures_qa.tmp --test=' tmdl.tl:0 ' ';
  if {rc,                                 put '--ftrace=1 '};
  if {stderr and not mdlstderrskip(tmdl), put '--fstderr=1 '};
  if {stdout and not mdlstdoutskip(tmdl), put '--fstdout=1 '};
  putclose allTests '--dir='%DIRNAMEREFACT% /;
  if {rc or (stderr and not mdlstderrskip(tmdl)) or (stdout and not mdlstdoutskip(tmdl)),
    err = err + 1;
    put failures;                                                                                         // failure_qa.gms
    put '$call =gams quality %FLAGS% --prefix=%PREFIX% --fail=failures_qa.tmp --test=' tmdl.tl:0 ' ';     // --fail defines alternative failures file
    if {rc,     put '--ftrace=1 '};                                                                       // execution error
    if {stderr and not mdlstderrskip(tmdl), put '--fstderr=1 '};                                          // writing to standard error
    if {stdout and not mdlstdoutskip(tmdl), put '--fstdout=1 '};                                          // writing to standard output
    putclose failures '--dir='%DIRNAMEREFACT% /;                                                          // name of kept directory
  };
};

$onecho > knitro.500
maxit 20000
$offecho
$onecho > knitro.501
feastol 1e-8
$offecho
$onecho > xpress.500
bargapstop      1e-8
barprimalstop   1e-7
bardualstop     1e-7
$offecho

$set DIRNAME "'%PREFIX%_qa_' tmdl.tl:0 '_' type.tl:0 '_' tsolver.tl:0"
loop {mt(tmdl,type)$[not sameas(type,'GAMS')],
  loop {tsolver$[SolverCapabilities(tsolver,type) and not skip(tsolver,tmdl)],
    cnt = cnt + 1;
    tot = tot + 1;
    put_utility fx 'shell' / 'rm -rf ' %DIRNAME%;
    put_utility fx 'shell' / 'mkdir ' %DIRNAME%;
    put oneTest
       '$call testlib -q ' tmdl.tl:0
     / '$if errorlevel 1 $abort'
     / '$echo JobStart ' tmdl.tl:0 ' >> %TRACE%'
     / '$call =gams ' tmdl.tl:0 ' jt=' tmdl.tl:0 ' trace=%TRACE% ' type.tl:0'='tsolver.tl:0 ' %FLAGS% ' solverFlags.te(tsolver):0 ' ' modelFlags.te(tmdl):0 ' ' modelSolverFlags.te(tmdl,tsolver):0 ' %gams.user1%';
    put$(not traceskip(tsolver,tmdl))
     / '$call gams %TRACE% a=gt ps=0 pw=255 tl=0 lo=0';
    putclose
     / '$if errorlevel 1 $set err 1'
     / '$if set err scalar err /%err%/'
     / '$call cat %TRACE% >> ..%SLASH%%TRACE%'
     / "$if %err% == 1 $abort 'Problem'";
    put_utility fx 'shell' / 'mv -f onetest.gms ' %DIRNAME% ' && cd ' %DIRNAME% ' && gams onetest lo=%GAMSlo% --err=0 gdx=..%SLASH%err > stdout.txt 2>stderr.txt'; rc=1; execute_load 'err' rc=err;
    putclose stdTest
       '$call =test -s ' %DIRNAME% '%SLASH%stderr.txt'
     / '$if errorlevel 1 $set stderr 0'
     / '$if set stderr scalar stderr /%stderr%/'
     / '$call =test -s ' %DIRNAME% '%SLASH%stdout.txt'
     / '$if errorlevel 1 $set stdout 0'
     / '$if set stdout scalar stdout /%stdout%/';
    execute 'gams stdtest.gms lo=2 --stderr=1 --stdout=1 gdx=std'; stderr=1; stdout=1; execute_load 'std' stderr,stdout;
    put allTests;
    put '$call =gams quality %FLAGS% --prefix=%PREFIX% --fail=failures_qa.tmp --test=' tmdl.tl:0 ' --solver=' tsolver.tl:0 ' ';
    if {rc,                                      put '--ftrace=1 '};
    if {stderr and not stderrskip(tsolver,tmdl), put '--fstderr=1 '};
    if {stdout and not stdoutskip(tsolver,tmdl), put '--fstdout=1 '};
    putclose allTests '--dir='%DIRNAME% /;
    if {rc or (stderr and not stderrskip(tsolver,tmdl)) or (stdout and not stdoutskip(tsolver,tmdl)),
      err = err + 1;
      put failures;
      put '$call =gams quality %FLAGS% --prefix=%PREFIX% --fail=failures_qa.tmp --test=' tmdl.tl:0 ' --solver=' tsolver.tl:0 ' ';
      if {rc,                                      put '--ftrace=1 '};
      if {stderr and not stderrskip(tsolver,tmdl), put '--fstderr=1 '};
      if {stdout and not stdoutskip(tsolver,tmdl), put '--fstdout=1 '};
      putclose failures '--dir='%DIRNAME% /;
    else
      putclose rmme '$call rm -rf ' %DIRNAME% /;
    };
    if(cnt=5,
      execute "=gams rmme lo=0";
      cnt = 0;
      execute "echo '* Delete all directories of tests without problems' > rmme.gms";
    );
  };
};

execute "=gams %TRACE% a=gt ps=0 pw=255 o=%TRACEREP% tl=%TL% lo=0";
execute "=gams rmme lo=0";

putclose oneTest '*Total tests: ', tot:0:0, '  Failed tests: ', err:0:0 ;
$if %FAIL% == failures_qa.gms execute 'cat onetest.gms >> %FAIL%'

execute 'rm -f rmme.* err.gdx std.gdx onetest.gms stdtest.*';

put log;
if {(err > 0),
  put 'There were errors: ', err:0:0, ' out of ',
       tot:0:0, ' tests failed.' /;
  put 'See the file failures_qa.gms to reproduce the failed runs'/;
  put 'You have some failures. See failures_qa.gms for details.';
else
  put 'Congratulations!  All ', tot:0:0, ' tests passed.'/;
};

put 'See the file alltests.gms to reproduce all the runs'/;