1    	/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2    	/*                                                                           */
3    	/*                  This file is part of the program and library             */
4    	/*         SCIP --- Solving Constraint Integer Programs                      */
5    	/*                                                                           */
6    	/*  Copyright (c) 2002-2023 Zuse Institute Berlin (ZIB)                      */
7    	/*                                                                           */
8    	/*  Licensed under the Apache License, Version 2.0 (the "License");          */
9    	/*  you may not use this file except in compliance with the License.         */
10   	/*  You may obtain a copy of the License at                                  */
11   	/*                                                                           */
12   	/*      http://www.apache.org/licenses/LICENSE-2.0                           */
13   	/*                                                                           */
14   	/*  Unless required by applicable law or agreed to in writing, software      */
15   	/*  distributed under the License is distributed on an "AS IS" BASIS,        */
16   	/*  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. */
17   	/*  See the License for the specific language governing permissions and      */
18   	/*  limitations under the License.                                           */
19   	/*                                                                           */
20   	/*  You should have received a copy of the Apache-2.0 license                */
21   	/*  along with SCIP; see the file LICENSE. If not visit scipopt.org.         */
22   	/*                                                                           */
23   	/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
24   	
25   	/**@file   reader_gms.c
26   	 * @ingroup DEFPLUGINS_READER
27   	 * @brief  GAMS file writer
28   	 * @author Ambros Gleixner
29   	 * @author Stefan Vigerske
30   	 *
31   	 * @todo Check for words reserved for GAMS.
32   	 */
33   	
34   	/*---+----1----+----2----+----3----+----4----+----5----+----6----+----7----+----8----+----9----+----0----+----1----+----2*/
35   	
36   	#include "blockmemshell/memory.h"
37   	#include "scip/cons_nonlinear.h"
38   	#include "scip/cons_indicator.h"
39   	#include "scip/cons_knapsack.h"
40   	#include "scip/cons_linear.h"
41   	#include "scip/cons_logicor.h"
42   	#include "scip/cons_setppc.h"
43   	#include "scip/cons_sos1.h"
44   	#include "scip/cons_sos2.h"
45   	#include "scip/cons_varbound.h"
46   	#include "scip/pub_cons.h"
47   	#include "scip/pub_message.h"
48   	#include "scip/pub_misc.h"
49   	#include "scip/pub_reader.h"
50   	#include "scip/pub_var.h"
51   	#include "scip/reader_gms.h"
52   	#include "scip/scip_cons.h"
53   	#include "scip/scip_general.h"
54   	#include "scip/scip_mem.h"
55   	#include "scip/scip_message.h"
56   	#include "scip/scip_numerics.h"
57   	#include "scip/scip_param.h"
58   	#include "scip/scip_reader.h"
59   	#include "scip/scip_var.h"
60   	#include "scip/expr_abs.h"
61   	#include <string.h>
62   	
63   	
64   	#define READER_NAME             "gmsreader"
65   	#define READER_DESC             "file writer for (MI)(N)LPs in GAMS file format"
66   	#define READER_EXTENSION        "gms"
67   	
68   	
69   	#define GMS_MAX_LINELEN      256
70   	#define GMS_MAX_PRINTLEN     256       /**< the maximum length of any line is 255 + '\\0' = 256*/
71   	#define GMS_MAX_NAMELEN      64        /**< the maximum length for any name is 63 + '\\0' = 64 */
72   	#define GMS_PRINTLEN         100
73   	#define GMS_DEFAULT_BIGM     1e+6
74   	#define GMS_DEFAULT_INDICATORREFORM 's'
75   	#define GMS_DEFAULT_SIGNPOWER FALSE
76   	
77   	/*
78   	 * Local methods (for writing)
79   	 */
80   	
81   	static const char badchars[] = "#*+/-@$[](){}";
82   	
83   	/** transforms given variables, scalars, and constant to the corresponding active variables, scalars, and constant */
84   	static
85   	SCIP_RETCODE getActiveVariables(
86   	   SCIP*                 scip,               /**< SCIP data structure */
87   	   SCIP_VAR***           vars,               /**< pointer to vars array to get active variables for */
88   	   SCIP_Real**           scalars,            /**< pointer to scalars a_1, ..., a_n in linear sum a_1*x_1 + ... + a_n*x_n + c */
89   	   int*                  nvars,              /**< pointer to number of variables and values in vars and vals array */
90   	   int*                  varssize,           /**< pointer to length of vars and scalars array */
91   	   SCIP_Real*            constant,           /**< pointer to constant c in linear sum a_1*x_1 + ... + a_n*x_n + c  */
92   	   SCIP_Bool             transformed         /**< transformed constraint? */
93   	   )
94   	{
95   	   int requiredsize;
96   	   int v;
97   	
98   	   assert( scip != NULL );
99   	   assert( vars != NULL );
100  	   assert( *vars != NULL );
101  	   assert( scalars != NULL );
102  	   assert( *scalars != NULL );
103  	   assert( nvars != NULL );
104  	   assert( varssize != NULL );
105  	   assert( *varssize >= *nvars );
106  	   assert( constant != NULL );
107  	
108  	   if( transformed )
109  	   {
110  	      SCIP_CALL( SCIPgetProbvarLinearSum(scip, *vars, *scalars, nvars, *varssize, constant, &requiredsize, TRUE) );
111  	
112  	      if( requiredsize > *varssize )
113  	      {
114  	         *varssize = SCIPcalcMemGrowSize(scip, requiredsize);
115  	         SCIP_CALL( SCIPreallocBufferArray(scip, vars, *varssize) );
116  	         SCIP_CALL( SCIPreallocBufferArray(scip, scalars, *varssize) );
117  	
118  	         SCIP_CALL( SCIPgetProbvarLinearSum(scip, *vars, *scalars, nvars, *varssize, constant, &requiredsize, TRUE) );
119  	         assert(requiredsize <= *varssize);
120  	      }
121  	   }
122  	   else
123  	   {
124  	      for( v = 0; v < *nvars; ++v )
125  	      {
126  	         SCIP_CALL( SCIPvarGetOrigvarSum(&(*vars)[v], &(*scalars)[v], constant) );
127  	      }
128  	   }
129  	
130  	   return SCIP_OKAY;
131  	}
132  	
133  	/** clears the given line buffer */
134  	static
135  	void clearLine(
136  	   char*                 linebuffer,         /**< line */
137  	   int*                  linecnt             /**< number of characters in line */
138  	   )
139  	{
140  	   assert( linebuffer != NULL );
141  	   assert( linecnt != NULL );
142  	
143  	   (*linecnt) = 0;
144  	   linebuffer[0] = '\0';
145  	}
146  	
147  	/** ends the given line with '\\0' and prints it to the given file stream, with a newline at the end */
148  	static
149  	void endLine(
150  	   SCIP*                 scip,               /**< SCIP data structure */
151  	   FILE*                 file,               /**< output file (or NULL for standard output) */
152  	   char*                 linebuffer,         /**< line */
153  	   int*                  linecnt             /**< number of characters in line */
154  	   )
155  	{
156  	   assert( scip != NULL );
157  	   assert( linebuffer != NULL );
158  	   assert( linecnt != NULL );
159  	   assert( 0 <= *linecnt && *linecnt < GMS_MAX_LINELEN );
160  	
161  	   if( (*linecnt) > 0 )
162  	   {
163  	      linebuffer[(*linecnt)] = '\0';
164  	      SCIPinfoMessage(scip, file, "%s\n", linebuffer);
165  	      clearLine(linebuffer, linecnt);
166  	   }
167  	}
168  	
169  	/** ends the given line with '\\0' and prints it to the given file stream, without a newline at the end */
170  	static
171  	void endLineNoNewline(
172  	   SCIP*                 scip,               /**< SCIP data structure */
173  	   FILE*                 file,               /**< output file (or NULL for standard output) */
174  	   char*                 linebuffer,         /**< line */
175  	   int*                  linecnt             /**< number of characters in line */
176  	   )
177  	{
178  	   assert( scip != NULL );
179  	   assert( linebuffer != NULL );
180  	   assert( linecnt != NULL );
181  	   assert( 0 <= *linecnt && *linecnt < GMS_MAX_LINELEN );
182  	
183  	   if( (*linecnt) > 0 )
184  	   {
185  	      linebuffer[(*linecnt)] = '\0';
186  	      SCIPinfoMessage(scip, file, "%s", linebuffer);
187  	      clearLine(linebuffer, linecnt);
188  	   }
189  	}
190  	
191  	/** appends extension to line and prints it to the give file stream if the
192  	 *  line exceeded the length given in the define GMS_PRINTLEN */
193  	static
194  	void appendLine(
195  	   SCIP*                 scip,               /**< SCIP data structure */
196  	   FILE*                 file,               /**< output file (or NULL for standard output) */
197  	   char*                 linebuffer,         /**< line */
198  	   int*                  linecnt,            /**< number of characters in line */
199  	   const char*           extension           /**< string to extend the line */
200  	   )
201  	{
202  	   size_t len;
203  	   assert( scip != NULL );
204  	   assert( linebuffer != NULL );
205  	   assert( linecnt != NULL );
206  	   assert( extension != NULL );
207  	   assert( strlen(linebuffer) + strlen(extension) < GMS_MAX_PRINTLEN );
208  	
209  	   /* NOTE: avoid
210  	    *   sprintf(linebuffer, "%s%s", linebuffer, extension); 
211  	    * because of overlapping memory areas in memcpy used in sprintf.
212  	    */
213  	   len = strlen(linebuffer);
214  	   (void) strncat(linebuffer, extension, GMS_MAX_PRINTLEN - len);
215  	
216  	   (*linecnt) += (int) strlen(extension);
217  	
218  	   SCIPdebugMsg(scip, "linebuffer <%s>, length = %lu\n", linebuffer, (unsigned long)len);
219  	
220  	   if( (*linecnt) > GMS_PRINTLEN )
221  	      endLine(scip, file, linebuffer, linecnt);
222  	}
223  	
224  	/** checks string for occurences of bad symbols and replace those by '_' */
225  	static
226  	void conformName(
227  	   char*                 name                /**< string to adjust */
228  	   )
229  	{
230  	   const char* badchar;
231  	
232  	   assert( name != NULL );
233  	
234  	   for( badchar = badchars; *badchar; ++badchar )
235  	   {
236  	      char* c = strchr(name, *badchar);
237  	
238  	      while( c != NULL )
239  	      {
240  	         assert( *c == *badchar );
241  	
242  	         *c = '_';
243  	         c = strchr(c, *badchar);
244  	      }
245  	   }
246  	}
247  	
248  	/* print first len-1 characters of name to string s and replace '#', '*', '+', '/', and '-' by '_' if necessary */
249  	static
250  	SCIP_RETCODE printConformName(
251  	   SCIP*                 scip,               /**< SCIP data structure */
252  	   char*                 t,                  /**< target string */
253  	   int                   len,                /**< length of t */
254  	   const char*           name                /**< source string or format string */
255  	   )
256  	{
257  	   SCIP_Bool replaceforbiddenchars;
258  	
259  	   assert( t != NULL );
260  	   assert( len > 0 );
261  	
262  	   SCIP_CALL( SCIPgetBoolParam(scip, "reading/gmsreader/replaceforbiddenchars", &replaceforbiddenchars) );
263  	
264  	   (void) SCIPsnprintf(t, len, "%s", name);
265  	
266  	   if( replaceforbiddenchars )
267  	      conformName(t);
268  	
269  	   return SCIP_OKAY;
270  	}
271  	
272  	
273  	/* retransform to active variables and print in GAMS format to file stream with surrounding bracket, pre- and suffix */
274  	static
275  	SCIP_RETCODE printActiveVariables(
276  	   SCIP*                 scip,               /**< SCIP data structure */
277  	   FILE*                 file,               /**< output file (or NULL for standard output) */
278  	   char*                 linebuffer,         /**< line */
279  	   int*                  linecnt,            /**< number of characters in line */
280  	   const char*           prefix,             /**< prefix (maybe NULL) */
281  	   const char*           suffix,             /**< suffix (maybe NULL) */
282  	   int                   nvars,              /**< number of variables */
283  	   SCIP_VAR**            vars,               /**< array of variables */
284  	   SCIP_Real*            vals,               /**< array of values (or NULL if all ones) */
285  	   SCIP_Bool             transformed         /**< transformed constraint? */
286  	   )
287  	{
288  	   int v;
289  	   int closingbracket;
290  	
291  	   SCIP_VAR* var;
292  	   char varname[GMS_MAX_NAMELEN];
293  	   char buffer[GMS_MAX_PRINTLEN];
294  	   char ext[GMS_MAX_PRINTLEN];
295  	
296  	   SCIP_VAR** activevars = NULL;
297  	   SCIP_Real* activevals = NULL;
298  	   int nactivevars;
299  	   int activevarssize;
300  	   SCIP_Real activeconstant = 0.0;
301  	
302  	   assert( scip != NULL );
303  	   assert( vars != NULL || nvars == 0 );
304  	
305  	   if( *linecnt == 0 )
306  	      /* we start a new line; therefore we tab this line */
307  	      appendLine(scip, file, linebuffer, linecnt, "     ");
308  	
309  	   if( nvars == 0 )
310  	   {
311  	      (void) SCIPsnprintf(buffer, GMS_MAX_PRINTLEN, "%s(0)%s", prefix != NULL ? prefix : "", suffix != NULL ? suffix : "");
312  	
313  	      appendLine(scip, file, linebuffer, linecnt, buffer);
314  	   }
315  	   else
316  	   {
317  	      nactivevars = nvars;
318  	
319  	      /* duplicate variable and value array */
320  	      SCIP_CALL( SCIPduplicateBufferArray(scip, &activevars, vars, nactivevars) );
321  	      if( vals != NULL )
322  	      {
323  	         SCIP_CALL( SCIPduplicateBufferArray(scip, &activevals, vals, nactivevars) );
324  	      }
325  	      else
326  	      {
327  	         SCIP_CALL( SCIPallocBufferArray(scip, &activevals, nactivevars) );
328  	
329  	         for( v = 0; v < nactivevars; ++v )
330  	            activevals[v] = 1.0;
331  	      }
332  	      activevarssize = nactivevars;
333  	
334  	      /* retransform given variables to active variables */
335  	      SCIP_CALL( getActiveVariables(scip, &activevars, &activevals, &nactivevars, &activevarssize, &activeconstant, transformed) );
336  	
337  	      assert( nactivevars == 0 || activevals != NULL );
338  	
339  	      if( nactivevars == 0 && SCIPisZero(scip, activeconstant) )
340  	      {
341  	         if( *linecnt == 0 )
342  	            /* we start a new line; therefore we tab this line */
343  	            appendLine(scip, file, linebuffer, linecnt, "     ");
344  	
345  	         (void) SCIPsnprintf(buffer, GMS_MAX_PRINTLEN, "%s(0)%s", prefix != NULL ? prefix : "", suffix != NULL ? suffix : "");
346  	
347  	         appendLine(scip, file, linebuffer, linecnt, buffer);
348  	      }
349  	      else
350  	      {
351  	         /* buffer prefix */
352  	         (void) SCIPsnprintf(ext, GMS_MAX_PRINTLEN, "%s(", prefix != NULL ? prefix : "");
353  	
354  	         /* find position of closing bracket */
355  	         closingbracket = nactivevars;
356  	         if( SCIPisZero(scip, activeconstant) )
357  	         {
358  	            do
359  	               --closingbracket;
360  	            while( SCIPisZero(scip, activevals[closingbracket]) && closingbracket > 0 );
361  	         }
362  	
363  	         /* print active variables */
364  	         for( v = 0; v < nactivevars; ++v )
365  	         {
366  	            var = activevars[v];
367  	            assert( var != NULL );
368  	
369  	            if( !SCIPisZero(scip, activevals[v]) )
370  	            {
371  	               if( *linecnt == 0 )
372  	                  /* we start a new line; therefore we tab this line */
373  	                  appendLine(scip, file, linebuffer, linecnt, "     ");
374  	
375  	               SCIP_CALL( printConformName(scip, varname, GMS_MAX_NAMELEN, SCIPvarGetName(var)) );
376  	
377  	               if( SCIPisEQ(scip, activevals[v], 1.0) )
378  	                  (void) SCIPsnprintf(buffer, GMS_MAX_PRINTLEN, "%s%s%s%s%s", ext, strchr(ext, '(') == NULL ? "+" : "",
379  	                        varname, (v == closingbracket) ? ")" : "", (v == closingbracket && suffix) ? suffix : "");
380  	               else if( SCIPisEQ(scip, activevals[v], -1.0) )
381  	                  (void) SCIPsnprintf(buffer, GMS_MAX_PRINTLEN, "%s-%s%s%s", ext,
382  	                        varname, (v == closingbracket) ? ")" : "", (v == closingbracket && suffix) ? suffix : "");
383  	               else if( strchr(ext, '(') != NULL )
384  	                  (void) SCIPsnprintf(buffer, GMS_MAX_PRINTLEN, "%s%.15g*%s%s%s", ext,
385  	                        activevals[v], varname, (v == closingbracket) ? ")" : "", (v == closingbracket && suffix) ? suffix : "");
386  	               else
387  	                  (void) SCIPsnprintf(buffer, GMS_MAX_PRINTLEN, "%s%+.15g*%s%s%s", ext,
388  	                        activevals[v], varname, (v == closingbracket) ? ")" : "", (v == closingbracket && suffix) ? suffix : "");
389  	
390  	               appendLine(scip, file, linebuffer, linecnt, buffer);
391  	
392  	               (void) SCIPsnprintf(ext, GMS_MAX_PRINTLEN, (*linecnt == 0) ? "" : " ");
393  	            }
394  	         }
395  	
396  	         /* print active constant */
397  	         if( !SCIPisZero(scip, activeconstant) )
398  	         {
399  	            if( *linecnt == 0 )
400  	               /* we start a new line; therefore we tab this line */
401  	               appendLine(scip, file, linebuffer, linecnt, "     ");
402  	
403  	            (void) SCIPsnprintf(buffer, GMS_MAX_PRINTLEN, "%s%+.15g)%s", ext, activeconstant, suffix ? suffix : "");
404  	
405  	            appendLine(scip, file, linebuffer, linecnt, buffer);
406  	         }
407  	         /* nothing has been printed, yet */
408  	         else if( strchr(ext, '(') != NULL )
409  	         {
410  	            if( *linecnt == 0 )
411  	               /* we start a new line; therefore we tab this line */
412  	               appendLine(scip, file, linebuffer, linecnt, "     ");
413  	
414  	            (void) SCIPsnprintf(buffer, GMS_MAX_PRINTLEN, "%s(0)%s", prefix ? prefix : "", suffix ? suffix : "");
415  	
416  	            appendLine(scip, file, linebuffer, linecnt, buffer);
417  	         }
418  	      }
419  	
420  	      /* free buffer arrays */
421  	      SCIPfreeBufferArray(scip, &activevars);
422  	      SCIPfreeBufferArray(scip, &activevals);
423  	   }
424  	
425  	   return SCIP_OKAY;
426  	}
427  	
428  	
429  	/* print linear row in GAMS format to file stream (without retransformation to active variables) */
430  	static
431  	SCIP_RETCODE printLinearRow(
432  	   SCIP*                 scip,               /**< SCIP data structure */
433  	   FILE*                 file,               /**< output file (or NULL for standard output) */
434  	   const char*           rowname,            /**< row name */
435  	   const char*           rownameextension,   /**< row name extension */
436  	   const char*           type,               /**< row type ("=e=", "=l=", or "=g=") */
437  	   int                   nvars,              /**< number of variables */
438  	   SCIP_VAR**            vars,               /**< array of variables */
439  	   SCIP_Real*            vals,               /**< array of values */
440  	   SCIP_Real             rhs                 /**< right hand side */
441  	   )
442  	{
443  	   int v;
444  	   char linebuffer[GMS_MAX_PRINTLEN+1] = { '\0' };
445  	   int linecnt;
446  	
447  	   SCIP_VAR* var;
448  	   char varname[GMS_MAX_NAMELEN];
449  	   char consname[GMS_MAX_NAMELEN + 3]; /* four extra characters for ' ..' */
450  	   char buffer[GMS_MAX_PRINTLEN];
451  	
452  	   assert( scip != NULL );
453  	   assert( strcmp(type, "=e=") == 0 || strcmp(type, "=l=") == 0 || strcmp(type, "=g=") == 0);
454  	   assert( nvars == 0 || (vars != NULL && vals != NULL) );
455  	
456  	   clearLine(linebuffer, &linecnt);
457  	
458  	   /* start each line with a space */
459  	   appendLine(scip, file, linebuffer, &linecnt, " ");
460  	
461  	   /* print row name */
462  	   if( strlen(rowname) > 0 || strlen(rownameextension) > 0 )
463  	   {
464  	      (void) SCIPsnprintf(buffer, GMS_MAX_NAMELEN + 3, "%s%s ..", rowname, rownameextension);
465  	      SCIP_CALL( printConformName(scip, consname, GMS_MAX_NAMELEN + 3, buffer) );
466  	      appendLine(scip, file, linebuffer, &linecnt, consname);
467  	   }
468  	
469  	   /* print coefficients */
470  	   if( nvars == 0 )
471  	   {
472  	      /* we start a new line; therefore we tab this line */
473  	      if( linecnt == 0 )
474  	         appendLine(scip, file, linebuffer, &linecnt, "     ");
475  	
476  	      (void) SCIPsnprintf(buffer, GMS_MAX_PRINTLEN, " 0");
477  	
478  	      appendLine(scip, file, linebuffer, &linecnt, buffer);
479  	   }
480  	
481  	   for( v = 0; v < nvars; ++v )
482  	   {
483  	      assert(vars != NULL);  /* for lint */
484  	      assert(vals != NULL);
485  	
486  	      var = vars[v];
487  	      assert( var != NULL );
488  	
489  	      /* we start a new line; therefore we tab this line */
490  	      if( linecnt == 0 )
491  	         appendLine(scip, file, linebuffer, &linecnt, "     ");
492  	
493  	      SCIP_CALL( printConformName(scip, varname, GMS_MAX_NAMELEN, SCIPvarGetName(var)) );
494  	      (void) SCIPsnprintf(buffer, GMS_MAX_PRINTLEN, " %+.15g*%s", vals[v], varname);
495  	
496  	      appendLine(scip, file, linebuffer, &linecnt, buffer);
497  	   }
498  	
499  	   /* print right hand side */
500  	   if( SCIPisZero(scip, rhs) )
501  	      rhs = 0.0;
502  	
503  	   (void) SCIPsnprintf(buffer, GMS_MAX_PRINTLEN, " %s %.15g;", type, rhs);
504  	
505  	   /* we start a new line; therefore we tab this line */
506  	   if( linecnt == 0 )
507  	      appendLine(scip, file, linebuffer, &linecnt, "     ");
508  	   appendLine(scip, file, linebuffer, &linecnt, buffer);
509  	
510  	   endLine(scip, file, linebuffer, &linecnt);
511  	
512  	   return SCIP_OKAY;
513  	}
514  	
515  	
516  	/** prints given linear constraint information in GAMS format to file stream */
517  	static
518  	SCIP_RETCODE printLinearCons(
519  	   SCIP*                 scip,               /**< SCIP data structure */
520  	   FILE*                 file,               /**< output file (or NULL for standard output) */
521  	   const char*           rowname,            /**< name of the row */
522  	   int                   nvars,              /**< number of variables */
523  	   SCIP_VAR**            vars,               /**< array of variables */
524  	   SCIP_Real*            vals,               /**< array of coefficients values (or NULL if all coefficient values are 1) */
525  	   SCIP_Real             lhs,                /**< left hand side */
526  	   SCIP_Real             rhs,                /**< right hand side */
527  	   SCIP_Bool             transformed         /**< transformed constraint? */
528  	   )
529  	{
530  	   int v;
531  	   SCIP_VAR** activevars = NULL;
532  	   SCIP_Real* activevals = NULL;
533  	   int nactivevars;
534  	   SCIP_Real activeconstant = 0.0;
535  	   int activevarssize;
536  	
537  	   assert( scip != NULL );
538  	   assert( rowname != NULL );
539  	
540  	   /* The GAMS format does not forbid that the variable array is empty */
541  	   assert( nvars == 0 || vars != NULL );
542  	
543  	   assert( lhs <= rhs );
544  	
545  	   if( SCIPisInfinity(scip, -lhs) && SCIPisInfinity(scip, rhs) )
546  	      return SCIP_OKAY;
547  	
548  	   nactivevars = nvars;
549  	   if( nvars > 0 ) 
550  	   {
551  	      /* duplicate variable and value array */
552  	      SCIP_CALL( SCIPduplicateBufferArray(scip, &activevars, vars, nactivevars) );
553  	      if( vals != NULL )
554  	      {
555  	         SCIP_CALL( SCIPduplicateBufferArray(scip, &activevals, vals, nactivevars) );
556  	      }
557  	      else
558  	      {
559  	         SCIP_CALL( SCIPallocBufferArray(scip, &activevals, nactivevars) );
560  	
561  	         for( v = 0; v < nactivevars; ++v )
562  	            activevals[v] = 1.0;
563  	      }
564  	      activevarssize = nactivevars;
565  	
566  	      /* retransform given variables to active variables */
567  	      SCIP_CALL( getActiveVariables(scip, &activevars, &activevals, &nactivevars, &activevarssize, &activeconstant, transformed) );
568  	   }
569  	
570  	   /* print row(s) in GAMS format */
571  	   if( SCIPisEQ(scip, lhs, rhs) )
572  	   {
573  	      assert( !SCIPisInfinity(scip, rhs) );
574  	
575  	      /* print equality constraint */
576  	      SCIP_CALL( printLinearRow(scip, file, rowname, "", "=e=", 
577  	            nactivevars, activevars, activevals, rhs - activeconstant) );
578  	   }
579  	   else
580  	   {
581  	      if( !SCIPisInfinity(scip, -lhs) )
582  	      {
583  	         /* print inequality ">=" */
584  	         SCIP_CALL( printLinearRow(scip, file, rowname, SCIPisInfinity(scip, rhs) ? "" : "_lhs", "=g=",
585  	               nactivevars, activevars, activevals, lhs - activeconstant) );
586  	      }
587  	      if( !SCIPisInfinity(scip, rhs) )
588  	      {
589  	         /* print inequality "<=" */
590  	         SCIP_CALL( printLinearRow(scip, file, rowname, SCIPisInfinity(scip, -lhs) ? "" : "_rhs", "=l=",
591  	               nactivevars, activevars, activevals, rhs - activeconstant) );
592  	      }
593  	   }
594  	
595  	   if( nvars > 0 )
596  	   {
597  	      /* free buffer arrays */
598  	      SCIPfreeBufferArray(scip, &activevars);
599  	      SCIPfreeBufferArray(scip, &activevals);
600  	   }
601  	
602  	   return SCIP_OKAY;
603  	}
604  	
605  	
606  	/* print indicator constraint in some GAMS format to file stream (performing retransformation to active variables)
607  	 * The constraints are of the following form:
608  	 * \f[
609  	 *    z = 1 -> s = 0
610  	 * \f]
611  	 * */
612  	static
613  	SCIP_RETCODE printIndicatorCons(
614  	   SCIP*                 scip,               /**< SCIP data structure */
615  	   FILE*                 file,               /**< output file (or NULL for standard output) */
616  	   const char*           rowname,            /**< row name */
617  	   SCIP_VAR*             z,                  /**< indicating variable (binary) */
618  	   SCIP_VAR*             s,                  /**< slack variable */
619  	   SCIP_Bool*            sossetdeclr,        /**< buffer to store whether we declared the SOS set for indicator reform */
620  	   SCIP_Bool             transformed         /**< transformed constraint? */
621  	   )
622  	{
623  	   char linebuffer[GMS_MAX_PRINTLEN+1] = { '\0' };
624  	   int linecnt;
625  	   SCIP_Real coef;
626  	   char indicatorform;
627  	
628  	   char consname[GMS_MAX_NAMELEN + 30];
629  	   char buffer[GMS_MAX_PRINTLEN];
630  	
631  	   assert( scip != NULL );
632  	   assert( strlen(rowname) > 0 );
633  	   assert( z != NULL );
634  	   assert( s != NULL );
635  	   assert( SCIPvarIsBinary(z) );
636  	   assert( sossetdeclr != NULL );
637  	
638  	   clearLine(linebuffer, &linecnt);
639  	
640  	   /* start each line with a space */
641  	   appendLine(scip, file, linebuffer, &linecnt, " ");
642  	
643  	   SCIP_CALL( SCIPgetCharParam(scip, "reading/gmsreader/indicatorreform", &indicatorform) );
644  	
645  	   switch( indicatorform )
646  	   {
647  	      case 'b':
648  	      {
649  	         /* print row name */
650  	         (void) SCIPsnprintf(buffer, GMS_MAX_NAMELEN + 3, "%s ..", rowname);
651  	         SCIP_CALL( printConformName(scip, consname, GMS_MAX_NAMELEN + 3, buffer) );
652  	
653  	         appendLine(scip, file, linebuffer, &linecnt, consname);
654  	
655  	         /* write as s <= upperbound(s)*(1-z) or s <= upperbound(s) * negation(z) */
656  	         coef = 1.0;
657  	         SCIP_CALL( printActiveVariables(scip, file, linebuffer, &linecnt, NULL, " =l= ", 1, &s, &coef, transformed) );
658  	
659  	         coef = SCIPvarGetUbGlobal(s);
660  	         if( SCIPisInfinity(scip, coef) )
661  	         {
662  	            SCIP_CALL( SCIPgetRealParam(scip, "reading/gmsreader/bigmdefault", &coef) );
663  	
664  	            SCIPwarningMessage(scip, "do not have upper bound on slack variable <%s> in indicator constraint <%s>, will use M = %g.\n",
665  	               SCIPvarGetName(s), rowname, coef);
666  	         }
667  	
668  	         if( SCIPvarIsNegated(z) )
669  	         {
670  	            SCIP_CALL( SCIPgetNegatedVar(scip, z, &z) );
671  	            SCIP_CALL( printActiveVariables(scip, file, linebuffer, &linecnt, "", ";", 1, &z, &coef, transformed) );
672  	         }
673  	         else
674  	         {
675  	            (void) SCIPsnprintf(buffer, GMS_MAX_PRINTLEN, "%.15g + ", coef);
676  	
677  	            coef = -coef;
678  	            SCIP_CALL( printActiveVariables(scip, file, linebuffer, &linecnt, buffer, ";", 1, &z, &coef, transformed) );
679  	         }
680  	
681  	         break;
682  	      }
683  	
684  	      case 's':
685  	      {
686  	         /* write as
687  	          * sos1 Variable name_sos(sosset);
688  	          *  name_soseq(sosset).. name_sos(sosset) =e= s$(sameas(sosset,'slack') + z$(sameas(sosset,'bin'));
689  	          */
690  	         coef = 1.0;
691  	         SCIP_CALL( printConformName(scip, consname, GMS_MAX_NAMELEN, rowname) );
692  	
693  	         /* declare set for SOS1 declarations from reformulation of indicator, if needed */
694  	         if( !*sossetdeclr )
695  	         {
696  	            SCIPinfoMessage(scip, file, " Set sosset / slack, bin /;\n");
697  	            *sossetdeclr = TRUE;
698  	         }
699  	
700  	         (void) SCIPsnprintf(buffer, GMS_MAX_PRINTLEN, "sos1 Variable %s_sos(sosset);", consname);
701  	         appendLine(scip, file, linebuffer, &linecnt, buffer);
702  	         endLine(scip, file, linebuffer, &linecnt);
703  	
704  	         (void) SCIPsnprintf(buffer, GMS_MAX_PRINTLEN, " %s(sosset).. %s_sos(sosset) =e= ", consname, consname);
705  	         appendLine(scip, file, linebuffer, &linecnt, buffer);
706  	         SCIP_CALL( printActiveVariables(scip, file, linebuffer, &linecnt, NULL, "$sameas(sosset,'slack')", 1, &s, &coef, transformed) );
707  	         if( SCIPvarIsNegated(z) )
708  	         {
709  	            SCIP_CALL( SCIPgetNegatedVar(scip, z, &z) );
710  	            SCIP_CALL( printActiveVariables(scip, file, linebuffer, &linecnt, " + (1-(", "))$sameas(sosset,'bin');", 1, &z, &coef, transformed) );
711  	         }
712  	         else
713  	         {
714  	            SCIP_CALL( printActiveVariables(scip, file, linebuffer, &linecnt, " + ", "$sameas(sosset,'bin');", 1, &z, &coef, transformed) );
715  	         }
716  	         endLine(scip, file, linebuffer, &linecnt);
717  	
718  	         break;
719  	      }
720  	
721  	      default:
722  	         SCIPerrorMessage("wrong value '%c' for parameter reading/gmsreader/indicatorreform\n", indicatorform);
723  	         return SCIP_ERROR;
724  	   }
725  	
726  	   endLine(scip, file, linebuffer, &linecnt);
727  	
728  	   return SCIP_OKAY;
729  	}
730  	
731  	/* print SOS constraint in some GAMS format to file stream (performing retransformation to active variables)
732  	 *
733  	 * write as
734  	 * Set name_sosset /1*nvars/;
735  	 * SOS1/2 Variable name_sosvar(name_sosset); name_sosvar.lo(name_sosset) = -inf;
736  	 * Equation name_sosequ(e1_sosset);
737  	 * name_sosequ(name_sosset).. name_sosvar(e1_sosset) =e=
738  	 * vars[0]$sameas(name_sosset, '1') + vars[1]$sameas(name_sosset, '2') + ... + vars[nvars-1]$sameas(name_sosset, nvars);
739  	 */
740  	static
741  	SCIP_RETCODE printSOSCons(
742  	   SCIP*                 scip,               /**< SCIP data structure */
743  	   FILE*                 file,               /**< output file (or NULL for standard output) */
744  	   const char*           rowname,            /**< row name */
745  	   int                   nvars,              /**< number of variables in SOS */
746  	   SCIP_VAR**            vars,               /**< variables in SOS */
747  	   int                   sostype,            /**< type of SOS: 1 or 2 */
748  	   SCIP_Bool             transformed         /**< transformed constraint? */
749  	   )
750  	{
751  	   char linebuffer[GMS_MAX_PRINTLEN+1] = { '\0' };
752  	   int linecnt;
753  	   SCIP_Real coef;
754  	   int v;
755  	
756  	   char consname[GMS_MAX_NAMELEN + 30];
757  	   char buffer[GMS_MAX_PRINTLEN];
758  	
759  	   assert( scip != NULL );
760  	   assert( strlen(rowname) > 0 );
761  	   assert( vars != NULL || nvars == 0 );
762  	   assert( sostype == 1 || sostype == 2 );
763  	
764  	   clearLine(linebuffer, &linecnt);
765  	
766  	   /* start each line with a space */
767  	   appendLine(scip, file, linebuffer, &linecnt, " ");
768  	
769  	   SCIP_CALL( printConformName(scip, consname, GMS_MAX_NAMELEN, rowname) );
770  	
771  	   (void) SCIPsnprintf(buffer, GMS_MAX_PRINTLEN, "Set %s_sosset /1*%d/;", consname, nvars);
772  	   appendLine(scip, file, linebuffer, &linecnt, buffer);
773  	   endLine(scip, file, linebuffer, &linecnt);
774  	
775  	   /* explicitly set lower bound of SOS variables to -inf, as GAMS default is 0.0 */
776  	   (void) SCIPsnprintf(buffer, GMS_MAX_PRINTLEN, " SOS%d Variable %s_sosvar(%s_sosset); %s_sosvar.lo(%s_sosset) = -inf;", sostype, consname, consname, consname, consname);
777  	   appendLine(scip, file, linebuffer, &linecnt, buffer);
778  	   endLine(scip, file, linebuffer, &linecnt);
779  	
780  	   (void) SCIPsnprintf(buffer, GMS_MAX_PRINTLEN, " %s(%s_sosset).. %s_sosvar(%s_sosset) =e= ", consname, consname, consname, consname);
781  	   appendLine(scip, file, linebuffer, &linecnt, buffer);
782  	   endLine(scip, file, linebuffer, &linecnt);
783  	
784  	   coef = 1.0;
785  	   for( v = 0; v < nvars; ++v )
786  	   {
787  	      (void) SCIPsnprintf(buffer, GMS_MAX_PRINTLEN, "$sameas(%s_sosset,'%d')", consname, v+1);
788  	      SCIP_CALL( printActiveVariables(scip, file, linebuffer, &linecnt, v > 0 ? " + " : NULL, buffer, 1, &vars[v], &coef, transformed) ); /*lint !e613*/
789  	   }
790  	   appendLine(scip, file, linebuffer, &linecnt, ";");
791  	   endLine(scip, file, linebuffer, &linecnt);
792  	
793  	   return SCIP_OKAY;
794  	}
795  	
796  	/** prints expression in GAMS format to file stream */
797  	static
798  	SCIP_RETCODE printExpr(
799  	   SCIP*                 scip,               /**< SCIP data structure */
800  	   FILE*                 file,               /**< output file (or NULL for standard output) */
801  	   char*                 linebuffer,         /**< line buffer of length GMS_MAX_PRINTLEN */
802  	   int*                  linecnt,            /**< number of characters in line so far */
803  	   SCIP_Bool*            nsmooth,            /**< buffer to store whether we printed a nonsmooth function */
804  	   SCIP_Bool*            nqcons,             /**< buffer to update whether we are still quadratic */
805  	   SCIP_Bool             transformed,        /**< expression belongs to transformed constraint? */
806  	   SCIP_EXPR*            expr                /**< expression to print */
807  	   )
808  	{
809  	   SCIP_EXPRITER* it;
810  	   SCIP_EXPRITER_STAGE stage;
811  	   int currentchild;
812  	   unsigned int parentprecedence;
813  	   long int fpos;
814  	   SCIP_VAR** activevars = NULL;
815  	   SCIP_Real* activecoefs = NULL;
816  	   int nactivevars;
817  	   int activevarssize;
818  	   SCIP_Real activeconstant = 0.0;
819  	   char varname[GMS_MAX_NAMELEN];
820  	   unsigned int sumprecedence;
821  	
822  	   assert(scip != NULL);
823  	   assert(linebuffer != NULL);
824  	   assert(linecnt != NULL);
825  	   assert(nsmooth != NULL);
826  	   assert(nqcons != NULL);
827  	   assert(expr != NULL);
828  	
829  	   if( file == NULL )
830  	      file = stdout;
831  	
832  	   appendLine(scip, file, linebuffer, linecnt, " ");
833  	
834  	   /* store file position at begin of current line */
835  	   fpos = ftell(file) - *linecnt;
836  	
837  	   /* print out current buffer, as we print the expression directly to file */
838  	   endLineNoNewline(scip, file, linebuffer, linecnt);
839  	
840  	   activevarssize = 5;
841  	   SCIP_CALL( SCIPallocBufferArray(scip, &activevars, activevarssize) );
842  	   SCIP_CALL( SCIPallocBufferArray(scip, &activecoefs, activevarssize) );
843  	
844  	   SCIP_CALL( SCIPcreateExpriter(scip, &it) );
845  	   SCIP_CALL( SCIPexpriterInit(it, expr, SCIP_EXPRITER_DFS, TRUE) );
846  	   SCIPexpriterSetStagesDFS(it, SCIP_EXPRITER_ALLSTAGES);
847  	
848  	   sumprecedence = SCIPexprhdlrGetPrecedence(SCIPgetExprhdlrSum(scip));
849  	
850  	   while( !SCIPexpriterIsEnd(it) )
851  	   {
852  	      stage = SCIPexpriterGetStageDFS(it);
853  	
854  	      if( stage == SCIP_EXPRITER_VISITEDCHILD || stage == SCIP_EXPRITER_VISITINGCHILD )
855  	         currentchild = SCIPexpriterGetChildIdxDFS(it);
856  	      else
857  	         currentchild = -1;
858  	
859  	      if( SCIPexpriterGetParentDFS(it) != NULL )
860  	         parentprecedence = SCIPexprhdlrGetPrecedence(SCIPexprGetHdlr(SCIPexpriterGetParentDFS(it)));
861  	      else
862  	         parentprecedence = 0;
863  	
864  	      /* print a newline, if we have printed at least GMS_PRINTLEN chars since the last newline */
865  	      if( ftell(file) > fpos + GMS_PRINTLEN )
866  	      {
867  	         SCIPinfoMessage(scip, file, "\n     ");
868  	         /* store file position at begin of current line again; the -5 is for the whitespace we printed already */
869  	         fpos = ftell(file) - 5;
870  	      }
871  	
872  	      if( SCIPisExprVar(scip, expr) )
873  	      {
874  	         /* special handler for variables:
875  	          * - map to active variables
876  	          * - pass variable name through printConformName
877  	          */
878  	         if( stage == SCIP_EXPRITER_ENTEREXPR )
879  	         {
880  	            activevars[0] = SCIPgetVarExprVar(expr);
881  	            activecoefs[0] = 1.0;
882  	            nactivevars = 1;
883  	
884  	            SCIP_CALL( getActiveVariables(scip, &activevars, &activecoefs, &nactivevars, &activevarssize, &activeconstant, transformed) );
885  	
886  	            if( nactivevars == 1 && activecoefs[0] == 1.0 && activeconstant == 0.0 )
887  	            {
888  	               SCIP_CALL( printConformName(scip, varname, GMS_MAX_NAMELEN, SCIPvarGetName(activevars[0])) );
889  	               SCIPinfoMessage(scip, file, "%s", varname);
890  	            }
891  	            else
892  	            {
893  	               SCIP_Bool needsign = FALSE;
894  	               int i;
895  	
896  	               /* do as in print of expr_sum: an opening parenthesis may be required */
897  	               if( sumprecedence <= parentprecedence )
898  	                  SCIPinfoMessage(scip, file, "(");
899  	
900  	               if( activeconstant != 0.0 )
901  	               {
902  	                  SCIPinfoMessage(scip, file, "%.15g", activeconstant);
903  	                  needsign = TRUE;
904  	               }
905  	               for( i = 0; i < nactivevars; ++i )
906  	               {
907  	                  if( REALABS(activecoefs[i]) != 1.0 )
908  	                  {
909  	                     SCIPinfoMessage(scip, file, needsign ? "%+.15g*" : "%.15g*", activecoefs[i]);
910  	                  }
911  	                  else if( activecoefs[i] == 1.0 && needsign )
912  	                  {
913  	                     SCIPinfoMessage(scip, file, "+");
914  	                  }
915  	                  else if( activecoefs[i] == -1.0 )
916  	                  {
917  	                     SCIPinfoMessage(scip, file, "-");
918  	                  }
919  	
920  	                  SCIP_CALL( printConformName(scip, varname, GMS_MAX_NAMELEN, SCIPvarGetName(activevars[0])) );
921  	                  SCIPinfoMessage(scip, file, "%s", varname);
922  	
923  	                  needsign = TRUE;
924  	
925  	                  /* check whether it is time for a linebreak */
926  	                  if( ftell(file) > fpos + GMS_PRINTLEN )
927  	                  {
928  	                     SCIPinfoMessage(scip, file, "\n     ");
929  	                     fpos = ftell(file) - 5;
930  	                  }
931  	               }
932  	
933  	               if( sumprecedence <= parentprecedence )
934  	                  SCIPinfoMessage(scip, file, ")");
935  	            }
936  	         }
937  	      }
938  	      else if( SCIPisExprPower(scip, expr) )
939  	      {
940  	         /* special handler for power */
941  	         SCIP_Real exponent = SCIPgetExponentExprPow(expr);
942  	
943  	         if( exponent == 2.0 )
944  	         {
945  	            /* write squares as "sqr(child)" */
946  	            if( stage == SCIP_EXPRITER_ENTEREXPR )
947  	               SCIPinfoMessage(scip, file, "sqr(");
948  	            else if( stage == SCIP_EXPRITER_LEAVEEXPR )
949  	               SCIPinfoMessage(scip, file, ")");
950  	         }
951  	         else if( EPSISINT(exponent, 0.0) )  /*lint !e835*/
952  	         {
953  	            /* write integer powers as "power(child, exponent)" */
954  	            if( stage == SCIP_EXPRITER_ENTEREXPR )
955  	               SCIPinfoMessage(scip, file, "power(");
956  	            else if( stage == SCIP_EXPRITER_LEAVEEXPR )
957  	               SCIPinfoMessage(scip, file, ",%g)", exponent);
958  	            /* if power but not square, then we are no longer quadratic */
959  	            *nqcons = FALSE;
960  	         }
961  	         else if( exponent == 0.5 )
962  	         {
963  	            /* write square roots as "sqrt(child)" */
964  	            if( stage == SCIP_EXPRITER_ENTEREXPR )
965  	               SCIPinfoMessage(scip, file, "sqrt(");
966  	            else if( stage == SCIP_EXPRITER_LEAVEEXPR )
967  	               SCIPinfoMessage(scip, file, ")");
968  	            *nqcons = FALSE;
969  	         }
970  	         else
971  	         {
972  	            /* write any other power as "(child)**exponent" */
973  	            if( stage == SCIP_EXPRITER_ENTEREXPR )
974  	               SCIPinfoMessage(scip, file, "(");
975  	            else if( stage == SCIP_EXPRITER_LEAVEEXPR )
976  	               SCIPinfoMessage(scip, file, exponent >= 0.0 ? ")**%.15g" : ")**(%.15g)", exponent);
977  	            *nqcons = FALSE;
978  	         }
979  	      }
980  	      else
981  	      {
982  	         /* for any other expression, use the print callback of the exprhdlr */
983  	         SCIP_CALL( SCIPcallExprPrint(scip, expr, stage, currentchild, parentprecedence, file) );
984  	
985  	         if( !*nsmooth )
986  	         {
987  	            /* check for expression types that require changing modeltype from NLP to DNLP: currently only abs */
988  	            if( SCIPisExprAbs(scip, expr) )
989  	            {
990  	               *nsmooth = TRUE;
991  	               *nqcons = FALSE;
992  	            }
993  	         }
994  	
995  	         /* if still quadratic, then check whether expression type is one that cannot occur in quadratics
996  	          * allowed are sum, product, value, var, and power; the latter two were handled above
997  	          */
998  	         if( *nqcons && !SCIPisExprSum(scip, expr) && !SCIPisExprProduct(scip, expr) && !SCIPisExprValue(scip, expr) )
999  	            *nqcons = FALSE;
1000 	      }
1001 	
1002 	      expr = SCIPexpriterGetNext(it);
1003 	   }
1004 	
1005 	   SCIPfreeExpriter(&it);
1006 	
1007 	   SCIPfreeBufferArray(scip, &activecoefs);
1008 	   SCIPfreeBufferArray(scip, &activevars);
1009 	
1010 	   return SCIP_OKAY;
1011 	}
1012 	
1013 	/** print nonlinear row in GAMS format to file stream */
1014 	static
1015 	SCIP_RETCODE printNonlinearRow(
1016 	   SCIP*                 scip,               /**< SCIP data structure */
1017 	   FILE*                 file,               /**< output file (or NULL for standard output) */
1018 	   const char*           rowname,            /**< row name */
1019 	   const char*           rownameextension,   /**< row name extension */
1020 	   const char*           type,               /**< row type ("=e=", "=l=", or "=g=") */
1021 	   SCIP_EXPR*            expr,               /**< expression */
1022 	   SCIP_Real             rhs,                /**< right hand side */
1023 	   SCIP_Bool             transformed,        /**< transformed constraint? */
1024 	   SCIP_Bool*            nsmooth,            /**< buffer to store whether we printed a nonsmooth function */
1025 	   SCIP_Bool*            nqcons              /**< buffer to update whether we are still quadratic */
1026 	   )
1027 	{
1028 	   char linebuffer[GMS_MAX_PRINTLEN+1] = { '\0' };
1029 	   int linecnt;
1030 	   char consname[GMS_MAX_NAMELEN + 3];
1031 	   char buffer[GMS_MAX_PRINTLEN];
1032 	
1033 	   assert( scip != NULL );
1034 	   assert( strlen(rowname) > 0 || strlen(rownameextension) > 0 );
1035 	   assert( strcmp(type, "=e=") == 0 || strcmp(type, "=l=") == 0 || strcmp(type, "=g=") == 0 );
1036 	
1037 	   clearLine(linebuffer, &linecnt);
1038 	
1039 	   /* start each line with a space */
1040 	   appendLine(scip, file, linebuffer, &linecnt, " ");
1041 	
1042 	   /* print row name */
1043 	   (void) SCIPsnprintf(buffer, GMS_MAX_NAMELEN + 3, "%s%s ..", rowname, rownameextension);
1044 	   SCIP_CALL( printConformName(scip, consname, GMS_MAX_NAMELEN + 3, buffer) );
1045 	   appendLine(scip, file, linebuffer, &linecnt, consname);
1046 	
1047 	   SCIP_CALL( printExpr(scip, file, linebuffer, &linecnt, nsmooth, nqcons, transformed, expr) );
1048 	
1049 	   /* print right hand side */
1050 	   (void) SCIPsnprintf(buffer, GMS_MAX_PRINTLEN, " %s %.15g;", type, rhs);
1051 	   appendLine(scip, file, linebuffer, &linecnt, buffer);
1052 	
1053 	   endLine(scip, file, linebuffer, &linecnt);
1054 	
1055 	   return SCIP_OKAY;
1056 	}
1057 	
1058 	/** print nonlinear row in GAMS format to file stream (performing retransformation to active linear variables) */
1059 	static
1060 	SCIP_RETCODE printNonlinearCons(
1061 	   SCIP*                 scip,               /**< SCIP data structure */
1062 	   FILE*                 file,               /**< output file (or NULL for standard output) */
1063 	   const char*           rowname,            /**< row name */
1064 	   SCIP_EXPR*            expr,               /**< expression */
1065 	   SCIP_Real             lhs,                /**< left hand side */
1066 	   SCIP_Real             rhs,                /**< right hand side */
1067 	   SCIP_Bool             transformed,        /**< transformed constraint? */
1068 	   SCIP_Bool*            nsmooth,            /**< buffer to store whether we printed a nonsmooth function */
1069 	   SCIP_Bool*            nqcons              /**< buffer to update whether we are still quadratic */
1070 	   )
1071 	{
1072 	   assert( scip != NULL );
1073 	   assert( strlen(rowname) > 0 );
1074 	
1075 	   /* print row(s) in GAMS format */
1076 	   if( SCIPisEQ(scip, lhs, rhs) )
1077 	   {
1078 	      assert( !SCIPisInfinity(scip, rhs) );
1079 	
1080 	      /* print equality constraint */
1081 	      SCIP_CALL( printNonlinearRow(scip, file, rowname, "", "=e=", expr, rhs, transformed, nsmooth, nqcons) );
1082 	   }
1083 	   else
1084 	   {
1085 	      if( !SCIPisInfinity(scip, -lhs) )
1086 	      {
1087 	         /* print inequality ">=" */
1088 	         SCIP_CALL( printNonlinearRow(scip, file, rowname, SCIPisInfinity(scip, rhs) ? "" : "_lhs", "=g=", expr, lhs, transformed, nsmooth, nqcons) );
1089 	      }
1090 	      if( !SCIPisInfinity(scip, rhs) )
1091 	      {
1092 	         /* print inequality "<=" */
1093 	         SCIP_CALL( printNonlinearRow(scip, file, rowname, SCIPisInfinity(scip, -lhs) ? "" : "_rhs", "=l=", expr, rhs, transformed, nsmooth, nqcons) );
1094 	      }
1095 	   }
1096 	
1097 	   if( *nqcons )
1098 	   {
1099 	      /* if we are still at most quadratic, check whether that is still the case when considering current constraint */
1100 	      SCIP_CALL( SCIPcheckExprQuadratic(scip, expr, nqcons) );
1101 	      if( *nqcons )
1102 	         *nqcons = SCIPexprAreQuadraticExprsVariables(expr);
1103 	   }
1104 	
1105 	   return SCIP_OKAY;
1106 	}
1107 	
1108 	/** method check if the variable names are not longer than GMS_MAX_NAMELEN */
1109 	static
1110 	SCIP_RETCODE checkVarnames(
1111 	   SCIP*                 scip,               /**< SCIP data structure */
1112 	   SCIP_VAR**            vars,               /**< array of variables */
1113 	   int                   nvars               /**< number of variables */
1114 	   )
1115 	{
1116 	   int v;
1117 	   SCIP_VAR* var;
1118 	   SCIP_Bool replaceforbiddenchars;
1119 	   const char* badchar;
1120 	
1121 	   assert( scip != NULL );
1122 	   assert( vars != NULL );
1123 	
1124 	   SCIP_CALL( SCIPgetBoolParam(scip, "reading/gmsreader/replaceforbiddenchars", &replaceforbiddenchars) );
1125 	
1126 	   /* check if the variable names contain any of the bad symbols */
1127 	   for( badchar = badchars; *badchar; ++badchar )
1128 	   {
1129 	      for( v = 0; v < nvars; ++v )
1130 	      {
1131 	         var = vars[v];
1132 	         assert( var != NULL );
1133 	
1134 	         if( strchr(SCIPvarGetName(var), *badchar) != NULL )
1135 	         {
1136 	            if( replaceforbiddenchars )
1137 	            {
1138 	               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);
1139 	            }
1140 	            else
1141 	            {
1142 	               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);
1143 	            }
1144 	
1145 	            break;
1146 	         }
1147 	      }
1148 	   }
1149 	
1150 	   /* check if the variable names are too long */
1151 	   for( v = 0; v < nvars; ++v )
1152 	   {
1153 	      var = vars[v];
1154 	      assert( var != NULL );
1155 	
1156 	      if( strlen(SCIPvarGetName(var)) > GMS_MAX_NAMELEN )
1157 	      {
1158 	         SCIPwarningMessage(scip, "there is a variable name which has to be cut down to %d characters; GAMS model might be corrupted.\n", 
1159 	            GMS_MAX_NAMELEN - 1);
1160 	         break;
1161 	      }
1162 	   }
1163 	
1164 	   return SCIP_OKAY;
1165 	}
1166 	
1167 	/** method check if the constraint names are not longer than GMS_MAX_NAMELEN */
1168 	static
1169 	SCIP_RETCODE checkConsnames(
1170 	   SCIP*                 scip,               /**< SCIP data structure */
1171 	   SCIP_CONS**           conss,              /**< array of constraints */
1172 	   int                   nconss,             /**< number of constraints */
1173 	   SCIP_Bool             transformed         /**< TRUE iff problem is the transformed problem */
1174 	   )
1175 	{
1176 	   int c;
1177 	   SCIP_CONS* cons;
1178 	   SCIP_CONSHDLR* conshdlr;
1179 	   const char* conshdlrname;
1180 	   SCIP_Bool replaceforbiddenchars;
1181 	   const char* badchar;
1182 	
1183 	   assert( scip != NULL );
1184 	   assert( conss != NULL );
1185 	
1186 	   SCIP_CALL( SCIPgetBoolParam(scip, "reading/gmsreader/replaceforbiddenchars", &replaceforbiddenchars) );
1187 	
1188 	   /* check if the constraint names contain any of the bad symbols */
1189 	   for( badchar = badchars; *badchar; ++badchar )
1190 	   {
1191 	      for( c = 0; c < nconss; ++c )
1192 	      {
1193 	         cons = conss[c];
1194 	         assert( cons != NULL );
1195 	
1196 	         if( strchr(SCIPconsGetName(cons), *badchar) != NULL )
1197 	         {
1198 	            if( replaceforbiddenchars )
1199 	            {
1200 	               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);
1201 	            }
1202 	            else
1203 	            {
1204 	               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);
1205 	            }
1206 	
1207 	            break;
1208 	         }
1209 	      }
1210 	   }
1211 	
1212 	   /* check if the constraint names are too long */
1213 	   for( c = 0; c < nconss; ++c )
1214 	   {
1215 	      cons = conss[c];
1216 	      assert( cons != NULL );
1217 	
1218 	      /* in case the transformed is written, only constraints are posted which are enabled in the current node */
1219 	      assert(!transformed || SCIPconsIsEnabled(cons));
1220 	
1221 	      conshdlr = SCIPconsGetHdlr(cons);
1222 	      assert( conshdlr != NULL );
1223 	
1224 	      conshdlrname = SCIPconshdlrGetName(conshdlr);
1225 	      assert( transformed == SCIPconsIsTransformed(cons) );
1226 	
1227 	      if( strcmp(conshdlrname, "linear") == 0 || strcmp(conshdlrname, "nonlinear") == 0 )
1228 	      {
1229 	         SCIP_Real lhs = strcmp(conshdlrname, "linear") == 0 ? SCIPgetLhsLinear(scip, cons) : SCIPgetLhsNonlinear(cons);
1230 	         SCIP_Real rhs = strcmp(conshdlrname, "linear") == 0 ? SCIPgetLhsLinear(scip, cons) : SCIPgetRhsNonlinear(cons);
1231 	
1232 	         if( SCIPisEQ(scip, lhs, rhs) && strlen(SCIPconsGetName(conss[c])) > GMS_MAX_NAMELEN )
1233 	         {
1234 	            SCIPwarningMessage(scip, "there is a constraint name which has to be cut down to %d characters;\n",
1235 	               GMS_MAX_NAMELEN - 1);
1236 	            break;
1237 	         }
1238 	         else if( !SCIPisEQ(scip, lhs, rhs) && strlen(SCIPconsGetName(conss[c])) > GMS_MAX_NAMELEN - 4 )
1239 	         {
1240 	            SCIPwarningMessage(scip, "there is a constraint name which has to be cut down to %d characters;\n",
1241 	               GMS_MAX_NAMELEN - 5);
1242 	            break;
1243 	         }
1244 	      }
1245 	      else if( strlen(SCIPconsGetName(conss[c])) > GMS_MAX_NAMELEN )
1246 	      {
1247 	         SCIPwarningMessage(scip, "there is a constraint name which has to be cut down to %d characters;\n",
1248 	            GMS_MAX_NAMELEN - 1);
1249 	         break;
1250 	      }
1251 	   }
1252 	   return SCIP_OKAY;
1253 	}
1254 	
1255 	
1256 	/*
1257 	 * Callback methods of reader
1258 	 */
1259 	
1260 	/** copy method for reader plugins (called when SCIP copies plugins) */
1261 	static
1262 	SCIP_DECL_READERCOPY(readerCopyGms)
1263 	{  /*lint --e{715}*/
1264 	   assert(scip != NULL);
1265 	   assert(reader != NULL);
1266 	   assert(strcmp(SCIPreaderGetName(reader), READER_NAME) == 0);
1267 	
1268 	   /* call inclusion method of reader */
1269 	   SCIP_CALL( SCIPincludeReaderGms(scip) );
1270 	
1271 	   return SCIP_OKAY;
1272 	}
1273 	
1274 	
1275 	/** problem writing method of reader */
1276 	static
1277 	SCIP_DECL_READERWRITE(readerWriteGms)
1278 	{  /*lint --e{715}*/
1279 	   SCIP_CALL( SCIPwriteGms(scip, file, name, transformed, objsense, objscale, objoffset, vars,
1280 	         nvars, nbinvars, nintvars, nimplvars, ncontvars, conss, nconss, result) );
1281 	
1282 	   return SCIP_OKAY;
1283 	}
1284 	
1285 	/*
1286 	 * reader specific interface methods
1287 	 */
1288 	
1289 	/** includes the gms file reader in SCIP */
1290 	SCIP_RETCODE SCIPincludeReaderGms(
1291 	   SCIP*                 scip                /**< SCIP data structure */
1292 	   )
1293 	{
1294 	   SCIP_READER* reader;
1295 	
1296 	   /* include reader */
1297 	   SCIP_CALL( SCIPincludeReaderBasic(scip, &reader, READER_NAME, READER_DESC, READER_EXTENSION, NULL) );
1298 	
1299 	   /* set non fundamental callbacks via setter functions */
1300 	   SCIP_CALL( SCIPsetReaderCopy(scip, reader, readerCopyGms) );
1301 	   SCIP_CALL( SCIPsetReaderWrite(scip, reader, readerWriteGms) );
1302 	
1303 	   /* add gms reader parameters for writing routines*/
1304 	   SCIP_CALL( SCIPaddBoolParam(scip,
1305 	         "reading/gmsreader/replaceforbiddenchars", "shall characters '#', '*', '+', '/', and '-' in variable and constraint names be replaced by '_'?",
1306 	         NULL, FALSE, FALSE, NULL, NULL) );
1307 	
1308 	   SCIP_CALL( SCIPaddRealParam(scip,
1309 	         "reading/gmsreader/bigmdefault", "default M value for big-M reformulation of indicator constraints in case no bound on slack variable is given",
1310 	         NULL, FALSE, GMS_DEFAULT_BIGM, 0.0, SCIP_REAL_MAX, NULL, NULL) );
1311 	
1312 	   SCIP_CALL( SCIPaddCharParam(scip,
1313 	         "reading/gmsreader/indicatorreform", "which reformulation to use for indicator constraints: 'b'ig-M, 's'os1",
1314 	         NULL, FALSE, GMS_DEFAULT_INDICATORREFORM, "bs", NULL, NULL) );
1315 	
1316 	   SCIP_CALL( SCIPaddBoolParam(scip,
1317 	         "reading/gmsreader/signpower", "is it allowed to use the gams function signpower(x,a)?",
1318 	         NULL, FALSE, GMS_DEFAULT_SIGNPOWER, NULL, NULL) );
1319 	
1320 	   return SCIP_OKAY;
1321 	}
1322 	
1323 	
1324 	/** writes problem to gms file */
1325 	SCIP_RETCODE SCIPwriteGms(
1326 	   SCIP*                 scip,               /**< SCIP data structure */
1327 	   FILE*                 file,               /**< output file, or NULL if standard output should be used */
1328 	   const char*           name,               /**< problem name */
1329 	   SCIP_Bool             transformed,        /**< TRUE iff problem is the transformed problem */
1330 	   SCIP_OBJSENSE         objsense,           /**< objective sense */
1331 	   SCIP_Real             objscale,           /**< scalar applied to objective function; external objective value is
1332 	                                              *   extobj = objsense * objscale * (intobj + objoffset) */
1333 	   SCIP_Real             objoffset,          /**< objective offset from bound shifting and fixing */
1334 	   SCIP_VAR**            vars,               /**< array with active variables ordered binary, integer, implicit, continuous */
1335 	   int                   nvars,              /**< number of active variables in the problem */
1336 	   int                   nbinvars,           /**< number of binary variables */
1337 	   int                   nintvars,           /**< number of general integer variables */
1338 	   int                   nimplvars,          /**< number of implicit integer variables */
1339 	   int                   ncontvars,          /**< number of continuous variables */
1340 	   SCIP_CONS**           conss,              /**< array with constraints of the problem */
1341 	   int                   nconss,             /**< number of constraints in the problem */
1342 	   SCIP_RESULT*          result              /**< pointer to store the result of the file writing call */
1343 	   )
1344 	{
1345 	   int c;
1346 	   int v;
1347 	   int linecnt;
1348 	   char linebuffer[GMS_MAX_PRINTLEN+1];
1349 	
1350 	   char varname[GMS_MAX_NAMELEN];
1351 	   char buffer[GMS_MAX_PRINTLEN];
1352 	
1353 	   SCIP_Real* objcoeffs;
1354 	
1355 	   SCIP_CONSHDLR* conshdlr;
1356 	   const char* conshdlrname;
1357 	   SCIP_CONS* cons;
1358 	
1359 	   char consname[GMS_MAX_NAMELEN];
1360 	
1361 	   SCIP_VAR** consvars;
1362 	   SCIP_Real* consvals;
1363 	   int nconsvars;
1364 	
1365 	   SCIP_VAR* var;
1366 	   SCIP_VAR* objvar;
1367 	   SCIP_Real lb;
1368 	   SCIP_Real ub;
1369 	   SCIP_Bool nondefbounds;
1370 	   SCIP_Bool nlcons = FALSE;  /* whether there are nonlinear constraints */
1371 	   SCIP_Bool nqcons = TRUE;   /* whether nonlinear constraints are at most quadratic */
1372 	   SCIP_Bool nsmooth = FALSE; /* whether there are nonsmooth nonlinear constraints */
1373 	   SCIP_Bool discrete;
1374 	   SCIP_Bool rangedrow;
1375 	   SCIP_Bool indicatorsosdef;
1376 	   SCIP_Bool signpowerallowed;
1377 	   SCIP_Bool needcomma;
1378 	
1379 	   assert( scip != NULL );
1380 	   assert( vars != NULL || nvars == 0 );
1381 	
1382 	   /* check if the variable names are not too long */
1383 	   SCIP_CALL( checkVarnames(scip, vars, nvars) );
1384 	   /* check if the constraint names are too long */
1385 	   SCIP_CALL( checkConsnames(scip, conss, nconss, transformed) );
1386 	
1387 	   SCIP_CALL( SCIPgetBoolParam(scip, "reading/gmsreader/signpower", &signpowerallowed) );
1388 	
1389 	   /* check if the objective is a single continuous variable, so we would not have to introduce an auxiliary variable
1390 	    * for GAMS
1391 	    */
1392 	   objvar = NULL;
1393 	   if( objscale == 1.0 && objoffset == 0.0 )
1394 	   {
1395 	      for( v = 0; v < nvars; ++v )
1396 	      {
1397 	         if( SCIPvarGetObj(vars[v]) == 0.0 ) /*lint !e613*/
1398 	            continue;
1399 	
1400 	         if( objvar == NULL )
1401 	         {
1402 	            /* first variable with nonzero obj coefficient
1403 	             * if not active or having coefficient != 1.0, or being binary/integer, then give up
1404 	             */
1405 	            if( !SCIPvarIsActive(vars[v]) || SCIPvarGetObj(vars[v]) != 1.0 ||
1406 	               SCIPvarGetType(vars[v]) < SCIP_VARTYPE_IMPLINT ) /*lint !e613*/
1407 	               break;
1408 	
1409 	            objvar = vars[v]; /*lint !e613*/
1410 	         }
1411 	         else
1412 	         {
1413 	            /* second variable with nonzero obj coefficient -> give up */
1414 	            objvar = NULL;
1415 	            break;
1416 	         }
1417 	      }
1418 	   }
1419 	
1420 	   /* print statistics as comment to file */
1421 	   SCIPinfoMessage(scip, file, "$OFFLISTING\n");
1422 	   SCIPinfoMessage(scip, file, "* SCIP STATISTICS\n");
1423 	   SCIPinfoMessage(scip, file, "*   Problem name     : %s\n", name);
1424 	   SCIPinfoMessage(scip, file, "*   Variables        : %d (%d binary, %d integer, %d implicit integer, %d continuous)\n",
1425 	      nvars, nbinvars, nintvars, nimplvars, ncontvars);
1426 	   SCIPinfoMessage(scip, file, "*   Constraints      : %d\n\n", nconss);
1427 	
1428 	   /* print flags */
1429 	   SCIPinfoMessage(scip, file, "$MAXCOL %d\n", GMS_MAX_LINELEN - 1);
1430 	   SCIPinfoMessage(scip, file, "$OFFDIGIT\n\n");
1431 	
1432 	   /* print variable section */
1433 	   SCIPinfoMessage(scip, file, "Variables\n");
1434 	   clearLine(linebuffer, &linecnt);
1435 	
1436 	   if( objvar == NULL )
1437 	   {
1438 	      /* auxiliary objective variable */
1439 	      SCIPinfoMessage(scip, file, " objvar%c", nvars > 0 ? ',' : ';');
1440 	   }
1441 	
1442 	   /* "model" variables */
1443 	   for( v = 0; v < nvars; ++v )
1444 	   {
1445 	      var = vars[v]; /*lint !e613*/
1446 	      assert( var != NULL );
1447 	
1448 	      SCIP_CALL( printConformName(scip, varname, GMS_MAX_NAMELEN, SCIPvarGetName(var)) );
1449 	      (void) SCIPsnprintf(buffer, GMS_MAX_PRINTLEN, " %s%c", varname, (v < nvars - 1) ? ',' : ';');
1450 	      appendLine(scip, file, linebuffer, &linecnt, buffer);
1451 	
1452 	      if( (linecnt > 0 && (v == nbinvars - 1 || v == nbinvars + nintvars - 1 ||
1453 	            v == nbinvars + nintvars + nimplvars - 1)) || v == nvars - 1 )
1454 	      {
1455 	         endLine(scip, file, linebuffer, &linecnt);
1456 	         clearLine(linebuffer, &linecnt);
1457 	      }
1458 	   }
1459 	
1460 	   SCIPinfoMessage(scip, file, "\n");
1461 	
1462 	   /* declare binary variables if present */
1463 	   if( nbinvars > 0 )
1464 	   {
1465 	      SCIPinfoMessage(scip, file, "Binary variables\n");
1466 	      clearLine(linebuffer, &linecnt);
1467 	
1468 	      for( v = 0; v < nbinvars; ++v )
1469 	      {
1470 	         var = vars[v]; /*lint !e613*/
1471 	
1472 	         SCIP_CALL( printConformName(scip, varname, GMS_MAX_NAMELEN, SCIPvarGetName(var)) );
1473 	         (void) SCIPsnprintf(buffer, GMS_MAX_PRINTLEN, " %s%s", varname, (v < nbinvars - 1) ? "," : ";");
1474 	
1475 	         appendLine(scip, file, linebuffer, &linecnt, buffer);
1476 	      }
1477 	
1478 	      endLine(scip, file, linebuffer, &linecnt);
1479 	      SCIPinfoMessage(scip, file, "\n");
1480 	   }
1481 	
1482 	   /* declare integer variables if present */
1483 	   if( nintvars > 0 )
1484 	   {
1485 	      SCIPinfoMessage(scip, file, "Integer variables\n");
1486 	      clearLine(linebuffer, &linecnt);
1487 	
1488 	      for( v = 0; v < nintvars; ++v )
1489 	      {
1490 	         var = vars[nbinvars + v]; /*lint !e613*/
1491 	
1492 	         SCIP_CALL( printConformName(scip, varname, GMS_MAX_NAMELEN, SCIPvarGetName(var)) );
1493 	         (void) SCIPsnprintf(buffer, GMS_MAX_PRINTLEN, " %s%s", varname, (v < nintvars - 1) ? "," : ";");
1494 	
1495 	         appendLine(scip, file, linebuffer, &linecnt, buffer);
1496 	      }
1497 	      endLine(scip, file, linebuffer, &linecnt);
1498 	      SCIPinfoMessage(scip, file, "\n");
1499 	   }
1500 	
1501 	   /* print variable bounds */
1502 	   SCIPinfoMessage(scip, file, "* Variable bounds\n");
1503 	   nondefbounds = FALSE;
1504 	
1505 	   for( v = 0; v < nvars; ++v )
1506 	   {
1507 	      var = vars[v]; /*lint !e613*/
1508 	      assert( var != NULL );
1509 	
1510 	      SCIP_CALL( printConformName(scip, varname, GMS_MAX_NAMELEN, SCIPvarGetName(var)) );
1511 	
1512 	      if( transformed )
1513 	      {
1514 	         /* in case the transformed is written only local bounds are posted which are valid in the current node */
1515 	         lb = SCIPvarGetLbLocal(var);
1516 	         ub = SCIPvarGetUbLocal(var);
1517 	      }
1518 	      else
1519 	      {
1520 	         lb = SCIPvarGetLbOriginal(var);
1521 	         ub = SCIPvarGetUbOriginal(var);
1522 	      }
1523 	      assert( lb <= ub );
1524 	
1525 	      /* fixed */
1526 	      if( SCIPisEQ(scip, lb, ub) )
1527 	      {
1528 	         if( v < nintvars )
1529 	            SCIPinfoMessage(scip, file, " %s.fx = %g;\n", varname, SCIPfloor(scip, lb + 0.5));
1530 	         else
1531 	            SCIPinfoMessage(scip, file, " %s.fx = %.15g;\n", varname, lb);
1532 	         nondefbounds = TRUE;
1533 	
1534 	         /* no need to write lower and upper bounds additionally */
1535 	         continue;
1536 	      }
1537 	
1538 	      /* lower bound */
1539 	      if( v < nbinvars + nintvars )
1540 	      {
1541 	         /* default lower bound of binaries and integers is 0 */
1542 	         if( !SCIPisZero(scip, lb) )
1543 	         {
1544 	            if( !SCIPisInfinity(scip, -lb) )
1545 	               SCIPinfoMessage(scip, file, " %s.lo = %g;\n", varname, SCIPceil(scip, lb));
1546 	            else
1547 	               SCIPinfoMessage(scip, file, " %s.lo = -inf;\n", varname);
1548 	            nondefbounds = TRUE;
1549 	         }
1550 	      }
1551 	      else if( v >= nbinvars + nintvars && !SCIPisInfinity(scip, -lb) )
1552 	      {
1553 	         /* continuous variables are free by default */
1554 	         SCIPinfoMessage(scip, file, " %s.lo = %.15g;\n", varname, lb);
1555 	         nondefbounds = TRUE;
1556 	      }
1557 	
1558 	      /* upper bound */
1559 	      if( v < nbinvars )
1560 	      {
1561 	         /* binary variables have default upper bound 1.0 */
1562 	         if( !SCIPisFeasEQ(scip, ub, 1.0) )
1563 	         {
1564 	            SCIPinfoMessage(scip, file, " %s.up = %g;\n", varname, SCIPfeasFloor(scip, ub));
1565 	            nondefbounds = TRUE;
1566 	         }
1567 	      }
1568 	      else if( v < nbinvars + nintvars )
1569 	      {
1570 	         /* integer variables have default upper bound +inf */
1571 	         if( !SCIPisInfinity(scip, ub) )
1572 	         {
1573 	            SCIPinfoMessage(scip, file, " %s.up = %g;\n", varname, SCIPfeasFloor(scip, ub));
1574 	            nondefbounds = TRUE;
1575 	         }
1576 	      }
1577 	      else
1578 	      {
1579 	         /* continuous variables have default upper bound +inf */
1580 	         if( !SCIPisInfinity(scip, ub) )
1581 	         {
1582 	            SCIPinfoMessage(scip, file, " %s.up = %.15g;\n", varname, ub);
1583 	            nondefbounds = TRUE;
1584 	         }
1585 	      }
1586 	   }
1587 	
1588 	   if( !nondefbounds )
1589 	      SCIPinfoMessage(scip, file, "* (All other bounds at default value: binary [0,1], integer [0,+inf], continuous [-inf,+inf].)\n");
1590 	   SCIPinfoMessage(scip, file, "\n");
1591 	
1592 	   /* print equations section */
1593 	   if( nconss > 0 || objvar == NULL )
1594 	   {
1595 	      SCIPinfoMessage(scip, file, "Equations\n");
1596 	      clearLine(linebuffer, &linecnt);
1597 	   }
1598 	   needcomma = FALSE;
1599 	
1600 	   if( objvar == NULL )
1601 	   {
1602 	      SCIPinfoMessage(scip, file, " objequ");
1603 	      needcomma = TRUE;
1604 	   }
1605 	
1606 	   /* declare equations */
1607 	   for( c = 0; c < nconss; ++c )
1608 	   {
1609 	      cons = conss[c];
1610 	      assert( cons != NULL );
1611 	
1612 	      conshdlr = SCIPconsGetHdlr(cons);
1613 	      assert( conshdlr != NULL );
1614 	
1615 	      SCIP_CALL( printConformName(scip, consname, GMS_MAX_NAMELEN, SCIPconsGetName(cons)) );
1616 	      conshdlrname = SCIPconshdlrGetName(conshdlr);
1617 	      assert( transformed == SCIPconsIsTransformed(cons) );
1618 	
1619 	      rangedrow = strcmp(conshdlrname, "linear") == 0
1620 	         && !SCIPisInfinity(scip, -SCIPgetLhsLinear(scip, cons)) && !SCIPisInfinity(scip, SCIPgetRhsLinear(scip, cons))
1621 	         && !SCIPisEQ(scip, SCIPgetLhsLinear(scip, cons), SCIPgetRhsLinear(scip, cons));
1622 	      rangedrow = rangedrow || (strcmp(conshdlrname, "nonlinear") == 0
1623 	         && !SCIPisInfinity(scip, -SCIPgetLhsNonlinear(cons)) && !SCIPisInfinity(scip, SCIPgetRhsNonlinear(cons))
1624 	         && !SCIPisEQ(scip, SCIPgetLhsNonlinear(cons), SCIPgetRhsNonlinear(cons)));
1625 	      rangedrow = rangedrow || (strcmp(conshdlrname, "varbound") == 0
1626 	         && !SCIPisInfinity(scip, -SCIPgetLhsVarbound(scip, cons)) && !SCIPisInfinity(scip, SCIPgetRhsVarbound(scip, cons))
1627 	         && !SCIPisEQ(scip, SCIPgetLhsVarbound(scip, cons), SCIPgetRhsVarbound(scip, cons)));
1628 	
1629 	      /* we declare only those constraints which we can print in GAMS format */
1630 	      if( strcmp(conshdlrname, "knapsack") != 0 && strcmp(conshdlrname, "logicor") != 0 && strcmp(conshdlrname, "setppc") != 0
1631 	          && strcmp(conshdlrname, "linear") != 0 && strcmp(conshdlrname, "SOS1") != 0 && strcmp(conshdlrname, "SOS2") != 0
1632 	          && strcmp(conshdlrname, "nonlinear") != 0
1633 	          && strcmp(conshdlrname, "varbound") != 0
1634 	          && strcmp(conshdlrname, "indicator") != 0 )
1635 	      {
1636 	         SCIPwarningMessage(scip, "Constraint type <%s> not supported. Skip writing constraint <%s>.\n", conshdlrname, SCIPconsGetName(cons));
1637 	         continue;
1638 	      }
1639 	
1640 	      if( needcomma )
1641 	         appendLine(scip, file, linebuffer, &linecnt, ",");
1642 	
1643 	      SCIP_CALL( printConformName(scip, consname, GMS_MAX_NAMELEN, SCIPconsGetName(cons)) );
1644 	      if( rangedrow )
1645 	      {
1646 	         (void) SCIPsnprintf(buffer, GMS_MAX_PRINTLEN, " %s%s%s%s", consname, "_lhs, ", consname, "_rhs");
1647 	         appendLine(scip, file, linebuffer, &linecnt, buffer);
1648 	      }
1649 	      else
1650 	      {
1651 	         (void) SCIPsnprintf(buffer, GMS_MAX_PRINTLEN, " %s", consname);
1652 	         appendLine(scip, file, linebuffer, &linecnt, buffer);
1653 	      }
1654 	      needcomma = TRUE;
1655 	   }
1656 	
1657 	   if( nconss > 0 || objvar == NULL )
1658 	   {
1659 	      (void) SCIPsnprintf(buffer, GMS_MAX_PRINTLEN, ";");
1660 	      appendLine(scip, file, linebuffer, &linecnt, buffer);
1661 	
1662 	      endLine(scip, file, linebuffer, &linecnt);
1663 	      SCIPinfoMessage(scip, file, "\n");
1664 	   }
1665 	
1666 	   if( objvar == NULL )
1667 	   {
1668 	      /* print objective function equation */
1669 	      clearLine(linebuffer, &linecnt);
1670 	      if( objoffset != 0.0 )
1671 	         (void) SCIPsnprintf(buffer, GMS_MAX_PRINTLEN, " objequ .. objvar =e= %.15g + ", objscale * objoffset);
1672 	      else
1673 	         (void) SCIPsnprintf(buffer, GMS_MAX_PRINTLEN, " objequ .. objvar =e= ");
1674 	      appendLine(scip, file, linebuffer, &linecnt, buffer);
1675 	
1676 	      SCIP_CALL( SCIPallocBufferArray(scip, &objcoeffs, nvars) );
1677 	
1678 	      for( v = 0; v < nvars; ++v )
1679 	      {
1680 	         var = vars[v]; /*lint !e613*/
1681 	         assert( var != NULL );
1682 	
1683 	         /* in case the original problem has to be posted the variables have to be either "original" or "negated" */
1684 	         assert( transformed || SCIPvarGetStatus(var) == SCIP_VARSTATUS_ORIGINAL || SCIPvarGetStatus(var) == SCIP_VARSTATUS_NEGATED );
1685 	
1686 	         objcoeffs[v] = SCIPisZero(scip, SCIPvarGetObj(var)) ? 0.0 : objscale * SCIPvarGetObj(var);
1687 	      }
1688 	
1689 	      SCIP_CALL( printActiveVariables(scip, file, linebuffer, &linecnt, "", ";", nvars, vars, objcoeffs, transformed) );
1690 	
1691 	      SCIPfreeBufferArray(scip, &objcoeffs);
1692 	      endLine(scip, file, linebuffer, &linecnt);
1693 	      SCIPinfoMessage(scip, file, "\n");
1694 	   }
1695 	
1696 	   /* print constraints */
1697 	   discrete = nbinvars > 0 || nintvars > 0;
1698 	   indicatorsosdef = FALSE;
1699 	   for( c = 0; c < nconss; ++c )
1700 	   {
1701 	      cons = conss[c];
1702 	      assert( cons != NULL );
1703 	
1704 	      /* in case the transformed is written, only constraints are posted which are enabled in the current node */
1705 	      assert(!transformed || SCIPconsIsEnabled(cons));
1706 	
1707 	      conshdlr = SCIPconsGetHdlr(cons);
1708 	      assert( conshdlr != NULL );
1709 	
1710 	      SCIP_CALL( printConformName(scip, consname, GMS_MAX_NAMELEN, SCIPconsGetName(cons)) );
1711 	      conshdlrname = SCIPconshdlrGetName(conshdlr);
1712 	      assert( transformed == SCIPconsIsTransformed(cons) );
1713 	
1714 	      if( strcmp(conshdlrname, "knapsack") == 0 )
1715 	      {
1716 	         SCIP_Longint* weights;
1717 	
1718 	         consvars = SCIPgetVarsKnapsack(scip, cons);
1719 	         nconsvars = SCIPgetNVarsKnapsack(scip, cons);
1720 	
1721 	         /* copy Longint array to SCIP_Real array */
1722 	         weights = SCIPgetWeightsKnapsack(scip, cons);
1723 	         SCIP_CALL( SCIPallocBufferArray(scip, &consvals, nconsvars) );
1724 	         for( v = 0; v < nconsvars; ++v )
1725 	            consvals[v] = (SCIP_Real)weights[v];
1726 	
1727 	         SCIP_CALL( printLinearCons(scip, file, consname, nconsvars, consvars, consvals,
1728 	               -SCIPinfinity(scip), (SCIP_Real) SCIPgetCapacityKnapsack(scip, cons), transformed) );
1729 	
1730 	         SCIPfreeBufferArray(scip, &consvals);
1731 	      }
1732 	      else if( strcmp(conshdlrname, "linear") == 0 )
1733 	      {
1734 	         SCIP_CALL( printLinearCons(scip, file, consname,
1735 	               SCIPgetNVarsLinear(scip, cons), SCIPgetVarsLinear(scip, cons), SCIPgetValsLinear(scip, cons),
1736 	               SCIPgetLhsLinear(scip, cons),  SCIPgetRhsLinear(scip, cons), transformed) );
1737 	      }
1738 	      else if( strcmp(conshdlrname, "logicor") == 0 )
1739 	      {
1740 	         SCIP_CALL( printLinearCons(scip, file, consname,
1741 	               SCIPgetNVarsLogicor(scip, cons), SCIPgetVarsLogicor(scip, cons), NULL,
1742 	               1.0, SCIPinfinity(scip), transformed) );
1743 	      }
1744 	      else if( strcmp(conshdlrname, "nonlinear") == 0 )
1745 	      {
1746 	         SCIP_CALL( printNonlinearCons(scip, file, consname,
1747 	            SCIPgetExprNonlinear(cons), SCIPgetLhsNonlinear(cons), SCIPgetRhsNonlinear(cons), transformed, &nsmooth, &nqcons) );
1748 	         nlcons = TRUE;
1749 	      }
1750 	      else if( strcmp(conshdlrname, "setppc") == 0 )
1751 	      {
1752 	         consvars = SCIPgetVarsSetppc(scip, cons);
1753 	         nconsvars = SCIPgetNVarsSetppc(scip, cons);
1754 	
1755 	         switch( SCIPgetTypeSetppc(scip, cons) )
1756 	         {
1757 	         case SCIP_SETPPCTYPE_PARTITIONING :
1758 	            SCIP_CALL( printLinearCons(scip, file, consname,
1759 	                  nconsvars, consvars, NULL, 1.0, 1.0, transformed) );
1760 	            break;
1761 	         case SCIP_SETPPCTYPE_PACKING :
1762 	            SCIP_CALL( printLinearCons(scip, file, consname,
1763 	                  nconsvars, consvars, NULL, -SCIPinfinity(scip), 1.0, transformed) );
1764 	            break;
1765 	         case SCIP_SETPPCTYPE_COVERING :
1766 	            SCIP_CALL( printLinearCons(scip, file, consname,
1767 	                  nconsvars, consvars, NULL, 1.0, SCIPinfinity(scip), transformed) );
1768 	            break;
1769 	         }
1770 	      }
1771 	      else if( strcmp(conshdlrname, "varbound") == 0 )
1772 	      {
1773 	         SCIP_CALL( SCIPallocBufferArray(scip, &consvars, 2) );
1774 	         SCIP_CALL( SCIPallocBufferArray(scip, &consvals, 2) );
1775 	
1776 	         consvars[0] = SCIPgetVarVarbound(scip, cons);
1777 	         consvars[1] = SCIPgetVbdvarVarbound(scip, cons);
1778 	
1779 	         consvals[0] = 1.0;
1780 	         consvals[1] = SCIPgetVbdcoefVarbound(scip, cons);
1781 	
1782 	         SCIP_CALL( printLinearCons(scip, file, consname,
1783 	               2, consvars, consvals,
1784 	               SCIPgetLhsVarbound(scip, cons), SCIPgetRhsVarbound(scip, cons), transformed) );
1785 	
1786 	         SCIPfreeBufferArray(scip, &consvars);
1787 	         SCIPfreeBufferArray(scip, &consvals);
1788 	      }
1789 	      else if( strcmp(conshdlrname, "indicator") == 0 )
1790 	      {
1791 	         SCIP_CALL( printIndicatorCons(scip, file, consname,
1792 	            SCIPgetBinaryVarIndicator(cons), SCIPgetSlackVarIndicator(cons), &indicatorsosdef,
1793 	            transformed) );
1794 	      }
1795 	      else if( strcmp(conshdlrname, "SOS1") == 0 )
1796 	      {
1797 	         SCIP_CALL( printSOSCons(scip, file, consname,
1798 	            SCIPgetNVarsSOS1(scip, cons), SCIPgetVarsSOS1(scip, cons), 1,
1799 	            transformed) );
1800 	         discrete = TRUE;
1801 	      }
1802 	      else if( strcmp(conshdlrname, "SOS2") == 0 )
1803 	      {
1804 	         SCIP_CALL( printSOSCons(scip, file, consname,
1805 	            SCIPgetNVarsSOS2(scip, cons), SCIPgetVarsSOS2(scip, cons), 2,
1806 	            transformed) );
1807 	         discrete = TRUE;
1808 	      }
1809 	      else
1810 	      {
1811 	         SCIPwarningMessage(scip, "constraint handler <%s> cannot print requested format\n", conshdlrname );
1812 	         SCIPinfoMessage(scip, file, "* ");
1813 	         SCIP_CALL( SCIPprintCons(scip, cons, file) );
1814 	         SCIPinfoMessage(scip, file, ";\n");
1815 	      }
1816 	
1817 	      SCIPinfoMessage(scip, file, "\n");
1818 	   }
1819 	   /* if at most quadratic, then cannot have nonsmooth functions */
1820 	   assert(nlcons || !nsmooth);
1821 	
1822 	   /* print model creation */
1823 	   SCIPinfoMessage(scip, file, "Model m / all /;\n\n");
1824 	
1825 	   /* set some options to reduce listing file size */
1826 	   SCIPinfoMessage(scip, file, "option limrow = 0;\n");
1827 	   SCIPinfoMessage(scip, file, "option limcol = 0;\n");
1828 	   /* if GAMS >= 24.2, then set option to ensure default upper bound on integer vars is inf (since 32.1 this is also the default) */
1829 	   SCIPinfoMessage(scip, file, "$if gamsversion 242 option intvarup = 0;\n\n");
1830 	
1831 	   /* print solve command */
1832 	   (void) SCIPsnprintf(buffer, GMS_MAX_PRINTLEN, "%s%s",
1833 	         discrete ? "MI" : "", nlcons ? (nqcons ? "QCP" : ((nsmooth && !discrete) ? "DNLP" : "NLP")) : (discrete > 0 ? "P" : "LP"));
1834 	
1835 	   if( objvar != NULL )
1836 	   {
1837 	      SCIP_CALL( printConformName(scip, varname, GMS_MAX_NAMELEN, SCIPvarGetName(objvar)) );
1838 	   }
1839 	
1840 	   SCIPinfoMessage(scip, file, "$if not set %s $set %s %s\n", buffer, buffer, buffer);
1841 	   SCIPinfoMessage(scip, file, "Solve m using %%%s%% %simizing %s;\n",
1842 	         buffer, objsense == SCIP_OBJSENSE_MINIMIZE ? "min" : "max", objvar != NULL ? varname : "objvar");
1843 	
1844 	   *result = SCIP_SUCCESS;
1845 	
1846 	   return SCIP_OKAY;
1847 	}
1848