Scippy

SCIP

Solving Constraint Integer Programs

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