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