1 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2 /* */
3 /* This file is part of the program and library */
4 /* SCIP --- Solving Constraint Integer Programs */
5 /* */
6 /* Copyright (C) 2002-2022 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_fzn.c
17 * @ingroup DEFPLUGINS_READER
18 * @brief FlatZinc file reader
19 * @author Timo Berthold
20 * @author Stefan Heinz
21 *
22 * FlatZinc is a low-level solver input language that is the target language for MiniZinc. It is designed to be easy to
23 * translate into the form required by a solver. For more details see https://www.minizinc.org. The format is described
24 * at https://github.com/MiniZinc/minizinc-doc/blob/develop/en/fzn-spec.rst.
25 *
26 * @todo Support more general constraint types
27 */
28
29 /*---+----1----+----2----+----3----+----4----+----5----+----6----+----7----+----8----+----9----+----0----+----1----+----2*/
30
31 #include "blockmemshell/memory.h"
32 #include <ctype.h>
33 #include "scip/cons_nonlinear.h"
34 #include "scip/cons_and.h"
35 #include "scip/cons_cumulative.h"
36 #include "scip/cons_knapsack.h"
37 #include "scip/cons_linear.h"
38 #include "scip/cons_logicor.h"
39 #include "scip/cons_or.h"
40 #include "scip/cons_setppc.h"
41 #include "scip/cons_varbound.h"
42 #include "scip/cons_xor.h"
43 #include "scip/pub_cons.h"
44 #include "scip/pub_fileio.h"
45 #include "scip/pub_message.h"
46 #include "scip/pub_misc.h"
47 #include "scip/pub_misc_sort.h"
48 #include "scip/pub_reader.h"
49 #include "scip/pub_var.h"
50 #include "scip/reader_fzn.h"
51 #include "scip/scip_cons.h"
52 #include "scip/scip_mem.h"
53 #include "scip/scip_message.h"
54 #include "scip/scip_numerics.h"
55 #include "scip/scip_param.h"
56 #include "scip/scip_prob.h"
57 #include "scip/scip_reader.h"
58 #include "scip/scip_sol.h"
59 #include "scip/scip_solvingstats.h"
60 #include "scip/scip_var.h"
61 #include <stdlib.h>
62 #include <string.h>
63
64 #ifdef ALLDIFFERENT
65 #include "scip/cons_alldifferent.h"
66 #endif
67
68 #define READER_NAME "fznreader"
69 #define READER_DESC "file reader for FlatZinc format"
70 #define READER_EXTENSION "fzn"
71
72
73 #define FZN_BUFFERLEN 65536 /**< size of the line buffer for reading or writing */
74 #define FZN_INIT_LINELEN 65536 /**< initial size of the line buffer for reading */
75 #define FZN_MAX_PUSHEDTOKENS 1
76
77 /*
78 * Data structures
79 */
80
81 /** number types */
82 enum FznNumberType
83 {
84 FZN_BOOL,
85 FZN_INT,
86 FZN_FLOAT
87 };
88 typedef enum FznNumberType FZNNUMBERTYPE;
89
90 /** Expression type in FlatZinc File */
91 enum FznExpType
92 {
93 FZN_EXP_NONE,
94 FZN_EXP_UNSIGNED,
95 FZN_EXP_SIGNED
96 };
97 typedef enum FznExpType FZNEXPTYPE;
98
99 /* structures to store the dimension information */
100 struct Dimensions
101 {
102 int* lbs; /**< lower bounds */
103 int* ubs; /**< upper bounds */
104 int ndims; /**< number of dimensions */
105 int size; /**< size of lbs and ubs */
106 };
107 typedef struct Dimensions DIMENSIONS;
108
109 /** FlatZinc constant */
110 struct FznConstant
111 {
112 const char* name; /**< constant name */
113 FZNNUMBERTYPE type; /**< constant type */
114 SCIP_Real value; /**< constant value */
115 };
116 typedef struct FznConstant FZNCONSTANT;
117
118 /** structure to store information for an array variable */
119 struct ConstArray
120 {
121 FZNCONSTANT** constants; /**< array of constants */
122 char* name; /**< name of constant array */
123 int nconstants; /**< number of constants */
124 FZNNUMBERTYPE type; /**< constant type */
125 };
126 typedef struct ConstArray CONSTARRAY;
127
128 /** structure to store information for an array variable */
129 struct VarArray
130 {
131 SCIP_VAR** vars; /**< variable belonging to the variable array */
132 char* name; /**< name of the array variable */
133 DIMENSIONS* info; /**< dimension information */
134 int nvars; /**< number of variables */
135 FZNNUMBERTYPE type; /**< variable type */
136 };
137 typedef struct VarArray VARARRAY;
138
139 /** data for FlatZinc reader */
140 struct SCIP_ReaderData
141 {
142 VARARRAY** vararrays; /**< variable arrays to output */
143 int nvararrays; /**< number of variables */
144 int vararrayssize; /**< size of variable array */
145 };
146
147 /** tries to creates and adds a constraint; sets parameter created to TRUE if method was successful
148 *
149 * input:
150 * - scip : SCIP main data structure
151 * - fzninput, : FZN reading data
152 * - fname, : functions identifier name
153 * - ftokens, : function identifier tokens
154 * - nftokens, : number of function identifier tokes
155 *
156 * output
157 * - created : pointer to store whether a constraint was created or not
158 */
159 #define CREATE_CONSTRAINT(x) SCIP_RETCODE x (SCIP* scip, FZNINPUT* fzninput, const char* fname, char** ftokens, int nftokens, SCIP_Bool* created)
160
161
162 /** FlatZinc reading data */
163 struct FznInput
164 {
165 SCIP_FILE* file;
166 SCIP_HASHTABLE* varHashtable;
167 SCIP_HASHTABLE* constantHashtable;
168 FZNCONSTANT** constants;
169 char* linebuf;
170 char* token;
171 char* pushedtokens[FZN_MAX_PUSHEDTOKENS];
172 int npushedtokens;
173 int linenumber;
174 int linepos;
175 int linebufsize;
176 int bufpos;
177 int nconstants;
178 int sconstants;
179 SCIP_OBJSENSE objsense;
180 SCIP_Bool hasdot; /**< if the current token is a number, this bool tells if it contains a dot */
181 SCIP_Bool comment; /**< current buffer contains everything until a comment starts */
182 SCIP_Bool haserror; /**< a error was detected during parsing */
183 SCIP_Bool valid;
184 SCIP_Bool initialconss; /**< should model constraints be marked as initial? */
185 SCIP_Bool dynamicconss; /**< should model constraints be subject to aging? */
186 SCIP_Bool dynamiccols; /**< should columns be added and removed dynamically to the LP? */
187 SCIP_Bool dynamicrows; /**< should rows be added and removed dynamically to the LP? */
188
189 VARARRAY** vararrays; /**< variable arrays */
190 int nvararrays; /**< number of variables */
191 int vararrayssize; /**< size of variable array */
192
193 CONSTARRAY** constarrays; /**< constant arrays */
194 int nconstarrays; /**< number of constant arrays */
195 int constarrayssize; /**< size of constant array */
196 };
197 typedef struct FznInput FZNINPUT;
198
199 /** FlatZinc writing data */
200 struct FznOutput
201 {
202 char* varbuffer; /* buffer for auxiliary variables (float representatives of discrete variables) */
203 int varbufferlen; /* current length of the above buffer */
204 int varbufferpos; /* current filling position in the above buffer */
205 char* castbuffer; /* buffer for int2float conversion constraints */
206 int castbufferlen; /* current length of the above buffer */
207 int castbufferpos; /* current filling position in the above buffer */
208 char* consbuffer; /* buffer for all problem constraints */
209 int consbufferlen; /* current length of the above buffer */
210 int consbufferpos; /* current filling position in the above buffer */
211 int ndiscretevars; /* number of discrete variables in the problem */
212 SCIP_Bool* varhasfloat; /* array which indicates, whether a discrete variable already has a float representative */
213 };
214 typedef struct FznOutput FZNOUTPUT;
215
216 static const char delimchars[] = " \f\n\r\t\v";
217 static const char tokenchars[] = ":<>=;{}[],()";
218 static const char commentchars[] = "%";
219
220 /*
221 * Hash functions
222 */
223
224 /** gets the key (i.e. the name) of the given variable */
225 static
226 SCIP_DECL_HASHGETKEY(hashGetKeyVar)
227 { /*lint --e{715}*/
228 SCIP_VAR* var = (SCIP_VAR*) elem;
229
230 assert(var != NULL);
231 return (void*) SCIPvarGetName(var);
232 }
233
234 /** gets the key (i.e. the name) of the flatzinc constant */
235 static
236 SCIP_DECL_HASHGETKEY(hashGetKeyConstant)
237 { /*lint --e{715}*/
238 FZNCONSTANT* constant = (FZNCONSTANT*) elem;
239
240 assert(constant != NULL);
241 return (void*) constant->name;
242 }
243
244 /** comparison method for sorting variable arrays w.r.t. to their name */
245 static
246 SCIP_DECL_SORTPTRCOMP(vararraysComp)
247 {
248 return strcmp( ((VARARRAY*)elem1)->name, ((VARARRAY*)elem2)->name );
249 }
250
251
252 /** frees a given buffer char* array */
253 static
254 void freeStringBufferArray(
255 SCIP* scip, /**< SCIP data structure */
256 char** array, /**< buffer array to free */
257 int nelements /**< number of elements */
258 )
259 {
260 int i;
261
262 for( i = nelements - 1; i >= 0; --i )
263 SCIPfreeBufferArray(scip, &array[i]);
264
265 SCIPfreeBufferArray(scip, &array);
266 }
267
268 /** returns whether the given character is a token delimiter */
269 static
270 SCIP_Bool isDelimChar(
271 char c /**< input character */
272 )
273 {
274 return (c == '\0') || (strchr(delimchars, c) != NULL);
275 }
276
277 /** returns whether the given character is a single token */
278 static
279 SCIP_Bool isTokenChar(
280 char c /**< input character */
281 )
282 {
283 return (strchr(tokenchars, c) != NULL);
284 }
285
286 /** check if the current token is equal to give char */
287 static
288 SCIP_Bool isChar(
289 const char* token, /**< token to be checked */
290 char c /**< char to compare */
291 )
292 {
293 if( strlen(token) == 1 && *token == c )
294 return TRUE;
295
296 return FALSE;
297 }
298
299 /** check if the current token is Bool expression, this means false or true */
300 static
301 SCIP_Bool isBoolExp(
302 const char* name, /**< name to check */
303 SCIP_Bool* value /**< pointer to store the Bool value */
304 )
305 {
306 /* check the name */
307 if( strlen(name) == 4 && strncmp(name, "true", 4) == 0 )
308 {
309 *value = TRUE;
310 return TRUE;
311 }
312 else if( strlen(name) == 1 && strncmp(name, "1", 1) == 0 )
313 {
314 /* we also allow 1 as true */
315 *value = TRUE;
316 return TRUE;
317 }
318 else if( strlen(name) == 5 && strncmp(name, "false", 5) == 0 )
319 {
320 *value = FALSE;
321 return TRUE;
322 }
323 else if( strlen(name) == 1 && strncmp(name, "0", 1) == 0 )
324 {
325 /* we also allow 0 as false */
326 *value = FALSE;
327 return TRUE;
328 }
329
330 return FALSE;
331 }
332
333
334 /** check if the current token is an identifier, this means [A-Za-z][A-Za-z0-9_]* */
335 static
336 SCIP_Bool isIdentifier(
337 const char* name /**< name to check */
338 )
339 {
340 int i;
341
342 /* check if the identifier starts with a letter */
343 if( strlen(name) == 0 || !isalpha((unsigned char)name[0]) )
344 return FALSE;
345
346 i = 1;
347 while( name[i] )
348 {
349 if( !isalnum((unsigned char)name[i]) && name[i] != '_' )
350 return FALSE;
351 i++;
352 }
353
354 return TRUE;
355 }
356
357 /** returns whether the current character is member of a value string */
358 static
359 SCIP_Bool isValueChar(
360 char c, /**< input character */
361 char nextc, /**< next input character */
362 SCIP_Bool firstchar, /**< is the given character the first char of the token? */
363 SCIP_Bool* hasdot, /**< pointer to update the dot flag */
364 FZNEXPTYPE* exptype /**< pointer to update the exponent type */
365 )
366 {
367 assert(hasdot != NULL);
368 assert(exptype != NULL);
369
370 if( isdigit((unsigned char)c) )
371 return TRUE;
372 else if( firstchar && (c == '+' || c == '-') )
373 return TRUE;
374 else if( (*exptype == FZN_EXP_NONE) && !(*hasdot) && (c == '.') && (isdigit((unsigned char)nextc)))
375 {
376 *hasdot = TRUE;
377 return TRUE;
378 }
379 else if( !firstchar && (*exptype == FZN_EXP_NONE) && (c == 'e' || c == 'E') )
380 {
381 if( nextc == '+' || nextc == '-' )
382 {
383 *exptype = FZN_EXP_SIGNED;
384 return TRUE;
385 }
386 else if( isdigit((unsigned char)nextc) )
387 {
388 *exptype = FZN_EXP_UNSIGNED;
389 return TRUE;
390 }
391 }
392 else if( (*exptype == FZN_EXP_SIGNED) && (c == '+' || c == '-') )
393 {
394 *exptype = FZN_EXP_UNSIGNED;
395 return TRUE;
396 }
397
398 return FALSE;
399 }
400
401 /** compares two token if they are equal */
402 static
403 SCIP_Bool equalTokens(
404 const char* token1, /**< first token */
405 const char* token2 /**< second token */
406 )
407 {
408 assert(token1 != NULL);
409 assert(token2 != NULL);
410
411 if( strlen(token1) != strlen(token2) )
412 return FALSE;
413
414 return !strncmp(token1, token2, strlen(token2) );
415 }
416
417 /** reads the next line from the input file into the line buffer; skips comments;
418 * returns whether a line could be read
419 */
420 static
421 SCIP_Bool getNextLine(
422 SCIP* scip, /**< SCIP data structure */
423 FZNINPUT* fzninput /**< FZN reading data */
424 )
425 {
426 int i;
427
428 assert(fzninput != NULL);
429
430 /* clear the line */
431 BMSclearMemoryArray(fzninput->linebuf, fzninput->linebufsize);
432 fzninput->linebuf[fzninput->linebufsize - 2] = '\0';
433
434 fzninput->linepos = 0;
435 fzninput->bufpos = 0;
436
437 if( SCIPfgets(fzninput->linebuf, fzninput->linebufsize, fzninput->file) == NULL )
438 return FALSE;
439
440 fzninput->linenumber++;
441
442 if( fzninput->linebuf[fzninput->linebufsize - 2] != '\0' )
443 {
444 int newsize;
445
446 newsize = SCIPcalcMemGrowSize(scip, fzninput->linebufsize + 1);
447 SCIP_CALL_ABORT( SCIPreallocBlockMemoryArray(scip, &fzninput->linebuf, fzninput->linebufsize, newsize) );
448
449 fzninput->linebuf[newsize-2] = '\0';
450 if ( SCIPfgets(fzninput->linebuf + fzninput->linebufsize - 1, newsize - fzninput->linebufsize + 1, fzninput->file) == NULL )
451 return FALSE;
452 fzninput->linebufsize = newsize;
453 }
454
455 fzninput->linebuf[fzninput->linebufsize - 1] = '\0'; /* we want to use lookahead of one char -> we need two \0 at the end */
456 fzninput->comment = FALSE;
457
458 /* skip characters after comment symbol */
459 for( i = 0; commentchars[i] != '\0'; ++i )
460 {
461 char* commentstart;
462
463 commentstart = strchr(fzninput->linebuf, commentchars[i]);
464 if( commentstart != NULL )
465 {
466 *commentstart = '\0';
467 *(commentstart+1) = '\0'; /* we want to use lookahead of one char -> we need two \0 at the end */
468 fzninput->comment = TRUE;
469 break;
470 }
471 }
472
473 return TRUE;
474 }
475
476
477 /** reads the next token from the input file into the token buffer; returns whether a token was read */
478 static
479 SCIP_Bool getNextToken(
480 SCIP* scip, /**< SCIP data structure */
481 FZNINPUT* fzninput /**< FZN reading data */
482 )
483 {
484 SCIP_Bool hasdot;
485 FZNEXPTYPE exptype;
486 char* buf;
487 int tokenlen;
488
489 assert(fzninput != NULL);
490 assert(fzninput->bufpos < fzninput->linebufsize);
491
492 /* if the current line got marked as comment get the next line */
493 if( fzninput->comment && !getNextLine(scip, fzninput) )
494 {
495 SCIPdebugMsg(scip, "(line %d) end of file\n", fzninput->linenumber);
496 return FALSE;
497 }
498
499 /* check the token stack */
500 if( fzninput->npushedtokens > 0 )
501 {
502 SCIPswapPointers((void**)&fzninput->token, (void**)&fzninput->pushedtokens[fzninput->npushedtokens-1]);
503 fzninput->npushedtokens--;
504 SCIPdebugMsg(scip, "(line %d) read token again: '%s'\n", fzninput->linenumber, fzninput->token);
505 return TRUE;
506 }
507
508 /* skip delimiters */
509 buf = fzninput->linebuf;
510 while( isDelimChar(buf[fzninput->bufpos]) )
511 {
512 if( buf[fzninput->bufpos] == '\0' )
513 {
514 if( !getNextLine(scip, fzninput) )
515 {
516 SCIPdebugMsg(scip, "(line %d) end of file\n", fzninput->linenumber);
517 return FALSE;
518 }
519 assert(fzninput->bufpos == 0);
520 /* update buf, because the linebuffer may have been reallocated */
521 buf = fzninput->linebuf;
522 }
523 else
524 {
525 fzninput->bufpos++;
526 fzninput->linepos++;
527 }
528 }
529 assert(fzninput->bufpos < fzninput->linebufsize);
530 assert(!isDelimChar(buf[fzninput->bufpos]));
531
532 hasdot = FALSE;
533 exptype = FZN_EXP_NONE;
534
535 if( buf[fzninput->bufpos] == '.' && buf[fzninput->bufpos+1] == '.')
536 {
537 /* found <..> which only occurs in Ranges and is a "keyword" */
538 tokenlen = 2;
539 fzninput->bufpos += 2;
540 fzninput->linepos += 2;
541 fzninput->token[0] = '.';
542 fzninput->token[1] = '.';
543 }
544 else if( isValueChar(buf[fzninput->bufpos], buf[fzninput->bufpos+1], TRUE, &hasdot, &exptype) )
545 {
546 /* read value token */
547 tokenlen = 0;
548 do
549 {
550 assert(tokenlen < fzninput->linebufsize);
551 assert(!isDelimChar(buf[fzninput->bufpos]));
552 fzninput->token[tokenlen] = buf[fzninput->bufpos];
553 tokenlen++;
554 fzninput->bufpos++;
555 fzninput->linepos++;
556 assert(fzninput->bufpos < fzninput->linebufsize);
557 }
558 while( isValueChar(buf[fzninput->bufpos], buf[fzninput->bufpos+1], FALSE, &hasdot, &exptype) );
559
560 fzninput->hasdot = hasdot;
561 }
562 else
563 {
564 /* read non-value token */
565 tokenlen = 0;
566 do
567 {
568 assert(tokenlen < fzninput->linebufsize);
569 fzninput->token[tokenlen] = buf[fzninput->bufpos];
570 tokenlen++;
571 fzninput->bufpos++;
572 fzninput->linepos++;
573
574 /* check for annotations */
575 if(tokenlen == 1 && fzninput->token[0] == ':' && buf[fzninput->bufpos] == ':')
576 {
577 fzninput->token[tokenlen] = buf[fzninput->bufpos];
578 tokenlen++;
579 fzninput->bufpos++;
580 fzninput->linepos++;
581 break;
582 }
583
584 if( tokenlen == 1 && isTokenChar(fzninput->token[0]) )
585 break;
586 }
587 while( !isDelimChar(buf[fzninput->bufpos]) && !isTokenChar(buf[fzninput->bufpos]) );
588 }
589
590 assert(tokenlen < fzninput->linebufsize);
591 fzninput->token[tokenlen] = '\0';
592
593 SCIPdebugMsg(scip, "(line %d) read token: '%s'\n", fzninput->linenumber, fzninput->token);
594
595 return TRUE;
596 }
597
598 /** puts the current token on the token stack, such that it is read at the next call to getNextToken() */
599 static
600 void pushToken(
601 FZNINPUT* fzninput /**< FZN reading data */
602 )
603 {
604 assert(fzninput != NULL);
605 assert(fzninput->npushedtokens < FZN_MAX_PUSHEDTOKENS);
606
607 SCIPswapPointers((void**)&fzninput->pushedtokens[fzninput->npushedtokens], (void**)&fzninput->token);
608 fzninput->npushedtokens++;
609 }
610
611 /** checks whether the current token is a semicolon which closes a statement */
612 static
613 SCIP_Bool isEndStatement(
614 FZNINPUT* fzninput /**< FZN reading data */
615 )
616 {
617 assert(fzninput != NULL);
618
619 return isChar(fzninput->token, ';');
620 }
621
622 /** returns whether the current token is a value */
623 static
624 SCIP_Bool isValue(
625 const char* token, /**< token to check */
626 SCIP_Real* value /**< pointer to store the value (unchanged, if token is no value) */
627 )
628 {
629 double val;
630 char* endptr;
631
632 assert(value != NULL);
633
634 val = strtod(token, &endptr);
635 if( endptr != token && *endptr == '\0' )
636 {
637 *value = val;
638 return TRUE;
639 }
640
641 return FALSE;
642 }
643
644 /*
645 * Local methods (for reading)
646 */
647
648 /** issues an error message and marks the FlatZinc data to have errors */
649 static
650 void syntaxError(
651 SCIP* scip, /**< SCIP data structure */
652 FZNINPUT* fzninput, /**< FZN reading data */
653 const char* msg /**< error message */
654 )
655 {
656 assert(fzninput != NULL);
657 assert(scip != NULL);
658
659 SCIPerrorMessage("Syntax error in line %d: %s found <%s>\n", fzninput->linenumber, msg, fzninput->token);
660 SCIPerrorMessage(" input: %s\n", fzninput->linebuf);
661
662 fzninput->haserror = TRUE;
663 }
664
665 /** returns whether a syntax error was detected */
666 static
667 SCIP_Bool hasError(
668 FZNINPUT* fzninput /**< FZN reading data */
669 )
670 {
671 assert(fzninput != NULL);
672
673 return (fzninput->haserror || !fzninput->valid);
674 }
675
676 /** create reader data */
677 static
678 SCIP_RETCODE readerdataCreate(
679 SCIP* scip, /**< SCIP data structure */
680 SCIP_READERDATA** readerdata /**< pointer to reader data */
681 )
682 {
683 SCIP_CALL( SCIPallocBlockMemory(scip, readerdata) );
684
685 (*readerdata)->vararrays = NULL;
686 (*readerdata)->nvararrays = 0;
687 (*readerdata)->vararrayssize = 0;
688
689 return SCIP_OKAY;
690 }
691
692 /** ensure the size if the variable array */
693 static
694 SCIP_RETCODE ensureVararrySize(
695 SCIP* scip, /**< SCIP data structure */
696 SCIP_READERDATA* readerdata /**< reader data */
697 )
698 {
699 int nvararrays;
700 int vararrayssize;
701
702 nvararrays = readerdata->nvararrays;
703 vararrayssize = readerdata->vararrayssize;
704
705 if( vararrayssize == nvararrays )
706 {
707 if( vararrayssize == 0 )
708 {
709 vararrayssize = 100;
710 SCIP_CALL( SCIPallocBlockMemoryArray(scip, &readerdata->vararrays, vararrayssize) );
711 }
712 else
713 {
714 vararrayssize *= 2;
715 SCIP_CALL( SCIPreallocBlockMemoryArray(scip, &readerdata->vararrays, readerdata->vararrayssize, vararrayssize) );
716 }
717 }
718
719 readerdata->vararrayssize = vararrayssize;
720
721 return SCIP_OKAY;
722 }
723
724 /** ensure the size if the variable array */
725 static
726 SCIP_RETCODE ensureVararrySizeFznInput(
727 SCIP* scip, /**< SCIP data structure */
728 FZNINPUT* fzninput /**< FZN reading data */
729 )
730 {
731 int nvararrays;
732 int vararrayssize;
733
734 nvararrays = fzninput->nvararrays;
735 vararrayssize = fzninput->vararrayssize;
736
737 if( vararrayssize == nvararrays )
738 {
739 if( vararrayssize == 0 )
740 {
741 vararrayssize = 100;
742 SCIP_CALL( SCIPallocBlockMemoryArray(scip, &fzninput->vararrays, vararrayssize) );
743 }
744 else
745 {
746 vararrayssize *= 2;
747 SCIP_CALL( SCIPreallocBlockMemoryArray(scip, &fzninput->vararrays, fzninput->vararrayssize, vararrayssize) );
748 }
749 }
750
751 fzninput->vararrayssize = vararrayssize;
752
753 return SCIP_OKAY;
754 }
755
756 /** ensure the size if the variable array */
757 static
758 SCIP_RETCODE ensureConstarrySizeFznInput(
759 SCIP* scip, /**< SCIP data structure */
760 FZNINPUT* fzninput /**< FZN reading data */
761 )
762 {
763 int nconstarrays;
764 int constarrayssize;
765
766 nconstarrays = fzninput->nconstarrays;
767 constarrayssize = fzninput->constarrayssize;
768
769 if( constarrayssize == nconstarrays )
770 {
771 if( constarrayssize == 0 )
772 {
773 constarrayssize = 100;
774 SCIP_CALL( SCIPallocBlockMemoryArray(scip, &fzninput->constarrays, constarrayssize) );
775 }
776 else
777 {
778 constarrayssize *= 2;
779 SCIP_CALL( SCIPreallocBlockMemoryArray(scip, &fzninput->constarrays, fzninput->constarrayssize, constarrayssize) );
780 }
781 }
782
783 fzninput->constarrayssize = constarrayssize;
784
785 return SCIP_OKAY;
786 }
787
788 /** print given value in FlatZinc format to given stream */
789 static
790 void printValue(
791 SCIP* scip, /**< SCIP data structure */
792 FILE* file, /**< output file (or NULL for standard output) */
793 SCIP_Real value, /**< value to print */
794 FZNNUMBERTYPE type /**< FlatZinc number type */
795 )
796 {
797 switch( type )
798 {
799 case FZN_BOOL:
800 if( value < 0.5 )
801 SCIPinfoMessage(scip, file, "false");
802 else
803 SCIPinfoMessage(scip, file, "true");
804 break;
805 case FZN_INT:
806 {
807 SCIP_Longint longvalue;
808 longvalue = SCIPconvertRealToLongint(scip, value);
809 SCIPinfoMessage(scip, file, "%" SCIP_LONGINT_FORMAT "", longvalue);
810 break;
811 }
812 case FZN_FLOAT:
813 if( SCIPisIntegral(scip, value) )
814 {
815 printValue(scip, file, value, FZN_INT);
816
817 /* add a ".0" to be type save */
818 SCIPinfoMessage(scip, file, ".0");
819 }
820 else
821 {
822 SCIPinfoMessage(scip, file, "%.1f", value);
823 }
824 break;
825 }
826 }
827
828 /*
829 * Local methods (for VARARRAY)
830 */
831
832 /** free dimension structure */
833 static
834 SCIP_RETCODE copyDimensions(
835 SCIP* scip, /**< SCIP data structure */
836 DIMENSIONS** target, /**< pointer to dimension target structure */
837 DIMENSIONS* source /**< dimension source */
838 )
839 {
840 if( source != NULL )
841 {
842 SCIP_CALL( SCIPallocBlockMemory(scip, target) );
843
844 SCIP_CALL( SCIPduplicateBlockMemoryArray(scip, &(*target)->lbs, source->lbs, source->ndims) );
845 SCIP_CALL( SCIPduplicateBlockMemoryArray(scip, &(*target)->ubs, source->ubs, source->ndims) );
846 (*target)->ndims = source->ndims;
847 (*target)->size = source->ndims;
848 }
849 else
850 *target = NULL;
851
852 return SCIP_OKAY;
853 }
854
855 /** create variable array data structure */
856 static
857 SCIP_RETCODE createVararray(
858 SCIP* scip, /**< SCIP data structure */
859 VARARRAY** vararray, /**< pointer to variable array */
860 const char* name, /**< name of the variable array */
861 SCIP_VAR** vars, /**< array of variables */
862 int nvars, /**< number of variables */
863 FZNNUMBERTYPE type, /**< variable type */
864 DIMENSIONS* info /**< dimension information for output */
865 )
866 {
867 /* allocate memory for the new vararray struct */
868 SCIP_CALL( SCIPallocBlockMemory(scip, vararray) );
869
870 /* copy variable pointers */
871 SCIP_CALL( SCIPduplicateBlockMemoryArray(scip, &(*vararray)->vars, vars, nvars) );
872
873 /* copy variable array name */
874 SCIP_CALL( SCIPduplicateBlockMemoryArray(scip, &(*vararray)->name, name, strlen(name)+1) );
875
876 SCIP_CALL( copyDimensions(scip, &(*vararray)->info, info) );
877
878 (*vararray)->nvars = nvars;
879 (*vararray)->type = type;
880
881 return SCIP_OKAY;
882 }
883
884 /** free dimension structure */
885 static
886 void freeDimensions(
887 SCIP* scip, /**< SCIP data structure */
888 DIMENSIONS** dim /**< pointer to dimension structure */
889 )
890 {
891 if( *dim != NULL )
892 {
893 SCIPfreeBlockMemoryArrayNull(scip, &(*dim)->lbs, (*dim)->size);
894 SCIPfreeBlockMemoryArrayNull(scip, &(*dim)->ubs, (*dim)->size);
895 SCIPfreeBlockMemory(scip, dim);
896 }
897 }
898
899 /** free variable array data structure */
900 static
901 void freeVararray(
902 SCIP* scip, /**< SCIP data structure */
903 VARARRAY** vararray /**< pointer to variable array */
904 )
905 {
906 freeDimensions(scip, &(*vararray)->info);
907
908 SCIPfreeBlockMemoryArray(scip, &(*vararray)->name, strlen((*vararray)->name) + 1);
909 SCIPfreeBlockMemoryArray(scip, &(*vararray)->vars, (*vararray)->nvars);
910
911 SCIPfreeBlockMemory(scip, vararray);
912 }
913
914 /** searches the variable array data base if a constant array exists with the given name; if it exists it is returned */
915 static
916 VARARRAY* findVararray(
917 FZNINPUT* fzninput, /**< FZN reading data */
918 const char* name /**< variable array name */
919 )
920 {
921 VARARRAY* vararray;
922 int c;
923
924 /* search in constants array list for a constants array with the given name */
925 for( c = 0; c < fzninput->nvararrays; ++c )
926 {
927 vararray = fzninput->vararrays[c];
928
929 if( equalTokens(name, vararray->name) )
930 return vararray;
931 }
932
933 return NULL;
934 }
935
936 /*
937 * Local methods (for CONSTARRAY)
938 */
939
940 /** create constant array data structure */
941 static
942 SCIP_RETCODE createConstarray(
943 SCIP* scip, /**< SCIP data structure */
944 CONSTARRAY** constarray, /**< pointer to constant array */
945 const char* name, /**< name of the variable array */
946 FZNCONSTANT** constants, /**< array of constants */
947 int nconstants, /**< number of constants */
948 FZNNUMBERTYPE type /**< constant type */
949 )
950 {
951 SCIPdebugMsg(scip, "create constant array <%s>\n", name);
952
953 /* allocate memory for the new constarray struct */
954 SCIP_CALL( SCIPallocBlockMemory(scip, constarray) );
955
956 /* copy constant values */
957 SCIP_CALL( SCIPduplicateBlockMemoryArray(scip, &(*constarray)->constants, constants, nconstants) );
958
959 /* copy constant array name */
960 SCIP_CALL( SCIPduplicateBlockMemoryArray(scip, &(*constarray)->name, name, strlen(name)+1) );
961
962 (*constarray)->nconstants = nconstants;
963 (*constarray)->type = type;
964
965 return SCIP_OKAY;
966 }
967
968 /** free constant array data structure */
969 static
970 void freeConstarray(
971 SCIP* scip, /**< SCIP data structure */
972 CONSTARRAY** constarray /**< pointer to constant array */
973 )
974 {
975 SCIPdebugMsg(scip, "free constant array <%s>\n", (*constarray)->name);
976
977 /* free variable pointers */
978 SCIPfreeBlockMemoryArray(scip, &(*constarray)->constants, (*constarray)->nconstants);
979
980 /* free variable array name */
981 SCIPfreeBlockMemoryArray(scip, &(*constarray)->name, strlen((*constarray)->name) + 1);
982
983 /* allocate memory for the new vararray struct */
984 SCIPfreeBlockMemory(scip, constarray);
985 }
986
987 /** searches the constant array data base if a constant array exists with the given name; if it exists it is returned */
988 static
989 CONSTARRAY* findConstarray(
990 FZNINPUT* fzninput, /**< FZN reading data */
991 const char* name /**< constant array name */
992 )
993 {
994 CONSTARRAY* constarray;
995 int c;
996
997 /* search in constants array list for a constants array with the given name */
998 for( c = 0; c < fzninput->nconstarrays; ++c )
999 {
1000 constarray = fzninput->constarrays[c];
1001
1002 if( equalTokens(name, constarray->name) )
1003 return constarray;
1004 }
1005
1006 return NULL;
1007 }
1008
1009 /** add variable to the reader data */
1010 static
1011 SCIP_RETCODE readerdataAddOutputvar(
1012 SCIP* scip, /**< SCIP data structure */
1013 SCIP_READERDATA* readerdata, /**< reader data */
1014 SCIP_VAR* var, /**< variable to add to the reader data */
1015 FZNNUMBERTYPE type /**< variable type */
1016 )
1017 {
1018 DIMENSIONS* info;
1019 const char* name;
1020 VARARRAY* vararray;
1021 int nvararrays;
1022
1023 nvararrays = readerdata->nvararrays;
1024
1025 SCIP_CALL( ensureVararrySize(scip, readerdata) );
1026 assert(nvararrays < readerdata->vararrayssize);
1027
1028 /* get variable name */
1029 name = SCIPvarGetName(var);
1030
1031 /* allocate memory for the new vararray struct */
1032 SCIP_CALL( SCIPallocBlockMemory(scip, &vararray) );
1033
1034 /* copy variable pointers */
1035 SCIP_CALL( SCIPduplicateBlockMemoryArray(scip, &vararray->vars, &var, 1) );
1036
1037 /* copy variable array name */
1038 SCIP_CALL( SCIPduplicateBlockMemoryArray(scip, &vararray->name, name, strlen(name)+1) );
1039
1040 SCIP_CALL( SCIPallocBlockMemory(scip, &info) );
1041 info->lbs = NULL;
1042 info->ubs = NULL;
1043 info->ndims = 0;
1044 info->size = 0;
1045
1046 vararray->info = info;
1047 vararray->nvars = 1;
1048 vararray->type = type;
1049
1050 readerdata->vararrays[nvararrays] = vararray;
1051 readerdata->nvararrays++;
1052
1053 return SCIP_OKAY;
1054 }
1055
1056 /** add variable to the reader data */
1057 static
1058 SCIP_RETCODE readerdataAddOutputvararray(
1059 SCIP* scip, /**< SCIP data structure */
1060 SCIP_READERDATA* readerdata, /**< reader data */
1061 const char* name, /**< name of the variable array */
1062 SCIP_VAR** vars, /**< array of variable to add to the reader data */
1063 int nvars, /**< number of variables */
1064 FZNNUMBERTYPE type, /**< variable type */
1065 DIMENSIONS* info /**< dimension information for output */
1066 )
1067 {
1068 VARARRAY* vararray;
1069 int nvararrays;
1070
1071 nvararrays = readerdata->nvararrays;
1072
1073 SCIP_CALL( ensureVararrySize(scip, readerdata) );
1074 assert(nvararrays < readerdata->vararrayssize);
1075
1076 /* create variable array data structure */
1077 SCIP_CALL( createVararray(scip, &vararray, name, vars, nvars, type, info) );
1078
1079 readerdata->vararrays[nvararrays] = vararray;
1080 readerdata->nvararrays++;
1081
1082 return SCIP_OKAY;
1083 }
1084
1085 /** add variable to the input data */
1086 static
1087 SCIP_RETCODE fzninputAddVararray(
1088 SCIP* scip, /**< SCIP data structure */
1089 FZNINPUT* fzninput, /**< FZN reading data */
1090 const char* name, /**< name of the variable array */
1091 SCIP_VAR** vars, /**< array of variables */
1092 int nvars, /**< number of variables */
1093 FZNNUMBERTYPE type, /**< variable type */
1094 DIMENSIONS* info /**< dimension information for output */
1095 )
1096 {
1097 VARARRAY* vararray;
1098 int nvararrays;
1099
1100 nvararrays = fzninput->nvararrays;
1101
1102 SCIP_CALL( ensureVararrySizeFznInput(scip, fzninput) );
1103 assert(nvararrays < fzninput->vararrayssize);
1104
1105 /* create variable array data structure */
1106 SCIP_CALL( createVararray(scip, &vararray, name, vars, nvars, type, info) );
1107
1108 fzninput->vararrays[nvararrays] = vararray;
1109 fzninput->nvararrays++;
1110
1111 return SCIP_OKAY;
1112 }
1113
1114 /** add variable to the reader data */
1115 static
1116 SCIP_RETCODE fzninputAddConstarray(
1117 SCIP* scip, /**< SCIP data structure */
1118 FZNINPUT* fzninput, /**< FZN reading data */
1119 const char* name, /**< name of the variable array */
1120 FZNCONSTANT** constants, /**< array of constants */
1121 int nconstants, /**< number of constants */
1122 FZNNUMBERTYPE type /**< variable type */
1123 )
1124 {
1125 CONSTARRAY* constarray;
1126 int nconstarrays;
1127
1128 nconstarrays = fzninput->nconstarrays;
1129
1130 SCIP_CALL( ensureConstarrySizeFznInput(scip, fzninput) );
1131 assert(nconstarrays < fzninput->constarrayssize);
1132
1133 /* create constant array structure */
1134 SCIP_CALL( createConstarray(scip, &constarray, name, constants, nconstants, type) );
1135
1136 fzninput->constarrays[nconstarrays] = constarray;
1137 fzninput->nconstarrays++;
1138
1139 return SCIP_OKAY;
1140 }
1141
1142 /** creates, adds, and releases a quadratic constraint */
1143 static
1144 SCIP_RETCODE createQuadraticCons(
1145 SCIP* scip, /**< SCIP data structure */
1146 const char* name, /**< name of constraint */
1147 int nlinvars, /**< number of linear terms (n) */
1148 SCIP_VAR** linvars, /**< array with variables in linear part (x_i) */
1149 SCIP_Real* lincoefs, /**< array with coefficients of variables in linear part (b_i) */
1150 int nquadterms, /**< number of quadratic terms (m) */
1151 SCIP_VAR** quadvars1, /**< array with first variables in quadratic terms (y_j) */
1152 SCIP_VAR** quadvars2, /**< array with second variables in quadratic terms (z_j) */
1153 SCIP_Real* quadcoefs, /**< array with coefficients of quadratic terms (a_j) */
1154 SCIP_Real lhs, /**< left hand side of quadratic equation (ell) */
1155 SCIP_Real rhs, /**< right hand side of quadratic equation (u) */
1156 SCIP_Bool initialconss, /**< should model constraints be marked as initial? */
1157 SCIP_Bool dynamicconss, /**< should model constraints be subject to aging? */
1158 SCIP_Bool dynamicrows /**< should rows be added and removed dynamically to the LP? */
1159 )
1160 {
1161 SCIP_CONS* cons;
1162
1163 SCIP_CALL( SCIPcreateConsQuadraticNonlinear(scip, &cons, name, nlinvars, linvars, lincoefs, nquadterms, quadvars1,
1164 quadvars2, quadcoefs, lhs, rhs, initialconss, TRUE, TRUE, TRUE, TRUE, FALSE, FALSE, dynamicconss,
1165 dynamicrows) );
1166
1167 SCIPdebugPrintCons(scip, cons, NULL);
1168
1169 SCIP_CALL( SCIPaddCons(scip, cons) );
1170 SCIP_CALL( SCIPreleaseCons(scip, &cons) );
1171
1172 return SCIP_OKAY;
1173 }
1174
1175 /** creates, adds, and releases a linear constraint */
1176 static
1177 SCIP_RETCODE createLinearCons(
1178 SCIP* scip, /**< SCIP data structure */
1179 const char* name, /**< name of constraint */
1180 int nvars, /**< number of nonzeros in the constraint */
1181 SCIP_VAR** vars, /**< array with variables of constraint entries */
1182 SCIP_Real* vals, /**< array with coefficients of constraint entries */
1183 SCIP_Real lhs, /**< left hand side of constraint */
1184 SCIP_Real rhs, /**< right hand side of constraint */
1185 SCIP_Bool initialconss, /**< should model constraints be marked as initial? */
1186 SCIP_Bool dynamicconss, /**< should model constraints be subject to aging? */
1187 SCIP_Bool dynamicrows /**< should rows be added and removed dynamically to the LP? */
1188 )
1189 {
1190 SCIP_CONS* cons;
1191
1192 SCIP_CALL( SCIPcreateConsLinear(scip, &cons, name, nvars, vars, vals, lhs, rhs,
1193 initialconss, TRUE, TRUE, TRUE, TRUE, FALSE, FALSE, dynamicconss, dynamicrows, FALSE) );
1194
1195 SCIPdebugPrintCons(scip, cons, NULL);
1196
1197 SCIP_CALL( SCIPaddCons(scip, cons) );
1198 SCIP_CALL( SCIPreleaseCons(scip, &cons) );
1199
1200 return SCIP_OKAY;
1201 }
1202
1203 /** create a linking between the two given identifiers */
1204 static
1205 SCIP_RETCODE createLinking(
1206 SCIP* scip, /**< SCIP data structure */
1207 FZNINPUT* fzninput, /**< FZN reading data */
1208 const char* consname, /**< name of constraint */
1209 const char* name1, /**< name of first identifier */
1210 const char* name2, /**< name of second identifier */
1211 SCIP_Real lhs, /**< left hand side of the linking */
1212 SCIP_Real rhs /**< right hand side of the linking */
1213 )
1214 {
1215 SCIP_VAR** vars;
1216 SCIP_Real vals[] = {0.0,0.0};
1217 SCIP_Real value1;
1218 SCIP_Real value2;
1219 int nvars;
1220
1221 nvars = 0;
1222 value1 = 0.0;
1223 value2 = 0.0;
1224
1225 SCIP_CALL( SCIPallocBufferArray(scip, &vars, 2) );
1226
1227 vars[nvars] = (SCIP_VAR*) SCIPhashtableRetrieve(fzninput->varHashtable, (char*) name1);
1228 if( vars[nvars] != NULL )
1229 {
1230 vals[nvars] = 1.0;
1231 nvars++;
1232 }
1233 else if( !isValue(name1, &value1) )
1234 {
1235 FZNCONSTANT* constant;
1236
1237 constant = (FZNCONSTANT*) SCIPhashtableRetrieve(fzninput->constantHashtable, (char*) name1);
1238 assert(constant != NULL);
1239
1240 value1 = constant->value;
1241 }
1242
1243 vars[nvars] = (SCIP_VAR*) SCIPhashtableRetrieve(fzninput->varHashtable, (char*) name2);
1244 if( vars[nvars] != NULL )
1245 {
1246 vals[nvars] = -1.0;
1247 nvars++;
1248 }
1249 else if( !isValue(name2, &value2) )
1250 {
1251 FZNCONSTANT* constant;
1252
1253 constant = (FZNCONSTANT*) SCIPhashtableRetrieve(fzninput->constantHashtable, (char*) name2);
1254 assert(constant != NULL);
1255
1256 value2 = constant->value;
1257 }
1258
1259 if( !SCIPisInfinity(scip, -lhs) )
1260 lhs += (value2 - value1);
1261
1262 if( !SCIPisInfinity(scip, rhs) )
1263 rhs += (value2 - value1);
1264
1265 SCIP_CALL( createLinearCons(scip, consname, nvars, vars, vals, lhs, rhs, fzninput->initialconss, fzninput->dynamicconss, fzninput->dynamicrows) );
1266
1267 SCIPfreeBufferArray(scip, &vars);
1268
1269 return SCIP_OKAY;
1270 }
1271
1272 /** parse array index expression */
1273 static
1274 void parseArrayIndex(
1275 SCIP* scip, /**< SCIP data structure */
1276 FZNINPUT* fzninput, /**< FZN reading data */
1277 int* idx /**< pointer to store the array index */
1278 )
1279 {
1280 SCIP_Real value;
1281
1282 assert( isChar(fzninput->token, '[') );
1283
1284 /* parse array index expression */
1285 if( !getNextToken(scip, fzninput) || isEndStatement(fzninput) )
1286 {
1287 syntaxError(scip, fzninput, "expecting array index expression");
1288 return;
1289 }
1290
1291 if( isIdentifier(fzninput->token) )
1292 {
1293 FZNCONSTANT* constant;
1294
1295 /* identifier has to be one of a constant */
1296 constant = (FZNCONSTANT*) SCIPhashtableRetrieve(fzninput->constantHashtable, fzninput->token);
1297
1298 if( constant == NULL )
1299 syntaxError(scip, fzninput, "unknown index name");
1300 else
1301 {
1302 assert(constant->type == FZN_INT);
1303 *idx = (int) constant->value;
1304 }
1305 }
1306 else if( isValue(fzninput->token, &value) )
1307 {
1308 assert( fzninput->hasdot == FALSE );
1309 *idx = (int) value;
1310 }
1311 else
1312 syntaxError(scip, fzninput, "expecting array index expression");
1313 }
1314
1315 /** unroll assignment if it is an array access one */
1316 static
1317 void flattenAssignment(
1318 SCIP* scip, /**< SCIP data structure */
1319 FZNINPUT* fzninput, /**< FZN reading data */
1320 char* assignment /**< assignment to unroll */
1321 )
1322 {
1323 assert(scip != NULL);
1324 assert(fzninput != NULL);
1325
1326 SCIPdebugMsg(scip, "parse assignment expression\n");
1327
1328 if( !getNextToken(scip, fzninput) || isEndStatement(fzninput) )
1329 {
1330 syntaxError(scip, fzninput, "expecting more tokens");
1331 return;
1332 }
1333
1334 if( isIdentifier(fzninput->token) )
1335 {
1336 char name[FZN_BUFFERLEN];
1337 int idx;
1338
1339 (void) SCIPsnprintf(name, FZN_BUFFERLEN, "%s", fzninput->token);
1340
1341 if( !getNextToken(scip, fzninput) )
1342 {
1343 syntaxError(scip, fzninput, "expecting at least a semicolon to close the statement");
1344 return;
1345 }
1346
1347 /* check if it is an array access expression */
1348 if( isChar(fzninput->token, '[') )
1349 {
1350 idx = -1;
1351 parseArrayIndex(scip, fzninput, &idx);
1352
1353 assert(idx >= 0);
1354
1355 if( !getNextToken(scip, fzninput) || !isChar(fzninput->token, ']') )
1356 {
1357 syntaxError(scip, fzninput, "expecting token <]>");
1358 return;
1359 }
1360
1361 /* put constant name or variable name together */
1362 (void) SCIPsnprintf(assignment, FZN_BUFFERLEN, "%s[%d]", name, idx);
1363 }
1364 else
1365 {
1366 (void) SCIPsnprintf(assignment, FZN_BUFFERLEN, "%s", name);
1367
1368 /* push the current token back for latter evaluations */
1369 pushToken(fzninput);
1370 }
1371 }
1372 else
1373 (void) SCIPsnprintf(assignment, FZN_BUFFERLEN, "%s", fzninput->token);
1374 }
1375
1376 /** computes w.r.t. to the given side value and relation the left and right side for a SCIP linear constraint */
1377 static
1378 void computeLinearConsSides(
1379 SCIP* scip, /**< SCIP data structure */
1380 FZNINPUT* fzninput, /**< FZN reading data */
1381 const char* name, /**< name of the relation */
1382 SCIP_Real sidevalue, /**< parsed side value */
1383 SCIP_Real* lhs, /**< pointer to left hand side */
1384 SCIP_Real* rhs /**< pointer to right hand side */
1385 )
1386 {
1387 SCIPdebugMsg(scip, "check relation <%s>\n", name);
1388
1389 /* compute left and right hand side of the linear constraint */
1390 if( equalTokens(name, "eq") )
1391 {
1392 *lhs = sidevalue;
1393 *rhs = sidevalue;
1394 }
1395 else if( equalTokens(name, "ge") )
1396 {
1397 *lhs = sidevalue;
1398 }
1399 else if( equalTokens(name, "le") )
1400 {
1401 *rhs = sidevalue;
1402 }
1403 else if( equalTokens(name, "gt") )
1404 {
1405 /* greater than only works if there are not continuous variables are involved */
1406 *lhs = sidevalue + 1.0;
1407 }
1408 else if( equalTokens(name, "lt") )
1409 {
1410 /* less than only works if there are not continuous variables are involved */
1411 *rhs = sidevalue - 1.0;
1412 }
1413 else
1414 syntaxError(scip, fzninput, "unknown relation in constraint identifier name");
1415
1416 SCIPdebugMsg(scip, "lhs = %g, rhs = %g\n", *lhs, *rhs);
1417 }
1418
1419 /** parse a list of elements which is separates by a comma */
1420 static
1421 SCIP_RETCODE parseList(
1422 SCIP* scip, /**< SCIP data structure */
1423 FZNINPUT* fzninput, /**< FZN reading data */
1424 char*** elements, /**< pointer to char* array for storing the elements of the list */
1425 int* nelements, /**< pointer to store the number of elements */
1426 int selements /**< size of the elements char* array */
1427 )
1428 {
1429 char assignment[FZN_BUFFERLEN];
1430 assert(selements > 0);
1431
1432 /* check if the list is not empty */
1433 if( getNextToken(scip, fzninput) && !isChar(fzninput->token, ']') )
1434 {
1435 /* push back token */
1436 pushToken(fzninput);
1437
1438 /* loop through the array */
1439 do
1440 {
1441 if(selements == *nelements)
1442 {
1443 selements *= 2;
1444 SCIP_CALL( SCIPreallocBufferArray(scip, elements, selements) );
1445 }
1446
1447 /* parse and flatten assignment */
1448 flattenAssignment(scip, fzninput, assignment);
1449
1450 if( hasError(fzninput) )
1451 break;
1452
1453 /* store assignment */
1454 SCIP_CALL( SCIPduplicateBufferArray(scip, &(*elements)[(*nelements)], assignment, (int) strlen(assignment) + 1) ); /*lint !e866*/
1455
1456 (*nelements)++;
1457 }
1458 while( getNextToken(scip, fzninput) && isChar(fzninput->token, ',') );
1459 }
1460 else
1461 {
1462 SCIPdebugMsg(scip, "list is empty\n");
1463 }
1464
1465 /* push back ']' which closes the list */
1466 pushToken(fzninput);
1467
1468 return SCIP_OKAY;
1469 }
1470
1471 /** parse range expression */
1472 static
1473 void parseRange(
1474 SCIP* scip, /**< SCIP data structure */
1475 FZNINPUT* fzninput, /**< FZN reading data */
1476 FZNNUMBERTYPE* type, /**< pointer to store the number type */
1477 SCIP_Real* lb, /**< pointer to store the lower bound */
1478 SCIP_Real* ub /**< pointer to store the upper bound */
1479 )
1480 {
1481 if( !getNextToken(scip, fzninput) )
1482 {
1483 syntaxError(scip, fzninput, "expected left side of range");
1484 return;
1485 }
1486
1487 /* current token should be the lower bound */
1488 if( !isValue(fzninput->token, lb) )
1489 {
1490 syntaxError(scip, fzninput, "expected lower bound value");
1491 return;
1492 }
1493
1494 /* check if we have a float notation or an integer notation which defines the type of the variable */
1495 if( fzninput->hasdot || !SCIPisIntegral(scip, *lb) )
1496 *type = FZN_FLOAT;
1497 else
1498 *type = FZN_INT;
1499
1500 /* parse next token which should be <..> */
1501 if( !getNextToken(scip, fzninput) || !equalTokens(fzninput->token, "..") )
1502 {
1503 syntaxError(scip, fzninput, "expected <..>");
1504 return;
1505 }
1506
1507 /* parse upper bound */
1508 if( !getNextToken(scip, fzninput) || !isValue(fzninput->token, ub) )
1509 {
1510 syntaxError(scip, fzninput, "expected upper bound value");
1511 return;
1512 }
1513
1514 /* check if upper bound notation fits which lower bound notation */
1515 if( fzninput->hasdot != (*type == FZN_FLOAT) )
1516 {
1517 SCIPwarningMessage(scip, "lower bound and upper bound mismatch in value type, assume %s variable type\n",
1518 fzninput->hasdot ? "an integer" : "a continuous");
1519 }
1520 }
1521
1522 /** parse dimension information */
1523 static
1524 SCIP_RETCODE parseOutputDimensioninfo(
1525 SCIP* scip, /**< SCIP data structure */
1526 FZNINPUT* fzninput, /**< FZN reading data */
1527 DIMENSIONS** info /**< pointer to store the output dimension information if one */
1528 )
1529 {
1530 FZNNUMBERTYPE type;
1531 SCIP_Real lb;
1532 SCIP_Real ub;
1533 int nelements;
1534 int size;
1535
1536 nelements = 0;
1537 size = 100;
1538
1539 SCIP_CALL( SCIPallocBlockMemory(scip, info) );
1540 SCIP_CALL( SCIPallocBlockMemoryArray(scip, &(*info)->lbs, size) );
1541 SCIP_CALL( SCIPallocBlockMemoryArray(scip, &(*info)->ubs, size) );
1542 (*info)->size = size;
1543
1544 /* check for bracket */
1545 if( !getNextToken(scip, fzninput) || !isChar(fzninput->token, '(') )
1546 {
1547 syntaxError(scip, fzninput, "expecting <(> after <output_array>");
1548 return SCIP_OKAY;
1549 }
1550
1551 while( getNextToken(scip, fzninput) && !isChar(fzninput->token, ']') )
1552 {
1553 parseRange(scip, fzninput, &type, &lb, &ub);
1554
1555 if( fzninput->haserror )
1556 return SCIP_OKAY;
1557
1558 assert(type == FZN_INT);
1559
1560 if( nelements == size )
1561 {
1562 size *= 2;
1563 SCIP_CALL( SCIPreallocBlockMemoryArray(scip, &(*info)->lbs, (*info)->size, size) );
1564 SCIP_CALL( SCIPreallocBlockMemoryArray(scip, &(*info)->ubs, (*info)->size, size) );
1565 (*info)->size = size;
1566 }
1567
1568 /* we assume integer bounds */
1569 (*info)->lbs[nelements] = (int) lb;
1570 (*info)->ubs[nelements] = (int) ub;
1571 nelements++;
1572 }
1573
1574 (*info)->ndims = nelements;
1575
1576 /* check for colon */
1577 if( !getNextToken(scip, fzninput) || !isChar(fzninput->token, ')') )
1578 syntaxError(scip, fzninput, "expecting <)>");
1579
1580 return SCIP_OKAY;
1581 }
1582
1583 /** parse identifier name without annotations */
1584 static
1585 SCIP_RETCODE parseName(
1586 SCIP* scip, /**< SCIP data structure */
1587 FZNINPUT* fzninput, /**< FZN reading data */
1588 char* name, /**< pointer to store the name */
1589 SCIP_Bool* output, /**< pointer to store if the name has the annotations to output */
1590 DIMENSIONS** info /**< pointer to store the output dimension information if one */
1591 )
1592 {
1593 if( output != NULL )
1594 (*output) = FALSE;
1595
1596 /* check for colon */
1597 if( !getNextToken(scip, fzninput) || !isChar(fzninput->token, ':') )
1598 {
1599 syntaxError(scip, fzninput, "expecting colon <:>");
1600 return SCIP_OKAY;
1601 }
1602
1603 /* parse identifier name */
1604 if( !getNextToken(scip, fzninput) || !isIdentifier(fzninput->token) )
1605 {
1606 syntaxError(scip, fzninput, "expecting identifier name");
1607 return SCIP_OKAY;
1608 }
1609
1610 /* copy identifier name */
1611 (void)SCIPsnprintf(name, FZN_BUFFERLEN-1, "%s", (const char*)fzninput->token);
1612
1613 /* search for an assignment; therefore, skip annotations */
1614 do
1615 {
1616 if( !getNextToken(scip, fzninput) )
1617 {
1618 syntaxError(scip, fzninput, "expected at least a semicolon to close statement");
1619 return SCIP_OKAY;
1620 }
1621
1622 /* check if the name has the annotation to be part of the output */
1623 if( equalTokens(fzninput->token, "output_var") && output != NULL )
1624 (*output) = TRUE;
1625 else if( equalTokens(fzninput->token, "output_array") && output != NULL)
1626 {
1627 (*output) = TRUE;
1628 assert(info != NULL);
1629 SCIP_CALL( parseOutputDimensioninfo(scip, fzninput, info) );
1630 }
1631
1632 if( isEndStatement(fzninput) )
1633 break;
1634 }
1635 while( !isChar(fzninput->token, '=') );
1636
1637 /* push back '=' or ';' */
1638 pushToken(fzninput);
1639
1640 return SCIP_OKAY;
1641 }
1642
1643 /** parse variable/constant (array) type (integer, float, bool, or set) */
1644 static
1645 void parseType(
1646 SCIP* scip, /**< SCIP data structure */
1647 FZNINPUT* fzninput, /**< FZN reading data */
1648 FZNNUMBERTYPE* type, /**< pointer to store the number type */
1649 SCIP_Real* lb, /**< pointer to store the lower bound */
1650 SCIP_Real* ub /**< pointer to store the lower bound */
1651 )
1652 {
1653 if( !getNextToken(scip, fzninput) || isEndStatement(fzninput) )
1654 {
1655 syntaxError(scip, fzninput, "missing token");
1656 return;
1657 }
1658
1659 *lb = -SCIPinfinity(scip);
1660 *ub = SCIPinfinity(scip);
1661
1662 /* parse variable type or bounds */
1663 if( equalTokens(fzninput->token, "bool") )
1664 {
1665 *type = FZN_BOOL;
1666 *lb = 0.0;
1667 *ub = 1.0;
1668 }
1669 else if( equalTokens(fzninput->token, "float") )
1670 *type = FZN_FLOAT;
1671 else if( equalTokens(fzninput->token, "int") )
1672 *type = FZN_INT;
1673 else if( equalTokens(fzninput->token, "set") || isChar(fzninput->token, '{') )
1674 {
1675 SCIPwarningMessage(scip, "sets are not supported yet\n");
1676 fzninput->valid = FALSE;
1677 return;
1678 }
1679 else
1680 {
1681 /* the type is not explicitly given; it is given through the a range
1682 * expression; therefore, push back the current token since it
1683 * belongs to the range expression */
1684 pushToken(fzninput);
1685 parseRange(scip, fzninput, type, lb, ub);
1686
1687 if( fzninput->haserror )
1688 return;
1689 }
1690
1691 SCIPdebugMsg(scip, "range = [%g,%g]\n", *lb, *ub);
1692
1693 assert(*lb <= *ub);
1694 }
1695
1696 /** applies assignment */
1697 static
1698 SCIP_RETCODE applyVariableAssignment(
1699 SCIP* scip, /**< SCIP data structure */
1700 FZNINPUT* fzninput, /**< FZN reading data */
1701 SCIP_VAR* var, /**< variable to assign something */
1702 FZNNUMBERTYPE type, /**< number type */
1703 const char* assignment /**< assignment */
1704 )
1705 {
1706 FZNCONSTANT* constant;
1707 SCIP_VAR* linkVar;
1708 SCIP_Bool boolvalue;
1709 SCIP_Real realvalue;
1710 SCIP_Real fixvalue;
1711 SCIP_Real vals[] = {1.0,-1.0};
1712
1713 linkVar = (SCIP_VAR*) SCIPhashtableRetrieve(fzninput->varHashtable, (char*) assignment);
1714 constant = (FZNCONSTANT*) SCIPhashtableRetrieve(fzninput->constantHashtable, (char*) assignment);
1715
1716 realvalue = SCIP_INVALID;
1717 boolvalue = FALSE;
1718
1719 if( linkVar == NULL )
1720 {
1721 if( isBoolExp(assignment, &boolvalue) && type == FZN_BOOL )
1722 fixvalue = (SCIP_Real) boolvalue;
1723 else if( isValue(assignment, &realvalue) && type != FZN_BOOL )
1724 fixvalue = realvalue;
1725 else if( constant != NULL )
1726 fixvalue = constant->value;
1727 else
1728 {
1729 syntaxError(scip, fzninput, "assignment is not recognizable");
1730 return SCIP_OKAY;
1731 }
1732
1733 /* create fixing constraint */
1734 SCIP_CALL( createLinearCons(scip, "fixing", 1, &var, vals, fixvalue, fixvalue, fzninput->initialconss, fzninput->dynamicconss, fzninput->dynamicrows) );
1735 }
1736 else
1737 {
1738 SCIP_VAR** vars;
1739
1740 SCIP_CALL( SCIPallocBufferArray(scip, &vars, 2) );
1741 vars[0] = var;
1742 vars[1] = linkVar;
1743
1744 SCIP_CALL( createLinearCons(scip, "link", 2, vars, vals, 0.0, 0.0, fzninput->initialconss, fzninput->dynamicconss, fzninput->dynamicrows) );
1745
1746 SCIPfreeBufferArray(scip, &vars);
1747 }
1748
1749 return SCIP_OKAY;
1750 }
1751
1752 /** applies constant assignment expression */
1753 static
1754 SCIP_RETCODE createConstantAssignment(
1755 SCIP* scip, /**< SCIP data structure */
1756 FZNCONSTANT** constant, /**< pointer to constant */
1757 FZNINPUT* fzninput, /**< FZN reading data */
1758 const char* name, /**< constant name */
1759 FZNNUMBERTYPE type, /**< number type */
1760 const char* assignment /**< assignment to apply */
1761 )
1762 {
1763 SCIP_Bool boolvalue;
1764 SCIP_Real realvalue;
1765 SCIP_Real value;
1766
1767 (*constant) = (FZNCONSTANT*) SCIPhashtableRetrieve(fzninput->constantHashtable, (char*) assignment);
1768 realvalue = SCIP_INVALID;
1769 boolvalue = FALSE;
1770
1771 if( *constant != NULL )
1772 {
1773 /* check if the constant type fits */
1774 if( type != (*constant)->type )
1775 {
1776 syntaxError(scip, fzninput, "type error");
1777 return SCIP_OKAY;
1778 }
1779
1780 value = (*constant)->value;
1781 }
1782 else if( isBoolExp(assignment, &boolvalue) && type == FZN_BOOL )
1783 {
1784 value = (SCIP_Real) boolvalue;
1785 }
1786 else if( isValue(assignment, &realvalue) && type != FZN_BOOL )
1787 {
1788 value = realvalue;
1789 }
1790 else
1791 {
1792 syntaxError(scip, fzninput, "assignment is not recognizable");
1793 return SCIP_OKAY;
1794 }
1795
1796 /* get buffer memory for FZNCONSTANT struct */
1797 SCIP_CALL( SCIPallocBuffer(scip, constant) );
1798
1799 (*constant)->type = type;
1800 SCIP_CALL( SCIPduplicateBufferArray(scip, &(*constant)->name, name, (int) strlen(name) + 1) );
1801 (*constant)->value = value;
1802
1803 /* store constant */
1804 if( fzninput->sconstants == fzninput->nconstants )
1805 {
1806 assert(fzninput->sconstants > 0);
1807 fzninput->sconstants *= 2;
1808 SCIP_CALL( SCIPreallocBufferArray(scip, &fzninput->constants, fzninput->sconstants) );
1809 }
1810
1811 assert(fzninput->sconstants > fzninput->nconstants);
1812 fzninput->constants[fzninput->nconstants] = *constant;
1813 fzninput->nconstants++;
1814
1815 SCIP_CALL( SCIPhashtableInsert(fzninput->constantHashtable, (void*) (*constant)) );
1816
1817 return SCIP_OKAY;
1818 }
1819
1820 /** parse array type ( (i) variable or constant; (ii) integer, float, bool, or set) */
1821 static
1822 void parseArrayType(
1823 SCIP* scip, /**< SCIP data structure */
1824 FZNINPUT* fzninput, /**< FZN reading data */
1825 SCIP_Bool* isvararray, /**< pointer to store if it is a variable or constant array */
1826 FZNNUMBERTYPE* type, /**< pointer to store number type */
1827 SCIP_Real* lb, /**< pointer to store the lower bound */
1828 SCIP_Real* ub /**< pointer to store the lower bound */
1829 )
1830 {
1831 if( !getNextToken(scip, fzninput) || !equalTokens(fzninput->token, "of") )
1832 {
1833 syntaxError(scip, fzninput, "expected keyword <of>");
1834 return;
1835 }
1836
1837 if( !getNextToken(scip, fzninput) )
1838 {
1839 syntaxError(scip, fzninput, "expected more tokens");
1840 return;
1841 }
1842
1843 /* check if it is a variable or constant array */
1844 if( equalTokens(fzninput->token, "var") )
1845 *isvararray = TRUE;
1846 else
1847 {
1848 /* push token back since it belongs to the type declaration */
1849 pushToken(fzninput);
1850 *isvararray = FALSE;
1851 }
1852
1853 /* pares array type and range */
1854 parseType(scip, fzninput, type, lb, ub);
1855 }
1856
1857 /** parse an array assignment */
1858 static
1859 SCIP_RETCODE parseArrayAssignment(
1860 SCIP* scip, /**< SCIP data structure */
1861 FZNINPUT* fzninput, /**< FZN reading data */
1862 char*** elements, /**< pointer to string array to store the parsed elements */
1863 int* nelements, /**< pointer to store the number of parsed elements */
1864 int selements /**< size of the string array elements */
1865 )
1866 {
1867 assert(scip != NULL);
1868 assert(fzninput != NULL);
1869 assert(*nelements >= 0);
1870 assert(selements >= *nelements);
1871
1872 /* check for opening brackets */
1873 if( !getNextToken(scip, fzninput) || !isChar(fzninput->token, '[') )
1874 {
1875 syntaxError(scip, fzninput, "expected token <[>");
1876 return SCIP_OKAY;
1877 }
1878
1879 SCIP_CALL( parseList(scip, fzninput, elements, nelements, selements) );
1880
1881 if( hasError(fzninput) )
1882 return SCIP_OKAY;
1883
1884 /* check for closing brackets */
1885 if( !getNextToken(scip, fzninput) || !isChar(fzninput->token, ']') )
1886 syntaxError(scip, fzninput, "expected token <]>");
1887
1888 return SCIP_OKAY;
1889 }
1890
1891 /** parse array dimension */
1892 static
1893 void parseArrayDimension(
1894 SCIP* scip, /**< SCIP data structure */
1895 FZNINPUT* fzninput, /**< FZN reading data */
1896 int* nelements /**< pointer to store the size of the array */
1897 )
1898 {
1899 FZNNUMBERTYPE type;
1900 SCIP_Real left;
1901 SCIP_Real right;
1902
1903 if( !getNextToken(scip, fzninput) || !isChar(fzninput->token, '[') )
1904 {
1905 syntaxError(scip, fzninput, "expected token <[> for array dimension");
1906 return;
1907 }
1908
1909 /* get array dimension */
1910 parseRange(scip, fzninput, &type, &left, &right);
1911
1912 if( fzninput->haserror )
1913 return;
1914
1915 if( type != FZN_INT || left != 1.0 || right <= 0.0 )
1916 {
1917 syntaxError(scip, fzninput, "invalid array dimension format");
1918 return;
1919 }
1920
1921 *nelements = (int) right;
1922
1923 if( !getNextToken(scip, fzninput) || !isChar(fzninput->token, ']') )
1924 {
1925 syntaxError(scip, fzninput, "expected token <]> for array dimension");
1926 return;
1927 }
1928 }
1929
1930 /** creates and adds a variable to SCIP and stores it for latter use in fzninput structure */
1931 static
1932 SCIP_RETCODE createVariable(
1933 SCIP* scip, /**< SCIP data structure */
1934 FZNINPUT* fzninput, /**< FZN reading data */
1935 SCIP_VAR** var, /**< pointer to hold the created variable, or NULL */
1936 const char* name, /**< name of the variable */
1937 SCIP_Real lb, /**< lower bound of the variable */
1938 SCIP_Real ub, /**< upper bound of the variable */
1939 FZNNUMBERTYPE type /**< number type */
1940 )
1941 {
1942 SCIP_VAR* varcopy;
1943 SCIP_VARTYPE vartype;
1944
1945 assert(scip != NULL);
1946 assert(fzninput != NULL);
1947 assert(lb <= ub);
1948
1949 switch(type)
1950 {
1951 case FZN_BOOL:
1952 vartype = SCIP_VARTYPE_BINARY;
1953 break;
1954 case FZN_INT:
1955 vartype = SCIP_VARTYPE_INTEGER;
1956 break;
1957 case FZN_FLOAT:
1958 vartype = SCIP_VARTYPE_CONTINUOUS;
1959 break;
1960 default:
1961 syntaxError(scip, fzninput, "unknown variable type");
1962 return SCIP_OKAY;
1963 }
1964
1965 /* create variable */
1966 SCIP_CALL( SCIPcreateVar(scip, &varcopy, name, lb, ub, 0.0, vartype, !(fzninput->dynamiccols), fzninput->dynamiccols, NULL, NULL, NULL, NULL, NULL) );
1967 SCIP_CALL( SCIPaddVar(scip, varcopy) );
1968
1969 SCIPdebugMsg(scip, "created variable\n");
1970 SCIPdebug( SCIP_CALL( SCIPprintVar(scip, varcopy, NULL) ) );
1971
1972 /* variable name should not exist before */
1973 assert(SCIPhashtableRetrieve(fzninput->varHashtable, varcopy) == NULL);
1974
1975 /* insert variable into the hashmap for later use in the constraint section */
1976 SCIP_CALL( SCIPhashtableInsert(fzninput->varHashtable, varcopy) );
1977
1978 /* copy variable pointer before releasing the variable to keep the pointer to the variable */
1979 if( var != NULL )
1980 *var = varcopy;
1981
1982 /* release variable */
1983 SCIP_CALL( SCIPreleaseVar(scip, &varcopy) );
1984
1985 return SCIP_OKAY;
1986 }
1987
1988
1989 /** parse variable array assignment and create the variables */
1990 static
1991 SCIP_RETCODE parseVariableArray(
1992 SCIP* scip, /**< SCIP data structure */
1993 SCIP_READERDATA* readerdata, /**< reader data */
1994 FZNINPUT* fzninput, /**< FZN reading data */
1995 const char* name, /**< array name */
1996 int nvars, /**< number of variables */
1997 FZNNUMBERTYPE type, /**< number type */
1998 SCIP_Real lb, /**< lower bound of the variables */
1999 SCIP_Real ub, /**< lower bound of the variables */
2000 DIMENSIONS* info /**< dimension information */
2001 )
2002 {
2003 SCIP_VAR** vars;
2004 char varname[FZN_BUFFERLEN];
2005 int v;
2006
2007 /* create variables and add them to the problem */
2008 SCIP_CALL( SCIPallocBufferArray(scip, &vars, nvars) );
2009
2010 for( v = 0; v < nvars; ++v )
2011 {
2012 (void) SCIPsnprintf(varname, FZN_BUFFERLEN, "%s[%d]", name, v + 1);
2013
2014 /* create variable */
2015 SCIP_CALL( createVariable(scip, fzninput, &vars[v], varname, lb, ub, type) );
2016 }
2017
2018 if( !getNextToken(scip, fzninput) )
2019 {
2020 syntaxError(scip, fzninput, "expected semicolon");
2021 }
2022 else
2023 {
2024 if( isChar(fzninput->token, '=') )
2025 {
2026 char** assigns;
2027 int nassigns;
2028
2029 SCIP_CALL( SCIPallocBufferArray(scip, &assigns, nvars) );
2030 nassigns = 0;
2031
2032 SCIP_CALL( parseArrayAssignment(scip, fzninput, &assigns, &nassigns, nvars) );
2033
2034 if(!hasError(fzninput) )
2035 {
2036 for( v = 0; v < nvars && !hasError(fzninput); ++v )
2037 {
2038 /* parse and apply assignment */
2039 SCIP_CALL( applyVariableAssignment(scip, fzninput, vars[v], type, assigns[v]) );
2040 }
2041 }
2042
2043 freeStringBufferArray(scip, assigns, nassigns);
2044 }
2045 else
2046 {
2047 /* push back the ';' */
2048 assert( isEndStatement(fzninput) );
2049 pushToken(fzninput);
2050 }
2051
2052 if( info != NULL )
2053 {
2054 SCIP_CALL( readerdataAddOutputvararray(scip, readerdata, name, vars, nvars, type, info) );
2055 }
2056
2057 /* add variable information to fzninput since this array name might be used later in the fzn file */
2058 SCIP_CALL( fzninputAddVararray(scip, fzninput, name, vars, nvars, type, info) );
2059 }
2060
2061 SCIPfreeBufferArray(scip, &vars);
2062
2063 return SCIP_OKAY;
2064 }
2065
2066 /** parse constant array assignment and create the constants */
2067 static
2068 SCIP_RETCODE parseConstantArray(
2069 SCIP* scip, /**< SCIP data structure */
2070 FZNINPUT* fzninput, /**< FZN reading data */
2071 const char* name, /**< array name */
2072 int nconstants, /**< number of constants */
2073 FZNNUMBERTYPE type /**< number type */
2074 )
2075 {
2076 FZNCONSTANT** constants;
2077 char** assigns;
2078 char constantname[FZN_BUFFERLEN];
2079 int nassigns;
2080 int c;
2081
2082 if( !getNextToken(scip, fzninput) || !isChar(fzninput->token, '=') )
2083 {
2084 syntaxError(scip, fzninput, "expected token <=>");
2085 return SCIP_OKAY;
2086 }
2087
2088 SCIP_CALL( SCIPallocBufferArray(scip, &assigns, nconstants) );
2089 SCIP_CALL( SCIPallocBufferArray(scip, &constants, nconstants) );
2090 nassigns = 0;
2091
2092 SCIP_CALL( parseArrayAssignment(scip, fzninput, &assigns, &nassigns, nconstants) );
2093
2094 if( !hasError(fzninput) )
2095 {
2096 for( c = 0; c < nconstants; ++c )
2097 {
2098 (void) SCIPsnprintf(constantname, FZN_BUFFERLEN, "%s[%d]", name, c + 1);
2099 SCIP_CALL( createConstantAssignment(scip, &constants[c], fzninput, constantname, type, assigns[c]) );
2100 }
2101
2102 /* add variable information to fzninput since this array name might be used later in the fzn file */
2103 SCIP_CALL( fzninputAddConstarray(scip, fzninput, name, constants, nconstants, type) );
2104 }
2105
2106 SCIPfreeBufferArray(scip, &constants);
2107 freeStringBufferArray(scip, assigns, nassigns);
2108
2109 return SCIP_OKAY;
2110 }
2111
2112 /** parse predicate expression */
2113 static
2114 SCIP_RETCODE parsePredicate(
2115 SCIP* scip, /**< SCIP data structure */
2116 FZNINPUT* fzninput /**< FZN reading data */
2117 )
2118 {
2119 assert(scip != NULL);
2120
2121 /* mark predicate expression as comment such that it gets skipped */
2122 fzninput->comment = TRUE;
2123
2124 return SCIP_OKAY;
2125 }
2126
2127 /** parse array expression */
2128 static
2129 SCIP_RETCODE parseArray(
2130 SCIP* scip, /**< SCIP data structure */
2131 SCIP_READERDATA* readerdata, /**< reader data */
2132 FZNINPUT* fzninput /**< FZN reading data */
2133 )
2134 {
2135 FZNNUMBERTYPE type;
2136 DIMENSIONS* info;
2137 int nelements;
2138 SCIP_Real lb;
2139 SCIP_Real ub;
2140 SCIP_Bool isvararray;
2141 SCIP_Bool output;
2142 char name[FZN_BUFFERLEN];
2143
2144 assert(scip != NULL);
2145 assert(fzninput != NULL);
2146
2147 info = NULL;
2148 isvararray = FALSE;
2149 nelements = -1;
2150
2151 SCIPdebugMsg(scip, "parse array expression\n");
2152
2153 /* parse array dimension */
2154 parseArrayDimension(scip, fzninput, &nelements);
2155 assert(hasError(fzninput) || nelements > 0);
2156
2157 if( hasError(fzninput) )
2158 return SCIP_OKAY;
2159
2160 /* parse array type ( (i) variable or constant; (ii) integer, float, bool, or set) */
2161 parseArrayType(scip, fzninput, &isvararray, &type, &lb, &ub);
2162
2163 if( hasError(fzninput) )
2164 return SCIP_OKAY;
2165
2166 /* parse array name */
2167 SCIP_CALL( parseName(scip, fzninput, name, &output, &info) );
2168 assert(!output || info != NULL);
2169
2170 if( hasError(fzninput) )
2171 return SCIP_OKAY;
2172
2173 SCIPdebugMsg(scip, "found <%s> array named <%s> of type <%s> and size <%d> with bounds [%g,%g] (output %u)\n",
2174 isvararray ? "variable" : "constant", name,
2175 type == FZN_BOOL ? "bool" : type == FZN_INT ? "integer" : "float", nelements, lb, ub, output);
2176
2177 if( isvararray )
2178 SCIP_CALL( parseVariableArray(scip, readerdata, fzninput, name, nelements, type, lb, ub, info) );
2179 else
2180 SCIP_CALL( parseConstantArray(scip, fzninput, name, nelements, type) );
2181
2182 freeDimensions(scip, &info);
2183
2184 return SCIP_OKAY;
2185 }
2186
2187 /** parse variable expression */
2188 static
2189 SCIP_RETCODE parseVariable(
2190 SCIP* scip, /**< SCIP data structure */
2191 SCIP_READERDATA* readerdata, /**< reader data */
2192 FZNINPUT* fzninput /**< FZN reading data */
2193 )
2194 {
2195 SCIP_VAR* var;
2196 FZNNUMBERTYPE type;
2197 SCIP_Real lb;
2198 SCIP_Real ub;
2199 SCIP_Bool output;
2200 char assignment[FZN_BUFFERLEN];
2201 char name[FZN_BUFFERLEN];
2202
2203 assert(scip != NULL);
2204 assert(fzninput != NULL);
2205
2206 SCIPdebugMsg(scip, "parse variable expression\n");
2207
2208 /* pares variable type and range */
2209 parseType(scip, fzninput, &type, &lb, &ub);
2210
2211 if( hasError(fzninput) )
2212 return SCIP_OKAY;
2213
2214 /* parse variable name without annotations */
2215 SCIP_CALL( parseName(scip, fzninput, name, &output, NULL) );
2216
2217 if( hasError(fzninput) )
2218 return SCIP_OKAY;
2219
2220 assert(type == FZN_BOOL || type == FZN_INT || type == FZN_FLOAT);
2221
2222 /* create variable */
2223 SCIP_CALL( createVariable(scip, fzninput, &var, name, lb, ub, type) );
2224
2225 /* check if the variable should be part of the output */
2226 if( output )
2227 {
2228 SCIP_CALL( readerdataAddOutputvar(scip, readerdata, var, type) );
2229 }
2230
2231 if( !getNextToken(scip, fzninput) )
2232 {
2233 syntaxError(scip, fzninput, "expected semicolon");
2234 return SCIP_OKAY;
2235 }
2236
2237 if( isChar(fzninput->token, '=') )
2238 {
2239 /* parse and flatten assignment */
2240 flattenAssignment(scip, fzninput, assignment);
2241
2242 /* apply assignment */
2243 SCIP_CALL( applyVariableAssignment(scip, fzninput, var, type, assignment) );
2244 }
2245 else
2246 pushToken(fzninput);
2247
2248 return SCIP_OKAY;
2249 }
2250
2251 /** parse constant expression */
2252 static
2253 SCIP_RETCODE parseConstant(
2254 SCIP* scip, /**< SCIP data structure */
2255 FZNINPUT* fzninput, /**< FZN reading data */
2256 FZNNUMBERTYPE type /**< constant type */
2257 )
2258 {
2259 FZNCONSTANT* constant;
2260 char name[FZN_BUFFERLEN];
2261 char assignment[FZN_BUFFERLEN];
2262
2263 assert(scip != NULL);
2264 assert(fzninput != NULL);
2265 assert(type == FZN_INT || type == FZN_FLOAT || type == FZN_BOOL);
2266
2267 SCIPdebugMsg(scip, "parse constant expression\n");
2268
2269 /* parse name of the constant */
2270 SCIP_CALL( parseName(scip, fzninput, name, NULL, NULL) );
2271
2272 if( hasError(fzninput) )
2273 return SCIP_OKAY;
2274
2275 if( !getNextToken(scip, fzninput) || !isChar(fzninput->token, '=') )
2276 {
2277 syntaxError(scip, fzninput, "expected token <=>");
2278 return SCIP_OKAY;
2279 }
2280
2281 /* the assignment has to be an other constant or a suitable value */
2282 flattenAssignment(scip, fzninput, assignment);
2283
2284 /* applies constant assignment and creates constant */
2285 SCIP_CALL( createConstantAssignment(scip, &constant, fzninput, name, type, assignment) );
2286
2287 return SCIP_OKAY;
2288 }
2289
2290 /** evaluates current token as constant */
2291 static
2292 void parseValue(
2293 SCIP* scip, /**< SCIP data structure */
2294 FZNINPUT* fzninput, /**< FZN reading data */
2295 SCIP_Real* value, /**< pointer to store value */
2296 const char* assignment /**< assignment to parse a value */
2297 )
2298 {
2299 if( isValue(assignment, value) )
2300 return;
2301
2302 /* if it is an identifier name, it has to belong to a constant or fixed variable */
2303 if( isIdentifier(assignment) )
2304 {
2305 FZNCONSTANT* constant;
2306
2307 /* identifier has to be one of a constant */
2308 constant = (FZNCONSTANT*) SCIPhashtableRetrieve(fzninput->constantHashtable, (char*) assignment);
2309
2310 if( constant == NULL )
2311 {
2312 SCIP_VAR* var;
2313
2314 var = (SCIP_VAR*) SCIPhashtableRetrieve(fzninput->varHashtable, (char*) assignment);
2315
2316 if( var == NULL )
2317 syntaxError(scip, fzninput, "unknown constant name");
2318 else
2319 {
2320 if( SCIPisEQ(scip, SCIPvarGetLbOriginal(var), SCIPvarGetUbOriginal(var)) )
2321 (*value) = SCIPvarGetLbOriginal(var);
2322 else
2323 syntaxError(scip, fzninput, "expected fixed variable");
2324 }
2325 }
2326 else
2327 (*value) = constant->value;
2328 }
2329 else
2330 syntaxError(scip, fzninput, "expected constant expression");
2331 }
2332
2333 /** parse array expression containing constants */
2334 static
2335 SCIP_RETCODE parseConstantArrayAssignment(
2336 SCIP* scip, /**< SCIP data structure */
2337 FZNINPUT* fzninput, /**< FZN reading data */
2338 SCIP_Real** vals, /**< pointer to value array */
2339 int* nvals, /**< pointer to store the number if values */
2340 int sizevals /**< size of the vals array */
2341 )
2342 {
2343 int c;
2344
2345 assert(*nvals <= sizevals);
2346
2347 /* check for next token */
2348 if( !getNextToken(scip, fzninput) )
2349 {
2350 syntaxError(scip, fzninput, "expected constant array");
2351 return SCIP_OKAY;
2352 }
2353
2354 /* check if an array is given explicitly */
2355 if( isChar(fzninput->token, '[') )
2356 {
2357 char** elements;
2358 SCIP_Real value;
2359 int nelements;
2360
2361 SCIP_CALL( SCIPallocBufferArray(scip, &elements, sizevals) );
2362 nelements = 0;
2363
2364 value = 0.0;
2365
2366 /* push back '[' which closes the list */
2367 pushToken(fzninput);
2368
2369 /* pares array assignment */
2370 SCIP_CALL( parseArrayAssignment(scip, fzninput, &elements, &nelements, sizevals) );
2371
2372 if( sizevals <= *nvals + nelements )
2373 {
2374 SCIP_CALL( SCIPreallocBufferArray(scip, vals, *nvals + nelements) );
2375 }
2376
2377 for( c = 0; c < nelements && !hasError(fzninput); ++c )
2378 {
2379 parseValue(scip, fzninput, &value, elements[c]);
2380 assert(!hasError(fzninput));
2381
2382 (*vals)[(*nvals)] = value;
2383 (*nvals)++;
2384 }
2385
2386 freeStringBufferArray(scip, elements, nelements);
2387 }
2388 else
2389 {
2390 /* array is not given explicitly; therefore, check constant array data base if the given constant array name was
2391 * parsed before
2392 */
2393
2394 CONSTARRAY* constarray;
2395
2396 constarray = findConstarray(fzninput, fzninput->token);
2397
2398 if( constarray != NULL )
2399 {
2400 /* ensure variable array size */
2401 if( sizevals <= *nvals + constarray->nconstants )
2402 {
2403 SCIP_CALL( SCIPreallocBufferArray(scip, vals, *nvals + constarray->nconstants) );
2404 }
2405
2406 for( c = 0; c < constarray->nconstants; ++c )
2407 {
2408 (*vals)[(*nvals)] = constarray->constants[c]->value;
2409 (*nvals)++;
2410 }
2411 }
2412 else
2413 {
2414 /* there is no constant array with the given name; therefore check the variable array data base if such an
2415 * array exist with fixed variables
2416 */
2417
2418 VARARRAY* vararray;
2419
2420 vararray = findVararray(fzninput, fzninput->token);
2421
2422 if( vararray == NULL )
2423 {
2424 syntaxError(scip, fzninput, "unknown constants array name");
2425 }
2426 else
2427 {
2428 /* ensure variable array size */
2429 if( sizevals <= *nvals + vararray->nvars )
2430 {
2431 SCIP_CALL( SCIPreallocBufferArray(scip, vals, *nvals + vararray->nvars) );
2432 }
2433
2434 for( c = 0; c < vararray->nvars; ++c )
2435 {
2436 SCIP_VAR* var;
2437
2438 var = vararray->vars[c];
2439 assert(var != NULL);
2440
2441 if( SCIPisEQ(scip, SCIPvarGetLbOriginal(var), SCIPvarGetUbOriginal(var)) )
2442 {
2443 (*vals)[(*nvals)] = SCIPvarGetLbOriginal(var);
2444 (*nvals)++;
2445 }
2446 else
2447 {
2448 syntaxError(scip, fzninput, "variable array contains unfixed variable");
2449 break;
2450 }
2451 }
2452 }
2453 }
2454 }
2455
2456 return SCIP_OKAY;
2457 }
2458
2459 /** parse array expression containing variables */
2460 static
2461 SCIP_RETCODE parseVariableArrayAssignment(
2462 SCIP* scip, /**< SCIP data structure */
2463 FZNINPUT* fzninput, /**< FZN reading data */
2464 SCIP_VAR*** vars, /**< pointer to variable array */
2465 int* nvars, /**< pointer to store the number if variable */
2466 int sizevars /**< size of the variable array */
2467 )
2468 {
2469 int v;
2470
2471 assert(*nvars <= sizevars);
2472
2473 /* check for next token */
2474 if( !getNextToken(scip, fzninput) )
2475 {
2476 syntaxError(scip, fzninput, "expected constant array");
2477 return SCIP_OKAY;
2478 }
2479
2480 if( isChar(fzninput->token, '[') )
2481 {
2482 char** elements;
2483 int nelements;
2484
2485 SCIP_CALL( SCIPallocBufferArray(scip, &elements, sizevars) );
2486 nelements = 0;
2487
2488 /* push back '[' which closes the list */
2489 pushToken(fzninput);
2490
2491 SCIP_CALL( parseArrayAssignment(scip, fzninput, &elements, &nelements, sizevars) );
2492
2493 if( sizevars <= *nvars + nelements )
2494 {
2495 SCIP_CALL( SCIPreallocBufferArray(scip, vars, *nvars + nelements) );
2496 }
2497
2498 for( v = 0; v < nelements; ++v )
2499 {
2500 (*vars)[(*nvars)] = (SCIP_VAR*) SCIPhashtableRetrieve(fzninput->varHashtable, elements[v]);
2501
2502 if( (*vars)[(*nvars)] == NULL )
2503 {
2504 /* since the given element does not correspond to a variable name
2505 * it might be the case that it is a constant which can be seen as
2506 * as a fixed variable
2507 */
2508
2509 FZNCONSTANT* constant;
2510 SCIP_Real value;
2511
2512 constant = (FZNCONSTANT*) SCIPhashtableRetrieve(fzninput->constantHashtable, (char*) elements[v]);
2513
2514 if( constant != NULL )
2515 {
2516 assert(constant->type == FZN_FLOAT);
2517 value = constant->value;
2518 }
2519 else if(!isValue(elements[v], &value) )
2520 {
2521 char* tmptoken;
2522
2523 tmptoken = fzninput->token;
2524 fzninput->token = elements[v];
2525 syntaxError(scip, fzninput, "expected variable name or constant");
2526
2527 fzninput->token = tmptoken;
2528 break;
2529 }
2530
2531 /* create a fixed variable */
2532 SCIP_CALL( createVariable(scip, fzninput, &(*vars)[*nvars], elements[v], value, value, FZN_FLOAT) );
2533 }
2534
2535 (*nvars)++;
2536 }
2537
2538 freeStringBufferArray(scip, elements, nelements);
2539 }
2540 else
2541 {
2542 VARARRAY* vararray;
2543
2544 vararray = findVararray(fzninput, fzninput->token);
2545
2546 if( vararray != NULL )
2547 {
2548 assert(vararray != NULL);
2549
2550 /* ensure variable array size */
2551 if( sizevars <= *nvars + vararray->nvars )
2552 {
2553 SCIP_CALL( SCIPreallocBufferArray(scip, vars, *nvars + vararray->nvars) );
2554 }
2555
2556 for( v = 0; v < vararray->nvars; ++v )
2557 {
2558 (*vars)[(*nvars)] = vararray->vars[v];
2559 (*nvars)++;
2560 }
2561 }
2562 else
2563 syntaxError(scip, fzninput, "unknown variable array name");
2564 }
2565
2566 return SCIP_OKAY;
2567 }
2568
2569 /** parse linking statement */
2570 static
2571 SCIP_RETCODE parseQuadratic(
2572 SCIP* scip, /**< SCIP data structure */
2573 FZNINPUT* fzninput, /**< FZN reading data */
2574 const char* name /**< name of constraint */
2575 )
2576 {
2577 char** elements;
2578 int nelements;
2579
2580 SCIP_CALL( SCIPallocBufferArray(scip, &elements, 3) );
2581 nelements = 0;
2582
2583 /* parse the list of three elements */
2584 SCIP_CALL( parseList(scip, fzninput, &elements, &nelements, 3) );
2585 assert(nelements == 3);
2586
2587 if( !hasError(fzninput) )
2588 {
2589 SCIP_VAR** vars;
2590 SCIP_Real* vals;
2591 SCIP_Real rhs;
2592 int v;
2593
2594 rhs = 0.0;
2595
2596 SCIP_CALL( SCIPallocBufferArray(scip, &vars, 3) );
2597 SCIP_CALL( SCIPallocBufferArray(scip, &vals, 3) );
2598
2599 for( v = 0; v < 3; ++v )
2600 {
2601 /* collect variable if constraint identifier is a variable */
2602 vars[v] = (SCIP_VAR*) SCIPhashtableRetrieve(fzninput->varHashtable, (char*) elements[v]);
2603
2604 /* parse the numeric value otherwise */
2605 if( vars[v] == NULL )
2606 {
2607 parseValue(scip, fzninput, &vals[v], elements[v]);
2608 assert(!hasError(fzninput));
2609 }
2610 else
2611 vals[v] = SCIP_INVALID;
2612 }
2613
2614 /* the first two identifiers are proper variables => the constraints is indeed quadratic */
2615 if( vars[0] != NULL && vars[1] != NULL )
2616 {
2617 SCIP_Real quadval;
2618 quadval = 1.0;
2619
2620 /* we might have an additional linear term or just a constant */
2621 if( vars[2] != NULL )
2622 {
2623 SCIP_Real linval;
2624 linval = -1.0;
2625
2626 SCIP_CALL( createQuadraticCons(scip, name, 1, &vars[2], &linval, 1, &vars[0], &vars[1], &quadval, rhs, rhs,
2627 fzninput->initialconss, fzninput->dynamicconss, fzninput->dynamicrows) );
2628 }
2629 else
2630 {
2631 rhs += vals[2];
2632 SCIP_CALL( createQuadraticCons(scip, name, 0, NULL, NULL, 1, &vars[0], &vars[1], &quadval, rhs, rhs,
2633 fzninput->initialconss, fzninput->dynamicconss, fzninput->dynamicrows));
2634 }
2635 }
2636 else if( vars[0] != NULL || vars[1] != NULL )
2637 {
2638 int nvars;
2639 nvars = 1;
2640
2641 /* the left hand side of x*y = z is linear (but not constant) */
2642 if( vars[0] == NULL )
2643 SCIPswapPointers((void**)&vars[0], (void**)&vars[1]);
2644 else
2645 SCIPswapPointers((void**)&vals[0], (void**)&vals[1]);
2646
2647 /* after swapping, the variable and the coefficient should stand in front */
2648 assert(vars[0] != NULL && vals[0] != SCIP_INVALID ); /*lint !e777*/
2649
2650 /* the right hand side might be a variable or a constant */
2651 if( vars[2] != NULL )
2652 {
2653 SCIPswapPointers((void**)&vars[1], (void**)&vars[2]);
2654 vals[1] = -1.0;
2655 nvars++;
2656 }
2657 else
2658 {
2659 assert(vals[2] != SCIP_INVALID); /*lint !e777*/
2660 rhs += vals[2];
2661 }
2662
2663 SCIP_CALL( createLinearCons(scip, name, nvars, vars, vals, rhs, rhs, fzninput->initialconss, fzninput->dynamicconss, fzninput->dynamicrows) );
2664 }
2665 else
2666 {
2667 /* the left hand side of x*y = z is constant */
2668 assert(vals[0] != SCIP_INVALID && vals[1] != SCIP_INVALID); /*lint !e777*/
2669
2670 rhs = rhs - vals[0]*vals[1];
2671
2672 /* the right hand side might be a variable or a constant */
2673 if( vars[2] != NULL )
2674 {
2675 SCIP_Real val;
2676 val = -1.0;
2677 SCIP_CALL( createLinearCons(scip, name, 1, &vars[2], &val, rhs, rhs, fzninput->initialconss, fzninput->dynamicconss, fzninput->dynamicrows) );
2678 }
2679 else
2680 {
2681 assert(vals[2] != SCIP_INVALID); /*lint !e777*/
2682 rhs += vals[2];
2683 SCIP_CALL( createLinearCons(scip, name, 0, NULL, NULL, rhs, rhs, fzninput->initialconss, fzninput->dynamicconss, fzninput->dynamicrows) );
2684 }
2685 }
2686
2687 /* free buffer arrays */
2688 SCIPfreeBufferArray(scip, &vals);
2689 SCIPfreeBufferArray(scip, &vars);
2690 }
2691
2692 /* free elements array */
2693 freeStringBufferArray(scip, elements, nelements);
2694
2695 return SCIP_OKAY;
2696 }
2697
2698 /** parse aggregation statement (plus, minus, negate) */
2699 static
2700 SCIP_RETCODE parseAggregation(
2701 SCIP* scip, /**< SCIP data structure */
2702 FZNINPUT* fzninput, /**< FZN reading data */
2703 const char* name, /**< name of constraint */
2704 const char* type /**< linear constraint type */
2705 )
2706 {
2707 /* here we take care of the three expression
2708 *
2709 * - int_plus(x1,x2,x3) -> x1 + x2 == x3
2710 * - int_minus(x1,x2,x3) -> x1 - x2 == x3
2711 * - int_negate(x1,x2) -> x1 + x2 == 0
2712 */
2713 char** elements;
2714 int nelements;
2715
2716 SCIP_CALL( SCIPallocBufferArray(scip, &elements, 3) );
2717 nelements = 0;
2718
2719 /* parse the list of three elements */
2720 SCIP_CALL( parseList(scip, fzninput, &elements, &nelements, 3) );
2721 assert(nelements == 3 || nelements == 2);
2722
2723 if( !hasError(fzninput) )
2724 {
2725 SCIP_VAR** vars;
2726 SCIP_Real* vals;
2727 SCIP_Real value;
2728 SCIP_Real rhs;
2729 int nvars;
2730
2731 nvars = 0;
2732 rhs = 0.0;
2733
2734 SCIP_CALL( SCIPallocBufferArray(scip, &vars, 3) );
2735 SCIP_CALL( SCIPallocBufferArray(scip, &vals, 3) );
2736
2737 /* parse first element */
2738 vars[nvars] = (SCIP_VAR*) SCIPhashtableRetrieve(fzninput->varHashtable, (char*) elements[0]);
2739 if( vars[nvars] == NULL )
2740 {
2741 parseValue(scip, fzninput, &value, elements[0]);
2742 assert(!hasError(fzninput));
2743
2744 rhs -= value;
2745 }
2746 else
2747 {
2748 vals[nvars] = 1.0;
2749 nvars++;
2750 }
2751
2752 /* parse second element */
2753 vars[nvars] = (SCIP_VAR*) SCIPhashtableRetrieve(fzninput->varHashtable, (char*) elements[1]);
2754 if( vars[nvars] == NULL )
2755 {
2756 parseValue(scip, fzninput, &value, elements[1]);
2757 assert(!hasError(fzninput));
2758
2759 if( equalTokens(type, "minus") )
2760 rhs += value;
2761 else
2762 rhs -= value;
2763 }
2764 else
2765 {
2766 if( equalTokens(type, "minus") )
2767 {
2768 /* in case of minus the second element get a -1.0 as coefficient */
2769 vals[nvars] = -1.0;
2770 }
2771 else
2772 vals[nvars] = 1.0;
2773
2774 nvars++;
2775 }
2776
2777 if( !equalTokens(type, "negate") )
2778 {
2779 /* parse third element in case of "minus" or "plus" */
2780 vars[nvars] = (SCIP_VAR*) SCIPhashtableRetrieve(fzninput->varHashtable, (char*) elements[2]);
2781 if( vars[nvars] == NULL )
2782 {
2783 parseValue(scip, fzninput, &value, elements[2]);
2784 assert(!hasError(fzninput));
2785
2786 rhs += value;
2787 }
2788 else
2789 {
2790 vals[nvars] = -1.0;
2791 nvars++;
2792 }
2793 }
2794
2795 SCIP_CALL( createLinearCons(scip, name, nvars, vars, vals, rhs, rhs, fzninput->initialconss, fzninput->dynamicconss, fzninput->dynamicrows) );
2796
2797 /* free buffer arrays */
2798 SCIPfreeBufferArray(scip, &vals);
2799 SCIPfreeBufferArray(scip, &vars);
2800 }
2801
2802 /* free elements array */
2803 freeStringBufferArray(scip, elements, nelements);
2804 return SCIP_OKAY;
2805 }
2806
2807 /** parse linking statement */
2808 static
2809 SCIP_RETCODE parseLinking(
2810 SCIP* scip, /**< SCIP data structure */
2811 FZNINPUT* fzninput, /**< FZN reading data */
2812 const char* name, /**< name of constraint */
2813 const char* type, /**< linear constraint type */
2814 SCIP_Real sidevalue /**< side value of constraint */
2815 )
2816 {
2817 char** names;
2818 SCIP_Real lhs = SCIP_INVALID;
2819 SCIP_Real rhs = SCIP_INVALID;
2820 int nnames;
2821
2822 nnames = 0;
2823 SCIP_CALL( SCIPallocBufferArray(scip, &names, 2) );
2824
2825 SCIP_CALL( parseList(scip, fzninput, &names, &nnames, 2) );
2826 assert(nnames == 2);
2827
2828 if( hasError(fzninput) )
2829 goto TERMINATE;
2830
2831 /* compute left and right side */
2832 computeLinearConsSides(scip, fzninput, type, sidevalue, &lhs, &rhs);
2833
2834 if( hasError(fzninput) )
2835 goto TERMINATE;
2836
2837 SCIP_CALL( createLinking(scip, fzninput, name, names[0], names[1], lhs, rhs) );
2838
2839 TERMINATE:
2840 freeStringBufferArray(scip, names, nnames);
2841
2842 return SCIP_OKAY;
2843 }
2844
2845 /** creates a linear constraint for an array operation */
2846 static
2847 CREATE_CONSTRAINT(createCoercionOpCons)
2848 { /*lint --e{715}*/
2849 assert(scip != NULL);
2850 assert(fzninput != NULL);
2851
2852 /* check if the function identifier name is array operation */
2853 if( !equalTokens(fname, "int2float") && !equalTokens(fname, "bool2int") )
2854 return SCIP_OKAY;
2855
2856 SCIP_CALL( parseLinking(scip, fzninput, fname, "eq", 0.0) );
2857
2858 *created = TRUE;
2859
2860 return SCIP_OKAY;
2861 }
2862
2863 /** creates a linear constraint for an array operation */
2864 static
2865 CREATE_CONSTRAINT(createSetOpCons)
2866 { /*lint --e{715}*/
2867 assert(scip != NULL);
2868 assert(fzninput != NULL);
2869
2870 /* check if the function identifier name is array operation */
2871 if( !equalTokens(ftokens[0], "set") )
2872 return SCIP_OKAY;
2873
2874 fzninput->valid = FALSE;
2875 SCIPwarningMessage(scip, "Line %d: set operations are not supported yet.\n", fzninput->linenumber);
2876
2877 return SCIP_OKAY;
2878 }
2879
2880 /** creates linear constraint for an array operation */
2881 static
2882 CREATE_CONSTRAINT(createArrayOpCons)
2883 { /*lint --e{715}*/
2884 assert(scip != NULL);
2885 assert(fzninput != NULL);
2886
2887 /* check if the function identifier name is array operation */
2888 if( !equalTokens(ftokens[0], "array") )
2889 return SCIP_OKAY;
2890
2891 fzninput->valid = FALSE;
2892 SCIPwarningMessage(scip, "Line %d: array operations are not supported yet.\n", fzninput->linenumber);
2893
2894 return SCIP_OKAY;
2895 }
2896
2897 /** creates a linear constraint for a logical operation */
2898 static
2899 CREATE_CONSTRAINT(createLogicalOpCons)
2900 { /*lint --e{715}*/
2901 assert(scip != NULL);
2902 assert(fzninput != NULL);
2903
2904 /* check if the function identifier name is array operation */
2905 if(nftokens < 2)
2906 return SCIP_OKAY;
2907
2908 if(equalTokens(ftokens[0], "bool") && nftokens == 2 )
2909 {
2910 char** elements;
2911 int nelements;
2912
2913 /* the bool_eq constraint is processed in createComparisonOpCons() */
2914 if( equalTokens(ftokens[1], "eq") || equalTokens(ftokens[1], "ge") || equalTokens(ftokens[1], "le")
2915 || equalTokens(ftokens[1], "lt") || equalTokens(ftokens[1], "gt") )
2916 return SCIP_OKAY;
2917
2918 SCIP_CALL( SCIPallocBufferArray(scip, &elements, 3) );
2919 nelements = 0;
2920
2921 SCIP_CALL( parseList(scip, fzninput, &elements, &nelements, 3) );
2922
2923 if( !hasError(fzninput) )
2924 {
2925 SCIP_CONS* cons;
2926 SCIP_VAR** vars;
2927 int v;
2928 int nvars;
2929
2930 if( equalTokens(ftokens[1], "ne") || equalTokens(ftokens[1], "not") )
2931 nvars = 2;
2932 else
2933 nvars = 3;
2934
2935 SCIP_CALL( SCIPallocBufferArray(scip, &vars, nvars) );
2936
2937 /* collect variable if constraint identifier is a variable */
2938 for( v = 0; v < nvars; ++v )
2939 {
2940 vars[v] = (SCIP_VAR*) SCIPhashtableRetrieve(fzninput->varHashtable, (char*) elements[v]);
2941
2942 if( vars[v] == NULL )
2943 {
2944 syntaxError(scip, fzninput, "unknown variable identifier name");
2945 goto TERMINATE;
2946 }
2947 }
2948
2949 if( equalTokens(ftokens[1], "ne" ) || equalTokens(ftokens[1], "not") )
2950 {
2951 SCIP_Real vals[] = {1.0, 1.0};
2952
2953 SCIP_CALL( SCIPcreateConsLinear(scip, &cons, fname, 2, vars, vals, 1.0, 1.0,
2954 fzninput->initialconss, TRUE, TRUE, TRUE, TRUE, FALSE, FALSE, fzninput->dynamicconss, fzninput->dynamicrows, FALSE) );
2955
2956 *created = TRUE;
2957 }
2958 else if( equalTokens(ftokens[1], "or" ) )
2959 {
2960 SCIP_CALL( SCIPcreateConsOr(scip, &cons, fname, vars[2], 2, vars,
2961 fzninput->initialconss, TRUE, TRUE, TRUE, TRUE, FALSE, FALSE, fzninput->dynamicconss, fzninput->dynamicrows, FALSE) );
2962
2963 *created = TRUE;
2964 }
2965 else if( equalTokens(ftokens[1], "and") )
2966 {
2967 SCIP_CALL( SCIPcreateConsAnd(scip, &cons, fname, vars[2], 2, vars,
2968 fzninput->initialconss, TRUE, TRUE, TRUE, TRUE, FALSE, FALSE, fzninput->dynamicconss, fzninput->dynamicrows, FALSE) );
2969
2970 *created = TRUE;
2971 }
2972 else if( equalTokens(ftokens[1], "xor") )
2973 {
2974 /* swap resultant to front */
2975 SCIPswapPointers((void**)&vars[0], (void**)&vars[2]);
2976
2977 SCIP_CALL( SCIPcreateConsXor(scip, &cons, fname, FALSE, 3, vars,
2978 fzninput->initialconss, TRUE, TRUE, TRUE, TRUE, FALSE, FALSE, fzninput->dynamicconss, fzninput->dynamicrows, FALSE) );
2979
2980 *created = TRUE;
2981 }
2982 else
2983 {
2984 fzninput->valid = FALSE;
2985 SCIPwarningMessage(scip, "logical operation <%s> is not supported yet\n", fname);
2986 goto TERMINATE;
2987 }
2988
2989 SCIPdebugPrintCons(scip, cons, NULL);
2990
2991 SCIP_CALL( SCIPaddCons(scip, cons) );
2992 SCIP_CALL( SCIPreleaseCons(scip, &cons) );
2993
2994 TERMINATE:
2995 SCIPfreeBufferArray(scip, &vars);
2996 }
2997
2998 /* free elements array */
2999 freeStringBufferArray(scip, elements, nelements);
3000 }
3001 else if(equalTokens(ftokens[1], "bool") && nftokens == 3 )
3002 {
3003 SCIP_CONS* cons;
3004 SCIP_VAR** vars;
3005 SCIP_VAR* resvar;
3006 int nvars;
3007 char** elements;
3008 int nelements;
3009 int size;
3010
3011 if( !equalTokens(ftokens[2], "or" ) && !equalTokens(ftokens[2], "and" ) )
3012 {
3013 fzninput->valid = FALSE;
3014 SCIPwarningMessage(scip, "logical operation <%s> is not supported yet\n", fname);
3015 return SCIP_OKAY;
3016 }
3017
3018 size = 10;
3019 nvars = 0;
3020
3021 SCIP_CALL( SCIPallocBufferArray(scip, &vars, size) );
3022 SCIP_CALL( SCIPallocBufferArray(scip, &elements, 1) );
3023 nelements = 0;
3024
3025 SCIPdebugMsg(scip, "found and constraint <%s>\n", fname);
3026
3027 /* parse operand variable array */
3028 SCIP_CALL( parseVariableArrayAssignment(scip, fzninput, &vars, &nvars, size) );
3029
3030 /* check error and for the comma between the variable array and side value */
3031 if( hasError(fzninput) || !getNextToken(scip, fzninput) || !isChar(fzninput->token, ',') )
3032 {
3033 if( hasError(fzninput) )
3034 syntaxError(scip, fzninput, "unexpected error in fzn input");
3035 else
3036 syntaxError(scip, fzninput, "expected token <,>");
3037
3038 goto TERMINATE2;
3039 }
3040
3041 /* parse resultant variable array */
3042 SCIP_CALL( parseList(scip, fzninput, &elements, &nelements, 1) );
3043 resvar = (SCIP_VAR*) SCIPhashtableRetrieve(fzninput->varHashtable, (char*) elements[0]);
3044
3045 /* check error and for the comma between the variable array and side value */
3046 if( hasError(fzninput) || resvar == NULL )
3047 {
3048 if( hasError(fzninput) )
3049 syntaxError(scip, fzninput, "unexpected error in fzn input");
3050 else
3051 syntaxError(scip, fzninput, "unknown variable identifier name");
3052 goto TERMINATE2;
3053 }
3054
3055 /* create the constraint */
3056 if( equalTokens(ftokens[2], "or" ) )
3057 {
3058 SCIP_CALL( SCIPcreateConsOr(scip, &cons, fname, resvar, nvars, vars,
3059 fzninput->initialconss, TRUE, TRUE, TRUE, TRUE, FALSE, FALSE, fzninput->dynamicconss, fzninput->dynamicrows, FALSE) );
3060 }
3061 else
3062 {
3063 assert( equalTokens(ftokens[2], "and") );
3064
3065 SCIP_CALL( SCIPcreateConsAnd(scip, &cons, fname, resvar, nvars, vars,
3066 fzninput->initialconss, TRUE, TRUE, TRUE, TRUE, FALSE, FALSE, fzninput->dynamicconss, fzninput->dynamicrows, FALSE) );
3067 }
3068
3069 SCIPdebugPrintCons(scip, cons, NULL);
3070 *created = TRUE;
3071
3072 SCIP_CALL( SCIPaddCons(scip, cons) );
3073 SCIP_CALL( SCIPreleaseCons(scip, &cons) );
3074
3075 TERMINATE2:
3076 /* free elements array */
3077 freeStringBufferArray(scip, elements, nelements);
3078 SCIPfreeBufferArray(scip, &vars);
3079 }
3080 else if( equalTokens(ftokens[1], "bool") )
3081 {
3082 fzninput->valid = FALSE;
3083 SCIPwarningMessage(scip, "logical operation <%s> is not supported yet\n", fname);
3084 return SCIP_OKAY;
3085 }
3086
3087 return SCIP_OKAY;
3088 }
3089
3090 /** creates a linear constraint for a comparison operation */
3091 static
3092 CREATE_CONSTRAINT(createComparisonOpCons)
3093 { /*lint --e{715}*/
3094 char assignment[FZN_BUFFERLEN];
3095
3096 assert(scip != NULL);
3097 assert(fzninput != NULL);
3098
3099 /* check if the function name ends of "reif" (reified constraint) which SCIP does not support yet */
3100 if( equalTokens(ftokens[nftokens - 1], "reif") )
3101 {
3102 SCIPwarningMessage(scip, "Line %d: reified constraints are not supported.\n", fzninput->linenumber);
3103 fzninput->valid = FALSE;
3104 return SCIP_OKAY;
3105 }
3106
3107 /* the last token can be
3108 * 'eq' -- equal
3109 * 'ne' -- not equal
3110 * 'lt' -- less than
3111 * 'gt' -- greater than
3112 * 'le' -- less or equal than
3113 * 'ge' -- greater or equal than
3114 * => these are comparison constraints
3115 * 'plus' -- addition
3116 * 'minus' -- subtraction
3117 * 'negate' -- negation
3118 * => these are aggregation constraints
3119 * 'times' -- multiplication
3120 * => this is a nonlinear constraint
3121 */
3122 if( strlen(ftokens[nftokens - 1]) != 2 && nftokens != 2 )
3123 return SCIP_OKAY;
3124
3125 /* check if any sets are involved in the constraint */
3126 if( equalTokens(ftokens[0], "set") )
3127 {
3128 SCIPwarningMessage(scip, "constraints using sets are not supported\n");
3129 fzninput->valid = FALSE;
3130 return SCIP_OKAY;
3131 }
3132
3133 /* check if the constraint is a 'not equal' one */
3134 if( equalTokens(ftokens[nftokens - 1], "ne") )
3135 {
3136 SCIPwarningMessage(scip, "constraints with 'not equal' relation are not supported\n");
3137 fzninput->valid = FALSE;
3138 return SCIP_OKAY;
3139 }
3140
3141 /* check if the constraint contains float variable and coefficients and '<' or '>' relation */
3142 if( equalTokens(ftokens[0], "float") &&
3143 (equalTokens(ftokens[nftokens - 1], "lt") || equalTokens(ftokens[nftokens - 1], "gt") ) )
3144 {
3145 SCIPwarningMessage(scip, "constraints with '<' or '>' relation and continuous variables are not supported\n");
3146 fzninput->valid = FALSE;
3147 return SCIP_OKAY;
3148 }
3149
3150 if( equalTokens(ftokens[1], "lin") )
3151 {
3152 SCIP_VAR** vars;
3153 SCIP_Real* vals;
3154 SCIP_Real sidevalue;
3155 int nvars;
3156 int nvals;
3157 int size;
3158
3159 assert(nftokens == 3);
3160
3161 size = 10;
3162 nvars = 0;
3163 nvals = 0;
3164 sidevalue = SCIP_INVALID;
3165
3166 SCIP_CALL( SCIPallocBufferArray(scip, &vars, size) );
3167 SCIP_CALL( SCIPallocBufferArray(scip, &vals, size) );
3168
3169 SCIPdebugMsg(scip, "found linear constraint <%s>\n", fname);
3170
3171 /* pares coefficients array */
3172 SCIP_CALL( parseConstantArrayAssignment(scip, fzninput, &vals, &nvals, size) );
3173
3174 /* check error and for the comma between the coefficient and variable array */
3175 if( hasError(fzninput) || !getNextToken(scip, fzninput) || !isChar(fzninput->token, ',') )
3176 {
3177 if( !hasError(fzninput) )
3178 syntaxError(scip, fzninput, "expected token <,>");
3179
3180 goto TERMINATE;
3181 }
3182
3183 /* pares variable array */
3184 SCIP_CALL( parseVariableArrayAssignment(scip, fzninput, &vars, &nvars, size) );
3185
3186 /* check error and for the comma between the variable array and side value */
3187 if( hasError(fzninput) || !getNextToken(scip, fzninput) || !isChar(fzninput->token, ',') )
3188 {
3189 if( !hasError(fzninput) )
3190 syntaxError(scip, fzninput, "expected token <,>");
3191
3192 goto TERMINATE;
3193 }
3194
3195 /* pares sidevalue */
3196 flattenAssignment(scip, fzninput, assignment);
3197 parseValue(scip, fzninput, &sidevalue, assignment);
3198
3199 if( !hasError(fzninput) )
3200 {
3201 SCIP_Real lhs = -SCIPinfinity(scip);
3202 SCIP_Real rhs = SCIPinfinity(scip);
3203
3204 assert(sidevalue != SCIP_INVALID); /*lint !e777*/
3205
3206 /* compute left and right side */
3207 computeLinearConsSides(scip, fzninput, ftokens[2], sidevalue, &lhs, &rhs);
3208
3209 if( hasError(fzninput) )
3210 goto TERMINATE;
3211
3212 SCIP_CALL( createLinearCons(scip, fname, nvars, vars, vals, lhs, rhs, fzninput->initialconss, fzninput->dynamicconss, fzninput->dynamicrows) );
3213 }
3214
3215 TERMINATE:
3216 SCIPfreeBufferArray(scip, &vals);
3217 SCIPfreeBufferArray(scip, &vars);
3218 }
3219 else if( equalTokens(ftokens[1], "minus") || equalTokens(ftokens[1], "plus") || equalTokens(ftokens[1], "negate") )
3220 {
3221 assert(nftokens == 2);
3222 SCIP_CALL( parseAggregation(scip, fzninput, fname, ftokens[1]) );
3223 }
3224 else if( equalTokens(ftokens[1], "eq") || equalTokens(ftokens[1], "le") || equalTokens(ftokens[1], "ge")
3225 || equalTokens(ftokens[1], "lt") || equalTokens(ftokens[1], "gt") )
3226 {
3227 assert(nftokens == 2);
3228 SCIP_CALL( parseLinking(scip, fzninput, fname, ftokens[1], 0.0) );
3229 }
3230 else if( equalTokens(ftokens[1], "times") )
3231 {
3232 assert(nftokens == 2);
3233 SCIP_CALL( parseQuadratic(scip, fzninput, fname) );
3234 }
3235 else
3236 {
3237 syntaxError(scip, fzninput, "unknown constraint type");
3238 }
3239
3240 *created = TRUE;
3241
3242 return SCIP_OKAY;
3243 }
3244
3245 /** creates an alldifferent constraint */
3246 static
3247 CREATE_CONSTRAINT(createAlldifferentOpCons)
3248 { /*lint --e{715}*/
3249 SCIP_VAR** vars;
3250 #ifdef ALLDIFFERENT
3251 SCIP_CONS* cons;
3252 #endif
3253 int nvars;
3254 int size;
3255
3256 assert(scip != NULL);
3257 assert(fzninput != NULL);
3258
3259 /* check if the function identifier name is array operation */
3260 if( !equalTokens(ftokens[0], "all") || !equalTokens(ftokens[1], "different") )
3261 return SCIP_OKAY;
3262
3263 size = 10;
3264 nvars = 0;
3265 SCIP_CALL( SCIPallocBufferArray(scip, &vars, size) );
3266
3267 SCIPdebugMsg(scip, "parse alldifferent expression\n");
3268
3269 /* pares variable array */
3270 SCIP_CALL( parseVariableArrayAssignment(scip, fzninput, &vars, &nvars, size) );
3271
3272 #ifdef ALLDIFFERENT
3273 /* create alldifferent constraint */
3274 SCIP_CALL( SCIPcreateConsAlldifferent(scip, &cons, fname, nvars, vars,
3275 fzninput->initialconss, TRUE, TRUE, TRUE, TRUE, FALSE, FALSE, fzninput->dynamicconss, fzninput->dynamicrows, FALSE) );
3276
3277 SCIPdebugPrintCons(scip, cons, NULL);
3278
3279 /* add and release the constraint to the problem */
3280 SCIP_CALL( SCIPaddCons(scip, cons) );
3281 SCIP_CALL( SCIPreleaseCons(scip, &cons) );
3282
3283 *created = TRUE;
3284 #endif
3285
3286 SCIPfreeBufferArray(scip, &vars);
3287
3288 return SCIP_OKAY;
3289 }
3290
3291 /** creates an alldifferent constraint */
3292 static
3293 CREATE_CONSTRAINT(createCumulativeOpCons)
3294 { /*lint --e{715}*/
3295 SCIP_CONS* cons;
3296 SCIP_VAR** vars;
3297 SCIP_Real* vals = NULL;
3298 int* durations = NULL;
3299 int* demands = NULL;
3300 SCIP_Real val;
3301 int capacity;
3302 char assignment[FZN_BUFFERLEN];
3303
3304 int nvars;
3305 int ndurations;
3306 int ndemads;
3307 int size;
3308 int i;
3309
3310 assert(scip != NULL);
3311 assert(fzninput != NULL);
3312
3313 /* check if the function identifier name is array operation */
3314 if( !equalTokens(ftokens[0], "cumulative") )
3315 return SCIP_OKAY;
3316
3317 size = 10;
3318 nvars = 0;
3319 ndurations = 0;
3320 ndemads = 0;
3321
3322 SCIPdebugMsg(scip, "parse cumulative expression\n");
3323
3324 /* pares start time variable array */
3325 SCIP_CALL( SCIPallocBufferArray(scip, &vars, size) );
3326 SCIP_CALL( parseVariableArrayAssignment(scip, fzninput, &vars, &nvars, size) );
3327
3328 /* check error and for the comma between the variable array and side value */
3329 if( hasError(fzninput) || !getNextToken(scip, fzninput) || !isChar(fzninput->token, ',') )
3330 {
3331 if( !hasError(fzninput) )
3332 syntaxError(scip, fzninput, "expected token <,>");
3333
3334 goto TERMINATE;
3335 }
3336
3337 /* pares job duration array */
3338 SCIP_CALL( SCIPallocBufferArray(scip, &vals, size) );
3339 SCIP_CALL( parseConstantArrayAssignment(scip, fzninput, &vals, &ndurations, size) );
3340
3341 SCIP_CALL( SCIPallocBufferArray(scip, &durations, ndurations) );
3342 for( i = 0; i < ndurations; ++i )
3343 durations[i] = (int)vals[i];
3344
3345 /* check error and for the comma between the variable array and side value */
3346 if( hasError(fzninput) || !getNextToken(scip, fzninput) || !isChar(fzninput->token, ',') )
3347 {
3348 if( !hasError(fzninput) )
3349 syntaxError(scip, fzninput, "expected token <,>");
3350
3351 goto TERMINATE;
3352 }
3353
3354 /* pares job demand array */
3355 SCIP_CALL( parseConstantArrayAssignment(scip, fzninput, &vals, &ndemads, size) );
3356
3357 SCIP_CALL( SCIPallocBufferArray(scip, &demands, ndemads) );
3358 for( i = 0; i < ndemads; ++i )
3359 demands[i] = (int)vals[i];
3360
3361 /* check error and for the comma between the variable array and side value */
3362 if( hasError(fzninput) || !getNextToken(scip, fzninput) || !isChar(fzninput->token, ',') )
3363 {
3364 if( !hasError(fzninput) )
3365 syntaxError(scip, fzninput, "expected token <,>");
3366
3367 goto TERMINATE;
3368 }
3369
3370 /* parse cumulative capacity */
3371 flattenAssignment(scip, fzninput, assignment);
3372 parseValue(scip, fzninput, &val, assignment);
3373 assert(!hasError(fzninput));
3374
3375 capacity = (int)val;
3376
3377 assert(nvars == ndurations);
3378 assert(nvars == ndemads);
3379
3380 /* create cumulative constraint */
3381 SCIP_CALL( SCIPcreateConsCumulative(scip, &cons, fname, nvars, vars, durations, demands, capacity,
3382 fzninput->initialconss, TRUE, TRUE, TRUE, TRUE, FALSE, FALSE, fzninput->dynamicconss, fzninput->dynamicrows, FALSE) );
3383
3384 SCIPdebugPrintCons(scip, cons, NULL);
3385
3386 /* add and release the constraint to the problem */
3387 SCIP_CALL( SCIPaddCons(scip, cons) );
3388 SCIP_CALL( SCIPreleaseCons(scip, &cons) );
3389
3390 assert(!hasError(fzninput));
3391 *created = TRUE;
3392
3393 TERMINATE:
3394 /* free buffers */
3395 SCIPfreeBufferArrayNull(scip, &demands);
3396 SCIPfreeBufferArrayNull(scip, &durations);
3397 SCIPfreeBufferArrayNull(scip, &vals);
3398 SCIPfreeBufferArray(scip, &vars);
3399
3400 return SCIP_OKAY;
3401 }
3402
3403 /* function pointer array containing all function which can create a constraint */
3404 static CREATE_CONSTRAINT((*constypes[])) = {
3405 createCoercionOpCons,
3406 createSetOpCons,
3407 createLogicalOpCons,
3408 createArrayOpCons,
3409 createComparisonOpCons,
3410 createAlldifferentOpCons,
3411 createCumulativeOpCons
3412 };
3413
3414 /** size of the function pointer array */
3415 static const int nconstypes = 7;
3416
3417
3418 /** parse constraint expression */
3419 static
3420 SCIP_RETCODE parseConstraint(
3421 SCIP* scip, /**< SCIP data structure */
3422 FZNINPUT* fzninput /**< FZN reading data */
3423 )
3424 {
3425 SCIP_VAR* var;
3426 char* tokens[4];
3427 char* token;
3428 char* nexttoken;
3429 char name[FZN_BUFFERLEN];
3430 char fname[FZN_BUFFERLEN];
3431 SCIP_Bool created;
3432 int ntokens;
3433 int i;
3434 int c;
3435
3436 assert(scip != NULL);
3437 assert(fzninput != NULL);
3438
3439 SCIPdebugMsg(scip, "parse constraint expression\n");
3440
3441 /* get next token already flatten */
3442 flattenAssignment(scip, fzninput, name);
3443
3444 /* check if constraint identifier is a variable */
3445 var = (SCIP_VAR*) SCIPhashtableRetrieve(fzninput->varHashtable, (char*) name);
3446
3447 if( var != NULL )
3448 {
3449 SCIP_Real vals[] = {1.0};
3450
3451 /* create fixing constraint */
3452 SCIP_CALL( createLinearCons(scip, "fixing", 1, &var, vals, 1.0, 1.0, fzninput->initialconss, fzninput->dynamicconss, fzninput->dynamicrows) );
3453 return SCIP_OKAY;
3454 }
3455
3456 /* check constraint identifier name */
3457 if( !isIdentifier(name) )
3458 {
3459 syntaxError(scip, fzninput, "expected constraint identifier name");
3460 return SCIP_OKAY;
3461 }
3462
3463 /* check if we have a opening parenthesis */
3464 if( !getNextToken(scip, fzninput) || !isChar(fzninput->token, '(') )
3465 {
3466 syntaxError(scip, fzninput, "expected token <(>");
3467 return SCIP_OKAY;
3468 }
3469
3470 /* copy function name */
3471 (void) SCIPsnprintf(fname, FZN_BUFFERLEN, "%s", name);
3472
3473 /* truncate the function identifier name in separate tokens */
3474 token = SCIPstrtok(name, "_", &nexttoken);
3475 ntokens = 0;
3476 while( token != NULL )
3477 {
3478 if( ntokens == 4 )
3479 break;
3480
3481 SCIP_CALL( SCIPduplicateBufferArray(scip, &(tokens[ntokens]), token, (int) strlen(token) + 1) ); /*lint !e866*/
3482 ntokens++;
3483
3484 token = SCIPstrtok(NULL, "_", &nexttoken);
3485 }
3486
3487 assert(token == NULL || tokens[0] != NULL); /*lint !e771*/
3488 for( i = 0; i < ntokens; ++i )
3489 {
3490 SCIPdebugMsgPrint(scip, "%s ", tokens[i]);
3491 }
3492 SCIPdebugMsgPrint(scip, "\n");
3493
3494 created = FALSE;
3495
3496 /* loop over all methods which can create a constraint */
3497 for( c = 0; c < nconstypes && !created && !hasError(fzninput); ++c )
3498 {
3499 SCIP_CALL( constypes[c](scip, fzninput, fname, tokens, ntokens, &created) );
3500 }
3501
3502 /* check if a constraint was created */
3503 if( !hasError(fzninput) && !created )
3504 {
3505 fzninput->valid = FALSE;
3506 SCIPwarningMessage(scip, "Line %d: Constraint <%s> is not supported yet.\n", fzninput->linenumber, fname);
3507 }
3508
3509 /* free memory */
3510 for( i = ntokens - 1; i >= 0 ; --i )
3511 {
3512 SCIPfreeBufferArray(scip, &tokens[i]);
3513 }
3514
3515 /* check for the closing parenthesis */
3516 if( !hasError(fzninput) && ( !getNextToken(scip, fzninput) || !isChar(fzninput->token, ')')) )
3517 syntaxError(scip, fzninput, "expected token <)>");
3518
3519 return SCIP_OKAY;
3520 }
3521
3522 /** parse solve item expression */
3523 static
3524 SCIP_RETCODE parseSolveItem(
3525 SCIP* scip, /**< SCIP data structure */
3526 FZNINPUT* fzninput /**< FZN reading data */
3527 )
3528 {
3529 assert(scip != NULL);
3530 assert(fzninput != NULL);
3531
3532 SCIPdebugMsg(scip, "parse solve item expression\n");
3533
3534 if( !getNextToken(scip, fzninput) )
3535 {
3536 syntaxError(scip, fzninput, "expected solving specification");
3537 return SCIP_OKAY;
3538 }
3539
3540 /* check for annotations */
3541 if( equalTokens(fzninput->token, "::") )
3542 {
3543 /* skip the annotation */
3544 do
3545 {
3546 if( !getNextToken(scip, fzninput) )
3547 syntaxError(scip, fzninput, "expected more tokens");
3548 }
3549 while( !equalTokens(fzninput->token, "satisfy")
3550 && !equalTokens(fzninput->token, "minimize")
3551 && !equalTokens(fzninput->token, "maximize") );
3552 }
3553
3554 if( equalTokens(fzninput->token, "satisfy") )
3555 {
3556 SCIPdebugMsg(scip, "detected a satisfiability problem\n");
3557 }
3558 else
3559 {
3560 SCIP_VAR* var;
3561 FZNCONSTANT* constant;
3562 char name[FZN_BUFFERLEN];
3563
3564 if( equalTokens(fzninput->token, "minimize") )
3565 {
3566 fzninput->objsense = SCIP_OBJSENSE_MINIMIZE;
3567 SCIPdebugMsg(scip, "detected a minimization problem\n");
3568 }
3569 else
3570 {
3571 assert(equalTokens(fzninput->token, "maximize"));
3572 fzninput->objsense = SCIP_OBJSENSE_MAXIMIZE;
3573 SCIPdebugMsg(scip, "detected a maximization problem\n");
3574 }
3575
3576 /* parse objective coefficients */
3577
3578 /* parse and flatten assignment */
3579 flattenAssignment(scip, fzninput, name);
3580
3581 var = (SCIP_VAR*) SCIPhashtableRetrieve(fzninput->varHashtable, (char*) name);
3582 constant = (FZNCONSTANT*) SCIPhashtableRetrieve(fzninput->constantHashtable, (char*) name);
3583
3584 if( var != NULL )
3585 {
3586 SCIP_CALL(SCIPchgVarObj(scip, var, 1.0) );
3587 }
3588 else if( constant != NULL )
3589 {
3590 SCIPdebugMsg(scip, "optimizing a constant is equal to a satisfiability problem!\n");
3591 }
3592 else if( equalTokens(name, "int_float_lin") )
3593 {
3594 SCIP_VAR** vars;
3595 SCIP_Real* vals;
3596 int nvars;
3597 int nvals;
3598 int size;
3599 int v;
3600
3601 nvars = 0;
3602 nvals = 0;
3603 size = 10;
3604
3605 SCIP_CALL( SCIPallocBufferArray(scip, &vars, size) );
3606 SCIP_CALL( SCIPallocBufferArray(scip, &vals, size) );
3607
3608 SCIPdebugMsg(scip, "found linear objective\n");
3609
3610 if( !getNextToken(scip, fzninput) || !isChar(fzninput->token, '(') )
3611 {
3612 syntaxError(scip, fzninput, "expected token <(>");
3613 goto TERMINATE;
3614 }
3615
3616 /* pares coefficients array for integer variables */
3617 SCIP_CALL( parseConstantArrayAssignment(scip, fzninput, &vals, &nvals, size) );
3618
3619 /* check error and for the comma between the coefficient and variable array */
3620 if( hasError(fzninput) || !getNextToken(scip, fzninput) || !isChar(fzninput->token, ',') )
3621 {
3622 if( !hasError(fzninput) )
3623 syntaxError(scip, fzninput, "expected token <,>");
3624
3625 goto TERMINATE;
3626 }
3627
3628 /* pares coefficients array for continuous variables */
3629 SCIP_CALL( parseConstantArrayAssignment(scip, fzninput, &vals, &nvals, MAX(size, nvals)) );
3630
3631 /* check error and for the comma between the coefficient and variable array */
3632 if( hasError(fzninput) || !getNextToken(scip, fzninput) || !isChar(fzninput->token, ',') )
3633 {
3634 if( !hasError(fzninput) )
3635 syntaxError(scip, fzninput, "expected token <,>");
3636
3637 goto TERMINATE;
3638 }
3639
3640 /* pares integer variable array */
3641 SCIP_CALL( parseVariableArrayAssignment(scip, fzninput, &vars, &nvars, size) );
3642
3643 /* check error and for the comma between the variable array and side value */
3644 if( hasError(fzninput) || !getNextToken(scip, fzninput) || !isChar(fzninput->token, ',') )
3645 {
3646 if( !hasError(fzninput) )
3647 syntaxError(scip, fzninput, "expected token <,>");
3648
3649 goto TERMINATE;
3650 }
3651
3652 assert(nvars <= nvals);
3653
3654 /* pares continuous variable array */
3655 SCIP_CALL( parseVariableArrayAssignment(scip, fzninput, &vars, &nvars, MAX(size, nvars)) );
3656
3657 /* check error and for the ')' */
3658 if( hasError(fzninput) || !getNextToken(scip, fzninput) || !isChar(fzninput->token, ')') )
3659 {
3660 if( !hasError(fzninput) )
3661 syntaxError(scip, fzninput, "expected token <)>");
3662
3663 goto TERMINATE;
3664 }
3665
3666 assert( nvars == nvals );
3667
3668 for( v = 0; v < nvars; ++v )
3669 {
3670 SCIP_CALL(SCIPchgVarObj(scip, vars[v], vals[v]) );
3671 }
3672
3673 TERMINATE:
3674 SCIPfreeBufferArray(scip, &vals);
3675 SCIPfreeBufferArray(scip, &vars);
3676 }
3677 else
3678 {
3679 syntaxError(scip, fzninput, "unknown identifier expression for a objective function");
3680 }
3681 }
3682
3683 return SCIP_OKAY;
3684 }
3685
3686 /** reads a FlatZinc model */
3687 static
3688 SCIP_RETCODE readFZNFile(
3689 SCIP* scip, /**< SCIP data structure */
3690 SCIP_READERDATA* readerdata, /**< reader data */
3691 FZNINPUT* fzninput, /**< FZN reading data */
3692 const char* filename /**< name of the input file */
3693 )
3694 {
3695 assert(scip != NULL);
3696 assert(readerdata != NULL);
3697 assert(fzninput != NULL);
3698
3699 /* open file */
3700 fzninput->file = SCIPfopen(filename, "r");
3701 if( fzninput->file == NULL )
3702 {
3703 SCIPerrorMessage("cannot open file <%s> for reading\n", filename);
3704 SCIPprintSysError(filename);
3705 return SCIP_NOFILE;
3706 }
3707
3708 /* create problem */
3709 SCIP_CALL( SCIPcreateProb(scip, filename, NULL, NULL, NULL, NULL, NULL, NULL, NULL) );
3710
3711 /* create two auxiliary variable for true and false values */
3712 SCIP_CALL( createVariable(scip, fzninput, NULL, "true", 1.0, 1.0, FZN_BOOL) );
3713 SCIP_CALL( createVariable(scip, fzninput, NULL, "false", 0.0, 0.0, FZN_BOOL) );
3714
3715 /* parse through statements one-by-one */
3716 while( !SCIPfeof( fzninput->file ) && !hasError(fzninput) )
3717 {
3718 /* read the first token (keyword) of a new statement */
3719 if( getNextToken(scip, fzninput) )
3720 {
3721 if( equalTokens(fzninput->token, "predicate") )
3722 {
3723 /* parse array expression containing constants or variables */
3724 SCIP_CALL( parsePredicate(scip, fzninput) );
3725 }
3726 else if( equalTokens(fzninput->token, "array") )
3727 {
3728 /* parse array expression containing constants or variables */
3729 SCIP_CALL( parseArray(scip, readerdata, fzninput) );
3730 }
3731 else if( equalTokens(fzninput->token, "constraint") )
3732 {
3733 /* parse a constraint */
3734 SCIP_CALL( parseConstraint(scip, fzninput) );
3735 }
3736 else if( equalTokens(fzninput->token, "int") )
3737 {
3738 /* parse an integer constant */
3739 SCIP_CALL( parseConstant(scip, fzninput, FZN_INT) );
3740 }
3741 else if( equalTokens(fzninput->token, "float") )
3742 {
3743 /* parse a float constant */
3744 SCIP_CALL( parseConstant(scip, fzninput, FZN_FLOAT) );
3745 }
3746 else if( equalTokens(fzninput->token, "bool") )
3747 {
3748 /* parse a bool constant */
3749 SCIP_CALL( parseConstant(scip, fzninput, FZN_BOOL) );
3750 }
3751 else if( equalTokens(fzninput->token, "set") )
3752 {
3753 /* deal with sets */
3754 SCIPwarningMessage(scip, "sets are not supported yet\n");
3755 fzninput->valid = FALSE;
3756 break;
3757 }
3758 else if( equalTokens(fzninput->token, "solve") )
3759 {
3760 /* parse solve item (objective sense and objective function) */
3761 SCIP_CALL( parseSolveItem(scip, fzninput) );
3762 }
3763 else if( equalTokens(fzninput->token, "var") )
3764 {
3765 /* parse variables */
3766 SCIP_CALL( parseVariable(scip, readerdata, fzninput) );
3767 }
3768 else if( equalTokens(fzninput->token, "output") )
3769 {
3770 /* the output section is the last section in the flatzinc model and can be skipped */
3771 SCIPdebugMsg(scip, "skip output section\n");
3772 break;
3773 }
3774 else
3775 {
3776 FZNNUMBERTYPE type;
3777 SCIP_Real lb;
3778 SCIP_Real ub;
3779
3780 /* check if the new statement starts with a range expression
3781 * which indicates a constant; therefore, push back the current token
3782 * since it belongs to the range expression */
3783 pushToken(fzninput);
3784
3785 /* parse range to detect constant type */
3786 parseRange(scip, fzninput, &type, &lb, &ub);
3787
3788 if( hasError(fzninput) )
3789 break;
3790
3791 /* parse the remaining constant statement */
3792 SCIP_CALL( parseConstant(scip, fzninput, type) );
3793
3794 if( hasError(fzninput) )
3795 {
3796 SCIPwarningMessage(scip, "unknown keyword <%s> skip statement\n", fzninput->token);
3797 SCIPABORT();
3798 return SCIP_OKAY; /*lint !e527*/
3799 }
3800 }
3801
3802 if( hasError(fzninput) )
3803 break;
3804
3805 /* if the current statement got marked as comment continue with the next line */
3806 if( fzninput->comment )
3807 continue;
3808
3809 /* each statement should be closed with a semicolon */
3810 if( !getNextToken(scip, fzninput) )
3811 syntaxError(scip, fzninput, "expected semicolon");
3812
3813 /* check for annotations */
3814 if( equalTokens(fzninput->token, "::") )
3815 {
3816 /* skip the annotation */
3817 do
3818 {
3819 if( !getNextToken(scip, fzninput) )
3820 syntaxError(scip, fzninput, "expected more tokens");
3821 }
3822 while( !isEndStatement(fzninput) );
3823 }
3824
3825 if( !isEndStatement(fzninput) )
3826 syntaxError(scip, fzninput, "expected semicolon");
3827 }
3828 }
3829
3830 /* close file */
3831 SCIPfclose(fzninput->file);
3832
3833 if( hasError(fzninput) )
3834 {
3835 SCIP_CALL( SCIPfreeProb(scip) );
3836
3837 /* create empty problem */
3838 SCIP_CALL( SCIPcreateProb(scip, filename, NULL, NULL, NULL, NULL, NULL, NULL, NULL) );
3839 }
3840 else
3841 {
3842 SCIP_CALL( SCIPsetObjsense(scip, fzninput->objsense) );
3843 }
3844
3845 return SCIP_OKAY;
3846 }
3847
3848
3849 /*
3850 * Local methods (for writing)
3851 */
3852
3853
3854 /** transforms given variables, scalars, and constant to the corresponding active variables, scalars, and constant */
3855 static
3856 SCIP_RETCODE getActiveVariables(
3857 SCIP* scip, /**< SCIP data structure */
3858 SCIP_VAR** vars, /**< vars array to get active variables for */
3859 SCIP_Real* scalars, /**< scalars a_1, ..., a_n in linear sum a_1*x_1 + ... + a_n*x_n + c */
3860 int* nvars, /**< pointer to number of variables and values in vars and vals array */
3861 SCIP_Real* constant, /**< pointer to constant c in linear sum a_1*x_1 + ... + a_n*x_n + c */
3862 SCIP_Bool transformed /**< transformed constraint? */
3863 )
3864 {
3865 int requiredsize; /* number of active variables */
3866 int v;
3867
3868 assert( scip != NULL );
3869 assert( scalars != NULL );
3870 assert( nvars != NULL );
3871 assert( vars != NULL || *nvars == 0 );
3872 assert( constant != NULL );
3873
(1) Event cond_true: |
Condition "transformed", taking true branch. |
3874 if( transformed )
3875 {
(2) Event deref_parm_in_call: |
Function "SCIPgetProbvarLinearSum" dereferences "vars". [details] |
3876 SCIP_CALL( SCIPgetProbvarLinearSum(scip, vars, scalars, nvars, *nvars, constant, &requiredsize, TRUE) );
3877
3878 /* avoid overflow by reallocation */
3879 if( requiredsize > *nvars )
3880 {
3881 SCIP_CALL( SCIPreallocBufferArray(scip, &vars, requiredsize) );
3882 SCIP_CALL( SCIPreallocBufferArray(scip, &scalars, requiredsize) );
3883
3884 SCIP_CALL( SCIPgetProbvarLinearSum(scip, vars, scalars, nvars, requiredsize, constant, &requiredsize, TRUE) );
3885 assert( requiredsize <= *nvars );
3886 }
3887 }
3888 else
3889 {
3890 if( *nvars > 0 && (vars == NULL || scalars == NULL) ) /*lint !e774 !e845*/
3891 {
3892 SCIPerrorMessage("Null pointer"); /* should not happen */
3893 SCIPABORT();
3894 return SCIP_INVALIDDATA; /*lint !e527*/
3895 }
3896
3897 for( v = 0; v < *nvars; ++v )
3898 {
3899 assert(vars != NULL);
3900 SCIP_CALL( SCIPvarGetOrigvarSum(&vars[v], &scalars[v], constant) );
3901 }
3902 }
3903
3904 return SCIP_OKAY;
3905 }
3906
3907 /** ends the given line with '\\0' and prints it to the given file stream */
3908 static
3909 void writeBuffer(
3910 SCIP* scip, /**< SCIP data structure */
3911 FILE* file, /**< output file (or NULL for standard output) */
3912 char* buffer, /**< line */
3913 int bufferpos /**< number of characters in buffer */
3914 )
3915 {
3916 assert( scip != NULL );
3917 assert( buffer != NULL );
3918
3919 if( bufferpos > 0 )
3920 {
3921 buffer[bufferpos] = '\0';
3922
3923 SCIPinfoMessage(scip, file, "%s", buffer);
3924 }
3925 }
3926
3927 /** appends extension to line and prints it to the give file stream if the line buffer get full */
3928 static
3929 SCIP_RETCODE appendBuffer(
3930 SCIP* scip, /**< SCIP data structure */
3931 char** buffer, /**< buffer which should be extended */
3932 int* bufferlen, /**< length of the buffer */
3933 int* bufferpos, /**< current position in the buffer */
3934 const char* extension /**< string to extend the line */
3935 )
3936 {
3937 int newpos;
3938 int extlen;
3939
3940 assert( scip != NULL );
3941 assert( buffer != NULL );
3942 assert( bufferlen != NULL );
3943 assert( bufferpos != NULL );
3944 assert( extension != NULL );
3945
3946 /* avoid overflow by reallocation */
3947 extlen = (int)strlen(extension);
3948 newpos = (*bufferpos) + extlen;
3949 if( newpos >= (*bufferlen) )
3950 {
3951 *bufferlen = MAX( newpos, 2 * (*bufferlen) );
3952
3953 SCIP_CALL( SCIPreallocBufferArray(scip, buffer, (*bufferlen)));
3954 }
3955
3956 /* append extension to linebuffer (+1 because of '\0') */
3957 (void)SCIPstrncpy((*buffer) + (*bufferpos), extension, extlen + 1);
3958 *bufferpos = newpos;
3959
3960 return SCIP_OKAY;
3961 }
3962
3963 /* Writes a real value to a string with full precision, if fractional and adds a ".0" if integral */
3964 static
3965 void flattenFloat(
3966 SCIP* scip, /**< SCIP data structure */
3967 SCIP_Real val, /**< value to flatten */
3968 char* buffer /**< string buffer to print in */
3969 )
3970 {
3971 if( SCIPisIntegral(scip, val) )
3972 (void) SCIPsnprintf(buffer, FZN_BUFFERLEN, "%.1f", SCIPround(scip, val));
3973 else
3974 (void) SCIPsnprintf(buffer, FZN_BUFFERLEN, "%+.15g", val);
3975 }
3976
3977 /* print row in FZN format to file stream */
3978 static
3979 SCIP_RETCODE printRow(
3980 SCIP* scip, /**< SCIP data structure */
3981 FZNOUTPUT* fznoutput, /**< output data structure containing the buffers to write to */
3982 const char* type, /**< row type ("eq", "le" or "ge") */
3983 SCIP_VAR** vars, /**< array of variables */
3984 SCIP_Real* vals, /**< array of values */
3985 int nvars, /**< number of variables */
3986 SCIP_Real rhs, /**< right hand side */
3987 SCIP_Bool hasfloats /**< are there continuous variables or coefficients in the constraint? */
3988 )
3989 {
3990 SCIP_VAR* var; /* some variable */
3991 int v; /* variable counter */
3992 char buffer[FZN_BUFFERLEN];
3993 char buffy[FZN_BUFFERLEN];
3994
3995 assert( scip != NULL );
3996 assert( vars != NULL || nvars == 0 );
3997 assert( strcmp(type, "eq") == 0 || strcmp(type, "le") == 0 || strcmp(type, "ge") == 0 );
3998
3999 /* Add a constraint of type float_lin or int_lin, depending on whether there are continuous variables or coefficients */
4000 SCIP_CALL( appendBuffer(scip, &(fznoutput->consbuffer), &(fznoutput->consbufferlen), &(fznoutput->consbufferpos), "constraint ") );
4001 if( hasfloats )
4002 (void) SCIPsnprintf(buffer, FZN_BUFFERLEN, "float_lin_%s([", type);
4003 else
4004 (void) SCIPsnprintf(buffer, FZN_BUFFERLEN, "int_lin_%s([", type);
4005 SCIP_CALL( appendBuffer(scip, &(fznoutput->consbuffer), &(fznoutput->consbufferlen), &(fznoutput->consbufferpos), buffer) );
4006
4007 /* print all coefficients but the last one */
4008 for( v = 0; v < nvars-1; ++v )
4009 {
4010 if( hasfloats )
4011 {
4012 flattenFloat(scip, vals[v], buffy);
4013 (void) SCIPsnprintf(buffer, FZN_BUFFERLEN, "%s, ", buffy);
4014 }
4015 else
4016 (void) SCIPsnprintf(buffer, FZN_BUFFERLEN, "%.f, ", vals[v]);
4017 SCIP_CALL( appendBuffer(scip, &(fznoutput->consbuffer), &(fznoutput->consbufferlen), &(fznoutput->consbufferpos), buffer) );
4018 }
4019
4020 /* print last coefficient */
4021 if( nvars > 0 )
4022 {
4023 if( hasfloats )
4024 {
4025 flattenFloat(scip, vals[nvars-1], buffy);
4026 (void) SCIPsnprintf(buffer, FZN_BUFFERLEN, "%s", buffy);
4027 }
4028 else
4029 (void) SCIPsnprintf(buffer, FZN_BUFFERLEN, "%.f", vals[nvars-1]);
4030
4031 SCIP_CALL( appendBuffer(scip, &(fznoutput->consbuffer), &(fznoutput->consbufferlen), &(fznoutput->consbufferpos), buffer) );
4032 }
4033
4034 SCIP_CALL( appendBuffer(scip, &(fznoutput->consbuffer), &(fznoutput->consbufferlen), &(fznoutput->consbufferpos), "], [") );
4035
4036 /* print all variables but the last one */
4037 for( v = 0; v < nvars-1; ++v )
4038 {
4039 var = vars[v]; /*lint !e613*/
4040 assert( var != NULL );
4041
4042 if( hasfloats )
4043 (void) SCIPsnprintf(buffer, FZN_BUFFERLEN, "%s%s, ", SCIPvarGetName(var), SCIPvarGetProbindex(var) < fznoutput->ndiscretevars ? "_float" : "");
4044 else
4045 (void) SCIPsnprintf(buffer, FZN_BUFFERLEN, "%s, ", SCIPvarGetName(var) );
4046 SCIP_CALL( appendBuffer(scip, &(fznoutput->consbuffer), &(fznoutput->consbufferlen), &(fznoutput->consbufferpos), buffer) );
4047 }
4048
4049 /* print last variable */
4050 if( nvars > 0 )
4051 {
4052 assert(vars != NULL); /* for lint */
4053 if( hasfloats )
4054 (void) SCIPsnprintf(buffer, FZN_BUFFERLEN, "%s%s",SCIPvarGetName(vars[nvars-1]),
4055 SCIPvarGetProbindex(vars[nvars-1]) < fznoutput->ndiscretevars ? "_float" : ""); /*lint !e613*/
4056 else
4057 (void) SCIPsnprintf(buffer, FZN_BUFFERLEN, "%s", SCIPvarGetName(vars[nvars-1])); /*lint !e613*/
4058
4059 SCIP_CALL( appendBuffer(scip, &(fznoutput->consbuffer), &(fznoutput->consbufferlen), &(fznoutput->consbufferpos),buffer) );
4060 }
4061
4062 SCIP_CALL( appendBuffer(scip, &(fznoutput->consbuffer), &(fznoutput->consbufferlen), &(fznoutput->consbufferpos), "], ") );
4063
4064 /* print right hand side */
4065 if( SCIPisZero(scip, rhs) )
4066 rhs = 0.0;
4067
4068 if( hasfloats )
4069 {
4070 flattenFloat(scip, rhs, buffy);
4071 (void) SCIPsnprintf(buffer, FZN_BUFFERLEN, "%s);\n", buffy);
4072 }
4073 else
4074 (void) SCIPsnprintf(buffer, FZN_BUFFERLEN, "%.f);\n", rhs);
4075 SCIP_CALL( appendBuffer(scip, &(fznoutput->consbuffer), &(fznoutput->consbufferlen), &(fznoutput->consbufferpos),buffer) );
4076
4077 return SCIP_OKAY;
4078 }
4079
4080 /** prints given linear constraint information in FZN format to file stream */
4081 static
4082 SCIP_RETCODE printLinearCons(
4083 SCIP* scip, /**< SCIP data structure */
4084 FZNOUTPUT* fznoutput, /**< output data structure containing the buffers to write to */
4085 SCIP_VAR** vars, /**< array of variables */
4086 SCIP_Real* vals, /**< array of coefficients values (or NULL if all coefficient values are 1) */
4087 int nvars, /**< number of variables */
4088 SCIP_Real lhs, /**< left hand side */
4089 SCIP_Real rhs, /**< right hand side */
4090 SCIP_Bool transformed, /**< transformed constraint? */
4091 SCIP_Bool mayhavefloats /**< may there be continuous variables in the constraint? */
4092 )
4093 {
4094 SCIP_VAR** activevars; /* active problem variables of a constraint */
4095 SCIP_Real* activevals; /* coefficients in the active representation */
4096
4097 SCIP_Real activeconstant; /* offset (e.g., due to fixings) in the active representation */
4098 int nactivevars; /* number of active problem variables */
4099 int v; /* variable counter */
4100
4101 char buffer[FZN_BUFFERLEN];
4102 SCIP_Bool hasfloats;
4103
4104 assert( scip != NULL );
4105 assert( vars != NULL || nvars == 0 );
4106 assert( fznoutput != NULL );
4107 assert( lhs <= rhs );
4108
(1) Event cond_true: |
Condition "-lhs >= scip->set->num_infinity", taking true branch. |
(2) Event cond_false: |
Condition "rhs >= scip->set->num_infinity", taking false branch. |
4109 if( SCIPisInfinity(scip, -lhs) && SCIPisInfinity(scip, rhs) )
(3) Event if_end: |
End of if statement. |
4110 return SCIP_OKAY;
4111
4112 /* duplicate variable and value array */
4113 nactivevars = nvars;
4114 hasfloats = FALSE;
(4) Event assign_zero: |
Assigning: "activevars" = "NULL". |
Also see events: |
[var_deref_model] |
4115 activevars = NULL;
4116 activeconstant = 0.0;
4117
(5) Event cond_false: |
Condition "vars != NULL", taking false branch. |
4118 if( vars != NULL )
4119 {
4120 SCIP_CALL( SCIPduplicateBufferArray(scip, &activevars, vars, nactivevars ) );
(6) Event if_end: |
End of if statement. |
4121 }
4122
(7) Event cond_true: |
Condition "vals != NULL", taking true branch. |
4123 if( vals != NULL )
(8) Event cond_false: |
Condition "(activevals = BMSduplicateBufferMemoryArray_call(SCIPbuffer(scip), (void const *)vals, (size_t)(ptrdiff_t)nactivevars, 8UL /* sizeof (*activevals) */, "/sapmnt/home1/d029903/my_work/SCIPSoPlex_coverity/scipoptsuite-8.0.1/scip/src/scip/reader_fzn.c", 4124)) == NULL", taking false branch. |
(9) Event cond_false: |
Condition "(_restat_ = (((activevals = BMSduplicateBufferMemoryArray_call(SCIPbuffer(scip), (void const *)vals, (size_t)(ptrdiff_t)nactivevars, 8UL /* sizeof (*activevals) */, "/sapmnt/home1/d029903/my_work/SCIPSoPlex_coverity/scipoptsuite-8.0.1/scip/src/scip/reader_fzn.c", 4124)) == NULL) ? SCIP_NOMEMORY : SCIP_OKAY)) != SCIP_OKAY", taking false branch. |
(10) Event if_end: |
End of if statement. |
(11) Event if_fallthrough: |
Falling through to end of if statement. |
4124 SCIP_CALL( SCIPduplicateBufferArray(scip, &activevals, vals, nactivevars ) );
4125 else
4126 {
4127 SCIP_CALL( SCIPallocBufferArray(scip, &activevals, nactivevars) );
4128
4129 for( v = 0; v < nactivevars; ++v )
4130 activevals[v] = 1.0;
(12) Event if_end: |
End of if statement. |
4131 }
4132
4133 /* retransform given variables to active variables */
(13) Event cond_true: |
Condition "nactivevars > 0", taking true branch. |
4134 if( nactivevars > 0 )
4135 {
(14) Event var_deref_model: |
Passing null pointer "activevars" to "getActiveVariables", which dereferences it. [details] |
Also see events: |
[assign_zero] |
4136 SCIP_CALL( getActiveVariables(scip, activevars, activevals, &nactivevars, &activeconstant, transformed) );
4137 }
4138
4139 /* If there may be continuous variables or coefficients in the constraint, scan for them */
4140 if( mayhavefloats )
4141 {
4142 /* fractional sides trigger a constraint to be of float type */
4143 if( !SCIPisInfinity(scip, -lhs) )
4144 hasfloats = hasfloats || !SCIPisIntegral(scip, lhs-activeconstant);
4145 if( !SCIPisInfinity(scip, rhs) )
4146 hasfloats = hasfloats || !SCIPisIntegral(scip, rhs-activeconstant);
4147
4148 /* any continuous variable or fractional variable coefficient triggers a constraint to be of float type */
4149 for( v = 0; v < nactivevars && !hasfloats; v++ )
4150 {
4151 SCIP_VAR* var;
4152
4153 assert(activevars != 0);
4154 var = activevars[v];
4155
4156 hasfloats = hasfloats || (SCIPvarGetType(var) != SCIP_VARTYPE_BINARY && SCIPvarGetType(var) != SCIP_VARTYPE_INTEGER);
4157 hasfloats = hasfloats || !SCIPisIntegral(scip, activevals[v]);
4158 }
4159
4160 /* If the constraint has to be written as float type, all discrete variables need to have a float counterpart */
4161 if( hasfloats )
4162 {
4163 for( v = 0; v < nactivevars; v++ )
4164 {
4165 SCIP_VAR* var;
4166 int idx;
4167
4168 assert(activevars != 0);
4169 var = activevars[v];
4170 idx = SCIPvarGetProbindex(var);
4171 assert( idx >= 0);
4172
4173 /* If there was no float representation of the variable before, add an auxiliary variable and a conversion constraint */
4174 if( idx < fznoutput->ndiscretevars && !fznoutput->varhasfloat[idx] )
4175 {
4176 assert(SCIPvarGetType(var) == SCIP_VARTYPE_BINARY || SCIPvarGetType(var) == SCIP_VARTYPE_INTEGER);
4177
4178 (void) SCIPsnprintf(buffer, FZN_BUFFERLEN, "var float: %s_float;\n", SCIPvarGetName(var));
4179 SCIP_CALL( appendBuffer(scip, &(fznoutput->varbuffer), &(fznoutput->varbufferlen), &(fznoutput->varbufferpos),buffer) );
4180
4181 (void) SCIPsnprintf(buffer, FZN_BUFFERLEN, "constraint int2float(%s, %s_float);\n", SCIPvarGetName(var), SCIPvarGetName(var));
4182 SCIP_CALL( appendBuffer(scip, &(fznoutput->castbuffer), &(fznoutput->castbufferlen), &(fznoutput->castbufferpos),buffer) );
4183
4184 fznoutput->varhasfloat[idx] = TRUE;
4185 }
4186 }
4187 }
4188 }
4189
4190 if( SCIPisEQ(scip, lhs, rhs) )
4191 {
4192 assert( !SCIPisInfinity(scip, rhs) );
4193
4194 /* equality constraint */
4195 SCIP_CALL( printRow(scip, fznoutput, "eq", activevars, activevals, nactivevars, rhs - activeconstant, hasfloats) );
4196 }
4197 else
4198 {
4199 if( !SCIPisInfinity(scip, -lhs) )
4200 {
4201 /* print inequality ">=" */
4202 SCIP_CALL( printRow(scip, fznoutput, "ge", activevars, activevals, nactivevars, lhs - activeconstant, hasfloats) );
4203 }
4204
4205 if( !SCIPisInfinity(scip, rhs) )
4206 {
4207 /* print inequality "<=" */
4208 SCIP_CALL( printRow(scip, fznoutput, "le", activevars, activevals, nactivevars, rhs - activeconstant, hasfloats) );
4209 }
4210 }
4211
4212 /* free buffer arrays */
4213 if( activevars != NULL )
4214 SCIPfreeBufferArray(scip, &activevars);
4215 SCIPfreeBufferArray(scip, &activevals);
4216
4217 return SCIP_OKAY;
4218 }
4219
4220 /* writes problem to a flatzinc conform file, including introduction of several auxiliary variables and constraints */
4221 static
4222 SCIP_RETCODE writeFzn(
4223 SCIP* scip, /**< SCIP data structure */
4224 FILE* file, /**< output file, or NULL if standard output should be used */
4225 const char* name, /**< problem name */
4226 SCIP_Bool transformed, /**< TRUE iff problem is the transformed problem */
4227 SCIP_OBJSENSE objsense, /**< objective sense */
4228 SCIP_Real objscale, /**< scalar applied to objective function; external objective value is
4229 * extobj = objsense * objscale * (intobj + objoffset) */
4230 SCIP_Real objoffset, /**< objective offset from bound shifting and fixing */
4231 SCIP_VAR** vars, /**< array with active variables ordered binary, integer, implicit, continuous */
4232 int nvars, /**< number of active variables in the problem */
4233 int nbinvars, /**< number of binary variables */
4234 int nintvars, /**< number of general integer variables */
4235 int nimplvars, /**< number of implicit integer variables */
4236 int ncontvars, /**< number of continuous variables */
4237 SCIP_CONS** conss, /**< array with constraints of the problem */
4238 int nconss, /**< number of constraints in the problem */
4239 SCIP_RESULT* result /**< pointer to store the result of the file writing call */
4240 )
4241 {
4242 FZNOUTPUT fznoutput; /* data structure for writing in fzn format */
4243
4244 SCIP_CONSHDLR* conshdlr;
4245 SCIP_CONS* cons;
4246 const char* conshdlrname;
4247 SCIP_VAR** consvars; /* variables of a specific constraint */
4248 SCIP_VAR* var;
4249 SCIP_BOUNDTYPE* boundtypes; /* indicates whether to which side the variables are bounded */
4250 SCIP_Real* consvals; /* coefficients of a specific constraint */
4251
4252 int* boundedvars; /* variables which are bounded to exactly one side */
4253 int* floatobjvars; /* discrete variables which have a fractional objective coefficient */
4254 int* intobjvars; /* discrete variables which have an integral objective coefficient */
4255
4256 SCIP_Real lb; /* lower bound of some variable */
4257 SCIP_Real ub; /* upper bound of some variable */
4258
4259 int nboundedvars; /* number of variables which are bounded to exactly one side */
4260 int nconsvars; /* number of variables appearing in a specific constraint */
4261 int nfloatobjvars; /* number of discrete variables which have a fractional objective coefficient */
4262 int nintobjvars; /* number of discrete variables which have an integral objective coefficient */
4263 int c; /* counter for the constraints */
4264 int v; /* counter for the variables */
4265 const int ndiscretevars = nbinvars+nintvars; /* number of discrete variables */
4266
4267 char varname[SCIP_MAXSTRLEN]; /* buffer for storing variable names */
4268 char buffer[FZN_BUFFERLEN]; /* buffer for storing auxiliary variables and constraints */
4269 char buffy[FZN_BUFFERLEN];
4270
4271 assert( scip != NULL );
4272
4273 /* print problem statistics as comment to file */
4274 SCIPinfoMessage(scip, file, "%% SCIP STATISTICS\n");
4275 SCIPinfoMessage(scip, file, "%% Problem name : %s\n", name);
4276 SCIPinfoMessage(scip, file, "%% Variables : %d (%d binary, %d integer, %d implicit integer, %d continuous)\n",
4277 nvars, nbinvars, nintvars, nimplvars, ncontvars);
4278 SCIPinfoMessage(scip, file, "%% Constraints : %d\n", nconss);
4279
4280 SCIP_CALL( SCIPallocBufferArray(scip, &boundedvars, nvars) );
4281 SCIP_CALL( SCIPallocBufferArray(scip, &boundtypes, nvars) );
4282 nboundedvars = 0;
4283
4284 if( nvars > 0 )
4285 SCIPinfoMessage(scip, file, "\n%%%%%%%%%%%% Problem variables %%%%%%%%%%%%\n");
4286
4287 /* write all (active) problem variables */
4288 for( v = 0; v < nvars; v++ )
4289 {
4290 var = vars[v];
4291 assert( var != NULL );
4292 (void) SCIPsnprintf(varname, SCIP_MAXSTRLEN, "%s", SCIPvarGetName(var) );
4293
4294 if( transformed )
4295 {
4296 /* in case the transformed is written only local bounds are posted which are valid in the current node */
4297 lb = SCIPvarGetLbLocal(var);
4298 ub = SCIPvarGetUbLocal(var);
4299 }
4300 else
4301 {
4302 lb = SCIPvarGetLbOriginal(var);
4303 ub = SCIPvarGetUbOriginal(var);
4304 }
4305
4306 /* If a variable is bounded to both sides, the bounds are added to the declaration,
4307 * for variables bounded to exactly one side, an auxiliary constraint will be added later-on.
4308 */
4309 if( !SCIPisInfinity(scip, -lb) && !SCIPisInfinity(scip, ub) )
4310 {
4311 SCIP_Bool fixed;
4312 fixed = FALSE;
4313
4314 if( SCIPisEQ(scip, lb, ub) )
4315 fixed = TRUE;
4316
4317 if( v < ndiscretevars )
4318 {
4319 assert( SCIPisFeasIntegral(scip, lb) && SCIPisFeasIntegral(scip, ub) );
4320
4321 if( fixed )
4322 SCIPinfoMessage(scip, file, "var int: %s = %.f;\n", varname, lb);
4323 else
4324 SCIPinfoMessage(scip, file, "var %.f..%.f: %s;\n", lb, ub, varname);
4325 }
4326 else
4327 {
4328 /* Real valued bounds have to be made type conform */
4329 if( fixed )
4330 {
4331 flattenFloat(scip, lb, buffy);
4332 SCIPinfoMessage(scip, file, "var float: %s = %s;\n", varname, buffy);
4333 }
4334 else
4335 {
4336 char buffy2[FZN_BUFFERLEN];
4337
4338 flattenFloat(scip, lb, buffy);
4339 flattenFloat(scip, ub, buffy2);
4340 SCIPinfoMessage(scip, file, "var %s..%s: %s;\n", buffy, buffy2, varname);
4341 }
4342 }
4343 }
4344 else
4345 {
4346 assert(SCIPvarGetType(var) != SCIP_VARTYPE_BINARY);
4347 assert( v >= nbinvars );
4348
4349 /* declare the variable without any bound */
4350 if( v < ndiscretevars )
4351 SCIPinfoMessage(scip, file, "var int: %s;\n", varname);
4352 else
4353 SCIPinfoMessage(scip, file, "var float: %s;\n", varname);
4354
4355 /* if there is a bound, store the variable and its boundtype for adding a corresponding constraint later-on */
4356 if( ! SCIPisInfinity(scip, ub) )
4357 {
4358 boundedvars[nboundedvars] = v;
4359 boundtypes[nboundedvars] = SCIP_BOUNDTYPE_UPPER;
4360 nboundedvars++;
4361 }
4362 if( ! SCIPisInfinity(scip, -lb) )
4363 {
4364 boundedvars[nboundedvars] = v;
4365 boundtypes[nboundedvars] = SCIP_BOUNDTYPE_LOWER;
4366 nboundedvars++;
4367 }
4368 }
4369 }
4370
4371 /* set up the datastructures for the auxiliary int2float variables, the casting constraints and the problem constraints */
4372 fznoutput.ndiscretevars = ndiscretevars;
4373 fznoutput.varbufferpos = 0;
4374 fznoutput.consbufferpos = 0;
4375 fznoutput.castbufferpos = 0;
4376
4377 SCIP_CALL( SCIPallocBufferArray(scip, &fznoutput.varhasfloat, ndiscretevars) );
4378 SCIP_CALL( SCIPallocBufferArray(scip, &fznoutput.varbuffer, FZN_BUFFERLEN) );
4379 SCIP_CALL( SCIPallocBufferArray(scip, &fznoutput.castbuffer, FZN_BUFFERLEN) );
4380 SCIP_CALL( SCIPallocBufferArray(scip, &fznoutput.consbuffer, FZN_BUFFERLEN) );
4381 fznoutput.consbufferlen = FZN_BUFFERLEN;
4382 fznoutput.varbufferlen = FZN_BUFFERLEN;
4383 fznoutput.castbufferlen = FZN_BUFFERLEN;
4384
4385 for( v = 0; v < ndiscretevars; v++ )
4386 fznoutput.varhasfloat[v] = FALSE;
4387 fznoutput.varbuffer[0] = '\0';
4388 fznoutput.consbuffer[0] = '\0';
4389 fznoutput.castbuffer[0] = '\0';
4390
4391 /* output all problem constraints */
4392 for( c = 0; c < nconss; c++ )
4393 {
4394 cons = conss[c];
4395 assert( cons != NULL);
4396
4397 /* in case the transformed is written only constraint are posted which are enabled in the current node */
4398 assert(!transformed || SCIPconsIsEnabled(cons));
4399
4400 conshdlr = SCIPconsGetHdlr(cons);
4401 assert( conshdlr != NULL );
4402
4403 conshdlrname = SCIPconshdlrGetName(conshdlr);
4404 assert( transformed == SCIPconsIsTransformed(cons) );
4405
4406 /* By now, only linear, setppc, logicor, knapsack, and varbound constraints can be written.
4407 * Since they are all linearizable, a linear representation of them is written.
4408 */
4409 if( strcmp(conshdlrname, "linear") == 0 )
4410 {
4411 SCIP_CALL( printLinearCons(scip, &fznoutput,
4412 SCIPgetVarsLinear(scip, cons), SCIPgetValsLinear(scip, cons), SCIPgetNVarsLinear(scip, cons),
4413 SCIPgetLhsLinear(scip, cons), SCIPgetRhsLinear(scip, cons), transformed, TRUE) );
4414 }
4415 else if( strcmp(conshdlrname, "setppc") == 0 )
4416 {
4417 consvars = SCIPgetVarsSetppc(scip, cons);
4418 nconsvars = SCIPgetNVarsSetppc(scip, cons);
4419
4420 /* Setppc constraints only differ in their lhs/rhs (+- INF or 1) */
4421 switch( SCIPgetTypeSetppc(scip, cons) )
4422 {
4423 case SCIP_SETPPCTYPE_PARTITIONING :
4424 SCIP_CALL( printLinearCons(scip, &fznoutput,
4425 consvars, NULL, nconsvars, 1.0, 1.0, transformed, FALSE) );
4426 break;
4427 case SCIP_SETPPCTYPE_PACKING :
4428 SCIP_CALL( printLinearCons(scip, &fznoutput,
4429 consvars, NULL, nconsvars, -SCIPinfinity(scip), 1.0, transformed, FALSE) );
4430 break;
4431 case SCIP_SETPPCTYPE_COVERING :
4432 SCIP_CALL( printLinearCons(scip, &fznoutput,
4433 consvars, NULL, nconsvars, 1.0, SCIPinfinity(scip), transformed, FALSE) );
4434 break;
4435 }
4436 }
4437 else if( strcmp(conshdlrname, "logicor") == 0 )
4438 {
4439 SCIP_CALL( printLinearCons(scip, &fznoutput,
4440 SCIPgetVarsLogicor(scip, cons), NULL, SCIPgetNVarsLogicor(scip, cons),
4441 1.0, SCIPinfinity(scip), transformed, FALSE) );
4442 }
4443 else if( strcmp(conshdlrname, "knapsack") == 0 )
4444 {
4445 SCIP_Longint* weights;
4446
4447 consvars = SCIPgetVarsKnapsack(scip, cons);
4448 nconsvars = SCIPgetNVarsKnapsack(scip, cons);
4449
4450 /* copy Longint array to SCIP_Real array */
4451 weights = SCIPgetWeightsKnapsack(scip, cons);
4452 SCIP_CALL( SCIPallocBufferArray(scip, &consvals, nconsvars) );
4453 for( v = 0; v < nconsvars; ++v )
4454 consvals[v] = (SCIP_Real)weights[v];
4455
4456 SCIP_CALL( printLinearCons(scip, &fznoutput, consvars, consvals, nconsvars, -SCIPinfinity(scip),
4457 (SCIP_Real) SCIPgetCapacityKnapsack(scip, cons), transformed, FALSE) );
4458
4459 SCIPfreeBufferArray(scip, &consvals);
4460 }
4461 else if( strcmp(conshdlrname, "varbound") == 0 )
4462 {
4463 SCIP_CALL( SCIPallocBufferArray(scip, &consvars, 2) );
4464 SCIP_CALL( SCIPallocBufferArray(scip, &consvals, 2) );
4465
4466 consvars[0] = SCIPgetVarVarbound(scip, cons);
4467 consvars[1] = SCIPgetVbdvarVarbound(scip, cons);
4468
4469 consvals[0] = 1.0;
4470 consvals[1] = SCIPgetVbdcoefVarbound(scip, cons);
4471
4472 /* Varbound constraints always consist of exactly two variables */
4473 SCIP_CALL( printLinearCons(scip, &fznoutput,
4474 consvars, consvals, 2,
4475 SCIPgetLhsVarbound(scip, cons), SCIPgetRhsVarbound(scip, cons), transformed, TRUE) );
4476
4477 SCIPfreeBufferArray(scip, &consvars);
4478 SCIPfreeBufferArray(scip, &consvals);
4479 }
4480 else if( strcmp(conshdlrname, "cumulative") == 0 )
4481 {
4482 int* intvals;
4483
4484 consvars = SCIPgetVarsCumulative(scip, cons);
4485 nconsvars = SCIPgetNVarsCumulative(scip, cons);
4486
4487 SCIP_CALL( appendBuffer(scip, &(fznoutput.consbuffer), &(fznoutput.consbufferlen), &(fznoutput.consbufferpos), "cumulative([") );
4488
4489 for( v = 0; v < nconsvars; ++v )
4490 {
4491 if( v < nconsvars - 1)
4492 (void) SCIPsnprintf(varname, SCIP_MAXSTRLEN, "%s, ", SCIPvarGetName(consvars[v]) );
4493 else
4494 (void) SCIPsnprintf(varname, SCIP_MAXSTRLEN, "%s", SCIPvarGetName(consvars[v]) );
4495
4496 SCIP_CALL( appendBuffer(scip, &(fznoutput.consbuffer), &(fznoutput.consbufferlen), &(fznoutput.consbufferpos), varname) );
4497 }
4498
4499 SCIP_CALL( appendBuffer(scip, &(fznoutput.consbuffer), &(fznoutput.consbufferlen), &(fznoutput.consbufferpos), "], [") );
4500
4501 intvals = SCIPgetDurationsCumulative(scip, cons);
4502
4503 for( v = 0; v < nconsvars; ++v )
4504 {
4505 if( v < nconsvars - 1)
4506 (void) SCIPsnprintf(buffy, SCIP_MAXSTRLEN, "%d, ", intvals[v] );
4507 else
4508 (void) SCIPsnprintf(buffy, SCIP_MAXSTRLEN, "%d", intvals[v] );
4509
4510 SCIP_CALL( appendBuffer(scip, &(fznoutput.consbuffer), &(fznoutput.consbufferlen), &(fznoutput.consbufferpos), buffy) );
4511 }
4512
4513 SCIP_CALL( appendBuffer(scip, &(fznoutput.consbuffer), &(fznoutput.consbufferlen), &(fznoutput.consbufferpos), "], [") );
4514
4515 intvals = SCIPgetDemandsCumulative(scip, cons);
4516
4517 for( v = 0; v < nconsvars; ++v )
4518 {
4519 if( v < nconsvars - 1)
4520 (void) SCIPsnprintf(buffy, SCIP_MAXSTRLEN, "%d, ", intvals[v] );
4521 else
4522 (void) SCIPsnprintf(buffy, SCIP_MAXSTRLEN, "%d", intvals[v] );
4523
4524 SCIP_CALL( appendBuffer(scip, &(fznoutput.consbuffer), &(fznoutput.consbufferlen), &(fznoutput.consbufferpos), buffy) );
4525 }
4526 (void) SCIPsnprintf(buffy, SCIP_MAXSTRLEN, "], %d);\n", SCIPgetCapacityCumulative(scip, cons) );
4527
4528 SCIP_CALL( appendBuffer(scip, &(fznoutput.consbuffer), &(fznoutput.consbufferlen), &(fznoutput.consbufferpos), buffy) );
4529 }
4530 else
4531 {
4532 SCIPwarningMessage(scip, "constraint handler <%s> cannot print flatzinc format\n", conshdlrname );
4533 }
4534 }
4535
4536 SCIP_CALL( SCIPallocBufferArray(scip,&intobjvars,ndiscretevars) );
4537 SCIP_CALL( SCIPallocBufferArray(scip,&floatobjvars,nvars) );
4538 nintobjvars = 0;
4539 nfloatobjvars = 0;
4540
4541 /* scan objective function: Which variables have to be put to the float part, which to the int part? */
4542 for( v = 0; v < nvars; v++ )
4543 {
4544 SCIP_Real obj;
4545
4546 var = vars[v];
4547 obj = SCIPvarGetObj(var);
4548
4549 if( !SCIPisZero(scip,obj) )
4550 {
4551 /* only discrete variables with integral objective coefficient will be put to the int part of the objective */
4552 if( v < ndiscretevars && SCIPisIntegral(scip, objscale*obj) )
4553 {
4554 intobjvars[nintobjvars] = v;
4555 SCIPdebugMsg(scip, "variable <%s> at pos <%d,%d> has an integral obj: %f=%f*%f\n",
4556 SCIPvarGetName(var), nintobjvars, v, obj, objscale, SCIPvarGetObj(var));
4557 nintobjvars++;
4558 }
4559 else
4560 {
4561 /* if not happened yet, introduce an auxiliary variable for discrete variables with fractional coefficients */
4562 if( v < ndiscretevars && !fznoutput.varhasfloat[v] )
4563 {
4564 assert(SCIPvarGetType(var) == SCIP_VARTYPE_BINARY || SCIPvarGetType(var) == SCIP_VARTYPE_INTEGER);
4565
4566 (void) SCIPsnprintf(buffer, FZN_BUFFERLEN, "var float: %s_float;\n", SCIPvarGetName(var));
4567 SCIP_CALL( appendBuffer(scip, &(fznoutput.varbuffer), &(fznoutput.varbufferlen), &(fznoutput.varbufferpos),buffer) );
4568
4569 (void) SCIPsnprintf(buffer, FZN_BUFFERLEN, "constraint int2float(%s, %s_float);\n", SCIPvarGetName(var), SCIPvarGetName(var));
4570 SCIP_CALL( appendBuffer(scip, &(fznoutput.castbuffer), &(fznoutput.castbufferlen), &(fznoutput.castbufferpos),buffer) );
4571
4572 fznoutput.varhasfloat[v] = TRUE;
4573 }
4574
4575 floatobjvars[nfloatobjvars] = v;
4576 nfloatobjvars++;
4577 }
4578 }
4579 }
4580
4581 /* output all created auxiliary variables (float equivalents of discrete variables) */
4582 if( fznoutput.varbufferpos > 0 )
4583 {
4584 SCIPinfoMessage(scip, file, "\n%%%%%%%%%%%% Auxiliary variables %%%%%%%%%%%%\n");
4585 writeBuffer(scip, file, fznoutput.varbuffer, fznoutput.varbufferpos );
4586 }
4587
4588 /* output all int2float casting/conversion constraints */
4589 if( fznoutput.castbufferpos > 0 )
4590 {
4591 SCIPinfoMessage(scip, file, "\n%%%%%%%%%%%% Variable conversions %%%%%%%%%%%%\n");
4592 writeBuffer(scip, file, fznoutput.castbuffer, fznoutput.castbufferpos );
4593 }
4594
4595 if( nboundedvars > 0 )
4596 SCIPinfoMessage(scip, file, "\n%%%%%%%%%%%% Variable bounds %%%%%%%%%%%%\n");
4597
4598 /* output all bounds of variables with exactly one bound*/
4599 for( v = 0; v < nboundedvars; v++ )
4600 {
4601 var = vars[boundedvars[v]];
4602
4603 if( SCIPvarGetType(var) == SCIP_VARTYPE_INTEGER )
4604 {
4605 if( boundtypes[v] == SCIP_BOUNDTYPE_LOWER )
4606 SCIPinfoMessage(scip, file,"constraint int_ge(%s, %.f);\n",SCIPvarGetName(var),
4607 transformed ? SCIPvarGetLbLocal(var) : SCIPvarGetLbOriginal(var));
4608 else
4609 {
4610 assert( boundtypes[v] == SCIP_BOUNDTYPE_UPPER );
4611 SCIPinfoMessage(scip, file,"constraint int_le(%s, %.f);\n",SCIPvarGetName(var),
4612 transformed ? SCIPvarGetUbLocal(var) : SCIPvarGetUbOriginal(var));
4613 }
4614 }
4615 else
4616 {
4617 assert(SCIPvarGetType(var) == SCIP_VARTYPE_IMPLINT || SCIPvarGetType(var) == SCIP_VARTYPE_CONTINUOUS);
4618
4619 if( boundtypes[v] == SCIP_BOUNDTYPE_LOWER )
4620 {
4621 flattenFloat(scip, transformed ? SCIPvarGetLbLocal(var) : SCIPvarGetLbOriginal(var), buffy);
4622 SCIPinfoMessage(scip, file,"constraint float_ge(%s, %s);\n", SCIPvarGetName(var), buffy);
4623 }
4624 else
4625 {
4626 assert( boundtypes[v] == SCIP_BOUNDTYPE_UPPER );
4627 flattenFloat(scip, transformed ? SCIPvarGetUbLocal(var) : SCIPvarGetUbOriginal(var), buffy);
4628 SCIPinfoMessage(scip, file,"constraint float_le(%s, %s);\n",SCIPvarGetName(var), buffy);
4629 }
4630 }
4631 }
4632
4633 /* output all problem constraints */
4634 if( fznoutput.consbufferpos > 0 )
4635 {
4636 SCIPinfoMessage(scip, file, "\n%%%%%%%%%%%% Problem constraints %%%%%%%%%%%%\n");
4637 writeBuffer(scip, file, fznoutput.consbuffer, fznoutput.consbufferpos );
4638 }
4639
4640 SCIPinfoMessage(scip, file, "\n%%%%%%%%%%%% Objective function %%%%%%%%%%%%\n");
4641
4642 /* If there is at least one variable in the objective function write down the optimization problem, else declare it to be a satisfiability problem */
4643 if( nintobjvars > 0 || nfloatobjvars > 0 )
4644 {
4645 SCIPinfoMessage(scip, file, "solve %s int_float_lin([", objsense == SCIP_OBJSENSE_MINIMIZE ? "minimize" : "maximize" );
4646
4647 /* first array: coefficients (in float representation) of discrete variables with integral objective coefficient */
4648 for( v = 0; v < nintobjvars; v++ )
4649 {
4650 SCIP_Real obj;
4651 var = vars[intobjvars[v]];
4652 obj = objscale * SCIPvarGetObj(var);
4653 SCIPdebugMsg(scip, "variable <%s> at pos <%d,%d> has an integral obj: %f=%f*%f\n", SCIPvarGetName(var), v, intobjvars[v], obj, objscale, SCIPvarGetObj(var));
4654
4655 assert( SCIPisIntegral(scip, obj) );
4656 flattenFloat(scip, obj, buffy);
4657 SCIPinfoMessage(scip, file, "%s%s", buffy, v < nintobjvars-1 ? ", " : "" );
4658 }
4659
4660 /* second array: all other objective coefficients */
4661 SCIPinfoMessage(scip, file, "], [");
4662 for( v = 0; v < nfloatobjvars; v++ )
4663 {
4664 SCIP_Real obj;
4665 obj = objscale * SCIPvarGetObj(vars[floatobjvars[v]]);
4666 flattenFloat(scip, obj, buffy);
4667 assert( !SCIPisIntegral(scip, obj) || SCIPvarGetType(vars[floatobjvars[v]]) == SCIP_VARTYPE_CONTINUOUS
4668 || SCIPvarGetType(vars[floatobjvars[v]]) == SCIP_VARTYPE_IMPLINT);
4669 SCIPinfoMessage(scip, file, "%s%s", buffy, v < nfloatobjvars-1 ? ", " : "" );
4670 }
4671
4672 /* potentially add an objective offset */
4673 if( !SCIPisZero(scip, objoffset) )
4674 {
4675 flattenFloat(scip, objscale * objoffset, buffy);
4676 SCIPinfoMessage(scip, file, "%s%s", nfloatobjvars == 0 ? "" : ", ", buffy );
4677 }
4678
4679 /* third array: all discrete variables with integral objective coefficient */
4680 SCIPinfoMessage(scip, file, "], [");
4681 for( v = 0; v < nintobjvars; v++ )
4682 SCIPinfoMessage(scip, file, "%s%s", SCIPvarGetName(vars[intobjvars[v]]), v < nintobjvars-1 ? ", " : "" );
4683
4684 /* fourth array: all other variables with nonzero objective coefficient */
4685 SCIPinfoMessage(scip, file, "], [");
4686 for( v = 0; v < nfloatobjvars; v++ )
4687 SCIPinfoMessage(scip, file, "%s%s%s", SCIPvarGetName(vars[floatobjvars[v]]), floatobjvars[v] < ndiscretevars ? "_float" : "", v < nfloatobjvars-1 ? ", " : "" );
4688
4689 /* potentially add a 1.0 for the objective offset */
4690 if( !SCIPisZero(scip, objoffset) )
4691 SCIPinfoMessage(scip, file, "%s%.1f", nfloatobjvars == 0 ? "" : ", ", 1.0 );
4692 SCIPinfoMessage(scip, file, "]);\n");
4693 }
4694 else
4695 SCIPinfoMessage(scip, file, "solve satisfy;\n");
4696
4697 /* free all memory */
4698 SCIPfreeBufferArray(scip, &fznoutput.castbuffer);
4699 SCIPfreeBufferArray(scip, &fznoutput.consbuffer);
4700 SCIPfreeBufferArray(scip, &fznoutput.varbuffer);
4701
4702 SCIPfreeBufferArray(scip, &boundtypes);
4703 SCIPfreeBufferArray(scip, &boundedvars);
4704 SCIPfreeBufferArray(scip, &floatobjvars);
4705 SCIPfreeBufferArray(scip, &intobjvars);
4706 SCIPfreeBufferArray(scip, &fznoutput.varhasfloat);
4707
4708 *result = SCIP_SUCCESS;
4709 return SCIP_OKAY;
4710 }
4711
4712 /*
4713 * Callback methods of reader
4714 */
4715
4716 /** copy method for reader plugins (called when SCIP copies plugins) */
4717 static
4718 SCIP_DECL_READERCOPY(readerCopyFzn)
4719 { /*lint --e{715}*/
4720 assert(scip != NULL);
4721 assert(reader != NULL);
4722 assert(strcmp(SCIPreaderGetName(reader), READER_NAME) == 0);
4723
4724 /* call inclusion method of reader */
4725 SCIP_CALL( SCIPincludeReaderFzn(scip) );
4726
4727 return SCIP_OKAY;
4728 }
4729
4730
4731 /** destructor of reader to free user data (called when SCIP is exiting) */
4732 static
4733 SCIP_DECL_READERFREE(readerFreeFzn)
4734 {
4735 SCIP_READERDATA* readerdata;
4736 int v;
4737
4738 readerdata = SCIPreaderGetData(reader);
4739 assert(readerdata != NULL);
4740
4741 /* free all variable array elements */
4742 for( v = 0; v < readerdata->nvararrays; ++v )
4743 {
4744 freeVararray(scip, &readerdata->vararrays[v]);
4745 }
4746
4747 SCIPfreeBlockMemoryArrayNull(scip, &readerdata->vararrays, readerdata->vararrayssize);
4748
4749 /* free reader data */
4750 SCIPfreeBlockMemory(scip, &readerdata);
4751
4752 return SCIP_OKAY;
4753 }
4754
4755
4756 /** problem reading method of reader */
4757 static
4758 SCIP_DECL_READERREAD(readerReadFzn)
4759 { /*lint --e{715}*/
4760 FZNINPUT fzninput;
4761 int i;
4762
4763 /* initialize FZN input data */
4764 fzninput.file = NULL;
4765 SCIP_CALL( SCIPallocBlockMemoryArray(scip, &fzninput.linebuf, FZN_INIT_LINELEN) );
4766 fzninput.linebuf[0] = '\0';
4767 fzninput.linebufsize = FZN_INIT_LINELEN;
4768 SCIP_CALL( SCIPallocBufferArray(scip, &fzninput.token, FZN_BUFFERLEN) );
4769 fzninput.token[0] = '\0';
4770
4771 for( i = 0; i < FZN_MAX_PUSHEDTOKENS; ++i )
4772 {
4773 SCIP_CALL( SCIPallocBufferArray(scip, &(fzninput.pushedtokens[i]), FZN_BUFFERLEN) ); /*lint !e866*/
4774 }
4775
4776 fzninput.npushedtokens = 0;
4777 fzninput.linenumber = 1;
4778 fzninput.bufpos = 0;
4779 fzninput.linepos = 0;
4780 fzninput.objsense = SCIP_OBJSENSE_MINIMIZE;
4781 fzninput.comment = FALSE;
4782 fzninput.haserror = FALSE;
4783 fzninput.valid = TRUE;
4784 fzninput.vararrays = NULL;
4785 fzninput.nvararrays = 0;
4786 fzninput.vararrayssize = 0;
4787 fzninput.constarrays = NULL;
4788 fzninput.nconstarrays = 0;
4789 fzninput.constarrayssize = 0;
4790
4791 SCIP_CALL( SCIPgetBoolParam(scip, "reading/initialconss", &(fzninput.initialconss)) );
4792 SCIP_CALL( SCIPgetBoolParam(scip, "reading/dynamicconss", &(fzninput.dynamicconss)) );
4793 SCIP_CALL( SCIPgetBoolParam(scip, "reading/dynamiccols", &(fzninput.dynamiccols)) );
4794 SCIP_CALL( SCIPgetBoolParam(scip, "reading/dynamicrows", &(fzninput.dynamicrows)) );
4795
4796 SCIP_CALL( SCIPhashtableCreate(&fzninput.varHashtable, SCIPblkmem(scip), SCIP_HASHSIZE_NAMES,
4797 hashGetKeyVar, SCIPhashKeyEqString, SCIPhashKeyValString, NULL) );
4798
4799 SCIP_CALL( SCIPhashtableCreate(&fzninput.constantHashtable, SCIPblkmem(scip), SCIP_HASHSIZE_NAMES,
4800 hashGetKeyConstant, SCIPhashKeyEqString, SCIPhashKeyValString, NULL) );
4801 SCIP_CALL( SCIPallocBufferArray(scip, &fzninput.constants, 10) );
4802
4803 fzninput.nconstants = 0;
4804 fzninput.sconstants = 10;
4805
4806 /* read the file */
4807 SCIP_CALL( readFZNFile(scip, SCIPreaderGetData(reader), &fzninput, filename) );
4808
4809 /* free dynamically allocated memory */
4810 for( i = fzninput.nconstants - 1; i >= 0; --i )
4811 {
4812 SCIPfreeBufferArray(scip, &fzninput.constants[i]->name);
4813 SCIPfreeBuffer(scip, &fzninput.constants[i]);
4814 }
4815 SCIPfreeBufferArray(scip, &fzninput.constants);
4816
4817 for( i = FZN_MAX_PUSHEDTOKENS - 1; i >= 0; --i ) /*lint !e778*/
4818 {
4819 SCIPfreeBufferArrayNull(scip, &fzninput.pushedtokens[i]);
4820 }
4821 SCIPfreeBufferArrayNull(scip, &fzninput.token);
4822
4823 /* free memory */
4824 SCIPhashtableFree(&fzninput.varHashtable);
4825 SCIPhashtableFree(&fzninput.constantHashtable);
4826
4827 /* free variable arrays */
4828 for( i = 0; i < fzninput.nvararrays; ++i )
4829 {
4830 freeVararray(scip, &fzninput.vararrays[i]);
4831 }
4832 SCIPfreeBlockMemoryArrayNull(scip, &(fzninput.vararrays), fzninput.vararrayssize);
4833
4834 /* free constant arrays */
4835 for( i = 0; i < fzninput.nconstarrays; ++i )
4836 {
4837 freeConstarray(scip, &(fzninput.constarrays[i]));
4838 }
4839 SCIPfreeBlockMemoryArrayNull(scip, &fzninput.constarrays, fzninput.constarrayssize);
4840
4841 SCIPfreeBlockMemoryArray(scip, &fzninput.linebuf, fzninput.linebufsize);
4842
4843 /* evaluate the result */
4844 if( fzninput.haserror || ! fzninput.valid )
4845 return SCIP_READERROR;
4846
4847 *result = SCIP_SUCCESS;
4848
4849 return SCIP_OKAY;
4850 }
4851
4852
4853 /** problem writing method of reader */
4854 static
4855 SCIP_DECL_READERWRITE(readerWriteFzn)
4856 { /*lint --e{715}*/
4857 if( genericnames )
4858 {
4859 SCIP_CALL( writeFzn(scip, file, name, transformed, objsense, objscale, objoffset, vars,
4860 nvars, nbinvars, nintvars, nimplvars, ncontvars, conss, nconss, result) );
4861 }
4862 else
4863 {
4864 int i;
4865 SCIP_Bool legal;
4866
4867 legal = TRUE;
4868
4869 /* Scan whether all variable names are flatzinc conform */
4870 for( i = 0; i < nvars; i++ )
4871 {
4872 const char* varname;
4873 size_t length;
4874
4875 varname = SCIPvarGetName(vars[i]);
4876 length = strlen(varname);
4877 legal = isIdentifier(varname);
4878 if( !legal )
4879 {
4880 SCIPwarningMessage(scip, "The name of variable <%d>: \"%s\" is not conform to the fzn standard.\n", i, varname);
4881 break;
4882 }
4883
4884 if( length >= 7 )
4885 legal = (strncmp(&varname[length-6],"_float",6) != 0);
4886 if( !legal )
4887 {
4888 SCIPwarningMessage(scip, "The name of variable <%d>: \"%s\" ends with \"_float\" which is not supported.\n", i, varname);
4889 break;
4890 }
4891 }
4892
4893 /* If there is at least one name, which is not conform, use generic names */
4894 if( legal )
4895 {
4896 SCIP_CALL( writeFzn(scip, file, name, transformed, objsense, objscale, objoffset, vars,
4897 nvars, nbinvars, nintvars, nimplvars, ncontvars, conss, nconss, result) );
4898 }
4899 else if( transformed )
4900 {
4901 SCIPwarningMessage(scip, "Write transformed problem with generic variable names.\n");
4902 SCIP_CALL( SCIPprintTransProblem(scip, file, "fzn", TRUE) );
4903 }
4904 else
4905 {
4906 SCIPwarningMessage(scip, "Write original problem with generic variable names.\n");
4907 SCIP_CALL( SCIPprintOrigProblem(scip, file, "fzn", TRUE) );
4908 }
4909 }
4910
4911 *result = SCIP_SUCCESS;
4912
4913 return SCIP_OKAY;
4914 }
4915
4916 /*
4917 * reader specific interface methods
4918 */
4919
4920 /** includes the fzn file reader in SCIP */
4921 SCIP_RETCODE SCIPincludeReaderFzn(
4922 SCIP* scip /**< SCIP data structure */
4923 )
4924 {
4925 SCIP_READERDATA* readerdata;
4926 SCIP_READER* reader;
4927
4928 /* create fzn reader data */
4929 SCIP_CALL( readerdataCreate(scip, &readerdata) );
4930
4931 /* include reader */
4932 SCIP_CALL( SCIPincludeReaderBasic(scip, &reader, READER_NAME, READER_DESC, READER_EXTENSION, readerdata) );
4933
4934 /* set non fundamental callbacks via setter functions */
4935 SCIP_CALL( SCIPsetReaderCopy(scip, reader, readerCopyFzn) );
4936 SCIP_CALL( SCIPsetReaderFree(scip, reader, readerFreeFzn) );
4937 SCIP_CALL( SCIPsetReaderRead(scip, reader, readerReadFzn) );
4938 SCIP_CALL( SCIPsetReaderWrite(scip, reader, readerWriteFzn) );
4939
4940 return SCIP_OKAY;
4941 }
4942
4943 /** print given solution in Flatzinc format w.r.t. the output annotation */
4944 SCIP_RETCODE SCIPprintSolReaderFzn(
4945 SCIP* scip, /**< SCIP data structure */
4946 SCIP_SOL* sol, /**< primal solution, or NULL for current LP/pseudo solution */
4947 FILE* file /**< output file (or NULL for standard output) */
4948 )
4949 {
4950 SCIP_READER* reader;
4951 SCIP_READERDATA* readerdata;
4952 SCIP_VAR** vars;
4953 VARARRAY** vararrays;
4954 DIMENSIONS* info;
4955 VARARRAY* vararray;
4956 FZNNUMBERTYPE type;
4957 SCIP_Real solvalue;
4958 int nvararrays;
4959 int nvars;
4960 int i;
4961 int v;
4962
4963 reader = SCIPfindReader(scip, READER_NAME);
4964 assert(reader != NULL);
4965
4966 readerdata = SCIPreaderGetData(reader);
4967 assert(readerdata != NULL);
4968
4969 vararrays = readerdata->vararrays;
4970 nvararrays = readerdata->nvararrays;
4971
4972 /* sort variable arrays */
4973 SCIPsortPtr((void**)vararrays, vararraysComp, nvararrays);
4974
4975 for( i = 0; i < nvararrays; ++i )
4976 {
4977 vararray = vararrays[i];
4978 info = vararray->info;
4979 vars = vararray->vars;
4980 nvars = vararray->nvars;
4981 type = vararray->type;
4982
4983 if( info->ndims == 0 )
4984 {
4985 solvalue = SCIPgetSolVal(scip, sol, vars[0]);
4986
4987 SCIPinfoMessage(scip, file, "%s = ", vararray->name);
4988
4989 printValue(scip, file, solvalue, type);
4990
4991 SCIPinfoMessage(scip, file, ";\n");
4992 }
4993 else
4994 {
4995 SCIPinfoMessage(scip, file, "%s = array%dd(", vararray->name, info->ndims);
4996
4997 for( v = 0; v < info->ndims; ++v )
4998 {
4999 SCIPinfoMessage(scip, file, "%d..%d, ", info->lbs[v], info->ubs[v]);
5000 }
5001
5002 SCIPinfoMessage(scip, file, "[");
5003
5004 for( v = 0; v < nvars; ++v )
5005 {
5006 if( v > 0)
5007 SCIPinfoMessage(scip, file, ", ");
5008
5009 solvalue = SCIPgetSolVal(scip, sol, vars[v]);
5010 printValue(scip, file, solvalue, type);
5011 }
5012
5013 SCIPinfoMessage(scip, file, "]);\n");
5014 }
5015 }
5016
5017 SCIPinfoMessage(scip, file, "----------\n");
5018
5019 return SCIP_OKAY;
5020 }
5021