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