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