1 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2 /*                                                                           */
3 /*                  This file is part of the program and library             */
4 /*         SCIP --- Solving Constraint Integer Programs                      */
5 /*                                                                           */
6 /*    Copyright (C) 2002-2021 Konrad-Zuse-Zentrum                            */
7 /*                            fuer Informationstechnik Berlin                */
8 /*                                                                           */
9 /*  SCIP is distributed under the terms of the ZIB Academic License.         */
10 /*                                                                           */
11 /*  You should have received a copy of the ZIB Academic License              */
12 /*  along with SCIP; see the file COPYING. If not visit scipopt.org.         */
13 /*                                                                           */
14 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
15 
16 /**@file   reader_gms.c
17  * @ingroup DEFPLUGINS_READER
18  * @brief  GAMS file writer
19  * @author Ambros Gleixner
20  * @author Stefan Vigerske
21  *
22  * @todo Check for words reserved for GAMS.
23  */
24 
25 /*---+----1----+----2----+----3----+----4----+----5----+----6----+----7----+----8----+----9----+----0----+----1----+----2*/
26 
27 #include "blockmemshell/memory.h"
28 #include "nlpi/pub_expr.h"
29 #include "scip/cons_abspower.h"
30 #include "scip/cons_bivariate.h"
31 #include "scip/cons_indicator.h"
32 #include "scip/cons_knapsack.h"
33 #include "scip/cons_linear.h"
34 #include "scip/cons_logicor.h"
35 #include "scip/cons_nonlinear.h"
36 #include "scip/cons_quadratic.h"
37 #include "scip/cons_setppc.h"
38 #include "scip/cons_soc.h"
39 #include "scip/cons_sos1.h"
40 #include "scip/cons_sos2.h"
41 #include "scip/cons_varbound.h"
42 #include "scip/pub_cons.h"
43 #include "scip/pub_message.h"
44 #include "scip/pub_misc.h"
45 #include "scip/pub_nlp.h"
46 #include "scip/pub_reader.h"
47 #include "scip/pub_var.h"
48 #include "scip/reader_gms.h"
49 #include "scip/scip_cons.h"
50 #include "scip/scip_general.h"
51 #include "scip/scip_mem.h"
52 #include "scip/scip_message.h"
53 #include "scip/scip_numerics.h"
54 #include "scip/scip_param.h"
55 #include "scip/scip_reader.h"
56 #include "scip/scip_var.h"
57 #include <string.h>
58 
59 #ifdef WITH_GAMS
60 #include <sys/stat.h>
61 
62 #include "gmomcc.h"
63 #include "gevmcc.h"
64 
65 #include "reader_gmo.h"
66 #endif
67 
68 
69 #define READER_NAME             "gmsreader"
70 #ifdef WITH_GAMS
71 #define READER_DESC             "file writer for MI(NL)(SOC)Ps in GAMS file format"
72 #else
73 #define READER_DESC             "file reader and writer for MI(NL)(SOC)Ps in GAMS file format"
74 #endif
75 #define READER_EXTENSION        "gms"
76 
77 
78 #define GMS_MAX_LINELEN      256
79 #define GMS_MAX_PRINTLEN     256       /**< the maximum length of any line is 255 + '\\0' = 256*/
80 #define GMS_MAX_NAMELEN      64        /**< the maximum length for any name is 63 + '\\0' = 64 */
81 #define GMS_PRINTLEN         100
82 #define GMS_DEFAULT_BIGM     1e+6
83 #define GMS_DEFAULT_INDICATORREFORM 's'
84 #define GMS_DEFAULT_SIGNPOWER FALSE
85 
86 /*
87  * Local methods (for writing)
88  */
89 
90 static const char badchars[] = "#*+/-@$[](){}";
91 
92 /** transforms given variables, scalars, and constant to the corresponding active variables, scalars, and constant */
93 static
getActiveVariables(SCIP * scip,SCIP_VAR ** vars,SCIP_Real * scalars,int * nvars,SCIP_Real * constant,SCIP_Bool transformed)94 SCIP_RETCODE getActiveVariables(
95    SCIP*                 scip,               /**< SCIP data structure */
96    SCIP_VAR**            vars,               /**< vars array to get active variables for */
97    SCIP_Real*            scalars,            /**< scalars a_1, ..., a_n in linear sum a_1*x_1 + ... + a_n*x_n + c */
98    int*                  nvars,              /**< pointer to number of variables and values in vars and vals array */
99    SCIP_Real*            constant,           /**< pointer to constant c in linear sum a_1*x_1 + ... + a_n*x_n + c  */
100    SCIP_Bool             transformed         /**< transformed constraint? */
101    )
102 {
103    int requiredsize;
104    int v;
105 
106    assert( scip != NULL );
107    assert( vars != NULL );
108    assert( scalars != NULL );
109    assert( nvars != NULL );
110    assert( constant != NULL );
111 
112    if( transformed )
113    {
114       SCIP_CALL( SCIPgetProbvarLinearSum(scip, vars, scalars, nvars, *nvars, constant, &requiredsize, TRUE) );
115 
116       if( requiredsize > *nvars )
117       {
118          SCIP_CALL( SCIPreallocBufferArray(scip, &vars, requiredsize) );
119          SCIP_CALL( SCIPreallocBufferArray(scip, &scalars, requiredsize) );
120 
121          SCIP_CALL( SCIPgetProbvarLinearSum(scip, vars, scalars, nvars, requiredsize, constant, &requiredsize, TRUE) );
122          assert( requiredsize <= *nvars );
123       }
124    }
125    else
126    {
127       for( v = 0; v < *nvars; ++v )
128       {
129          SCIP_CALL( SCIPvarGetOrigvarSum(&vars[v], &scalars[v], constant) );
130       }
131    }
132    return SCIP_OKAY;
133 }
134 
135 /** clears the given line buffer */
136 static
clearLine(char * linebuffer,int * linecnt)137 void clearLine(
138    char*                 linebuffer,         /**< line */
139    int*                  linecnt             /**< number of characters in line */
140    )
141 {
142    assert( linebuffer != NULL );
143    assert( linecnt != NULL );
144 
145    (*linecnt) = 0;
146    linebuffer[0] = '\0';
147 }
148 
149 /** ends the given line with '\\0' and prints it to the given file stream */
150 static
endLine(SCIP * scip,FILE * file,char * linebuffer,int * linecnt)151 void endLine(
152    SCIP*                 scip,               /**< SCIP data structure */
153    FILE*                 file,               /**< output file (or NULL for standard output) */
154    char*                 linebuffer,         /**< line */
155    int*                  linecnt             /**< number of characters in line */
156    )
157 {
158    assert( scip != NULL );
159    assert( linebuffer != NULL );
160    assert( linecnt != NULL );
161    assert( 0 <= *linecnt && *linecnt < GMS_MAX_LINELEN );
162 
163    if( (*linecnt) > 0 )
164    {
165       linebuffer[(*linecnt)] = '\0';
166       SCIPinfoMessage(scip, file, "%s\n", linebuffer);
167       clearLine(linebuffer, linecnt);
168    }
169 }
170 
171 /** appends extension to line and prints it to the give file stream if the
172  *  line exceeded the length given in the define GMS_PRINTLEN */
173 static
appendLine(SCIP * scip,FILE * file,char * linebuffer,int * linecnt,const char * extension)174 void appendLine(
175    SCIP*                 scip,               /**< SCIP data structure */
176    FILE*                 file,               /**< output file (or NULL for standard output) */
177    char*                 linebuffer,         /**< line */
178    int*                  linecnt,            /**< number of characters in line */
179    const char*           extension           /**< string to extend the line */
180    )
181 {
182    size_t len;
183    assert( scip != NULL );
184    assert( linebuffer != NULL );
185    assert( linecnt != NULL );
186    assert( extension != NULL );
187    assert( strlen(linebuffer) + strlen(extension) < GMS_MAX_PRINTLEN );
188 
189    /* NOTE: avoid
190     *   sprintf(linebuffer, "%s%s", linebuffer, extension);
191     * because of overlapping memory areas in memcpy used in sprintf.
192     */
193    len = strlen(linebuffer);
194    (void) strncat(linebuffer, extension, GMS_MAX_PRINTLEN - len);
195 
196    (*linecnt) += (int) strlen(extension);
197 
198    SCIPdebugMsg(scip, "linebuffer <%s>, length = %lu\n", linebuffer, (unsigned long)len);
199 
200    if( (*linecnt) > GMS_PRINTLEN )
201       endLine(scip, file, linebuffer, linecnt);
202 }
203 
204 /** appends extension to line and prints it to the give file stream if the
205  *  line exceeded the length given in the define GMS_PRINTLEN
206  *  indents the line by some spaces if it is a new line */
207 static
appendLineWithIndent(SCIP * scip,FILE * file,char * linebuffer,int * linecnt,const char * extension)208 void appendLineWithIndent(
209    SCIP*                 scip,               /**< SCIP data structure */
210    FILE*                 file,               /**< output file (or NULL for standard output) */
211    char*                 linebuffer,         /**< line */
212    int*                  linecnt,            /**< number of characters in line */
213    const char*           extension           /**< string to extend the line */
214    )
215 {
216    if( *linecnt == 0 )
217       /* we start a new line; therefore we indent line */
218       appendLine(scip, file, linebuffer, linecnt, "     ");
219 
220    appendLine(scip, file, linebuffer, linecnt, extension);
221 }
222 
223 /** checks string for occurences of bad symbols and replace those by '_' */
224 static
conformName(char * name)225 void conformName(
226    char*                 name                /**< string to adjust */
227    )
228 {
229    const char* badchar;
230 
231    assert( name != NULL );
232 
233    for( badchar = badchars; *badchar; ++badchar )
234    {
235       char* c = strchr(name, *badchar);
236 
237       while( c != NULL )
238       {
239          assert( *c == *badchar );
240 
241          *c = '_';
242          c = strchr(c, *badchar);
243       }
244    }
245 }
246 
247 /* print first len-1 characters of name to string s and replace '#', '*', '+', '/', and '-' by '_' if necessary */
248 static
printConformName(SCIP * scip,char * t,int len,const char * name)249 SCIP_RETCODE printConformName(
250    SCIP*                 scip,               /**< SCIP data structure */
251    char*                 t,                  /**< target string */
252    int                   len,                /**< length of t */
253    const char*           name                /**< source string or format string */
254    )
255 {
256    SCIP_Bool replaceforbiddenchars;
257 
258    assert( t != NULL );
259    assert( len > 0 );
260 
261    SCIP_CALL( SCIPgetBoolParam(scip, "reading/gmsreader/replaceforbiddenchars", &replaceforbiddenchars) );
262 
263    (void) SCIPsnprintf(t, len, "%s", name);
264 
265    if( replaceforbiddenchars )
266       conformName(t);
267 
268    return SCIP_OKAY;
269 }
270 
271 
272 /* retransform to active variables and print in GAMS format to file stream with surrounding bracket, pre- and suffix */
273 static
printActiveVariables(SCIP * scip,FILE * file,char * linebuffer,int * linecnt,const char * prefix,const char * suffix,int nvars,SCIP_VAR ** vars,SCIP_Real * vals,SCIP_Bool transformed)274 SCIP_RETCODE printActiveVariables(
275    SCIP*                 scip,               /**< SCIP data structure */
276    FILE*                 file,               /**< output file (or NULL for standard output) */
277    char*                 linebuffer,         /**< line */
278    int*                  linecnt,            /**< number of characters in line */
279    const char*           prefix,             /**< prefix (maybe NULL) */
280    const char*           suffix,             /**< suffix (maybe NULL) */
281    int                   nvars,              /**< number of variables */
282    SCIP_VAR**            vars,               /**< array of variables */
283    SCIP_Real*            vals,               /**< array of values (or NULL if all ones) */
284    SCIP_Bool             transformed         /**< transformed constraint? */
285    )
286 {
287    int v;
288    int closingbracket;
289 
290    SCIP_VAR* var;
291    char varname[GMS_MAX_NAMELEN];
292    char buffer[GMS_MAX_PRINTLEN];
293    char ext[GMS_MAX_PRINTLEN];
294 
295    SCIP_VAR** activevars = NULL;
296    SCIP_Real* activevals = NULL;
297    int nactivevars;
298    SCIP_Real activeconstant = 0.0;
299 
300    assert( scip != NULL );
301    assert( vars != NULL || nvars == 0 );
302 
303    if( *linecnt == 0 )
304       /* we start a new line; therefore we tab this line */
305       appendLine(scip, file, linebuffer, linecnt, "     ");
306 
307    if( nvars == 0 )
308    {
309       (void) SCIPsnprintf(buffer, GMS_MAX_PRINTLEN, "%s(0)%s", prefix != NULL ? prefix : "", suffix != NULL ? suffix : "");
310 
311       appendLine(scip, file, linebuffer, linecnt, buffer);
312    }
313    else
314    {
315       nactivevars = nvars;
316 
317       /* duplicate variable and value array */
318       SCIP_CALL( SCIPduplicateBufferArray(scip, &activevars, vars, nactivevars) );
319       if( vals != NULL )
320       {
321          SCIP_CALL( SCIPduplicateBufferArray(scip, &activevals, vals, nactivevars) );
322       }
323       else
324       {
325          SCIP_CALL( SCIPallocBufferArray(scip, &activevals, nactivevars) );
326 
327          for( v = 0; v < nactivevars; ++v )
328             activevals[v] = 1.0;
329       }
330 
331       /* retransform given variables to active variables */
332       SCIP_CALL( getActiveVariables(scip, activevars, activevals, &nactivevars, &activeconstant, transformed) );
333 
334       assert( nactivevars == 0 || activevals != NULL );
335 
336       if( nactivevars == 0 && SCIPisZero(scip, activeconstant) )
337       {
338          if( *linecnt == 0 )
339             /* we start a new line; therefore we tab this line */
340             appendLine(scip, file, linebuffer, linecnt, "     ");
341 
342          (void) SCIPsnprintf(buffer, GMS_MAX_PRINTLEN, "%s(0)%s", prefix != NULL ? prefix : "", suffix != NULL ? suffix : "");
343 
344          appendLine(scip, file, linebuffer, linecnt, buffer);
345       }
346       else
347       {
348          /* buffer prefix */
349          (void) SCIPsnprintf(ext, GMS_MAX_PRINTLEN, "%s(", prefix != NULL ? prefix : "");
350 
351          /* find position of closing bracket */
352          closingbracket = nactivevars;
353          if( SCIPisZero(scip, activeconstant) )
354          {
355             do
356                --closingbracket;
357             while( SCIPisZero(scip, activevals[closingbracket]) && closingbracket > 0 );
358          }
359 
360          /* print active variables */
361          for( v = 0; v < nactivevars; ++v )
362          {
363             var = activevars[v];
364             assert( var != NULL );
365 
366             if( !SCIPisZero(scip, activevals[v]) )
367             {
368                if( *linecnt == 0 )
369                   /* we start a new line; therefore we tab this line */
370                   appendLine(scip, file, linebuffer, linecnt, "     ");
371 
372                SCIP_CALL( printConformName(scip, varname, GMS_MAX_NAMELEN, SCIPvarGetName(var)) );
373 
374                if( SCIPisEQ(scip, activevals[v], 1.0) )
375                   (void) SCIPsnprintf(buffer, GMS_MAX_PRINTLEN, "%s%s%s%s%s", ext, strchr(ext, '(') == NULL ? "+" : "",
376                         varname, (v == closingbracket) ? ")" : "", (v == closingbracket && suffix) ? suffix : "");
377                else if( SCIPisEQ(scip, activevals[v], -1.0) )
378                   (void) SCIPsnprintf(buffer, GMS_MAX_PRINTLEN, "%s-%s%s%s", ext,
379                         varname, (v == closingbracket) ? ")" : "", (v == closingbracket && suffix) ? suffix : "");
380                else if( strchr(ext, '(') != NULL )
381                   (void) SCIPsnprintf(buffer, GMS_MAX_PRINTLEN, "%s%.15g*%s%s%s", ext,
382                         activevals[v], varname, (v == closingbracket) ? ")" : "", (v == closingbracket && suffix) ? suffix : "");
383                else
384                   (void) SCIPsnprintf(buffer, GMS_MAX_PRINTLEN, "%s%+.15g*%s%s%s", ext,
385                         activevals[v], varname, (v == closingbracket) ? ")" : "", (v == closingbracket && suffix) ? suffix : "");
386 
387                appendLine(scip, file, linebuffer, linecnt, buffer);
388 
389                (void) SCIPsnprintf(ext, GMS_MAX_PRINTLEN, (*linecnt == 0) ? "" : " ");
390             }
391          }
392 
393          /* print active constant */
394          if( !SCIPisZero(scip, activeconstant) )
395          {
396             if( *linecnt == 0 )
397                /* we start a new line; therefore we tab this line */
398                appendLine(scip, file, linebuffer, linecnt, "     ");
399 
400             (void) SCIPsnprintf(buffer, GMS_MAX_PRINTLEN, "%s%+.15g)%s", ext, activeconstant, suffix ? suffix : "");
401 
402             appendLine(scip, file, linebuffer, linecnt, buffer);
403          }
404          /* nothing has been printed, yet */
405          else if( strchr(ext, '(') != NULL )
406          {
407             if( *linecnt == 0 )
408                /* we start a new line; therefore we tab this line */
409                appendLine(scip, file, linebuffer, linecnt, "     ");
410 
411             (void) SCIPsnprintf(buffer, GMS_MAX_PRINTLEN, "%s(0)%s", prefix ? prefix : "", suffix ? suffix : "");
412 
413             appendLine(scip, file, linebuffer, linecnt, buffer);
414          }
415       }
416 
417       /* free buffer arrays */
418       SCIPfreeBufferArray(scip, &activevars);
419       SCIPfreeBufferArray(scip, &activevals);
420    }
421 
422    return SCIP_OKAY;
423 }
424 
425 
426 /* print linear row in GAMS format to file stream (without retransformation to active variables) */
427 static
printLinearRow(SCIP * scip,FILE * file,const char * rowname,const char * rownameextension,const char * type,int nvars,SCIP_VAR ** vars,SCIP_Real * vals,SCIP_Real rhs)428 SCIP_RETCODE printLinearRow(
429    SCIP*                 scip,               /**< SCIP data structure */
430    FILE*                 file,               /**< output file (or NULL for standard output) */
431    const char*           rowname,            /**< row name */
432    const char*           rownameextension,   /**< row name extension */
433    const char*           type,               /**< row type ("=e=", "=l=", or "=g=") */
434    int                   nvars,              /**< number of variables */
435    SCIP_VAR**            vars,               /**< array of variables */
436    SCIP_Real*            vals,               /**< array of values */
437    SCIP_Real             rhs                 /**< right hand side */
438    )
439 {
440    int v;
441    char linebuffer[GMS_MAX_PRINTLEN+1] = { '\0' };
442    int linecnt;
443 
444    SCIP_VAR* var;
445    char varname[GMS_MAX_NAMELEN];
446    char consname[GMS_MAX_NAMELEN + 3]; /* four extra characters for ' ..' */
447    char buffer[GMS_MAX_PRINTLEN];
448 
449    assert( scip != NULL );
450    assert( strcmp(type, "=e=") == 0 || strcmp(type, "=l=") == 0 || strcmp(type, "=g=") == 0);
451    assert( nvars == 0 || (vars != NULL && vals != NULL) );
452 
453    clearLine(linebuffer, &linecnt);
454 
455    /* start each line with a space */
456    appendLine(scip, file, linebuffer, &linecnt, " ");
457 
458    /* print row name */
459    if( strlen(rowname) > 0 || strlen(rownameextension) > 0 )
460    {
461       (void) SCIPsnprintf(buffer, GMS_MAX_NAMELEN + 3, "%s%s ..", rowname, rownameextension);
462       SCIP_CALL( printConformName(scip, consname, GMS_MAX_NAMELEN + 3, buffer) );
463       appendLine(scip, file, linebuffer, &linecnt, consname);
464    }
465 
466    /* print coefficients */
467    if( nvars == 0 )
468    {
469       /* we start a new line; therefore we tab this line */
470       if( linecnt == 0 )
471          appendLine(scip, file, linebuffer, &linecnt, "     ");
472 
473       (void) SCIPsnprintf(buffer, GMS_MAX_PRINTLEN, " 0");
474 
475       appendLine(scip, file, linebuffer, &linecnt, buffer);
476    }
477 
478    for( v = 0; v < nvars; ++v )
479    {
480       assert(vars != NULL);  /* for lint */
481       assert(vals != NULL);
482 
483       var = vars[v];
484       assert( var != NULL );
485 
486       /* we start a new line; therefore we tab this line */
487       if( linecnt == 0 )
488          appendLine(scip, file, linebuffer, &linecnt, "     ");
489 
490       SCIP_CALL( printConformName(scip, varname, GMS_MAX_NAMELEN, SCIPvarGetName(var)) );
491       (void) SCIPsnprintf(buffer, GMS_MAX_PRINTLEN, " %+.15g*%s", vals[v], varname);
492 
493       appendLine(scip, file, linebuffer, &linecnt, buffer);
494    }
495 
496    /* print right hand side */
497    if( SCIPisZero(scip, rhs) )
498       rhs = 0.0;
499 
500    (void) SCIPsnprintf(buffer, GMS_MAX_PRINTLEN, " %s %.15g;", type, rhs);
501 
502    /* we start a new line; therefore we tab this line */
503    if( linecnt == 0 )
504       appendLine(scip, file, linebuffer, &linecnt, "     ");
505    appendLine(scip, file, linebuffer, &linecnt, buffer);
506 
507    endLine(scip, file, linebuffer, &linecnt);
508 
509    return SCIP_OKAY;
510 }
511 
512 
513 /** prints given linear constraint information in GAMS format to file stream */
514 static
printLinearCons(SCIP * scip,FILE * file,const char * rowname,int nvars,SCIP_VAR ** vars,SCIP_Real * vals,SCIP_Real lhs,SCIP_Real rhs,SCIP_Bool transformed)515 SCIP_RETCODE printLinearCons(
516    SCIP*                 scip,               /**< SCIP data structure */
517    FILE*                 file,               /**< output file (or NULL for standard output) */
518    const char*           rowname,            /**< name of the row */
519    int                   nvars,              /**< number of variables */
520    SCIP_VAR**            vars,               /**< array of variables */
521    SCIP_Real*            vals,               /**< array of coefficients values (or NULL if all coefficient values are 1) */
522    SCIP_Real             lhs,                /**< left hand side */
523    SCIP_Real             rhs,                /**< right hand side */
524    SCIP_Bool             transformed         /**< transformed constraint? */
525    )
526 {
527    int v;
528    SCIP_VAR** activevars = NULL;
529    SCIP_Real* activevals = NULL;
530    int nactivevars;
531    SCIP_Real activeconstant = 0.0;
532 
533    assert( scip != NULL );
534    assert( rowname != NULL );
535 
536    /* The GAMS format does not forbid that the variable array is empty */
537    assert( nvars == 0 || vars != NULL );
538 
539    assert( lhs <= rhs );
540 
541    if( SCIPisInfinity(scip, -lhs) && SCIPisInfinity(scip, rhs) )
542       return SCIP_OKAY;
543 
544    nactivevars = nvars;
545    if( nvars > 0 )
546    {
547       /* duplicate variable and value array */
548       SCIP_CALL( SCIPduplicateBufferArray(scip, &activevars, vars, nactivevars) );
549       if( vals != NULL )
550       {
551          SCIP_CALL( SCIPduplicateBufferArray(scip, &activevals, vals, nactivevars) );
552       }
553       else
554       {
555          SCIP_CALL( SCIPallocBufferArray(scip, &activevals, nactivevars) );
556 
557          for( v = 0; v < nactivevars; ++v )
558             activevals[v] = 1.0;
559       }
560 
561       /* retransform given variables to active variables */
562       SCIP_CALL( getActiveVariables(scip, activevars, activevals, &nactivevars, &activeconstant, transformed) );
563    }
564 
565    /* print row(s) in GAMS format */
566    if( SCIPisEQ(scip, lhs, rhs) )
567    {
568       assert( !SCIPisInfinity(scip, rhs) );
569 
570       /* print equality constraint */
571       SCIP_CALL( printLinearRow(scip, file, rowname, "", "=e=",
572             nactivevars, activevars, activevals, rhs - activeconstant) );
573    }
574    else
575    {
576       if( !SCIPisInfinity(scip, -lhs) )
577       {
578          /* print inequality ">=" */
579          SCIP_CALL( printLinearRow(scip, file, rowname, SCIPisInfinity(scip, rhs) ? "" : "_lhs", "=g=",
580                nactivevars, activevars, activevals, lhs - activeconstant) );
581       }
582       if( !SCIPisInfinity(scip, rhs) )
583       {
584          /* print inequality "<=" */
585          SCIP_CALL( printLinearRow(scip, file, rowname, SCIPisInfinity(scip, -lhs) ? "" : "_rhs", "=l=",
586                nactivevars, activevars, activevals, rhs - activeconstant) );
587       }
588    }
589 
590    if( nvars > 0 )
591    {
592       /* free buffer arrays */
593       SCIPfreeBufferArray(scip, &activevars);
594       SCIPfreeBufferArray(scip, &activevals);
595    }
596 
597    return SCIP_OKAY;
598 }
599 
600 
601 /* print quadratic row in GAMS format to file stream (performing retransformation to active variables) */
602 static
printQuadraticRow(SCIP * scip,FILE * file,const char * rowname,const char * rownameextension,const char * type,int nlinvars,SCIP_VAR ** linvars,SCIP_Real * lincoeffs,int nquadvarterms,SCIP_QUADVARTERM * quadvarterms,int nbilinterms,SCIP_BILINTERM * bilinterms,SCIP_Real rhs,SCIP_Bool transformed)603 SCIP_RETCODE printQuadraticRow(
604    SCIP*                 scip,               /**< SCIP data structure */
605    FILE*                 file,               /**< output file (or NULL for standard output) */
606    const char*           rowname,            /**< row name */
607    const char*           rownameextension,   /**< row name extension */
608    const char*           type,               /**< row type ("=e=", "=l=", or "=g=") */
609    int                   nlinvars,           /**< number of linear terms */
610    SCIP_VAR**            linvars,            /**< variables in linear part */
611    SCIP_Real*            lincoeffs,          /**< coefficients of variables in linear part */
612    int                   nquadvarterms,      /**< number of quadratic variable terms */
613    SCIP_QUADVARTERM*     quadvarterms,       /**< quadratic variable terms */
614    int                   nbilinterms,        /**< number of bilinear terms */
615    SCIP_BILINTERM*       bilinterms,         /**< bilinear terms */
616    SCIP_Real             rhs,                /**< right hand side */
617    SCIP_Bool             transformed         /**< transformed constraint? */
618    )
619 {
620    int t;
621    char linebuffer[GMS_MAX_PRINTLEN+1] = { '\0' };
622    int linecnt;
623 
624    SCIP_VAR* var;
625    char consname[GMS_MAX_NAMELEN + 3]; /* four extra characters for ' ..' */
626    char buffer[GMS_MAX_PRINTLEN];
627 
628    assert( scip != NULL );
629    assert( strlen(rowname) > 0 || strlen(rownameextension) > 0 );
630    assert( strcmp(type, "=e=") == 0 || strcmp(type, "=l=") == 0 || strcmp(type, "=g=") == 0 );
631    assert( nlinvars == 0 || (linvars != NULL && lincoeffs != NULL) );
632    assert( nquadvarterms == 0 || quadvarterms != NULL );
633    assert( nbilinterms == 0 || bilinterms != NULL );
634    assert( nquadvarterms > 0 || nbilinterms == 0 );
635 
636    clearLine(linebuffer, &linecnt);
637 
638    /* start each line with a space */
639    appendLine(scip, file, linebuffer, &linecnt, " ");
640 
641    /* print row name */
642    (void) SCIPsnprintf(buffer, GMS_MAX_NAMELEN + 3, "%s%s ..", rowname, rownameextension);
643    SCIP_CALL( printConformName(scip, consname, GMS_MAX_NAMELEN + 3, buffer) );
644 
645    appendLine(scip, file, linebuffer, &linecnt, consname);
646 
647    /* print linear terms */
648    if( nlinvars > 0 )
649    {
650       SCIP_CALL( printActiveVariables(scip, file, linebuffer, &linecnt, "+", " ", nlinvars, linvars, lincoeffs, transformed) );
651    }
652 
653    /* print linear coefficients of quadratic terms */
654    for( t = 0; t < nquadvarterms; ++t )
655    {
656       var = quadvarterms[t].var;
657       assert( var != NULL );
658 
659       if( !SCIPisZero(scip, quadvarterms[t].lincoef) )
660       {
661          (void) SCIPsnprintf(buffer, GMS_MAX_PRINTLEN, "%+.15g*", quadvarterms[t].lincoef);
662 
663          SCIP_CALL( printActiveVariables(scip, file, linebuffer, &linecnt, buffer, NULL, 1, &var, NULL, transformed) );
664       }
665    }
666 
667    /* print square coefficients of quadratic terms */
668    for( t = 0; t < nquadvarterms; ++t )
669    {
670       var = quadvarterms[t].var;
671       assert( var != NULL );
672 
673       if( !SCIPisZero(scip, quadvarterms[t].sqrcoef) )
674       {
675          (void) SCIPsnprintf(buffer, GMS_MAX_PRINTLEN, "%+.15g*sqr", quadvarterms[t].sqrcoef);
676 
677          SCIP_CALL( printActiveVariables(scip, file, linebuffer, &linecnt, buffer, NULL, 1, &var, NULL, transformed) );
678       }
679    }
680 
681    /* print bilinear terms */
682    for( t = 0; t < nbilinterms; ++t )
683    {
684       if( !SCIPisZero(scip, bilinterms[t].coef) )
685       {
686          (void) SCIPsnprintf(buffer, GMS_MAX_PRINTLEN, "%+.15g*", bilinterms[t].coef);
687 
688          /* print first variable (retransformed to active variables) */
689          var = bilinterms[t].var1;
690          assert( var != NULL );
691 
692          SCIP_CALL( printActiveVariables(scip, file, linebuffer, &linecnt, buffer, "", 1, &var, NULL, transformed) );
693 
694          /* print second variable (retransformed to active variables) */
695          var = bilinterms[t].var2;
696          assert( var != NULL );
697 
698          SCIP_CALL( printActiveVariables(scip, file, linebuffer, &linecnt, "*", " ", 1, &var, NULL, transformed) );
699       }
700    }
701 
702    /* print right hand side */
703    if( linecnt == 0 )
704       /* we start a new line; therefore we tab this line */
705       appendLine(scip, file, linebuffer, &linecnt, "     ");
706 
707    if( SCIPisZero(scip, rhs) )
708       rhs = 0.0;
709 
710    (void) SCIPsnprintf(buffer, GMS_MAX_PRINTLEN, "%s%s %.15g;", (nlinvars == 0 && nquadvarterms == 0) ? "0 " : "", type, rhs);
711 
712    appendLine(scip, file, linebuffer, &linecnt, buffer);
713 
714    endLine(scip, file, linebuffer, &linecnt);
715 
716    return SCIP_OKAY;
717 }
718 
719 
720 /** prints given quadratic constraint information in GAMS format to file stream */
721 static
printQuadraticCons(SCIP * scip,FILE * file,const char * rowname,int nlinvars,SCIP_VAR ** linvars,SCIP_Real * lincoeffs,int nquadvarterms,SCIP_QUADVARTERM * quadvarterms,int nbilinterms,SCIP_BILINTERM * bilinterms,SCIP_Real lhs,SCIP_Real rhs,SCIP_Bool transformed)722 SCIP_RETCODE printQuadraticCons(
723    SCIP*                 scip,               /**< SCIP data structure */
724    FILE*                 file,               /**< output file (or NULL for standard output) */
725    const char*           rowname,            /**< name of the row */
726    int                   nlinvars,           /**< number of linear terms */
727    SCIP_VAR**            linvars,            /**< variables in linear part */
728    SCIP_Real*            lincoeffs,          /**< coefficients of variables in linear part */
729    int                   nquadvarterms,      /**< number of quadratic variable terms */
730    SCIP_QUADVARTERM*     quadvarterms,       /**< quadratic variable terms */
731    int                   nbilinterms,        /**< number of bilinear terms */
732    SCIP_BILINTERM*       bilinterms,         /**< bilinear terms */
733    SCIP_Real             lhs,                /**< left hand side */
734    SCIP_Real             rhs,                /**< right hand side */
735    SCIP_Bool             transformed         /**< transformed constraint? */
736    )
737 {
738    assert( scip != NULL );
739    assert( rowname != NULL );
740    assert( nlinvars == 0 || (linvars != NULL && lincoeffs != NULL) );
741    assert( nquadvarterms == 0 || quadvarterms != NULL );
742    assert( nbilinterms == 0 || bilinterms != NULL );
743    assert( nquadvarterms > 0 || nbilinterms == 0 );
744    assert( lhs <= rhs );
745 
746    if( SCIPisInfinity(scip, -lhs) && SCIPisInfinity(scip, rhs) )
747       return SCIP_OKAY;
748 
749    /* print row(s) in GAMS format */
750    if( SCIPisEQ(scip, lhs, rhs) )
751    {
752       assert( !SCIPisInfinity(scip, rhs) );
753 
754       /* print equality constraint */
755       SCIP_CALL( printQuadraticRow(scip, file, rowname, "", "=e=",
756          nlinvars, linvars, lincoeffs,
757          nquadvarterms, quadvarterms,
758          nbilinterms, bilinterms, rhs, transformed) );
759    }
760    else
761    {
762       if( !SCIPisInfinity(scip, -lhs) )
763       {
764          /* print inequality ">=" */
765          SCIP_CALL( printQuadraticRow(scip, file, rowname, SCIPisInfinity(scip, rhs) ? "" : "_lhs", "=g=",
766             nlinvars, linvars, lincoeffs,
767             nquadvarterms, quadvarterms,
768             nbilinterms, bilinterms, lhs, transformed) );
769       }
770       if( !SCIPisInfinity(scip, rhs) )
771       {
772          /* print inequality "<=" */
773          SCIP_CALL( printQuadraticRow(scip, file, rowname, SCIPisInfinity(scip, -lhs) ? "" : "_rhs", "=l=",
774             nlinvars, linvars, lincoeffs,
775             nquadvarterms, quadvarterms,
776             nbilinterms, bilinterms, rhs, transformed) );
777       }
778    }
779 
780    return SCIP_OKAY;
781 }
782 
783 /** check GAMS limitations on SOC constraints
784  * returns true of constraint can be written as conic equation in GAMS (using equation type =C=)
785  */
786 static
isGAMSprintableSOC(int nlhsvars,SCIP_VAR ** lhsvars,SCIP_Real * lhscoeffs,SCIP_Real * lhsoffsets,SCIP_Real lhsconstant,SCIP_VAR * rhsvar,SCIP_Real rhscoef,SCIP_Real rhsoffset)787 SCIP_Bool isGAMSprintableSOC(
788    int                   nlhsvars,           /**< number of variables on left hand side */
789    SCIP_VAR**            lhsvars,            /**< variables on left hand side */
790    SCIP_Real*            lhscoeffs,          /**< coefficients of variables on left hand side, or NULL if == 1.0 */
791    SCIP_Real*            lhsoffsets,         /**< offsets of variables on left hand side, or NULL if == 0.0 */
792    SCIP_Real             lhsconstant,        /**< constant on left hand side */
793    SCIP_VAR*             rhsvar,             /**< variable on right hand side */
794    SCIP_Real             rhscoef,            /**< coefficient of variable on right hand side */
795    SCIP_Real             rhsoffset           /**< offset of variable on right hand side */
796    )
797 {
798    int i;
799 
800    assert(nlhsvars == 0 || lhsvars != NULL);
801 
802    if( rhscoef != 1.0 )
803       return FALSE;
804 
805    if( rhsoffset != 0.0 )
806       return FALSE;
807 
808    if( rhsvar == NULL )
809       return FALSE;
810 
811    if( !SCIPvarIsActive(rhsvar) )
812       return FALSE;
813 
814    if( lhsconstant != 0.0 )
815       return FALSE;
816 
817    if( nlhsvars < 2 )
818       return FALSE;
819 
820    for( i = 0; i < nlhsvars; ++i )
821    {
822       if( lhscoeffs [i] != 1.0 )
823          return FALSE;
824 
825       if( lhsoffsets[i] != 0.0 )
826          return FALSE;
827 
828       if( !SCIPvarIsActive(lhsvars[i]) )
829          return FALSE;
830    }
831 
832    return TRUE;
833 }
834 
835 /* print second order cone row in GAMS format to file stream (performing retransformation to active variables)
836  * The constraints are of the following form:
837  * \f[
838  *    \left\{ x \;:\; \sqrt{\gamma + \sum_{i=1}^{n} (\alpha_i\, (x_i + \beta_i))^2} \leq \alpha_{n+1}\, (x_{n+1}+\beta_{n+1}) \right\}.
839  * \f]
840  * */
841 static
printSOCCons(SCIP * scip,FILE * file,const char * rowname,int nlhsvars,SCIP_VAR ** lhsvars,SCIP_Real * lhscoeffs,SCIP_Real * lhsoffsets,SCIP_Real lhsconstant,SCIP_VAR * rhsvar,SCIP_Real rhscoef,SCIP_Real rhsoffset,SCIP_Bool transformed)842 SCIP_RETCODE printSOCCons(
843    SCIP*                 scip,               /**< SCIP data structure */
844    FILE*                 file,               /**< output file (or NULL for standard output) */
845    const char*           rowname,            /**< row name */
846    int                   nlhsvars,           /**< number of variables on left hand side */
847    SCIP_VAR**            lhsvars,            /**< variables on left hand side */
848    SCIP_Real*            lhscoeffs,          /**< coefficients of variables on left hand side, or NULL if == 1.0 */
849    SCIP_Real*            lhsoffsets,         /**< offsets of variables on left hand side, or NULL if == 0.0 */
850    SCIP_Real             lhsconstant,        /**< constant on left hand side */
851    SCIP_VAR*             rhsvar,             /**< variable on right hand side */
852    SCIP_Real             rhscoef,            /**< coefficient of variable on right hand side */
853    SCIP_Real             rhsoffset,          /**< offset of variable on right hand side */
854    SCIP_Bool             transformed         /**< transformed constraint? */
855    )
856 {
857    char linebuffer[GMS_MAX_PRINTLEN+1] = { '\0' };
858    int linecnt;
859 
860    char consname[GMS_MAX_NAMELEN + 3]; /* four extra characters for ' ..' */
861    char buffer[GMS_MAX_PRINTLEN];
862 
863    assert( scip != NULL );
864    assert( strlen(rowname) > 0 );
865    assert( nlhsvars == 0 || lhsvars != NULL );
866 
867    clearLine(linebuffer, &linecnt);
868 
869    /* start each line with a space */
870    appendLine(scip, file, linebuffer, &linecnt, " ");
871 
872    /* print row name */
873    (void) SCIPsnprintf(buffer, GMS_MAX_NAMELEN + 3, "%s ..", rowname);
874    SCIP_CALL( printConformName(scip, consname, GMS_MAX_NAMELEN + 3, buffer) );
875 
876    appendLine(scip, file, linebuffer, &linecnt, consname);
877 
878    if( !isGAMSprintableSOC(nlhsvars, lhsvars, lhscoeffs, lhsoffsets, lhsconstant, rhsvar, rhscoef, rhsoffset) )
879    {
880       int t;
881 
882       /* print right-hand side on left */
883       (void) SCIPsnprintf(buffer, GMS_MAX_PRINTLEN, "sqr(%.15g +", rhsoffset);
884 
885       SCIP_CALL( printActiveVariables(scip, file, linebuffer, &linecnt, buffer, ")", 1, &rhsvar, &rhscoef, transformed) );
886 
887       appendLine(scip, file, linebuffer, &linecnt, " =g= ");
888 
889       /* print left-hand side on right */
890 
891       if( lhsconstant != 0.0 )
892       {
893          (void) SCIPsnprintf(buffer, GMS_MAX_PRINTLEN, "%.15g", lhsconstant);
894 
895          appendLine(scip, file, linebuffer, &linecnt, buffer);
896       }
897 
898       for( t = 0; t < nlhsvars; ++t )
899       {
900          assert( lhsvars[t] != NULL );
901 
902          (void) SCIPsnprintf(buffer, GMS_MAX_PRINTLEN, "+ sqr(%.15g * (%.15g + ", lhscoeffs ? lhscoeffs[t] : 1.0, lhsoffsets ? lhsoffsets[t] : 0.0);
903 
904          SCIP_CALL( printActiveVariables(scip, file, linebuffer, &linecnt, buffer, "))", 1, &lhsvars[t], NULL, transformed) );
905       }
906    }
907    else
908    {
909       /* print right-hand side on left */
910       SCIP_CALL( printActiveVariables(scip, file, linebuffer, &linecnt, "+", " ", 1, &rhsvar, &rhscoef, transformed) );
911 
912       appendLine(scip, file, linebuffer, &linecnt, " =c= ");
913 
914       /* print left-hand side on right */
915       SCIP_CALL( printActiveVariables(scip, file, linebuffer, &linecnt, "+", " ", nlhsvars, lhsvars, lhscoeffs, transformed) );
916    }
917 
918    appendLine(scip, file, linebuffer, &linecnt, ";");
919 
920    endLine(scip, file, linebuffer, &linecnt);
921 
922    return SCIP_OKAY;
923 }
924 
925 /* print indicator constraint in some GAMS format to file stream (performing retransformation to active variables)
926  * The constraints are of the following form:
927  * \f[
928  *    z = 1 -> s = 0
929  * \f]
930  * */
931 static
printIndicatorCons(SCIP * scip,FILE * file,const char * rowname,SCIP_VAR * z,SCIP_VAR * s,SCIP_Bool * sossetdeclr,SCIP_Bool transformed)932 SCIP_RETCODE printIndicatorCons(
933    SCIP*                 scip,               /**< SCIP data structure */
934    FILE*                 file,               /**< output file (or NULL for standard output) */
935    const char*           rowname,            /**< row name */
936    SCIP_VAR*             z,                  /**< indicating variable (binary) */
937    SCIP_VAR*             s,                  /**< slack variable */
938    SCIP_Bool*            sossetdeclr,        /**< buffer to store whether we declared the SOS set for indicator reform */
939    SCIP_Bool             transformed         /**< transformed constraint? */
940    )
941 {
942    char linebuffer[GMS_MAX_PRINTLEN+1] = { '\0' };
943    int linecnt;
944    SCIP_Real coef;
945    char indicatorform;
946 
947    char consname[GMS_MAX_NAMELEN + 30];
948    char buffer[GMS_MAX_PRINTLEN];
949 
950    assert( scip != NULL );
951    assert( strlen(rowname) > 0 );
952    assert( z != NULL );
953    assert( s != NULL );
954    assert( SCIPvarIsBinary(z) );
955    assert( sossetdeclr != NULL );
956 
957    clearLine(linebuffer, &linecnt);
958 
959    /* start each line with a space */
960    appendLine(scip, file, linebuffer, &linecnt, " ");
961 
962    SCIP_CALL( SCIPgetCharParam(scip, "reading/gmsreader/indicatorreform", &indicatorform) );
963 
964    switch( indicatorform )
965    {
966       case 'b':
967       {
968          /* print row name */
969          (void) SCIPsnprintf(buffer, GMS_MAX_NAMELEN + 3, "%s ..", rowname);
970          SCIP_CALL( printConformName(scip, consname, GMS_MAX_NAMELEN + 3, buffer) );
971 
972          appendLine(scip, file, linebuffer, &linecnt, consname);
973 
974          /* write as s <= upperbound(s)*(1-z) or s <= upperbound(s) * negation(z) */
975          coef = 1.0;
976          SCIP_CALL( printActiveVariables(scip, file, linebuffer, &linecnt, NULL, " =l= ", 1, &s, &coef, transformed) );
977 
978          coef = SCIPvarGetUbGlobal(s);
979          if( SCIPisInfinity(scip, coef) )
980          {
981             SCIP_CALL( SCIPgetRealParam(scip, "reading/gmsreader/bigmdefault", &coef) );
982 
983             SCIPwarningMessage(scip, "do not have upper bound on slack variable <%s> in indicator constraint <%s>, will use M = %g.\n",
984                SCIPvarGetName(s), rowname, coef);
985          }
986 
987          if( SCIPvarIsNegated(z) )
988          {
989             SCIP_CALL( SCIPgetNegatedVar(scip, z, &z) );
990             SCIP_CALL( printActiveVariables(scip, file, linebuffer, &linecnt, "", ";", 1, &z, &coef, transformed) );
991          }
992          else
993          {
994             (void) SCIPsnprintf(buffer, GMS_MAX_PRINTLEN, "%.15g + ", coef);
995 
996             coef = -coef;
997             SCIP_CALL( printActiveVariables(scip, file, linebuffer, &linecnt, buffer, ";", 1, &z, &coef, transformed) );
998          }
999 
1000          break;
1001       }
1002 
1003       case 's':
1004       {
1005          /* write as
1006           * sos1 Variable name_sos(sosset);
1007           *  name_soseq(sosset).. name_sos(sosset) =e= s$(sameas(sosset,'slack') + z$(sameas(sosset,'bin'));
1008           */
1009          coef = 1.0;
1010          SCIP_CALL( printConformName(scip, consname, GMS_MAX_NAMELEN, rowname) );
1011 
1012          /* declare set for SOS1 declarations from reformulation of indicator, if needed */
1013          if( !*sossetdeclr )
1014          {
1015             SCIPinfoMessage(scip, file, " Set sosset / slack, bin /;\n");
1016             *sossetdeclr = TRUE;
1017          }
1018 
1019          (void) SCIPsnprintf(buffer, GMS_MAX_PRINTLEN, "sos1 Variable %s_sos(sosset);", consname);
1020          appendLine(scip, file, linebuffer, &linecnt, buffer);
1021          endLine(scip, file, linebuffer, &linecnt);
1022 
1023          (void) SCIPsnprintf(buffer, GMS_MAX_PRINTLEN, " %s(sosset).. %s_sos(sosset) =e= ", consname, consname);
1024          appendLine(scip, file, linebuffer, &linecnt, buffer);
1025          SCIP_CALL( printActiveVariables(scip, file, linebuffer, &linecnt, NULL, "$sameas(sosset,'slack')", 1, &s, &coef, transformed) );
1026          if( SCIPvarIsNegated(z) )
1027          {
1028             SCIP_CALL( SCIPgetNegatedVar(scip, z, &z) );
1029             SCIP_CALL( printActiveVariables(scip, file, linebuffer, &linecnt, " + (1-(", "))$sameas(sosset,'bin');", 1, &z, &coef, transformed) );
1030          }
1031          else
1032          {
1033             SCIP_CALL( printActiveVariables(scip, file, linebuffer, &linecnt, " + ", "$sameas(sosset,'bin');", 1, &z, &coef, transformed) );
1034          }
1035          endLine(scip, file, linebuffer, &linecnt);
1036 
1037          break;
1038       }
1039 
1040       default:
1041          SCIPerrorMessage("wrong value '%c' for parameter reading/gmsreader/indicatorreform\n", indicatorform);
1042          return SCIP_ERROR;
1043    }
1044 
1045    endLine(scip, file, linebuffer, &linecnt);
1046 
1047    return SCIP_OKAY;
1048 }
1049 
1050 /* print SOS constraint in some GAMS format to file stream (performing retransformation to active variables)
1051  *
1052  * write as
1053  * Set name_sosset /1*nvars/;
1054  * SOS1/2 Variable name_sosvar(name_sosset); name_sosvar.lo(name_sosset) = -inf;
1055  * Equation name_sosequ(e1_sosset);
1056  * name_sosequ(name_sosset).. name_sosvar(e1_sosset) =e=
1057  * vars[0]$sameas(name_sosset, '1') + vars[1]$sameas(name_sosset, '2') + ... + vars[nvars-1]$sameas(name_sosset, nvars);
1058  */
1059 static
printSOSCons(SCIP * scip,FILE * file,const char * rowname,int nvars,SCIP_VAR ** vars,int sostype,SCIP_Bool transformed)1060 SCIP_RETCODE printSOSCons(
1061    SCIP*                 scip,               /**< SCIP data structure */
1062    FILE*                 file,               /**< output file (or NULL for standard output) */
1063    const char*           rowname,            /**< row name */
1064    int                   nvars,              /**< number of variables in SOS */
1065    SCIP_VAR**            vars,               /**< variables in SOS */
1066    int                   sostype,            /**< type of SOS: 1 or 2 */
1067    SCIP_Bool             transformed         /**< transformed constraint? */
1068    )
1069 {
1070    char linebuffer[GMS_MAX_PRINTLEN+1] = { '\0' };
1071    int linecnt;
1072    SCIP_Real coef;
1073    int v;
1074 
1075    char consname[GMS_MAX_NAMELEN + 30];
1076    char buffer[GMS_MAX_PRINTLEN];
1077 
1078    assert( scip != NULL );
1079    assert( strlen(rowname) > 0 );
1080    assert( vars != NULL || nvars == 0 );
1081    assert( sostype == 1 || sostype == 2 );
1082 
1083    clearLine(linebuffer, &linecnt);
1084 
1085    /* start each line with a space */
1086    appendLine(scip, file, linebuffer, &linecnt, " ");
1087 
1088    SCIP_CALL( printConformName(scip, consname, GMS_MAX_NAMELEN, rowname) );
1089 
1090    (void) SCIPsnprintf(buffer, GMS_MAX_PRINTLEN, "Set %s_sosset /1*%d/;", consname, nvars);
1091    appendLine(scip, file, linebuffer, &linecnt, buffer);
1092    endLine(scip, file, linebuffer, &linecnt);
1093 
1094    /* explicitly set lower bound of SOS variables to -inf, as GAMS default is 0.0 */
1095    (void) SCIPsnprintf(buffer, GMS_MAX_PRINTLEN, " SOS%d Variable %s_sosvar(%s_sosset); %s_sosvar.lo(%s_sosset) = -inf;", sostype, consname, consname, consname, consname);
1096    appendLine(scip, file, linebuffer, &linecnt, buffer);
1097    endLine(scip, file, linebuffer, &linecnt);
1098 
1099    (void) SCIPsnprintf(buffer, GMS_MAX_PRINTLEN, " %s(%s_sosset).. %s_sosvar(%s_sosset) =e= ", consname, consname, consname, consname);
1100    appendLine(scip, file, linebuffer, &linecnt, buffer);
1101    endLine(scip, file, linebuffer, &linecnt);
1102 
1103    coef = 1.0;
1104    for( v = 0; v < nvars; ++v )
1105    {
1106       (void) SCIPsnprintf(buffer, GMS_MAX_PRINTLEN, "$sameas(%s_sosset,'%d')", consname, v+1);
1107       SCIP_CALL( printActiveVariables(scip, file, linebuffer, &linecnt, v > 0 ? " + " : NULL, buffer, 1, &vars[v], &coef, transformed) ); /*lint !e613*/
1108    }
1109    appendLine(scip, file, linebuffer, &linecnt, ";");
1110    endLine(scip, file, linebuffer, &linecnt);
1111 
1112    return SCIP_OKAY;
1113 }
1114 
1115 /* print signpower row in GAMS format to file stream (performing retransformation to active variables) */
1116 static
printSignpowerRow(SCIP * scip,FILE * file,const char * rowname,const char * rownameextension,const char * type,SCIP_VAR * nonlinvar,SCIP_VAR * linvar,SCIP_Real exponent,SCIP_Real offset,SCIP_Real coeflinear,SCIP_Real rhs,SCIP_Bool transformed,SCIP_Bool signpowerallowed,SCIP_Bool * nsmooth)1117 SCIP_RETCODE printSignpowerRow(
1118    SCIP*                 scip,               /**< SCIP data structure */
1119    FILE*                 file,               /**< output file (or NULL for standard output) */
1120    const char*           rowname,            /**< row name */
1121    const char*           rownameextension,   /**< row name extension */
1122    const char*           type,               /**< row type ("=e=", "=l=", or "=g=") */
1123    SCIP_VAR*             nonlinvar,          /**< nonlinear variable */
1124    SCIP_VAR*             linvar,             /**< linear variable, may be NULL */
1125    SCIP_Real             exponent,           /**< exponent of nonlinear variable */
1126    SCIP_Real             offset,             /**< offset of nonlinear variable */
1127    SCIP_Real             coeflinear,         /**< coefficient of linear variable */
1128    SCIP_Real             rhs,                /**< right hand side */
1129    SCIP_Bool             transformed,        /**< transformed constraint? */
1130    SCIP_Bool             signpowerallowed,   /**< allowed to use signpower operator in GAMS? */
1131    SCIP_Bool*            nsmooth             /**< buffer to store whether we printed a nonsmooth function */
1132    )
1133 {
1134    char linebuffer[GMS_MAX_PRINTLEN+1] = { '\0' };
1135    int linecnt;
1136    SCIP_Bool nisoddint;
1137    SCIP_Bool fixedsign;
1138 
1139    char consname[GMS_MAX_NAMELEN + 3]; /* four extra characters for ' ..' */
1140    char buffer[GMS_MAX_PRINTLEN];
1141 
1142    assert( scip != NULL );
1143    assert( strlen(rowname) > 0 || strlen(rownameextension) > 0 );
1144    assert( strcmp(type, "=e=") == 0 || strcmp(type, "=l=") == 0 || strcmp(type, "=g=") == 0 );
1145    assert( nonlinvar != NULL );
1146    assert( exponent > 1.0 );
1147    assert( nsmooth != NULL );
1148 
1149    clearLine(linebuffer, &linecnt);
1150 
1151    /* start each line with a space */
1152    appendLine(scip, file, linebuffer, &linecnt, " ");
1153 
1154    /* print row name */
1155    (void) SCIPsnprintf(buffer, GMS_MAX_NAMELEN + 3, "%s%s ..", rowname, rownameextension);
1156    SCIP_CALL( printConformName(scip, consname, GMS_MAX_NAMELEN + 3, buffer) );
1157 
1158    appendLine(scip, file, linebuffer, &linecnt, consname);
1159 
1160    /* print nonlinear term
1161     * if not signpowerallowed, then signpow(x,n) is printed as x*abs(x) if n == 2, x*(abs(x)**(n-1)) if n is not 2 and not an odd integer, and as power(x,n) if n is an odd integer
1162     * if signpowerallowed, then signpow(x,n) is printed as power(x,n) if n is an odd integer and as signpower(x,n) otherwiser
1163     */
1164    nisoddint = SCIPisIntegral(scip, exponent) && ((int)SCIPfloor(scip, exponent+0.5))%2 == 1;
1165    fixedsign = !SCIPisNegative(scip, SCIPvarGetLbGlobal(nonlinvar)) || !SCIPisPositive(scip, SCIPvarGetUbGlobal(nonlinvar));
1166    if( !nisoddint && !fixedsign )
1167    {
1168       if( signpowerallowed )
1169       {
1170          if( offset != 0.0 )
1171          {
1172             (void) SCIPsnprintf(buffer, GMS_MAX_PRINTLEN, "signpower(%g ", offset);
1173             appendLine(scip, file, linebuffer, &linecnt, buffer);
1174             SCIP_CALL( printActiveVariables(scip, file, linebuffer, &linecnt, "+", ",", 1, &nonlinvar, NULL, transformed) );
1175          }
1176          else
1177          {
1178             SCIP_CALL( printActiveVariables(scip, file, linebuffer, &linecnt, "signpower(", ",", 1, &nonlinvar, NULL, transformed) );
1179          }
1180          (void) SCIPsnprintf(buffer, GMS_MAX_PRINTLEN, "%g)", exponent);
1181          appendLine(scip, file, linebuffer, &linecnt, buffer);
1182       }
1183       else
1184       {
1185          if( offset != 0.0 )
1186          {
1187             (void) SCIPsnprintf(buffer, GMS_MAX_PRINTLEN, "(%g ", offset);
1188             appendLine(scip, file, linebuffer, &linecnt, buffer);
1189             SCIP_CALL( printActiveVariables(scip, file, linebuffer, &linecnt, "+", ") * ", 1, &nonlinvar, NULL, transformed) );
1190          }
1191          else
1192          {
1193             SCIP_CALL( printActiveVariables(scip, file, linebuffer, &linecnt, NULL, " * ", 1, &nonlinvar, NULL, transformed) );
1194          }
1195 
1196          if( exponent == 2.0)
1197          {
1198             if( offset != 0.0 )
1199             {
1200                (void) SCIPsnprintf(buffer, GMS_MAX_PRINTLEN, "abs(%g ", offset);
1201                appendLine(scip, file, linebuffer, &linecnt, buffer);
1202                SCIP_CALL( printActiveVariables(scip, file, linebuffer, &linecnt, "+", ")", 1, &nonlinvar, NULL, transformed) );
1203             }
1204             else
1205             {
1206                SCIP_CALL( printActiveVariables(scip, file, linebuffer, &linecnt, "abs", NULL, 1, &nonlinvar, NULL, transformed) );
1207             }
1208          }
1209          else
1210          {
1211             if( offset != 0.0 )
1212             {
1213                (void) SCIPsnprintf(buffer, GMS_MAX_PRINTLEN, "abs(%g ", offset);
1214                appendLine(scip, file, linebuffer, &linecnt, buffer);
1215                SCIP_CALL( printActiveVariables(scip, file, linebuffer, &linecnt, "+", ")", 1, &nonlinvar, NULL, transformed) );
1216             }
1217             else
1218             {
1219                SCIP_CALL( printActiveVariables(scip, file, linebuffer, &linecnt, "abs", NULL, 1, &nonlinvar, NULL, transformed) );
1220             }
1221             (void) SCIPsnprintf(buffer, GMS_MAX_PRINTLEN, "**%g", exponent-1.0);
1222             appendLine(scip, file, linebuffer, &linecnt, buffer);
1223          }
1224       }
1225       *nsmooth = TRUE;
1226    }
1227    else if( nisoddint || !SCIPisNegative(scip, SCIPvarGetLbGlobal(nonlinvar)) )
1228    {
1229       if( exponent == 2.0 )
1230       {
1231          if( offset != 0.0 )
1232          {
1233             (void) SCIPsnprintf(buffer, GMS_MAX_PRINTLEN, "sqr(%g ", offset);
1234             appendLine(scip, file, linebuffer, &linecnt, buffer);
1235             SCIP_CALL( printActiveVariables(scip, file, linebuffer, &linecnt, "+", ")", 1, &nonlinvar, NULL, transformed) );
1236          }
1237          else
1238          {
1239             SCIP_CALL( printActiveVariables(scip, file, linebuffer, &linecnt, "sqr", NULL, 1, &nonlinvar, NULL, transformed) );
1240          }
1241       }
1242       else
1243       {
1244          if( offset != 0.0 )
1245          {
1246             (void) SCIPsnprintf(buffer, GMS_MAX_PRINTLEN, "power(%g ", offset);
1247             appendLine(scip, file, linebuffer, &linecnt, buffer);
1248             SCIP_CALL( printActiveVariables(scip, file, linebuffer, &linecnt, "+", ",", 1, &nonlinvar, NULL, transformed) );
1249          }
1250          else
1251          {
1252             SCIP_CALL( printActiveVariables(scip, file, linebuffer, &linecnt, "power(", ",", 1, &nonlinvar, NULL, transformed) );
1253          }
1254          (void) SCIPsnprintf(buffer, GMS_MAX_PRINTLEN, "%g)", exponent);
1255          appendLine(scip, file, linebuffer, &linecnt, buffer);
1256       }
1257    }
1258    else
1259    {
1260       assert(fixedsign && !SCIPisPositive(scip, SCIPvarGetUbGlobal(nonlinvar)));
1261       if( exponent == 2.0 )
1262       {
1263          if( offset != 0.0 )
1264          {
1265             (void) SCIPsnprintf(buffer, GMS_MAX_PRINTLEN, "-sqr(%g ", -offset);
1266             appendLine(scip, file, linebuffer, &linecnt, buffer);
1267             SCIP_CALL( printActiveVariables(scip, file, linebuffer, &linecnt, "-", ")", 1, &nonlinvar, NULL, transformed) );
1268          }
1269          else
1270          {
1271             SCIP_CALL( printActiveVariables(scip, file, linebuffer, &linecnt, "-sqr(-", ")", 1, &nonlinvar, NULL, transformed) );
1272          }
1273       }
1274       else
1275       {
1276          if( offset != 0.0 )
1277          {
1278             (void) SCIPsnprintf(buffer, GMS_MAX_PRINTLEN, "-power(%g ", -offset);
1279             appendLine(scip, file, linebuffer, &linecnt, buffer);
1280             SCIP_CALL( printActiveVariables(scip, file, linebuffer, &linecnt, "-", ",", 1, &nonlinvar, NULL, transformed) );
1281             (void) SCIPsnprintf(buffer, GMS_MAX_PRINTLEN, "%g)", exponent);
1282             appendLine(scip, file, linebuffer, &linecnt, buffer);
1283          }
1284          else
1285          {
1286             SCIP_CALL( printActiveVariables(scip, file, linebuffer, &linecnt, "-power(-", ",", 1, &nonlinvar, NULL, transformed) );
1287             (void) SCIPsnprintf(buffer, GMS_MAX_PRINTLEN, "%g)", exponent);
1288             appendLine(scip, file, linebuffer, &linecnt, buffer);
1289          }
1290       }
1291    }
1292 
1293    /* print linear term */
1294    if( linvar != NULL )
1295    {
1296       SCIP_CALL( printActiveVariables(scip, file, linebuffer, &linecnt, " +", "", 1, &linvar, &coeflinear, transformed) );
1297    }
1298 
1299    /* print right hand side */
1300    if( linecnt == 0 )
1301    {
1302       /* we start a new line; therefore we tab this line */
1303       appendLine(scip, file, linebuffer, &linecnt, "     ");
1304    }
1305 
1306    if( SCIPisZero(scip, rhs) )
1307       rhs = 0.0;
1308 
1309    (void) SCIPsnprintf(buffer, GMS_MAX_PRINTLEN, "%s %.15g;", type, rhs);
1310 
1311    appendLine(scip, file, linebuffer, &linecnt, buffer);
1312 
1313    endLine(scip, file, linebuffer, &linecnt);
1314 
1315    return SCIP_OKAY;
1316 }
1317 
1318 /* print signpower cons in GAMS format to file stream (performing retransformation to active variables)
1319  */
1320 static
printSignpowerCons(SCIP * scip,FILE * file,const char * rowname,SCIP_VAR * nonlinvar,SCIP_VAR * linvar,SCIP_Real exponent,SCIP_Real offset,SCIP_Real coeflinear,SCIP_Real lhs,SCIP_Real rhs,SCIP_Bool transformed,SCIP_Bool signpowerallowed,SCIP_Bool * nsmooth)1321 SCIP_RETCODE printSignpowerCons(
1322    SCIP*                 scip,               /**< SCIP data structure */
1323    FILE*                 file,               /**< output file (or NULL for standard output) */
1324    const char*           rowname,            /**< row name */
1325    SCIP_VAR*             nonlinvar,          /**< nonlinear variable */
1326    SCIP_VAR*             linvar,             /**< linear variable, may be NULL */
1327    SCIP_Real             exponent,           /**< exponent of nonlinear variable */
1328    SCIP_Real             offset,             /**< offset of nonlinear variable */
1329    SCIP_Real             coeflinear,         /**< coefficient of linear variable */
1330    SCIP_Real             lhs,                /**< left hand side */
1331    SCIP_Real             rhs,                /**< right hand side */
1332    SCIP_Bool             transformed,        /**< transformed constraint? */
1333    SCIP_Bool             signpowerallowed,   /**< allowed to use signpower operator in GAMS? */
1334    SCIP_Bool*            nsmooth             /**< buffer to store whether we printed a nonsmooth function */
1335    )
1336 {
1337    assert( scip != NULL );
1338    assert( strlen(rowname) > 0 );
1339 
1340    /* print row(s) in GAMS format */
1341    if( SCIPisEQ(scip, lhs, rhs) )
1342    {
1343       assert( !SCIPisInfinity(scip, rhs) );
1344 
1345       /* print equality constraint */
1346       SCIP_CALL( printSignpowerRow(scip, file, rowname, "", "=e=",
1347          nonlinvar, linvar, exponent, offset, coeflinear, rhs, transformed, signpowerallowed, nsmooth) );
1348    }
1349    else
1350    {
1351       if( !SCIPisInfinity(scip, -lhs) )
1352       {
1353          /* print inequality ">=" */
1354          SCIP_CALL( printSignpowerRow(scip, file, rowname, SCIPisInfinity(scip, rhs) ? "" : "_lhs", "=g=",
1355             nonlinvar, linvar, exponent, offset, coeflinear, lhs, transformed, signpowerallowed, nsmooth) );
1356       }
1357       if( !SCIPisInfinity(scip, rhs) )
1358       {
1359          /* print inequality "<=" */
1360          SCIP_CALL( printSignpowerRow(scip, file, rowname, SCIPisInfinity(scip, -lhs) ? "" : "_rhs", "=l=",
1361             nonlinvar, linvar, exponent, offset, coeflinear, rhs, transformed, signpowerallowed, nsmooth) );
1362       }
1363    }
1364 
1365    return SCIP_OKAY;
1366 }
1367 
1368 /* prints expression in GAMS format to file stream */
1369 static
printExpr(SCIP * scip,FILE * file,char * linebuffer,int * linecnt,SCIP_Bool * nsmooth,SCIP_Bool transformed,SCIP_EXPR * expr,SCIP_VAR ** exprvars)1370 SCIP_RETCODE printExpr(
1371    SCIP*                 scip,               /**< SCIP data structure */
1372    FILE*                 file,               /**< output file (or NULL for standard output) */
1373    char*                 linebuffer,         /**< line buffer of length GMS_MAX_PRINTLEN */
1374    int*                  linecnt,            /**< number of characters in line so far */
1375    SCIP_Bool*            nsmooth,            /**< buffer to store whether we printed a nonsmooth function */
1376    SCIP_Bool             transformed,        /**< expression belongs to transformed constraint? */
1377    SCIP_EXPR*            expr,               /**< expression to print */
1378    SCIP_VAR**            exprvars            /**< variables of expression */
1379    )
1380 {
1381    char buffer[GMS_MAX_PRINTLEN];
1382 
1383    assert(scip != NULL);
1384    assert(linebuffer != NULL);
1385    assert(linecnt != NULL);
1386    assert(expr != NULL);
1387    assert(nsmooth != NULL);
1388 
1389    switch( SCIPexprGetOperator(expr) )
1390    {
1391       case SCIP_EXPR_VARIDX:
1392       {
1393          SCIP_Real one;
1394 
1395          assert(exprvars != NULL);
1396 
1397          one = 1.0;
1398          SCIP_CALL( printActiveVariables(scip, file, linebuffer, linecnt, "",  "",  1, &exprvars[SCIPexprGetOpIndex(expr)], &one, transformed) );
1399 
1400          break;
1401       }
1402 
1403       case SCIP_EXPR_PARAM:
1404       {
1405          SCIPwarningMessage(scip, "parameterized expression in GAMS writer. GAMS file will not compile.\n");
1406 
1407          (void) SCIPsnprintf(buffer, GMS_MAX_PRINTLEN, "param%d", SCIPexprGetOpIndex(expr));
1408          appendLineWithIndent(scip, file, linebuffer, linecnt, buffer);
1409 
1410          break;
1411       }
1412 
1413       case SCIP_EXPR_CONST:
1414       {
1415          if( SCIPexprGetOpReal(expr) < 0.0 )
1416             (void) SCIPsnprintf(buffer, GMS_MAX_PRINTLEN, "(%.15g)", SCIPexprGetOpReal(expr));
1417          else
1418             (void) SCIPsnprintf(buffer, GMS_MAX_PRINTLEN, "%.15g", SCIPexprGetOpReal(expr));
1419          appendLineWithIndent(scip, file, linebuffer, linecnt, buffer);
1420 
1421          break;
1422       }
1423 
1424       case SCIP_EXPR_PLUS:
1425       {
1426          appendLineWithIndent(scip, file, linebuffer, linecnt, "(");
1427          SCIP_CALL( printExpr(scip, file, linebuffer, linecnt, nsmooth, transformed, SCIPexprGetChildren(expr)[0], exprvars) );
1428          appendLineWithIndent(scip, file, linebuffer, linecnt, " + ");
1429          SCIP_CALL( printExpr(scip, file, linebuffer, linecnt, nsmooth, transformed, SCIPexprGetChildren(expr)[1], exprvars) );
1430          appendLineWithIndent(scip, file, linebuffer, linecnt, ")");
1431          break;
1432       }
1433 
1434       case SCIP_EXPR_MINUS:
1435       {
1436          appendLineWithIndent(scip, file, linebuffer, linecnt, "(");
1437          SCIP_CALL( printExpr(scip, file, linebuffer, linecnt, nsmooth, transformed, SCIPexprGetChildren(expr)[0], exprvars) );
1438          appendLineWithIndent(scip, file, linebuffer, linecnt, " - ");
1439          SCIP_CALL( printExpr(scip, file, linebuffer, linecnt, nsmooth, transformed, SCIPexprGetChildren(expr)[1], exprvars) );
1440          appendLineWithIndent(scip, file, linebuffer, linecnt, ")");
1441          break;
1442       }
1443 
1444       case SCIP_EXPR_MUL:
1445       {
1446          appendLineWithIndent(scip, file, linebuffer, linecnt, "(");
1447          SCIP_CALL( printExpr(scip, file, linebuffer, linecnt, nsmooth, transformed, SCIPexprGetChildren(expr)[0], exprvars) );
1448          appendLineWithIndent(scip, file, linebuffer, linecnt, " * ");
1449          SCIP_CALL( printExpr(scip, file, linebuffer, linecnt, nsmooth, transformed, SCIPexprGetChildren(expr)[1], exprvars) );
1450          appendLineWithIndent(scip, file, linebuffer, linecnt, ")");
1451          break;
1452       }
1453 
1454       case SCIP_EXPR_DIV:
1455       {
1456          appendLineWithIndent(scip, file, linebuffer, linecnt, "(");
1457          SCIP_CALL( printExpr(scip, file, linebuffer, linecnt, nsmooth, transformed, SCIPexprGetChildren(expr)[0], exprvars) );
1458          appendLineWithIndent(scip, file, linebuffer, linecnt, " / ");
1459          SCIP_CALL( printExpr(scip, file, linebuffer, linecnt, nsmooth, transformed, SCIPexprGetChildren(expr)[1], exprvars) );
1460          appendLineWithIndent(scip, file, linebuffer, linecnt, ")");
1461          break;
1462       }
1463 
1464       case SCIP_EXPR_REALPOWER:
1465       {
1466          appendLineWithIndent(scip, file, linebuffer, linecnt, "(");
1467          SCIP_CALL( printExpr(scip, file, linebuffer, linecnt, nsmooth, transformed, SCIPexprGetChildren(expr)[0], exprvars) );
1468          (void) SCIPsnprintf(buffer, GMS_MAX_PRINTLEN, ")**(%.15g)", SCIPexprGetRealPowerExponent(expr));
1469          appendLineWithIndent(scip, file, linebuffer, linecnt, buffer);
1470          break;
1471       }
1472 
1473       case SCIP_EXPR_INTPOWER:
1474       {
1475          appendLineWithIndent(scip, file, linebuffer, linecnt, "power(");
1476          SCIP_CALL( printExpr(scip, file, linebuffer, linecnt, nsmooth, transformed, SCIPexprGetChildren(expr)[0], exprvars) );
1477          (void) SCIPsnprintf(buffer, GMS_MAX_PRINTLEN, ", %d)", SCIPexprGetIntPowerExponent(expr));
1478          appendLineWithIndent(scip, file, linebuffer, linecnt, buffer);
1479          break;
1480       }
1481 
1482       case SCIP_EXPR_SIGNPOWER:
1483       {
1484          SCIP_Real exponent;
1485          SCIP_Bool nisoddint;
1486 
1487          /* signpow(x,y) is printed as x*abs(x) if y == 2, x*(abs(x) ** (y-1)) if y is not 2 and not an odd integer, and as intpower(x,y) if y is an odd integer
1488           * but if reading/gmsreader/signpower is TRUE, then we print as signpower(x,y), unless y is odd integer
1489           */
1490          exponent = SCIPexprGetSignPowerExponent(expr);
1491          nisoddint = (((SCIP_Real)((int)exponent)) == exponent) && (((int)exponent)%2 == 1); /*lint !e777*/
1492 
1493          if( !nisoddint )
1494          {
1495             SCIP_Bool signpowerallowed;
1496 
1497             SCIP_CALL( SCIPgetBoolParam(scip, "reading/gmsreader/signpower", &signpowerallowed) );
1498 
1499             if( signpowerallowed )
1500             {
1501                appendLineWithIndent(scip, file, linebuffer, linecnt, " * signpower(");
1502                SCIP_CALL( printExpr(scip, file, linebuffer, linecnt, nsmooth, transformed, SCIPexprGetChildren(expr)[0], exprvars) );
1503                (void) SCIPsnprintf(buffer, GMS_MAX_PRINTLEN, ", %.15g)", exponent);
1504                appendLineWithIndent(scip, file, linebuffer, linecnt, buffer);
1505             }
1506             else
1507             {
1508                appendLineWithIndent(scip, file, linebuffer, linecnt, "(");
1509                SCIP_CALL( printExpr(scip, file, linebuffer, linecnt, nsmooth, transformed, SCIPexprGetChildren(expr)[0], exprvars) );
1510                appendLineWithIndent(scip, file, linebuffer, linecnt, ")");
1511 
1512                if( exponent == 2.0)
1513                {
1514                   appendLineWithIndent(scip, file, linebuffer, linecnt, " * abs(");
1515                   SCIP_CALL( printExpr(scip, file, linebuffer, linecnt, nsmooth, transformed, SCIPexprGetChildren(expr)[0], exprvars) );
1516                   appendLineWithIndent(scip, file, linebuffer, linecnt, ")");
1517                }
1518                else
1519                {
1520                   appendLineWithIndent(scip, file, linebuffer, linecnt, " * abs(");
1521                   SCIP_CALL( printExpr(scip, file, linebuffer, linecnt, nsmooth, transformed, SCIPexprGetChildren(expr)[0], exprvars) );
1522                   (void) SCIPsnprintf(buffer, GMS_MAX_PRINTLEN, ")**(%g)", SCIPexprGetRealPowerExponent(expr)-1.0);
1523                   appendLineWithIndent(scip, file, linebuffer, linecnt, buffer);
1524                }
1525             }
1526             *nsmooth = TRUE;
1527          }
1528          else
1529          {
1530             appendLineWithIndent(scip, file, linebuffer, linecnt, " * power(");
1531             SCIP_CALL( printExpr(scip, file, linebuffer, linecnt, nsmooth, transformed, SCIPexprGetChildren(expr)[0], exprvars) );
1532             (void) SCIPsnprintf(buffer, GMS_MAX_PRINTLEN, ", %.15g)", exponent);
1533             appendLineWithIndent(scip, file, linebuffer, linecnt, buffer);
1534          }
1535 
1536          break;
1537       }
1538 
1539       case SCIP_EXPR_ABS:
1540       case SCIP_EXPR_SIGN:
1541          *nsmooth = TRUE; /*lint -fallthrough*/
1542       case SCIP_EXPR_SQUARE:
1543       case SCIP_EXPR_SQRT:
1544       case SCIP_EXPR_EXP:
1545       case SCIP_EXPR_LOG:
1546       case SCIP_EXPR_SIN:
1547       case SCIP_EXPR_COS:
1548       case SCIP_EXPR_TAN:
1549       /* case SCIP_EXPR_ERF: */
1550       /* case SCIP_EXPR_ERFI: */
1551       case SCIP_EXPR_MIN:
1552       case SCIP_EXPR_MAX:
1553       {
1554          int i;
1555 
1556          (void) SCIPsnprintf(buffer, GMS_MAX_PRINTLEN, "%s(", SCIPexpropGetName(SCIPexprGetOperator(expr)));
1557          appendLineWithIndent(scip, file, linebuffer, linecnt, buffer);
1558 
1559          for( i = 0; i < SCIPexprGetNChildren(expr); ++i )
1560          {
1561             SCIP_CALL( printExpr(scip, file, linebuffer, linecnt, nsmooth, transformed, SCIPexprGetChildren(expr)[i], exprvars) );
1562             if( i + 1 < SCIPexprGetNChildren(expr) )
1563                appendLineWithIndent(scip, file, linebuffer, linecnt, ", ");
1564          }
1565 
1566          appendLineWithIndent(scip, file, linebuffer, linecnt, ")");
1567          break;
1568       }
1569 
1570       case SCIP_EXPR_SUM:
1571       case SCIP_EXPR_PRODUCT:
1572       {
1573          switch( SCIPexprGetNChildren(expr) )
1574          {
1575             case 0:
1576             {
1577                appendLineWithIndent(scip, file, linebuffer, linecnt, SCIPexprGetOperator(expr) == SCIP_EXPR_SUM ? "0" : "1");
1578                break;
1579             }
1580             case 1:
1581             {
1582                SCIP_CALL( printExpr(scip, file, linebuffer, linecnt, nsmooth, transformed, SCIPexprGetChildren(expr)[0], exprvars) );
1583                break;
1584             }
1585             default:
1586             {
1587                int i;
1588                char opstr[GMS_MAX_PRINTLEN];
1589 
1590                (void) SCIPsnprintf(opstr, GMS_MAX_PRINTLEN, SCIPexprGetOperator(expr) == SCIP_EXPR_SUM ? " + " : " * ");
1591                appendLineWithIndent(scip, file, linebuffer, linecnt, "(");
1592                for( i = 0; i < SCIPexprGetNChildren(expr); ++i )
1593                {
1594                   if( i > 0 )
1595                   {
1596                      appendLineWithIndent(scip, file, linebuffer, linecnt, opstr);
1597                   }
1598                   SCIP_CALL( printExpr(scip, file, linebuffer, linecnt, nsmooth, transformed, SCIPexprGetChildren(expr)[i], exprvars) );
1599                }
1600                appendLineWithIndent(scip, file, linebuffer, linecnt, ")");
1601             }
1602          }
1603          break;
1604       }
1605 
1606       case SCIP_EXPR_LINEAR:
1607       {
1608          SCIP_Real constant;
1609          int i;
1610 
1611          constant = SCIPexprGetLinearConstant(expr);
1612 
1613          if( SCIPexprGetNChildren(expr) == 0 )
1614          {
1615             (void) SCIPsnprintf(buffer, GMS_MAX_PRINTLEN, "%.15g", constant);
1616             appendLineWithIndent(scip, file, linebuffer, linecnt, buffer);
1617             break;
1618          }
1619 
1620          appendLineWithIndent(scip, file, linebuffer, linecnt, "(");
1621 
1622          if( constant != 0.0 )
1623          {
1624             (void) SCIPsnprintf(buffer, GMS_MAX_PRINTLEN, "%.15g", constant);
1625             appendLineWithIndent(scip, file, linebuffer, linecnt, buffer);
1626          }
1627 
1628          for( i = 0; i < SCIPexprGetNChildren(expr); ++i )
1629          {
1630             (void) SCIPsnprintf(buffer, GMS_MAX_PRINTLEN, " %+.15g * ", SCIPexprGetLinearCoefs(expr)[i]);
1631             appendLineWithIndent(scip, file, linebuffer, linecnt, buffer);
1632             SCIP_CALL( printExpr(scip, file, linebuffer, linecnt, nsmooth, transformed, SCIPexprGetChildren(expr)[i], exprvars) );
1633          }
1634 
1635          appendLineWithIndent(scip, file, linebuffer, linecnt, ")");
1636          break;
1637       }
1638 
1639       case SCIP_EXPR_QUADRATIC:
1640       {
1641          SCIP_Real constant;
1642          int i;
1643          SCIP_QUADELEM* quadelems;
1644          SCIP_Real* lincoefs;
1645 
1646          constant = SCIPexprGetQuadConstant(expr);
1647 
1648          if( SCIPexprGetNChildren(expr) == 0 )
1649          {
1650             (void) SCIPsnprintf(buffer, GMS_MAX_PRINTLEN, "%.15g", constant);
1651             appendLineWithIndent(scip, file, linebuffer, linecnt, buffer);
1652             break;
1653          }
1654 
1655          appendLineWithIndent(scip, file, linebuffer, linecnt, "(");
1656 
1657          if( constant != 0.0 )
1658          {
1659             (void) SCIPsnprintf(buffer, GMS_MAX_PRINTLEN, "%.15g", constant);
1660             appendLineWithIndent(scip, file, linebuffer, linecnt, buffer);
1661          }
1662 
1663          lincoefs = SCIPexprGetQuadLinearCoefs(expr);
1664          if( lincoefs != NULL )
1665             for( i = 0; i < SCIPexprGetNChildren(expr); ++i )
1666             {
1667                (void) SCIPsnprintf(buffer, GMS_MAX_PRINTLEN, " %+.15g * ", lincoefs[i]);
1668                appendLineWithIndent(scip, file, linebuffer, linecnt, buffer);
1669                SCIP_CALL( printExpr(scip, file, linebuffer, linecnt, nsmooth, transformed, SCIPexprGetChildren(expr)[i], exprvars) );
1670             }
1671 
1672          quadelems = SCIPexprGetQuadElements(expr);
1673          for( i = 0; i < SCIPexprGetNQuadElements(expr); ++i )
1674          {
1675             (void) SCIPsnprintf(buffer, GMS_MAX_PRINTLEN, " %+.15g * ", quadelems[i].coef);
1676             appendLineWithIndent(scip, file, linebuffer, linecnt, buffer);
1677 
1678             if( quadelems[i].idx1 == quadelems[i].idx2 )
1679             {
1680                appendLineWithIndent(scip, file, linebuffer, linecnt, "sqr(");
1681                SCIP_CALL( printExpr(scip, file, linebuffer, linecnt, nsmooth, transformed, SCIPexprGetChildren(expr)[quadelems[i].idx1], exprvars) );
1682                appendLineWithIndent(scip, file, linebuffer, linecnt, ")");
1683             }
1684             else
1685             {
1686                SCIP_CALL( printExpr(scip, file, linebuffer, linecnt, nsmooth, transformed, SCIPexprGetChildren(expr)[quadelems[i].idx1], exprvars) );
1687                appendLineWithIndent(scip, file, linebuffer, linecnt, " * ");
1688                SCIP_CALL( printExpr(scip, file, linebuffer, linecnt, nsmooth, transformed, SCIPexprGetChildren(expr)[quadelems[i].idx2], exprvars) );
1689             }
1690          }
1691 
1692          appendLineWithIndent(scip, file, linebuffer, linecnt, ")");
1693          break;
1694       }
1695 
1696       case SCIP_EXPR_POLYNOMIAL:
1697       {
1698          SCIP_EXPRDATA_MONOMIAL* monomdata;
1699          SCIP_Real exponent;
1700          int i;
1701          int j;
1702 
1703          appendLineWithIndent(scip, file, linebuffer, linecnt, "(");
1704 
1705          if( SCIPexprGetPolynomialConstant(expr) != 0.0 || SCIPexprGetNMonomials(expr) == 0 )
1706          {
1707             (void) SCIPsnprintf(buffer, GMS_MAX_PRINTLEN, "%.15g", SCIPexprGetPolynomialConstant(expr));
1708             appendLineWithIndent(scip, file, linebuffer, linecnt, buffer);
1709          }
1710 
1711          for( i = 0; i < SCIPexprGetNMonomials(expr); ++i )
1712          {
1713             monomdata = SCIPexprGetMonomials(expr)[i];
1714             assert(monomdata != NULL);
1715 
1716             (void) SCIPsnprintf(buffer, GMS_MAX_PRINTLEN, " %+.15g", SCIPexprGetMonomialCoef(monomdata));
1717             appendLineWithIndent(scip, file, linebuffer, linecnt, buffer);
1718 
1719             for( j = 0; j < SCIPexprGetMonomialNFactors(monomdata); ++j )
1720             {
1721                appendLineWithIndent(scip, file, linebuffer, linecnt, "*");
1722 
1723                exponent = SCIPexprGetMonomialExponents(monomdata)[j];
1724                if( exponent == 1.0 )
1725                {
1726                   SCIP_CALL( printExpr(scip, file, linebuffer, linecnt, nsmooth, transformed, SCIPexprGetChildren(expr)[SCIPexprGetMonomialChildIndices(monomdata)[j]], exprvars) );
1727                }
1728                else if( exponent == 2.0 )
1729                {
1730                   appendLineWithIndent(scip, file, linebuffer, linecnt, "sqr(");
1731                   SCIP_CALL( printExpr(scip, file, linebuffer, linecnt, nsmooth, transformed, SCIPexprGetChildren(expr)[SCIPexprGetMonomialChildIndices(monomdata)[j]], exprvars) );
1732                   appendLineWithIndent(scip, file, linebuffer, linecnt, ")");
1733                }
1734                else if( exponent == 0.5 )
1735                {
1736                   appendLineWithIndent(scip, file, linebuffer, linecnt, "sqrt(");
1737                   SCIP_CALL( printExpr(scip, file, linebuffer, linecnt, nsmooth, transformed, SCIPexprGetChildren(expr)[SCIPexprGetMonomialChildIndices(monomdata)[j]], exprvars) );
1738                   appendLineWithIndent(scip, file, linebuffer, linecnt, ")");
1739                }
1740                else if( ((SCIP_Real)((int)exponent)) == exponent ) /*lint !e777*/
1741                {
1742                   appendLineWithIndent(scip, file, linebuffer, linecnt, "power(");
1743                   SCIP_CALL( printExpr(scip, file, linebuffer, linecnt, nsmooth, transformed, SCIPexprGetChildren(expr)[SCIPexprGetMonomialChildIndices(monomdata)[j]], exprvars) );
1744                   (void) SCIPsnprintf(buffer, GMS_MAX_PRINTLEN, ", %d)", (int)SCIPround(scip, exponent));
1745                   appendLineWithIndent(scip, file, linebuffer, linecnt, buffer);
1746                }
1747                else
1748                {
1749                   SCIP_CALL( printExpr(scip, file, linebuffer, linecnt, nsmooth, transformed, SCIPexprGetChildren(expr)[SCIPexprGetMonomialChildIndices(monomdata)[j]], exprvars) );
1750                   (void) SCIPsnprintf(buffer, GMS_MAX_PRINTLEN, " ** %.15g", exponent);
1751                   appendLineWithIndent(scip, file, linebuffer, linecnt, buffer);
1752                }
1753             }
1754          }
1755 
1756          appendLineWithIndent(scip, file, linebuffer, linecnt, ")");
1757          break;
1758       }
1759 
1760       default:
1761          SCIPerrorMessage("unexpected operand %d in expression\n", SCIPexprGetOperator(expr));
1762          return SCIP_OKAY;
1763    } /*lint !e788*/
1764 
1765    return SCIP_OKAY;
1766 }
1767 
1768 /* print nonlinear row in GAMS format to file stream */
1769 static
printNonlinearRow(SCIP * scip,FILE * file,const char * rowname,const char * rownameextension,const char * type,int nlinvars,SCIP_VAR ** linvars,SCIP_Real * lincoeffs,int nexprtrees,SCIP_EXPRTREE ** exprtrees,SCIP_Real * exprtreecoefs,SCIP_Real rhs,SCIP_Bool transformed,SCIP_Bool * nsmooth)1770 SCIP_RETCODE printNonlinearRow(
1771    SCIP*                 scip,               /**< SCIP data structure */
1772    FILE*                 file,               /**< output file (or NULL for standard output) */
1773    const char*           rowname,            /**< row name */
1774    const char*           rownameextension,   /**< row name extension */
1775    const char*           type,               /**< row type ("=e=", "=l=", or "=g=") */
1776    int                   nlinvars,           /**< number of linear terms */
1777    SCIP_VAR**            linvars,            /**< variables in linear part */
1778    SCIP_Real*            lincoeffs,          /**< coefficients of variables in linear part */
1779    int                   nexprtrees,         /**< number of expression trees */
1780    SCIP_EXPRTREE**       exprtrees,          /**< expression trees */
1781    SCIP_Real*            exprtreecoefs,      /**< expression tree coefficients */
1782    SCIP_Real             rhs,                /**< right hand side */
1783    SCIP_Bool             transformed,        /**< transformed constraint? */
1784    SCIP_Bool*            nsmooth             /**< buffer to store whether we printed a nonsmooth function */
1785    )
1786 {
1787    char linebuffer[GMS_MAX_PRINTLEN+1] = { '\0' };
1788    int linecnt;
1789 
1790    char consname[GMS_MAX_NAMELEN + 3]; /* four extra characters for ' ..' */
1791    char buffer[GMS_MAX_PRINTLEN];
1792 
1793    int i;
1794 
1795    assert( scip != NULL );
1796    assert( strlen(rowname) > 0 || strlen(rownameextension) > 0 );
1797    assert( strcmp(type, "=e=") == 0 || strcmp(type, "=l=") == 0 || strcmp(type, "=g=") == 0 );
1798 
1799    clearLine(linebuffer, &linecnt);
1800 
1801    /* start each line with a space */
1802    appendLine(scip, file, linebuffer, &linecnt, " ");
1803 
1804    /* print row name */
1805    (void) SCIPsnprintf(buffer, GMS_MAX_NAMELEN + 3, "%s%s ..", rowname, rownameextension);
1806    SCIP_CALL( printConformName(scip, consname, GMS_MAX_NAMELEN + 3, buffer) );
1807 
1808    appendLine(scip, file, linebuffer, &linecnt, consname);
1809 
1810    /* print nonlinear terms
1811     */
1812    for( i = 0; i < nexprtrees; ++i )
1813    {
1814       assert(exprtrees[i] != NULL);
1815       if( exprtreecoefs[i] != 0.0 )
1816       {
1817          (void) SCIPsnprintf(buffer, GMS_MAX_NAMELEN + 3, "%+g * (", exprtreecoefs[i]);
1818          appendLineWithIndent(scip, file, linebuffer, &linecnt, buffer);
1819          SCIP_CALL( printExpr(scip, file, linebuffer, &linecnt, nsmooth, transformed, SCIPexprtreeGetRoot(exprtrees[i]), SCIPexprtreeGetVars(exprtrees[i])) );
1820          appendLineWithIndent(scip, file, linebuffer, &linecnt, ")");
1821       }
1822    }
1823 
1824    /* print linear terms, do after nonlinear since nonlinear may not print sign in beginning */
1825    if( nlinvars > 0 )
1826    {
1827       SCIP_CALL( printActiveVariables(scip, file, linebuffer, &linecnt, "+", " ", nlinvars, linvars, lincoeffs, transformed) );
1828    }
1829 
1830    /* print right hand side */
1831    if( linecnt == 0 )
1832       /* we start a new line; therefore we tab this line */
1833       appendLine(scip, file, linebuffer, &linecnt, "     ");
1834 
1835    if( SCIPisZero(scip, rhs) )
1836       rhs = 0.0;
1837 
1838    (void) SCIPsnprintf(buffer, GMS_MAX_PRINTLEN, "%s %.15g;", type, rhs);
1839 
1840    appendLine(scip, file, linebuffer, &linecnt, buffer);
1841 
1842    endLine(scip, file, linebuffer, &linecnt);
1843 
1844    return SCIP_OKAY;
1845 }
1846 
1847 /* print nonlinear row in GAMS format to file stream (performing retransformation to active linear variables)
1848  * */
1849 static
printNonlinearCons(SCIP * scip,FILE * file,const char * rowname,int nlinvars,SCIP_VAR ** linvars,SCIP_Real * lincoeffs,int nexprtrees,SCIP_EXPRTREE ** exprtrees,SCIP_Real * exprtreecoefs,SCIP_Real lhs,SCIP_Real rhs,SCIP_Bool transformed,SCIP_Bool * nsmooth)1850 SCIP_RETCODE printNonlinearCons(
1851    SCIP*                 scip,               /**< SCIP data structure */
1852    FILE*                 file,               /**< output file (or NULL for standard output) */
1853    const char*           rowname,            /**< row name */
1854    int                   nlinvars,           /**< number of linear terms */
1855    SCIP_VAR**            linvars,            /**< variables in linear part */
1856    SCIP_Real*            lincoeffs,          /**< coefficients of variables in linear part */
1857    int                   nexprtrees,         /**< number of expression trees */
1858    SCIP_EXPRTREE**       exprtrees,          /**< expression trees */
1859    SCIP_Real*            exprtreecoefs,      /**< expression tree coefficients */
1860    SCIP_Real             lhs,                /**< left hand side */
1861    SCIP_Real             rhs,                /**< right hand side */
1862    SCIP_Bool             transformed,        /**< transformed constraint? */
1863    SCIP_Bool*            nsmooth             /**< buffer to store whether we printed a nonsmooth function */
1864    )
1865 {
1866    assert( scip != NULL );
1867    assert( strlen(rowname) > 0 );
1868 
1869    /* print row(s) in GAMS format */
1870    if( SCIPisEQ(scip, lhs, rhs) )
1871    {
1872       assert( !SCIPisInfinity(scip, rhs) );
1873 
1874       /* print equality constraint */
1875       SCIP_CALL( printNonlinearRow(scip, file, rowname, "", "=e=",
1876          nlinvars, linvars, lincoeffs, nexprtrees, exprtrees, exprtreecoefs, rhs, transformed, nsmooth) );
1877    }
1878    else
1879    {
1880       if( !SCIPisInfinity(scip, -lhs) )
1881       {
1882          /* print inequality ">=" */
1883          SCIP_CALL( printNonlinearRow(scip, file, rowname, SCIPisInfinity(scip, rhs) ? "" : "_lhs", "=g=",
1884             nlinvars, linvars, lincoeffs, nexprtrees, exprtrees, exprtreecoefs, lhs, transformed, nsmooth) );
1885       }
1886       if( !SCIPisInfinity(scip, rhs) )
1887       {
1888          /* print inequality "<=" */
1889          SCIP_CALL( printNonlinearRow(scip, file, rowname, SCIPisInfinity(scip, -lhs) ? "" : "_rhs", "=l=",
1890             nlinvars, linvars, lincoeffs, nexprtrees, exprtrees, exprtreecoefs, rhs, transformed, nsmooth) );
1891       }
1892    }
1893 
1894    return SCIP_OKAY;
1895 }
1896 
1897 /** method check if the variable names are not longer than GMS_MAX_NAMELEN */
1898 static
checkVarnames(SCIP * scip,SCIP_VAR ** vars,int nvars)1899 SCIP_RETCODE checkVarnames(
1900    SCIP*                 scip,               /**< SCIP data structure */
1901    SCIP_VAR**            vars,               /**< array of variables */
1902    int                   nvars               /**< number of variables */
1903    )
1904 {
1905    int v;
1906    SCIP_VAR* var;
1907    SCIP_Bool replaceforbiddenchars;
1908    const char* badchar;
1909 
1910    assert( scip != NULL );
1911    assert( vars != NULL );
1912 
1913    SCIP_CALL( SCIPgetBoolParam(scip, "reading/gmsreader/replaceforbiddenchars", &replaceforbiddenchars) );
1914 
1915    /* check if the variable names contain any of the bad symbols */
1916    for( badchar = badchars; *badchar; ++badchar )
1917    {
1918       for( v = 0; v < nvars; ++v )
1919       {
1920          var = vars[v];
1921          assert( var != NULL );
1922 
1923          if( strchr(SCIPvarGetName(var), *badchar) != NULL )
1924          {
1925             if( replaceforbiddenchars )
1926             {
1927                SCIPinfoMessage(scip, NULL, "there is a variable name with symbol '%c', not allowed in GAMS format; all '%c' replaced by '_' (consider using 'write genproblem'/'write gentransproblem').\n", *badchar, *badchar);
1928             }
1929             else
1930             {
1931                SCIPwarningMessage(scip, "there is a variable name with symbol '%c', not allowed in GAMS format; use 'write genproblem'/'write gentransproblem', or set 'reading/gmsreader/replaceforbiddenchars' to TRUE and risk duplicate variable names.\n", *badchar);
1932             }
1933 
1934             break;
1935          }
1936       }
1937    }
1938 
1939    /* check if the variable names are too long */
1940    for( v = 0; v < nvars; ++v )
1941    {
1942       var = vars[v];
1943       assert( var != NULL );
1944 
1945       if( strlen(SCIPvarGetName(var)) > GMS_MAX_NAMELEN )
1946       {
1947          SCIPwarningMessage(scip, "there is a variable name which has to be cut down to %d characters; GAMS model might be corrupted.\n",
1948             GMS_MAX_NAMELEN - 1);
1949          break;
1950       }
1951    }
1952 
1953    return SCIP_OKAY;
1954 }
1955 
1956 /** method check if the constraint names are not longer than GMS_MAX_NAMELEN */
1957 static
checkConsnames(SCIP * scip,SCIP_CONS ** conss,int nconss,SCIP_Bool transformed)1958 SCIP_RETCODE checkConsnames(
1959    SCIP*                 scip,               /**< SCIP data structure */
1960    SCIP_CONS**           conss,              /**< array of constraints */
1961    int                   nconss,             /**< number of constraints */
1962    SCIP_Bool             transformed         /**< TRUE iff problem is the transformed problem */
1963    )
1964 {
1965    int c;
1966    SCIP_CONS* cons;
1967    SCIP_CONSHDLR* conshdlr;
1968    const char* conshdlrname;
1969    SCIP_Bool replaceforbiddenchars;
1970    const char* badchar;
1971 
1972    assert( scip != NULL );
1973    assert( conss != NULL );
1974 
1975    SCIP_CALL( SCIPgetBoolParam(scip, "reading/gmsreader/replaceforbiddenchars", &replaceforbiddenchars) );
1976 
1977    /* check if the constraint names contain any of the bad symbols */
1978    for( badchar = badchars; *badchar; ++badchar )
1979    {
1980       for( c = 0; c < nconss; ++c )
1981       {
1982          cons = conss[c];
1983          assert( cons != NULL );
1984 
1985          if( strchr(SCIPconsGetName(cons), *badchar) != NULL )
1986          {
1987             if( replaceforbiddenchars )
1988             {
1989                SCIPinfoMessage(scip, NULL, "there is a constraint name with symbol '%c', not allowed in GAMS format; all '%c' replaced by '_' (consider using 'write genproblem'/'write gentransproblem').\n", *badchar, *badchar);
1990             }
1991             else
1992             {
1993                SCIPwarningMessage(scip, "there is a constraint name with symbol '%c', not allowed in GAMS format; use 'write genproblem'/'write gentransproblem', or set 'reading/gmsreader/replaceforbiddenchars' to TRUE and risk duplicate variable names.\n", *badchar);
1994             }
1995 
1996             break;
1997          }
1998       }
1999    }
2000 
2001    /* check if the constraint names are too long */
2002    for( c = 0; c < nconss; ++c )
2003    {
2004       cons = conss[c];
2005       assert( cons != NULL );
2006 
2007       /* in case the transformed is written, only constraints are posted which are enabled in the current node */
2008       assert(!transformed || SCIPconsIsEnabled(cons));
2009 
2010       conshdlr = SCIPconsGetHdlr(cons);
2011       assert( conshdlr != NULL );
2012 
2013       conshdlrname = SCIPconshdlrGetName(conshdlr);
2014       assert( transformed == SCIPconsIsTransformed(cons) );
2015 
2016       if( strcmp(conshdlrname, "linear") == 0 || strcmp(conshdlrname, "quadratic") == 0 )
2017       {
2018          SCIP_Real lhs = strcmp(conshdlrname, "linear") == 0 ? SCIPgetLhsLinear(scip, cons) : SCIPgetLhsQuadratic(scip, cons);
2019          SCIP_Real rhs = strcmp(conshdlrname, "linear") == 0 ? SCIPgetLhsLinear(scip, cons) : SCIPgetRhsQuadratic(scip, cons);
2020 
2021          if( SCIPisEQ(scip, lhs, rhs) && strlen(SCIPconsGetName(conss[c])) > GMS_MAX_NAMELEN )
2022          {
2023             SCIPwarningMessage(scip, "there is a constraint name which has to be cut down to %d characters;\n",
2024                GMS_MAX_NAMELEN - 1);
2025             break;
2026          }
2027          else if( !SCIPisEQ(scip, lhs, rhs) && strlen(SCIPconsGetName(conss[c])) > GMS_MAX_NAMELEN - 4 )
2028          {
2029             SCIPwarningMessage(scip, "there is a constraint name which has to be cut down to %d characters;\n",
2030                GMS_MAX_NAMELEN - 5);
2031             break;
2032          }
2033       }
2034       else if( strlen(SCIPconsGetName(conss[c])) > GMS_MAX_NAMELEN )
2035       {
2036          SCIPwarningMessage(scip, "there is a constraint name which has to be cut down to %d characters;\n",
2037             GMS_MAX_NAMELEN - 1);
2038          break;
2039       }
2040    }
2041    return SCIP_OKAY;
2042 }
2043 
2044 
2045 /*
2046  * Callback methods of reader
2047  */
2048 
2049 /** copy method for reader plugins (called when SCIP copies plugins) */
2050 static
SCIP_DECL_READERCOPY(readerCopyGms)2051 SCIP_DECL_READERCOPY(readerCopyGms)
2052 {  /*lint --e{715}*/
2053    assert(scip != NULL);
2054    assert(reader != NULL);
2055    assert(strcmp(SCIPreaderGetName(reader), READER_NAME) == 0);
2056 
2057    /* call inclusion method of reader */
2058    SCIP_CALL( SCIPincludeReaderGms(scip) );
2059 
2060    return SCIP_OKAY;
2061 }
2062 
2063 #ifdef WITH_GAMS
2064 /** problem reading method of reader */
2065 static
SCIP_DECL_READERREAD(readerReadGms)2066 SCIP_DECL_READERREAD(readerReadGms)
2067 {
2068    SCIP_RETCODE ret;
2069    FILE* convertdopt;
2070    char gamscall[SCIP_MAXSTRLEN];
2071    char buffer[GMS_SSSIZE];
2072    int rc;
2073    gmoHandle_t gmo = NULL;
2074    gevHandle_t gev = NULL;
2075 
2076    assert(scip != NULL);
2077    assert(reader != NULL);
2078    assert(filename != NULL);
2079    assert(result != NULL);
2080 
2081    *result = SCIP_DIDNOTRUN;
2082    ret = SCIP_ERROR;
2083 
2084    /* create temporary directory */
2085    mkdir("loadgms.tmp", S_IRWXU);
2086 
2087    /* create empty convertd options file */
2088    convertdopt = fopen("loadgms.tmp/convertd.opt", "w");
2089    if( convertdopt == NULL )
2090    {
2091       SCIPerrorMessage("Could not create convertd options file. Do you have write permissions in execution directory?\n");
2092       goto TERMINATE;
2093    }
2094    fputs(" ", convertdopt);
2095    fclose(convertdopt);
2096 
2097    /* call GAMS with convertd solver to get compiled model instance in temporary directory */
2098    SCIPsnprintf(gamscall, SCIP_MAXSTRLEN, WITH_GAMS "/gams %s LP=CONVERTD RMIP=CONVERTD QCP=CONVERTD RMIQCP=CONVERTD NLP=CONVERTD DNLP=CONVERTD RMINLP=CONVERTD CNS=CONVERTD MIP=CONVERTD MIQCP=CONVERTD MINLP=CONVERTD MCP=CONVERTD MPEC=CONVERTD RMPEC=CONVERTD SCRDIR=loadgms.tmp output=loadgms.tmp/listing optdir=loadgms.tmp optfile=1 pf4=0 solprint=0 limcol=0 limrow=0 pc=2 lo=%d",
2099       filename, SCIPgetVerbLevel(scip) == SCIP_VERBLEVEL_FULL ? 3 : 0);
2100    SCIPdebugMsg(scip, gamscall);
2101    rc = system(gamscall);
2102    if( rc != 0 )
2103    {
2104       SCIPerrorMessage("GAMS call returned with code %d, check loadgms.tmp/listing for details.\n", rc);
2105       /* likely the GAMS model could not be compiled, which we could report as a readerror */
2106       ret = SCIP_READERROR;
2107       goto TERMINATE;
2108    }
2109 
2110    /* initialize GEV library and create GEV */
2111    if( !gevCreateDD(&gev, WITH_GAMS, buffer, sizeof(buffer)) )
2112    {
2113       SCIPerrorMessage(buffer);
2114       goto TERMINATE;
2115    }
2116 
2117    /* initialize GMO library and create GMO */
2118    if( !gmoCreateDD(&gmo, WITH_GAMS, buffer, sizeof(buffer)) )
2119    {
2120       SCIPerrorMessage(buffer);
2121       goto TERMINATE;
2122    }
2123 
2124    /* load control file */
2125    if( gevInitEnvironmentLegacy(gev, "loadgms.tmp/gamscntr.dat") )
2126    {
2127       SCIPerrorMessage("Could not load control file loadgms.tmp/gamscntr.dat\n");
2128       goto TERMINATE;
2129    }
2130 
2131    /* tell GMO about GEV */
2132    if( gmoRegisterEnvironment(gmo, gev, buffer) )
2133    {
2134       SCIPerrorMessage("Error registering GAMS Environment: %s\n", buffer);
2135       goto TERMINATE;
2136    }
2137 
2138    /* load GAMS model instance into GMO */
2139    if( gmoLoadDataLegacy(gmo, buffer) )
2140    {
2141       SCIPerrorMessage("Could not load model data.\n");
2142       goto TERMINATE;
2143    }
2144 
2145    /* create SCIP problem out of GMO, using the magic from reader_gmo in interfaces/gams */
2146    SCIP_CALL( SCIPcreateProblemReaderGmo(scip, gmo, NULL, FALSE) );
2147    *result = SCIP_SUCCESS;
2148 
2149    ret = SCIP_OKAY;
2150 
2151 TERMINATE:
2152    if( gmo != NULL )
2153       gmoFree(&gmo);
2154    if( gev != NULL )
2155       gevFree(&gev);
2156 
2157    /* remove temporary directory content (should have only files and directory itself) */
2158    if( ret != SCIP_READERROR )
2159       system("rm loadgms.tmp/* && rmdir loadgms.tmp");
2160 
2161    return ret;
2162 }
2163 #endif
2164 
2165 /** problem writing method of reader */
2166 static
SCIP_DECL_READERWRITE(readerWriteGms)2167 SCIP_DECL_READERWRITE(readerWriteGms)
2168 {  /*lint --e{715}*/
2169    SCIP_CALL( SCIPwriteGms(scip, file, name, transformed, objsense, objscale, objoffset, vars,
2170          nvars, nbinvars, nintvars, nimplvars, ncontvars, conss, nconss, result) );
2171 
2172    return SCIP_OKAY;
2173 }
2174 
2175 #ifdef WITH_GAMS
2176 /** destructor of reader to free user data (called when SCIP is exiting) */
2177 static
SCIP_DECL_READERFREE(readerFreeGms)2178 SCIP_DECL_READERFREE(readerFreeGms)
2179 {
2180    if( gmoLibraryLoaded() )
2181       gmoLibraryUnload();
2182    if( gevLibraryLoaded() )
2183       gevLibraryUnload();
2184 
2185    return SCIP_OKAY;
2186 }
2187 #endif
2188 
2189 /*
2190  * reader specific interface methods
2191  */
2192 
2193 /** includes the gms file reader in SCIP */
SCIPincludeReaderGms(SCIP * scip)2194 SCIP_RETCODE SCIPincludeReaderGms(
2195    SCIP*                 scip                /**< SCIP data structure */
2196    )
2197 {
2198    SCIP_READER* reader;
2199 
2200    /* include reader */
2201    SCIP_CALL( SCIPincludeReaderBasic(scip, &reader, READER_NAME, READER_DESC, READER_EXTENSION, NULL) );
2202 
2203    /* set non fundamental callbacks via setter functions */
2204    SCIP_CALL( SCIPsetReaderCopy(scip, reader, readerCopyGms) );
2205 #ifdef WITH_GAMS
2206    SCIP_CALL( SCIPsetReaderRead(scip, reader, readerReadGms) );
2207    SCIP_CALL( SCIPsetReaderFree(scip, reader, readerFreeGms) );
2208 #endif
2209    SCIP_CALL( SCIPsetReaderWrite(scip, reader, readerWriteGms) );
2210 
2211    /* add gms reader parameters for writing routines*/
2212    SCIP_CALL( SCIPaddBoolParam(scip,
2213          "reading/gmsreader/freeints", "have integer variables no upper bound by default (depending on GAMS version)?",
2214          NULL, FALSE, FALSE, NULL, NULL) );
2215 
2216    SCIP_CALL( SCIPaddBoolParam(scip,
2217          "reading/gmsreader/replaceforbiddenchars", "shall characters '#', '*', '+', '/', and '-' in variable and constraint names be replaced by '_'?",
2218          NULL, FALSE, FALSE, NULL, NULL) );
2219 
2220    SCIP_CALL( SCIPaddRealParam(scip,
2221          "reading/gmsreader/bigmdefault", "default M value for big-M reformulation of indicator constraints in case no bound on slack variable is given",
2222          NULL, FALSE, GMS_DEFAULT_BIGM, 0.0, SCIP_REAL_MAX, NULL, NULL) );
2223 
2224    SCIP_CALL( SCIPaddCharParam(scip,
2225          "reading/gmsreader/indicatorreform", "which reformulation to use for indicator constraints: 'b'ig-M, 's'os1",
2226          NULL, FALSE, GMS_DEFAULT_INDICATORREFORM, "bs", NULL, NULL) );
2227 
2228    SCIP_CALL( SCIPaddBoolParam(scip,
2229          "reading/gmsreader/signpower", "is it allowed to use the gams function signpower(x,a)?",
2230          NULL, FALSE, GMS_DEFAULT_SIGNPOWER, NULL, NULL) );
2231 
2232    return SCIP_OKAY;
2233 }
2234 
2235 
2236 /** writes problem to gms file */
SCIPwriteGms(SCIP * scip,FILE * file,const char * name,SCIP_Bool transformed,SCIP_OBJSENSE objsense,SCIP_Real objscale,SCIP_Real objoffset,SCIP_VAR ** vars,int nvars,int nbinvars,int nintvars,int nimplvars,int ncontvars,SCIP_CONS ** conss,int nconss,SCIP_RESULT * result)2237 SCIP_RETCODE SCIPwriteGms(
2238    SCIP*                 scip,               /**< SCIP data structure */
2239    FILE*                 file,               /**< output file, or NULL if standard output should be used */
2240    const char*           name,               /**< problem name */
2241    SCIP_Bool             transformed,        /**< TRUE iff problem is the transformed problem */
2242    SCIP_OBJSENSE         objsense,           /**< objective sense */
2243    SCIP_Real             objscale,           /**< scalar applied to objective function; external objective value is
2244                                               *   extobj = objsense * objscale * (intobj + objoffset) */
2245    SCIP_Real             objoffset,          /**< objective offset from bound shifting and fixing */
2246    SCIP_VAR**            vars,               /**< array with active variables ordered binary, integer, implicit, continuous */
2247    int                   nvars,              /**< number of active variables in the problem */
2248    int                   nbinvars,           /**< number of binary variables */
2249    int                   nintvars,           /**< number of general integer variables */
2250    int                   nimplvars,          /**< number of implicit integer variables */
2251    int                   ncontvars,          /**< number of continuous variables */
2252    SCIP_CONS**           conss,              /**< array with constraints of the problem */
2253    int                   nconss,             /**< number of constraints in the problem */
2254    SCIP_RESULT*          result              /**< pointer to store the result of the file writing call */
2255    )
2256 {
2257    int c;
2258    int v;
2259    int linecnt;
2260    char linebuffer[GMS_MAX_PRINTLEN+1];
2261 
2262    char varname[GMS_MAX_NAMELEN];
2263    char buffer[GMS_MAX_PRINTLEN];
2264 
2265    SCIP_Real* objcoeffs;
2266 
2267    SCIP_CONSHDLR* conshdlr;
2268    const char* conshdlrname;
2269    SCIP_CONS* cons;
2270 
2271    char consname[GMS_MAX_NAMELEN];
2272 
2273    SCIP_VAR** consvars;
2274    SCIP_Real* consvals;
2275    int nconsvars;
2276 
2277    SCIP_VAR* var;
2278    SCIP_VAR* objvar;
2279    SCIP_Real lb;
2280    SCIP_Real ub;
2281    SCIP_Bool freeints;
2282    SCIP_Bool nondefbounds;
2283    SCIP_Bool nlcons;
2284    SCIP_Bool nqcons;
2285    SCIP_Bool nsmooth;
2286    SCIP_Bool discrete;
2287    SCIP_Bool rangedrow;
2288    SCIP_Bool indicatorsosdef;
2289    SCIP_Bool signpowerallowed;
2290    SCIP_Bool needcomma;
2291 
2292    assert( scip != NULL );
2293    assert( vars != NULL || nvars == 0 );
2294 
2295    /* check if the variable names are not too long */
2296    SCIP_CALL( checkVarnames(scip, vars, nvars) );
2297    /* check if the constraint names are too long */
2298    SCIP_CALL( checkConsnames(scip, conss, nconss, transformed) );
2299 
2300    SCIP_CALL( SCIPgetBoolParam(scip, "reading/gmsreader/signpower", &signpowerallowed) );
2301 
2302    /* check if the objective is a single continuous variable, so we would not have to introduce an auxiliary variable
2303     * for GAMS
2304     */
2305    objvar = NULL;
2306    if( objscale == 1.0 && objoffset == 0.0 )
2307    {
2308       for( v = 0; v < nvars; ++v )
2309       {
2310          if( SCIPvarGetObj(vars[v]) == 0.0 ) /*lint !e613*/
2311             continue;
2312 
2313          if( objvar == NULL )
2314          {
2315             /* first variable with nonzero obj coefficient
2316              * if not active or having coefficient != 1.0, or being binary/integer, then give up
2317              */
2318             if( !SCIPvarIsActive(vars[v]) || SCIPvarGetObj(vars[v]) != 1.0 ||
2319                SCIPvarGetType(vars[v]) < SCIP_VARTYPE_IMPLINT ) /*lint !e613*/
2320                break;
2321 
2322             objvar = vars[v]; /*lint !e613*/
2323          }
2324          else
2325          {
2326             /* second variable with nonzero obj coefficient -> give up */
2327             objvar = NULL;
2328             break;
2329          }
2330       }
2331    }
2332 
2333    /* print statistics as comment to file */
2334    SCIPinfoMessage(scip, file, "$OFFLISTING\n");
2335    SCIPinfoMessage(scip, file, "* SCIP STATISTICS\n");
2336    SCIPinfoMessage(scip, file, "*   Problem name     : %s\n", name);
2337    SCIPinfoMessage(scip, file, "*   Variables        : %d (%d binary, %d integer, %d implicit integer, %d continuous)\n",
2338       nvars, nbinvars, nintvars, nimplvars, ncontvars);
2339    SCIPinfoMessage(scip, file, "*   Constraints      : %d\n\n", nconss);
2340 
2341    /* print flags */
2342    SCIPinfoMessage(scip, file, "$MAXCOL %d\n", GMS_MAX_LINELEN - 1);
2343    SCIPinfoMessage(scip, file, "$OFFDIGIT\n\n");
2344 
2345    /* print variable section */
2346    SCIPinfoMessage(scip, file, "Variables\n");
2347    clearLine(linebuffer, &linecnt);
2348 
2349    if( objvar == NULL )
2350    {
2351       /* auxiliary objective variable */
2352       SCIPinfoMessage(scip, file, " objvar%c", nvars > 0 ? ',' : ';');
2353    }
2354 
2355    /* "model" variables */
2356    for( v = 0; v < nvars; ++v )
2357    {
2358       var = vars[v]; /*lint !e613*/
2359       assert( var != NULL );
2360 
2361       SCIP_CALL( printConformName(scip, varname, GMS_MAX_NAMELEN, SCIPvarGetName(var)) );
2362       (void) SCIPsnprintf(buffer, GMS_MAX_PRINTLEN, " %s%c", varname, (v < nvars - 1) ? ',' : ';');
2363       appendLine(scip, file, linebuffer, &linecnt, buffer);
2364 
2365       if( (linecnt > 0 && (v == nbinvars - 1 || v == nbinvars + nintvars - 1 ||
2366             v == nbinvars + nintvars + nimplvars - 1)) || v == nvars - 1 )
2367       {
2368          endLine(scip, file, linebuffer, &linecnt);
2369          clearLine(linebuffer, &linecnt);
2370       }
2371    }
2372 
2373    SCIPinfoMessage(scip, file, "\n");
2374 
2375    /* declare binary variables if present */
2376    if( nbinvars > 0 )
2377    {
2378       SCIPinfoMessage(scip, file, "Binary variables\n");
2379       clearLine(linebuffer, &linecnt);
2380 
2381       for( v = 0; v < nbinvars; ++v )
2382       {
2383          var = vars[v]; /*lint !e613*/
2384 
2385          SCIP_CALL( printConformName(scip, varname, GMS_MAX_NAMELEN, SCIPvarGetName(var)) );
2386          (void) SCIPsnprintf(buffer, GMS_MAX_PRINTLEN, " %s%s", varname, (v < nbinvars - 1) ? "," : ";");
2387 
2388          appendLine(scip, file, linebuffer, &linecnt, buffer);
2389       }
2390 
2391       endLine(scip, file, linebuffer, &linecnt);
2392       SCIPinfoMessage(scip, file, "\n");
2393    }
2394 
2395    /* declare integer variables if present */
2396    if( nintvars > 0 )
2397    {
2398       SCIPinfoMessage(scip, file, "Integer variables\n");
2399       clearLine(linebuffer, &linecnt);
2400 
2401       for( v = 0; v < nintvars; ++v )
2402       {
2403          var = vars[nbinvars + v]; /*lint !e613*/
2404 
2405          SCIP_CALL( printConformName(scip, varname, GMS_MAX_NAMELEN, SCIPvarGetName(var)) );
2406          (void) SCIPsnprintf(buffer, GMS_MAX_PRINTLEN, " %s%s", varname, (v < nintvars - 1) ? "," : ";");
2407 
2408          appendLine(scip, file, linebuffer, &linecnt, buffer);
2409       }
2410       endLine(scip, file, linebuffer, &linecnt);
2411       SCIPinfoMessage(scip, file, "\n");
2412    }
2413 
2414    /* print variable bounds */
2415    SCIPinfoMessage(scip, file, "* Variable bounds\n");
2416    SCIP_CALL( SCIPgetBoolParam(scip, "reading/gmsreader/freeints", &freeints) );
2417    nondefbounds = FALSE;
2418 
2419    for( v = 0; v < nvars; ++v )
2420    {
2421       var = vars[v]; /*lint !e613*/
2422       assert( var != NULL );
2423 
2424       SCIP_CALL( printConformName(scip, varname, GMS_MAX_NAMELEN, SCIPvarGetName(var)) );
2425 
2426       if( transformed )
2427       {
2428          /* in case the transformed is written only local bounds are posted which are valid in the current node */
2429          lb = SCIPvarGetLbLocal(var);
2430          ub = SCIPvarGetUbLocal(var);
2431       }
2432       else
2433       {
2434          lb = SCIPvarGetLbOriginal(var);
2435          ub = SCIPvarGetUbOriginal(var);
2436       }
2437       assert( lb <= ub );
2438 
2439       /* fixed */
2440       if( SCIPisEQ(scip, lb, ub) )
2441       {
2442          if( v < nintvars )
2443             SCIPinfoMessage(scip, file, " %s.fx = %g;\n", varname, SCIPfloor(scip, lb + 0.5));
2444          else
2445             SCIPinfoMessage(scip, file, " %s.fx = %.15g;\n", varname, lb);
2446          nondefbounds = TRUE;
2447 
2448          /* no need to write lower and upper bounds additionally */
2449          continue;
2450       }
2451 
2452       /* lower bound */
2453       if( v < nbinvars + nintvars )
2454       {
2455          /* default lower bound of binaries and integers is 0 (also in recent gams versions if pf4=0 is given) */
2456          if( !SCIPisZero(scip, lb) )
2457          {
2458             if( !SCIPisInfinity(scip, -lb) )
2459                SCIPinfoMessage(scip, file, " %s.lo = %g;\n", varname, SCIPceil(scip, lb));
2460             else if( freeints )
2461                SCIPinfoMessage(scip, file, " %s.lo = -inf;\n", varname); /* -inf is allowed when running gams with pf4=0, which we assume if freeints is TRUE */
2462             else
2463                SCIPinfoMessage(scip, file, " %s.lo = %g;\n", varname, -SCIPinfinity(scip)); /* sorry, -inf not allowed in gams file here */
2464             nondefbounds = TRUE;
2465          }
2466       }
2467       else if( v >= nbinvars + nintvars && !SCIPisInfinity(scip, -lb) )
2468       {
2469          /* continuous variables are free by default */
2470          SCIPinfoMessage(scip, file, " %s.lo = %.15g;\n", varname, lb);
2471          nondefbounds = TRUE;
2472       }
2473 
2474       /* upper bound */
2475       if( v < nbinvars )
2476       {
2477          if( !SCIPisFeasEQ(scip, ub, 1.0) )
2478          {
2479             SCIPinfoMessage(scip, file, " %s.up = %g;\n", varname, SCIPfeasFloor(scip, ub));
2480             nondefbounds = TRUE;
2481          }
2482       }
2483       else if( v < nbinvars + nintvars && !freeints )
2484       {
2485          /* freeints == FALSE: integer variables have upper bound 100 by default */
2486          if( !SCIPisFeasEQ(scip, ub, 100.0) )
2487          {
2488             if( !SCIPisInfinity(scip, ub) )
2489                SCIPinfoMessage(scip, file, " %s.up = %g;\n", varname, SCIPfeasFloor(scip, ub));
2490             else
2491                SCIPinfoMessage(scip, file, " %s.up = +inf;\n", varname);
2492             nondefbounds = TRUE;
2493          }
2494       }
2495       else if( v < nbinvars + nintvars && !SCIPisInfinity(scip, ub) )
2496       {
2497          /* freeints == TRUE: integer variables have no upper bound by default */
2498          SCIPinfoMessage(scip, file, " %s.up = %g;\n", varname, SCIPfloor(scip, ub));
2499          nondefbounds = TRUE;
2500       }
2501       else if( v >= nbinvars + nintvars && !SCIPisInfinity(scip, ub) )
2502       {
2503          /* continuous variables are free by default */
2504          SCIPinfoMessage(scip, file, " %s.up = %.15g;\n", varname, ub);
2505          nondefbounds = TRUE;
2506       }
2507    }
2508 
2509    if( !nondefbounds )
2510       SCIPinfoMessage(scip, file, "* (All other bounds at default value: binary [0,1], integer [%s], continuous [-inf,+inf].)\n", freeints ? "0,+inf" : "0,100");
2511    SCIPinfoMessage(scip, file, "\n");
2512 
2513    /* print equations section */
2514    if( nconss > 0 || objvar == NULL )
2515    {
2516       SCIPinfoMessage(scip, file, "Equations\n");
2517       clearLine(linebuffer, &linecnt);
2518    }
2519    needcomma = FALSE;
2520 
2521    if( objvar == NULL )
2522    {
2523       SCIPinfoMessage(scip, file, " objequ");
2524       needcomma = TRUE;
2525    }
2526 
2527    /* declare equations */
2528    for( c = 0; c < nconss; ++c )
2529    {
2530       cons = conss[c];
2531       assert( cons != NULL );
2532 
2533       conshdlr = SCIPconsGetHdlr(cons);
2534       assert( conshdlr != NULL );
2535 
2536       SCIP_CALL( printConformName(scip, consname, GMS_MAX_NAMELEN, SCIPconsGetName(cons)) );
2537       conshdlrname = SCIPconshdlrGetName(conshdlr);
2538       assert( transformed == SCIPconsIsTransformed(cons) );
2539 
2540       rangedrow = strcmp(conshdlrname, "linear") == 0
2541          && !SCIPisInfinity(scip, -SCIPgetLhsLinear(scip, cons)) && !SCIPisInfinity(scip, SCIPgetRhsLinear(scip, cons))
2542          && !SCIPisEQ(scip, SCIPgetLhsLinear(scip, cons), SCIPgetRhsLinear(scip, cons));
2543       rangedrow = rangedrow || (strcmp(conshdlrname, "quadratic") == 0
2544          && !SCIPisInfinity(scip, -SCIPgetLhsQuadratic(scip, cons)) && !SCIPisInfinity(scip, SCIPgetRhsQuadratic(scip, cons))
2545          && !SCIPisEQ(scip, SCIPgetLhsQuadratic(scip, cons), SCIPgetRhsQuadratic(scip, cons)));
2546       rangedrow = rangedrow || (strcmp(conshdlrname, "nonlinear") == 0
2547          && !SCIPisInfinity(scip, -SCIPgetLhsNonlinear(scip, cons)) && !SCIPisInfinity(scip, SCIPgetRhsNonlinear(scip, cons))
2548          && !SCIPisEQ(scip, SCIPgetLhsNonlinear(scip, cons), SCIPgetRhsNonlinear(scip, cons)));
2549       rangedrow = rangedrow || (strcmp(conshdlrname, "abspower") == 0
2550          && !SCIPisInfinity(scip, -SCIPgetLhsAbspower(scip, cons)) && !SCIPisInfinity(scip, SCIPgetRhsAbspower(scip, cons))
2551          && !SCIPisEQ(scip, SCIPgetLhsAbspower(scip, cons), SCIPgetRhsAbspower(scip, cons)));
2552       rangedrow = rangedrow || (strcmp(conshdlrname, "bivariate") == 0
2553          && !SCIPisInfinity(scip, -SCIPgetLhsBivariate(scip, cons)) && !SCIPisInfinity(scip, SCIPgetRhsBivariate(scip, cons))
2554          && !SCIPisEQ(scip, SCIPgetLhsBivariate(scip, cons), SCIPgetRhsBivariate(scip, cons)));
2555       rangedrow = rangedrow || (strcmp(conshdlrname, "varbound") == 0
2556          && !SCIPisInfinity(scip, -SCIPgetLhsVarbound(scip, cons)) && !SCIPisInfinity(scip, SCIPgetRhsVarbound(scip, cons))
2557          && !SCIPisEQ(scip, SCIPgetLhsVarbound(scip, cons), SCIPgetRhsVarbound(scip, cons)));
2558 
2559       /* we declare only those constraints which we can print in GAMS format */
2560       if( strcmp(conshdlrname, "knapsack") != 0 && strcmp(conshdlrname, "logicor") != 0 && strcmp(conshdlrname, "setppc") != 0
2561           && strcmp(conshdlrname, "linear") != 0 && strcmp(conshdlrname, "quadratic") != 0 && strcmp(conshdlrname, "varbound") != 0
2562           && strcmp(conshdlrname, "soc") != 0 && strcmp(conshdlrname, "abspower") != 0 && strcmp(conshdlrname, "bivariate") != 0
2563           && strcmp(conshdlrname, "nonlinear") != 0 && strcmp(conshdlrname, "SOS1") != 0 && strcmp(conshdlrname, "SOS2") != 0
2564           && strcmp(conshdlrname, "indicator") != 0 )
2565       {
2566          SCIPwarningMessage(scip, "Constraint type <%s> not supported. Skip writing constraint <%s>.\n", conshdlrname, SCIPconsGetName(cons));
2567          continue;
2568       }
2569 
2570       if( needcomma )
2571          appendLine(scip, file, linebuffer, &linecnt, ",");
2572 
2573       SCIP_CALL( printConformName(scip, consname, GMS_MAX_NAMELEN, SCIPconsGetName(cons)) );
2574       if( rangedrow )
2575       {
2576          (void) SCIPsnprintf(buffer, GMS_MAX_PRINTLEN, " %s%s%s%s", consname, "_lhs, ", consname, "_rhs");
2577          appendLine(scip, file, linebuffer, &linecnt, buffer);
2578       }
2579       else
2580       {
2581          (void) SCIPsnprintf(buffer, GMS_MAX_PRINTLEN, " %s", consname);
2582          appendLine(scip, file, linebuffer, &linecnt, buffer);
2583       }
2584       needcomma = TRUE;
2585    }
2586 
2587    if( nconss > 0 || objvar == NULL )
2588    {
2589       (void) SCIPsnprintf(buffer, GMS_MAX_PRINTLEN, ";");
2590       appendLine(scip, file, linebuffer, &linecnt, buffer);
2591 
2592       endLine(scip, file, linebuffer, &linecnt);
2593       SCIPinfoMessage(scip, file, "\n");
2594    }
2595 
2596    if( objvar == NULL )
2597    {
2598       /* print objective function equation */
2599       clearLine(linebuffer, &linecnt);
2600       if( objoffset != 0.0 )
2601          (void) SCIPsnprintf(buffer, GMS_MAX_PRINTLEN, " objequ .. objvar =e= %.15g + ", objscale * objoffset);
2602       else
2603          (void) SCIPsnprintf(buffer, GMS_MAX_PRINTLEN, " objequ .. objvar =e= ");
2604       appendLine(scip, file, linebuffer, &linecnt, buffer);
2605 
2606       SCIP_CALL( SCIPallocBufferArray(scip, &objcoeffs, nvars) );
2607 
2608       for( v = 0; v < nvars; ++v )
2609       {
2610          var = vars[v]; /*lint !e613*/
2611          assert( var != NULL );
2612 
2613          /* in case the original problem has to be posted the variables have to be either "original" or "negated" */
2614          assert( transformed || SCIPvarGetStatus(var) == SCIP_VARSTATUS_ORIGINAL || SCIPvarGetStatus(var) == SCIP_VARSTATUS_NEGATED );
2615 
2616          objcoeffs[v] = SCIPisZero(scip, SCIPvarGetObj(var)) ? 0.0 : objscale * SCIPvarGetObj(var);
2617       }
2618 
2619       SCIP_CALL( printActiveVariables(scip, file, linebuffer, &linecnt, "", ";", nvars, vars, objcoeffs, transformed) );
2620 
2621       SCIPfreeBufferArray(scip, &objcoeffs);
2622       endLine(scip, file, linebuffer, &linecnt);
2623       SCIPinfoMessage(scip, file, "\n");
2624    }
2625 
2626    /* print constraints */
2627    nlcons = FALSE;
2628    nqcons = FALSE;
2629    nsmooth = FALSE;
2630    discrete = nbinvars > 0 || nintvars > 0;
2631    indicatorsosdef = FALSE;
2632    for( c = 0; c < nconss; ++c )
2633    {
2634       cons = conss[c];
2635       assert( cons != NULL );
2636 
2637       /* in case the transformed is written, only constraints are posted which are enabled in the current node */
2638       assert(!transformed || SCIPconsIsEnabled(cons));
2639 
2640       conshdlr = SCIPconsGetHdlr(cons);
2641       assert( conshdlr != NULL );
2642 
2643       SCIP_CALL( printConformName(scip, consname, GMS_MAX_NAMELEN, SCIPconsGetName(cons)) );
2644       conshdlrname = SCIPconshdlrGetName(conshdlr);
2645       assert( transformed == SCIPconsIsTransformed(cons) );
2646 
2647       if( strcmp(conshdlrname, "knapsack") == 0 )
2648       {
2649          SCIP_Longint* weights;
2650 
2651          consvars = SCIPgetVarsKnapsack(scip, cons);
2652          nconsvars = SCIPgetNVarsKnapsack(scip, cons);
2653 
2654          /* copy Longint array to SCIP_Real array */
2655          weights = SCIPgetWeightsKnapsack(scip, cons);
2656          SCIP_CALL( SCIPallocBufferArray(scip, &consvals, nconsvars) );
2657          for( v = 0; v < nconsvars; ++v )
2658             consvals[v] = (SCIP_Real)weights[v];
2659 
2660          SCIP_CALL( printLinearCons(scip, file, consname, nconsvars, consvars, consvals,
2661                -SCIPinfinity(scip), (SCIP_Real) SCIPgetCapacityKnapsack(scip, cons), transformed) );
2662 
2663          SCIPfreeBufferArray(scip, &consvals);
2664       }
2665       else if( strcmp(conshdlrname, "linear") == 0 )
2666       {
2667          SCIP_CALL( printLinearCons(scip, file, consname,
2668                SCIPgetNVarsLinear(scip, cons), SCIPgetVarsLinear(scip, cons), SCIPgetValsLinear(scip, cons),
2669                SCIPgetLhsLinear(scip, cons),  SCIPgetRhsLinear(scip, cons), transformed) );
2670       }
2671       else if( strcmp(conshdlrname, "logicor") == 0 )
2672       {
2673          SCIP_CALL( printLinearCons(scip, file, consname,
2674                SCIPgetNVarsLogicor(scip, cons), SCIPgetVarsLogicor(scip, cons), NULL,
2675                1.0, SCIPinfinity(scip), transformed) );
2676       }
2677       else if( strcmp(conshdlrname, "quadratic") == 0 )
2678       {
2679          SCIP_CALL( printQuadraticCons(scip, file, consname,
2680                SCIPgetNLinearVarsQuadratic(scip, cons), SCIPgetLinearVarsQuadratic(scip, cons), SCIPgetCoefsLinearVarsQuadratic(scip, cons),
2681                SCIPgetNQuadVarTermsQuadratic(scip, cons), SCIPgetQuadVarTermsQuadratic(scip, cons),
2682                SCIPgetNBilinTermsQuadratic(scip, cons), SCIPgetBilinTermsQuadratic(scip, cons),
2683                SCIPgetLhsQuadratic(scip, cons),  SCIPgetRhsQuadratic(scip, cons), transformed) );
2684 
2685          nlcons = TRUE;
2686       }
2687       else if( strcmp(conshdlrname, "nonlinear") == 0 )
2688       {
2689          /* cons_nonlinear does not have exprtree's at hand during presolve */
2690          if( SCIPgetStage(scip) >= SCIP_STAGE_INITPRESOLVE && SCIPgetStage(scip) <= SCIP_STAGE_EXITPRESOLVE
2691              && SCIPgetExprgraphNonlinear(scip,conshdlr) != NULL )
2692          {
2693             SCIP_EXPRTREE* exprtree;
2694             SCIP_Real coef;
2695 
2696             SCIP_CALL( SCIPexprgraphGetTree(SCIPgetExprgraphNonlinear(scip,conshdlr), SCIPgetExprgraphNodeNonlinear(scip,cons), &exprtree) );
2697             coef = 1.0;
2698             SCIP_CALL( printNonlinearCons(scip, file, consname,
2699                   SCIPgetNLinearVarsNonlinear(scip, cons), SCIPgetLinearVarsNonlinear(scip, cons), SCIPgetLinearCoefsNonlinear(scip, cons),
2700                   1, &exprtree, &coef,
2701                   SCIPgetLhsNonlinear(scip, cons),  SCIPgetRhsNonlinear(scip, cons), transformed, &nsmooth) );
2702 
2703             SCIP_CALL( SCIPexprtreeFree(&exprtree) );
2704          }
2705          else
2706          {
2707             SCIP_CALL( printNonlinearCons(scip, file, consname,
2708                   SCIPgetNLinearVarsNonlinear(scip, cons), SCIPgetLinearVarsNonlinear(scip, cons), SCIPgetLinearCoefsNonlinear(scip, cons),
2709                   SCIPgetNExprtreesNonlinear(scip, cons), SCIPgetExprtreesNonlinear(scip, cons), SCIPgetExprtreeCoefsNonlinear(scip, cons),
2710                   SCIPgetLhsNonlinear(scip, cons),  SCIPgetRhsNonlinear(scip, cons), transformed, &nsmooth) );
2711          }
2712          nlcons = TRUE;
2713          nqcons = TRUE;
2714       }
2715       else if( strcmp(conshdlrname, "bivariate") == 0 )
2716       {
2717          SCIP_EXPRTREE* exprtree;
2718          SCIP_VAR* linvar;
2719          SCIP_Real lincoef;
2720          int exprdegree;
2721          SCIP_Real one;
2722 
2723          exprtree = SCIPgetExprtreeBivariate(scip, cons);
2724          assert(exprtree != NULL);
2725 
2726          linvar  = SCIPgetLinearVarBivariate(scip, cons);
2727          lincoef = SCIPgetLinearCoefBivariate(scip, cons);
2728          one = 1.0;
2729          SCIP_CALL( printNonlinearCons(scip, file, consname,
2730             linvar == NULL ? 0 : 1, &linvar, &lincoef,
2731             1, &exprtree, &one,
2732             SCIPgetLhsBivariate(scip, cons),  SCIPgetRhsBivariate(scip, cons), transformed, &nsmooth) );
2733 
2734          SCIP_CALL( SCIPexprtreeGetMaxDegree(exprtree, &exprdegree) );
2735          if( exprdegree > 1 )
2736             nlcons = TRUE;
2737          if( exprdegree > 2)
2738             nqcons = TRUE;
2739       }
2740       else if( strcmp(conshdlrname, "setppc") == 0 )
2741       {
2742          consvars = SCIPgetVarsSetppc(scip, cons);
2743          nconsvars = SCIPgetNVarsSetppc(scip, cons);
2744 
2745          switch( SCIPgetTypeSetppc(scip, cons) )
2746          {
2747          case SCIP_SETPPCTYPE_PARTITIONING :
2748             SCIP_CALL( printLinearCons(scip, file, consname,
2749                   nconsvars, consvars, NULL, 1.0, 1.0, transformed) );
2750             break;
2751          case SCIP_SETPPCTYPE_PACKING :
2752             SCIP_CALL( printLinearCons(scip, file, consname,
2753                   nconsvars, consvars, NULL, -SCIPinfinity(scip), 1.0, transformed) );
2754             break;
2755          case SCIP_SETPPCTYPE_COVERING :
2756             SCIP_CALL( printLinearCons(scip, file, consname,
2757                   nconsvars, consvars, NULL, 1.0, SCIPinfinity(scip), transformed) );
2758             break;
2759          }
2760       }
2761       else if( strcmp(conshdlrname, "varbound") == 0 )
2762       {
2763          SCIP_CALL( SCIPallocBufferArray(scip, &consvars, 2) );
2764          SCIP_CALL( SCIPallocBufferArray(scip, &consvals, 2) );
2765 
2766          consvars[0] = SCIPgetVarVarbound(scip, cons);
2767          consvars[1] = SCIPgetVbdvarVarbound(scip, cons);
2768 
2769          consvals[0] = 1.0;
2770          consvals[1] = SCIPgetVbdcoefVarbound(scip, cons);
2771 
2772          SCIP_CALL( printLinearCons(scip, file, consname,
2773                2, consvars, consvals,
2774                SCIPgetLhsVarbound(scip, cons), SCIPgetRhsVarbound(scip, cons), transformed) );
2775 
2776          SCIPfreeBufferArray(scip, &consvars);
2777          SCIPfreeBufferArray(scip, &consvals);
2778       }
2779       else if( strcmp(conshdlrname, "soc") == 0 )
2780       {
2781          SCIP_CALL( printSOCCons(scip, file, consname,
2782             SCIPgetNLhsVarsSOC(scip, cons), SCIPgetLhsVarsSOC(scip, cons), SCIPgetLhsCoefsSOC(scip, cons), SCIPgetLhsOffsetsSOC(scip, cons), SCIPgetLhsConstantSOC(scip, cons),
2783             SCIPgetRhsVarSOC(scip, cons), SCIPgetRhsCoefSOC(scip, cons), SCIPgetRhsOffsetSOC(scip, cons), transformed) );
2784 
2785          nlcons = nlcons || !isGAMSprintableSOC(SCIPgetNLhsVarsSOC(scip, cons), SCIPgetLhsVarsSOC(scip, cons), SCIPgetLhsCoefsSOC(scip, cons), SCIPgetLhsOffsetsSOC(scip, cons), SCIPgetLhsConstantSOC(scip, cons),
2786             SCIPgetRhsVarSOC(scip, cons), SCIPgetRhsCoefSOC(scip, cons), SCIPgetRhsOffsetSOC(scip, cons));
2787       }
2788       else if( strcmp(conshdlrname, "indicator") == 0 )
2789       {
2790          SCIP_CALL( printIndicatorCons(scip, file, consname,
2791             SCIPgetBinaryVarIndicator(cons), SCIPgetSlackVarIndicator(cons), &indicatorsosdef,
2792             transformed) );
2793       }
2794       else if( strcmp(conshdlrname, "abspower") == 0 )
2795       {
2796          SCIP_CALL( printSignpowerCons(scip, file, consname,
2797             SCIPgetNonlinearVarAbspower(scip, cons), SCIPgetLinearVarAbspower(scip, cons),
2798             SCIPgetExponentAbspower(scip, cons), SCIPgetOffsetAbspower(scip, cons), SCIPgetCoefLinearAbspower(scip, cons),
2799             SCIPgetLhsAbspower(scip, cons),  SCIPgetRhsAbspower(scip, cons), transformed, signpowerallowed, &nsmooth) );
2800 
2801          nlcons = TRUE;
2802          nqcons = TRUE;
2803       }
2804       else if( strcmp(conshdlrname, "SOS1") == 0 )
2805       {
2806          SCIP_CALL( printSOSCons(scip, file, consname,
2807             SCIPgetNVarsSOS1(scip, cons), SCIPgetVarsSOS1(scip, cons), 1,
2808             transformed) );
2809          discrete = TRUE;
2810       }
2811       else if( strcmp(conshdlrname, "SOS2") == 0 )
2812       {
2813          SCIP_CALL( printSOSCons(scip, file, consname,
2814             SCIPgetNVarsSOS2(scip, cons), SCIPgetVarsSOS2(scip, cons), 2,
2815             transformed) );
2816          discrete = TRUE;
2817       }
2818       else
2819       {
2820          SCIPwarningMessage(scip, "constraint handler <%s> cannot print requested format\n", conshdlrname );
2821          SCIPinfoMessage(scip, file, "* ");
2822          SCIP_CALL( SCIPprintCons(scip, cons, file) );
2823          SCIPinfoMessage(scip, file, ";\n");
2824       }
2825 
2826       SCIPinfoMessage(scip, file, "\n");
2827    }
2828    /* if at most quadratic, then cannot have nonsmooth functions */
2829    assert(nlcons || !nsmooth);
2830 
2831    /* print model creation */
2832    SCIPinfoMessage(scip, file, "Model m / all /;\n\n");
2833 
2834    /* set some options to reduce listing file size */
2835    SCIPinfoMessage(scip, file, "option limrow = 0;\n");
2836    SCIPinfoMessage(scip, file, "option limcol = 0;\n\n");
2837 
2838    /* print solve command */
2839    (void) SCIPsnprintf(buffer, GMS_MAX_PRINTLEN, "%s%s",
2840          discrete ? "MI" : "", nlcons ? (nqcons ? ((nsmooth && !discrete) ? "DNLP" : "NLP") : "QCP") : (discrete > 0 ? "P" : "LP"));
2841 
2842    if( objvar != NULL )
2843    {
2844       SCIP_CALL( printConformName(scip, varname, GMS_MAX_NAMELEN, SCIPvarGetName(objvar)) );
2845    }
2846 
2847    SCIPinfoMessage(scip, file, "$if not set %s $set %s %s\n", buffer, buffer, buffer);
2848    SCIPinfoMessage(scip, file, "Solve m using %%%s%% %simizing %s;\n",
2849          buffer, objsense == SCIP_OBJSENSE_MINIMIZE ? "min" : "max", objvar != NULL ? varname : "objvar");
2850 
2851    *result = SCIP_SUCCESS;
2852 
2853    return SCIP_OKAY;
2854 }
2855