Scippy

SCIP

Solving Constraint Integer Programs

reader_diff.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-2024 Zuse Institute Berlin (ZIB) */
7/* */
8/* Licensed under the Apache License, Version 2.0 (the "License"); */
9/* you may not use this file except in compliance with the License. */
10/* You may obtain a copy of the License at */
11/* */
12/* http://www.apache.org/licenses/LICENSE-2.0 */
13/* */
14/* Unless required by applicable law or agreed to in writing, software */
15/* distributed under the License is distributed on an "AS IS" BASIS, */
16/* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. */
17/* See the License for the specific language governing permissions and */
18/* limitations under the License. */
19/* */
20/* You should have received a copy of the Apache-2.0 license */
21/* along with SCIP; see the file LICENSE. If not visit scipopt.org. */
22/* */
23/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
24
25/**@file reader_diff.c
26 * @ingroup DEFPLUGINS_READER
27 * @brief DIFF file reader
28 * @author Jakob Witzig
29 *
30 * This reader allows to parse a new objective function in the style of CPLEX .lp files.
31 *
32 * The lp format is defined within the CPLEX documentation.
33 *
34 * An example of a *.diff file looks like this:
35 *
36 * Minimize
37 * obj: - STM6 + STM7
38 *
39 * Here is the objective sense set to minimize the function -STM6 + STM7.
40 */
41
42/*---+----1----+----2----+----3----+----4----+----5----+----6----+----7----+----8----+----9----+----0----+----1----+----2*/
43
44#include <ctype.h>
45#include "scip/pub_fileio.h"
46#include "scip/pub_message.h"
47#include "scip/pub_misc.h"
48#include "scip/pub_reader.h"
49#include "scip/pub_var.h"
50#include "scip/reader_diff.h"
51#include "scip/scip_general.h"
52#include "scip/scip_mem.h"
53#include "scip/scip_message.h"
54#include "scip/scip_numerics.h"
55#include "scip/scip_prob.h"
56#include "scip/scip_reader.h"
57#include "scip/scip_solve.h"
58#include <stdlib.h>
59#include <string.h>
60
61#if !defined(_WIN32) && !defined(_WIN64)
62#include <strings.h> /*lint --e{766}*/ /* needed for strncasecmp() */
63#endif
64
65#define READER_NAME "diffreader"
66#define READER_DESC "file reader for changes in the LP file"
67#define READER_EXTENSION "diff"
68
69/*
70 * Data structures
71 */
72#define LP_MAX_LINELEN 65536
73#define LP_MAX_PUSHEDTOKENS 2
74#define LP_INIT_COEFSSIZE 8192
75
76/** Section in LP File */
78{
80};
81typedef enum LpSection LPSECTION;
82
84{
86};
87typedef enum LpExpType LPEXPTYPE;
88
90{
92};
93typedef enum LpSense LPSENSE;
94
95/** LP reading data */
96struct LpInput
97{
98 SCIP_FILE* file;
99 char* linebuf;
100 char probname[LP_MAX_LINELEN];
101 char objname[LP_MAX_LINELEN];
102 char* token;
103 char* tokenbuf;
104 char* pushedtokens[LP_MAX_PUSHEDTOKENS];
105 int npushedtokens;
106 int linenumber;
107 int linepos;
108 int linebufsize;
109 LPSECTION section;
110 SCIP_OBJSENSE objsense;
111 SCIP_Bool haserror;
112};
113typedef struct LpInput LPINPUT;
114
115static const char commentchars[] = "\\";
116
117
118/*
119 * Local methods (for reading)
120 */
121
122/** issues an error message and marks the LP data to have errors */
123static
125 SCIP* scip, /**< SCIP data structure */
126 LPINPUT* lpinput, /**< LP reading data */
127 const char* msg /**< error message */
128 )
129{
130 char formatstr[256];
131
132 assert(lpinput != NULL);
133
134 SCIPerrorMessage("Syntax error in line %d ('%s'): %s \n", lpinput->linenumber, lpinput->token, msg);
135 if( lpinput->linebuf[lpinput->linebufsize - 1] == '\n' )
136 {
137 SCIPverbMessage(scip, SCIP_VERBLEVEL_MINIMAL, NULL, " input: %s", lpinput->linebuf);
138 }
139 else
140 {
141 SCIPverbMessage(scip, SCIP_VERBLEVEL_MINIMAL, NULL, " input: %s\n", lpinput->linebuf);
142 }
143 (void) SCIPsnprintf(formatstr, 256, " %%%ds\n", lpinput->linepos);
144 SCIPverbMessage(scip, SCIP_VERBLEVEL_MINIMAL, NULL, (const char*)formatstr, "^");
145 lpinput->section = LP_END;
146 lpinput->haserror = TRUE;
147}
148
149/** returns whether a syntax error was detected */
150static
152 LPINPUT* lpinput /**< LP reading data */
153 )
154{
155 assert(lpinput != NULL);
156
157 return lpinput->haserror;
158}
159
160/** returns whether the given character is a token delimiter */
161static
163 char c /**< input character */
164 )
165{
166 switch (c)
167 {
168 case ' ':
169 case '\f':
170 case '\n':
171 case '\r':
172 case '\t':
173 case '\v':
174 case '\0':
175 return TRUE;
176 default:
177 return FALSE;
178 }
179}
180
181/** returns whether the given character is a single token */
182static
184 char c /**< input character */
185 )
186{
187 switch (c)
188 {
189 case '-':
190 case '+':
191 case ':':
192 case '<':
193 case '>':
194 case '=':
195 case '[':
196 case ']':
197 case '*':
198 case '^':
199 return TRUE;
200 default:
201 return FALSE;
202 }
203}
204
205/** returns whether the current character is member of a value string */
206static
208 char c, /**< input character */
209 char nextc, /**< next input character */
210 SCIP_Bool firstchar, /**< is the given character the first char of the token? */
211 SCIP_Bool* hasdot, /**< pointer to update the dot flag */
212 LPEXPTYPE* exptype /**< pointer to update the exponent type */
213 )
214{
215 assert(hasdot != NULL);
216 assert(exptype != NULL);
217
218 if( isdigit((unsigned char)c) )
219 return TRUE;
220 else if( (*exptype == LP_EXP_NONE) && !(*hasdot) && (c == '.') && isdigit((unsigned char)nextc) )
221 {
222 *hasdot = TRUE;
223 return TRUE;
224 }
225 else if( !firstchar && (*exptype == LP_EXP_NONE) && (c == 'e' || c == 'E') )
226 {
227 if( nextc == '+' || nextc == '-' )
228 {
229 *exptype = LP_EXP_SIGNED;
230 return TRUE;
231 }
232 else if( isdigit((unsigned char)nextc) )
233 {
234 *exptype = LP_EXP_UNSIGNED;
235 return TRUE;
236 }
237 }
238 else if( (*exptype == LP_EXP_SIGNED) && (c == '+' || c == '-') )
239 {
240 *exptype = LP_EXP_UNSIGNED;
241 return TRUE;
242 }
243
244 return FALSE;
245}
246
247/** reads the next line from the input file into the line buffer; skips comments;
248 * returns whether a line could be read
249 */
250static
252 SCIP* scip, /**< SCIP data structure */
253 LPINPUT* lpinput /**< LP reading data */
254 )
255{
256 int i;
257
258 assert(lpinput != NULL);
259
260 /* read next line */
261 lpinput->linepos = 0;
262 lpinput->linebuf[lpinput->linebufsize - 2] = '\0';
263
264 if( SCIPfgets(lpinput->linebuf, lpinput->linebufsize, lpinput->file) == NULL )
265 {
266 /* clear the line, this is really necessary here! */
267 BMSclearMemoryArray(lpinput->linebuf, lpinput->linebufsize);
268
269 return FALSE;
270 }
271
272 lpinput->linenumber++;
273
274 /* if line is too long for our buffer reallocate buffer */
275 while( lpinput->linebuf[lpinput->linebufsize - 2] != '\0' )
276 {
277 int newsize;
278
279 newsize = SCIPcalcMemGrowSize(scip, lpinput->linebufsize + 1);
280 SCIP_CALL_ABORT( SCIPreallocBlockMemoryArray(scip, &lpinput->linebuf, lpinput->linebufsize, newsize) );
281
282 lpinput->linebuf[newsize-2] = '\0';
283 if ( SCIPfgets(lpinput->linebuf + lpinput->linebufsize - 1, newsize - lpinput->linebufsize + 1, lpinput->file) == NULL )
284 return FALSE;
285 lpinput->linebufsize = newsize;
286 }
287 lpinput->linebuf[lpinput->linebufsize - 1] = '\0'; /* we want to use lookahead of one char -> we need two \0 at the end */
288
289 /* skip characters after comment symbol */
290 for( i = 0; commentchars[i] != '\0'; ++i )
291 {
292 char* commentstart;
293
294 commentstart = strchr(lpinput->linebuf, commentchars[i]);
295 if( commentstart != NULL )
296 {
297 *commentstart = '\0';
298 *(commentstart+1) = '\0'; /* we want to use lookahead of one char -> we need two \0 at the end */
299
300 break;
301 }
302 }
303
304 return TRUE;
305}
306
307/** swaps the addresses of two pointers */
308static
310 char** pointer1, /**< first pointer */
311 char** pointer2 /**< second pointer */
312 )
313{
314 char* tmp;
315
316 tmp = *pointer1;
317 *pointer1 = *pointer2;
318 *pointer2 = tmp;
319}
320
321/** reads the next token from the input file into the token buffer; returns whether a token was read */
322static
324 SCIP* scip, /**< SCIP data structure */
325 LPINPUT* lpinput /**< LP reading data */
326 )
327{
328 SCIP_Bool hasdot;
329 LPEXPTYPE exptype;
330 char* buf;
331 int tokenlen;
332
333 assert(lpinput != NULL);
334 assert(lpinput->linepos < lpinput->linebufsize);
335
336 /* check the token stack */
337 if( lpinput->npushedtokens > 0 )
338 {
339 swapPointers(&lpinput->token, &lpinput->pushedtokens[lpinput->npushedtokens-1]);
340 lpinput->npushedtokens--;
341
342 SCIPdebugMsg(scip, "(line %d) read token again: '%s'\n", lpinput->linenumber, lpinput->token);
343 return TRUE;
344 }
345
346 /* skip delimiters */
347 buf = lpinput->linebuf;
348 while( isDelimChar(buf[lpinput->linepos]) )
349 {
350 if( buf[lpinput->linepos] == '\0' )
351 {
352 if( !getNextLine(scip, lpinput) )
353 {
354 lpinput->section = LP_END;
355 SCIPdebugMsg(scip, "(line %d) end of file\n", lpinput->linenumber);
356 return FALSE;
357 }
358 assert(lpinput->linepos == 0);
359 /* update buf, because the linebuffer may have been reallocated */
360 buf = lpinput->linebuf;
361 }
362 else
363 lpinput->linepos++;
364 }
365 assert(lpinput->linepos < lpinput->linebufsize);
366 assert(!isDelimChar(buf[lpinput->linepos]));
367 assert(buf[lpinput->linepos] != '\0'); /* '\0' is a delim-char, so this assert is redundant, but it helps to suppress a scan-build warning */
368
369 /* check if the token is a value */
370 hasdot = FALSE;
371 exptype = LP_EXP_NONE;
372 if( isValueChar(buf[lpinput->linepos], buf[lpinput->linepos+1], TRUE, &hasdot, &exptype) )
373 {
374 /* read value token */
375 tokenlen = 0;
376 do
377 {
378 assert(tokenlen < LP_MAX_LINELEN);
379 assert(!isDelimChar(buf[lpinput->linepos]));
380 lpinput->token[tokenlen] = buf[lpinput->linepos];
381 tokenlen++;
382 lpinput->linepos++;
383 }
384 while( isValueChar(buf[lpinput->linepos], buf[lpinput->linepos+1], FALSE, &hasdot, &exptype) );
385 }
386 else
387 {
388 /* read non-value token */
389 tokenlen = 0;
390 do
391 {
392 assert(tokenlen < LP_MAX_LINELEN);
393 lpinput->token[tokenlen] = buf[lpinput->linepos];
394 tokenlen++;
395 lpinput->linepos++;
396 if( tokenlen == 1 && isTokenChar(lpinput->token[0]) )
397 break;
398 }
399 while( !isDelimChar(buf[lpinput->linepos]) && !isTokenChar(buf[lpinput->linepos]) );
400
401 /* if the token is a power sign '^', skip a following '2'
402 * if the token is an equation sense '<', '>', or '=', skip a following '='
403 * if the token is an equality token '=' and the next character is a '<' or '>', replace the token by the inequality sense
404 */
405 if( tokenlen >= 1 && lpinput->token[tokenlen-1] == '^' && buf[lpinput->linepos] == '2' )
406 {
407 lpinput->linepos++;
408 }
409 if( tokenlen >= 1
410 && (lpinput->token[tokenlen-1] == '<' || lpinput->token[tokenlen-1] == '>' || lpinput->token[tokenlen-1] == '=')
411 && buf[lpinput->linepos] == '=' )
412 {
413 lpinput->linepos++;
414 }
415 else if( lpinput->token[tokenlen-1] == '=' && (buf[lpinput->linepos] == '<' || buf[lpinput->linepos] == '>') )
416 {
417 lpinput->token[tokenlen-1] = buf[lpinput->linepos];
418 lpinput->linepos++;
419 }
420 }
421 assert(tokenlen < LP_MAX_LINELEN);
422 lpinput->token[tokenlen] = '\0';
423
424 SCIPdebugMsg(scip, "(line %d) read token: '%s'\n", lpinput->linenumber, lpinput->token);
425
426 return TRUE;
427}
428
429/** puts the current token on the token stack, such that it is read at the next call to getNextToken() */
430static
432 LPINPUT* lpinput /**< LP reading data */
433 )
434{
435 assert(lpinput != NULL);
436 assert(lpinput->npushedtokens < LP_MAX_PUSHEDTOKENS);
437
438 swapPointers(&lpinput->pushedtokens[lpinput->npushedtokens], &lpinput->token);
439 lpinput->npushedtokens++;
440}
441
442/** puts the buffered token on the token stack, such that it is read at the next call to getNextToken() */
443static
445 LPINPUT* lpinput /**< LP reading data */
446 )
447{
448 assert(lpinput != NULL);
449 assert(lpinput->npushedtokens < LP_MAX_PUSHEDTOKENS);
450
451 swapPointers(&lpinput->pushedtokens[lpinput->npushedtokens], &lpinput->tokenbuf);
452 lpinput->npushedtokens++;
453}
454
455/** swaps the current token with the token buffer */
456static
458 LPINPUT* lpinput /**< LP reading data */
459 )
460{
461 assert(lpinput != NULL);
462
463 swapPointers(&lpinput->token, &lpinput->tokenbuf);
464}
465
466/** checks whether the current token is a section identifier, and if yes, switches to the corresponding section */
467static
469 SCIP* scip, /**< SCIP data structure */
470 LPINPUT* lpinput /**< LP reading data */
471 )
472{
473 SCIP_Bool iscolon;
474 size_t len;
475
476 assert(lpinput != NULL);
477
478 /* remember first token by swapping the token buffer */
479 swapTokenBuffer(lpinput);
480
481 /* look at next token: if this is a ':', the first token is a name and no section keyword */
482 iscolon = FALSE;
483 if( getNextToken(scip, lpinput) )
484 {
485 iscolon = (*lpinput->token == ':');
486 pushToken(lpinput);
487 }
488
489 /* reinstall the previous token by swapping back the token buffer */
490 swapTokenBuffer(lpinput);
491
492 /* check for ':' */
493 if( iscolon )
494 return FALSE;
495
496 len = strlen(lpinput->token);
497 assert(len < LP_MAX_LINELEN);
498
499 /* the section keywords are at least 2 characters up to 8 or exactly 15 characters long */
500 if( len > 1 && (len < 9 || len == 15) )
501 {
502 char token[16];
503 int c = 0;
504
505 while( lpinput->token[c] != '\0' )
506 {
507 token[c] = toupper(lpinput->token[c]); /*lint !e734*/
508 ++c;
509 assert(c < 16);
510 }
511 token[c] = '\0';
512
513 if( (len == 3 && strcmp(token, "MIN") == 0)
514 || (len == 7 && strcmp(token, "MINIMUM") == 0)
515 || (len == 8 && strcmp(token, "MINIMIZE") == 0) )
516 {
517 SCIPdebugMsg(scip, "(line %d) new section: OBJECTIVE\n", lpinput->linenumber);
518 lpinput->section = LP_OBJECTIVE;
519 lpinput->objsense = SCIP_OBJSENSE_MINIMIZE;
520 return TRUE;
521 }
522
523 if( (len == 3 && strcmp(token, "MAX") == 0)
524 || (len == 7 && strcmp(token, "MAXIMUM") == 0)
525 || (len == 8 && strcmp(token, "MAXIMIZE") == 0) )
526 {
527 SCIPdebugMsg(scip, "(line %d) new section: OBJECTIVE\n", lpinput->linenumber);
528 lpinput->section = LP_OBJECTIVE;
529 lpinput->objsense = SCIP_OBJSENSE_MAXIMIZE;
530 return TRUE;
531 }
532
533 if( len == 3 && strcmp(token, "END") == 0 )
534 {
535 SCIPdebugMsg(scip, "(line %d) new section: END\n", lpinput->linenumber);
536 lpinput->section = LP_END;
537 return TRUE;
538 }
539 }
540
541 return FALSE;
542}
543
544/** returns whether the current token is a sign */
545static
547 LPINPUT* lpinput, /**< LP reading data */
548 int* sign /**< pointer to update the sign */
549 )
550{
551 assert(lpinput != NULL);
552 assert(sign != NULL);
553 assert(*sign == +1 || *sign == -1);
554
555 if( lpinput->token[1] == '\0' )
556 {
557 if( *lpinput->token == '+' )
558 return TRUE;
559 else if( *lpinput->token == '-' )
560 {
561 *sign *= -1;
562 return TRUE;
563 }
564 }
565
566 return FALSE;
567}
568
569/** returns whether the current token is a value */
570static
572 SCIP* scip, /**< SCIP data structure */
573 LPINPUT* lpinput, /**< LP reading data */
574 SCIP_Real* value /**< pointer to store the value (unchanged, if token is no value) */
575 )
576{
577 assert(lpinput != NULL);
578 assert(value != NULL);
579
580 if( strcasecmp(lpinput->token, "INFINITY") == 0 || strcasecmp(lpinput->token, "INF") == 0 )
581 {
582 *value = SCIPinfinity(scip);
583 return TRUE;
584 }
585 else
586 {
587 double val;
588 char* endptr;
589
590 val = strtod(lpinput->token, &endptr);
591 if( endptr != lpinput->token && *endptr == '\0' )
592 {
593 *value = val;
594 return TRUE;
595 }
596 }
597
598 return FALSE;
599}
600
601/** returns whether the current token is an equation sense */
602static
604 LPINPUT* lpinput, /**< LP reading data */
605 LPSENSE* sense /**< pointer to store the equation sense, or NULL */
606 )
607{
608 assert(lpinput != NULL);
609
610 if( strcmp(lpinput->token, "<") == 0 )
611 {
612 if( sense != NULL )
613 *sense = LP_SENSE_LE;
614 return TRUE;
615 }
616 else if( strcmp(lpinput->token, ">") == 0 )
617 {
618 if( sense != NULL )
619 *sense = LP_SENSE_GE;
620 return TRUE;
621 }
622 else if( strcmp(lpinput->token, "=") == 0 )
623 {
624 if( sense != NULL )
625 *sense = LP_SENSE_EQ;
626 return TRUE;
627 }
628
629 return FALSE;
630}
631
632/** returns the variable with the given name, or creates a new variable if it does not exist */
633static
635 SCIP* scip, /**< SCIP data structure */
636 char* name, /**< name of the variable */
637 SCIP_VAR** var /**< pointer to store the variable */
638 )
639{
640 assert(name != NULL);
641 assert(var != NULL);
642
643 *var = SCIPfindVar(scip, name);
644
645 if( *var == NULL )
646 return SCIP_READERROR;
647
648 return SCIP_OKAY;
649}
650
651/** reads the header of the file */
652static
654 SCIP* scip, /**< SCIP data structure */
655 LPINPUT* lpinput /**< LP reading data */
656 )
657{
658 assert(lpinput != NULL);
659
660 /* everything before first section is treated as comment */
661 do
662 {
663 /* get token */
664 if( !getNextToken(scip, lpinput) )
665 return SCIP_OKAY;
666 }
667 while( !isNewSection(scip, lpinput) );
668
669 return SCIP_OKAY;
670}
671
672/** reads an objective or constraint with name and coefficients */
673static
675 SCIP* scip, /**< SCIP data structure */
676 LPINPUT* lpinput, /**< LP reading data */
677 SCIP_Bool isobjective, /**< indicates whether we are currently reading the coefficients of the objective */
678 char* name, /**< pointer to store the name of the line; must be at least of size
679 * LP_MAX_LINELEN */
680 int* coefssize, /**< size of vars and coefs arrays */
681 SCIP_VAR*** vars, /**< pointer to store the array with variables (must be freed by caller) */
682 SCIP_Real** coefs, /**< pointer to store the array with coefficients (must be freed by caller) */
683 int* ncoefs, /**< pointer to store the number of coefficients */
684 SCIP_Bool* newsection /**< pointer to store whether a new section was encountered */
685 )
686{
687 SCIP_Bool havesign;
688 SCIP_Bool havevalue;
689 SCIP_Real coef;
690 int coefsign;
691
692 assert(lpinput != NULL);
693 assert(name != NULL);
694 assert(coefssize != NULL);
695 assert(vars != NULL);
696 assert(coefs != NULL);
697 assert(ncoefs != NULL);
698 assert(newsection != NULL);
699
700 *coefssize = 0;
701 *vars = NULL;
702 *coefs = NULL;
703 *name = '\0';
704 *ncoefs = 0;
705 *newsection = FALSE;
706
707 /* read the first token, which may be the name of the line */
708 if( getNextToken(scip, lpinput) )
709 {
710 /* check if we reached a new section */
711 if( isNewSection(scip, lpinput) )
712 {
713 *newsection = TRUE;
714 return SCIP_OKAY;
715 }
716
717 /* remember the token in the token buffer */
718 swapTokenBuffer(lpinput);
719
720 /* get the next token and check, whether it is a colon */
721 if( getNextToken(scip, lpinput) )
722 {
723 if( strcmp(lpinput->token, ":") == 0 )
724 {
725 /* the second token was a colon: the first token is the line name */
726 (void)SCIPmemccpy(name, lpinput->tokenbuf, '\0', LP_MAX_LINELEN);
727
728 name[LP_MAX_LINELEN - 1] = '\0';
729 SCIPdebugMsg(scip, "(line %d) read constraint name: '%s'\n", lpinput->linenumber, name);
730 }
731 else
732 {
733 /* the second token was no colon: push the tokens back onto the token stack and parse them as coefficients */
734 pushToken(lpinput);
735 pushBufferToken(lpinput);
736 }
737 }
738 else
739 {
740 /* there was only one token left: push it back onto the token stack and parse it as coefficient */
741 pushBufferToken(lpinput);
742 }
743 }
744
745 /* initialize buffers for storing the coefficients */
746 *coefssize = LP_INIT_COEFSSIZE;
747 SCIP_CALL( SCIPallocBlockMemoryArray(scip, vars, *coefssize) );
748 SCIP_CALL( SCIPallocBlockMemoryArray(scip, coefs, *coefssize) );
749
750 /* read the coefficients */
751 coefsign = +1;
752 coef = 1.0;
753 havesign = FALSE;
754 havevalue = FALSE;
755 *ncoefs = 0;
756 while( getNextToken(scip, lpinput) )
757 {
758 SCIP_VAR* var;
759
760 /* check if we read a sign */
761 if( isSign(lpinput, &coefsign) )
762 {
763 SCIPdebugMsg(scip, "(line %d) read coefficient sign: %+d\n", lpinput->linenumber, coefsign);
764 havesign = TRUE;
765 continue;
766 }
767
768 /* check if we read a value */
769 if( isValue(scip, lpinput, &coef) )
770 {
771 SCIPdebugMsg(scip, "(line %d) read coefficient value: %g with sign %+d\n", lpinput->linenumber, coef, coefsign);
772 if( havevalue )
773 {
774 syntaxError(scip, lpinput, "two consecutive values.");
775 return SCIP_OKAY;
776 }
777 havevalue = TRUE;
778 continue;
779 }
780
781 /* check if we reached an equation sense */
782 if( isSense(lpinput, NULL) )
783 {
784 if( isobjective )
785 {
786 syntaxError(scip, lpinput, "no sense allowed in objective");
787 return SCIP_OKAY;
788 }
789
790 /* put the sense back onto the token stack */
791 pushToken(lpinput);
792 break;
793 }
794
795 /* check if we reached a new section, that will be only allowed when having no current sign and value and if we
796 * are not in the quadratic part
797 */
798 if( (isobjective || (!havevalue && !havesign)) && isNewSection(scip, lpinput) )
799 {
800 if( havesign && !havevalue )
801 {
802 SCIPwarningMessage(scip, "skipped single sign %c without value or variable in objective\n", coefsign == 1 ? '+' : '-');
803 }
804 else if( isobjective && havevalue && !SCIPisZero(scip, coef) )
805 {
806 SCIPwarningMessage(scip, "constant term %+g in objective is skipped\n", coef * coefsign);
807 }
808
809 *newsection = TRUE;
810 return SCIP_OKAY;
811 }
812
813 /* check if we start a quadratic part */
814 if( *lpinput->token == '[' )
815 {
816 syntaxError(scip, lpinput, "diff reader does not support quadratic objective function.");
817 return SCIP_READERROR;
818 }
819
820 /* all but the first coefficient need a sign */
821 if( *ncoefs > 0 && !havesign )
822 {
823 syntaxError(scip, lpinput, "expected sign ('+' or '-') or sense ('<' or '>').");
824 return SCIP_OKAY;
825 }
826
827 /* check if the last variable should be squared */
828 if( *lpinput->token == '^' )
829 {
830 syntaxError(scip, lpinput, "diff reader does not support quadratic objective function.");
831 return SCIP_READERROR;
832 }
833 else
834 {
835 /* the token is a variable name: get the corresponding variable */
836 SCIP_CALL( getVariable(scip, lpinput->token, &var) );
837 }
838
839 /* insert the linear coefficient */
840 SCIPdebugMsg(scip, "(line %d) read linear coefficient: %+g<%s>\n", lpinput->linenumber, coefsign * coef, SCIPvarGetName(var));
841 if( !SCIPisZero(scip, coef) )
842 {
843 /* resize the vars and coefs array if needed */
844 if( *ncoefs >= *coefssize )
845 {
846 int oldcoefssize;
847
848 oldcoefssize = *coefssize;
849 *coefssize *= 2;
850 *coefssize = MAX(*coefssize, (*ncoefs)+1);
851 SCIP_CALL( SCIPreallocBlockMemoryArray(scip, vars, oldcoefssize, *coefssize) );
852 SCIP_CALL( SCIPreallocBlockMemoryArray(scip, coefs, oldcoefssize, *coefssize) );
853 }
854 assert(*ncoefs < *coefssize);
855
856 /* add coefficient */
857 (*vars)[*ncoefs] = var;
858 (*coefs)[*ncoefs] = coefsign * coef;
859 (*ncoefs)++;
860 }
861
862 /* reset the flags and coefficient value for the next coefficient */
863 coefsign = +1;
864 coef = 1.0;
865 havesign = FALSE;
866 havevalue = FALSE;
867 }
868
869 return SCIP_OKAY;
870}
871
872/** reads the objective section */
873static
875 SCIP* scip, /**< SCIP data structure */
876 LPINPUT* lpinput /**< LP reading data */
877 )
878{
879 char name[LP_MAX_LINELEN];
880 SCIP_VAR** vars;
881 SCIP_Real* coefs;
882 SCIP_Bool newsection;
883 int coefssize;
884 int ncoefs;
885
886 assert(lpinput != NULL);
887
888 /* read the objective coefficients */
889 SCIP_CALL( readCoefficients(scip, lpinput, TRUE, name, &coefssize, &vars, &coefs, &ncoefs, &newsection) );
890
891 /* change the objective function */
892 SCIP_CALL( SCIPchgReoptObjective(scip, lpinput->objsense, vars, coefs, ncoefs) );
893
894 /* free memory */
895 SCIPfreeBlockMemoryArrayNull(scip, &coefs, coefssize);
896 SCIPfreeBlockMemoryArrayNull(scip, &vars, coefssize);
897
898 return SCIP_OKAY; /*lint !e438*/
899}
900
901/** reads a diff file */
902static
904 SCIP* scip, /**< SCIP data structure */
905 LPINPUT* lpinput, /**< LP reading data */
906 const char* filename /**< name of the input file */
907 )
908{
909 assert(lpinput != NULL);
910
911 /* open file */
912 lpinput->file = SCIPfopen(filename, "r");
913 if( lpinput->file == NULL )
914 {
915 SCIPerrorMessage("cannot open file <%s> for reading\n", filename);
916 SCIPprintSysError(filename);
917 return SCIP_NOFILE;
918 }
919
920 /* free transformed problem */
922 {
924 }
925 else
926 {
928 }
929
930 /* parse the file */
931 lpinput->section = LP_START;
932 while( lpinput->section != LP_END && !hasError(lpinput) )
933 {
934 switch( lpinput->section )
935 {
936 case LP_START:
937 SCIP_CALL( readStart(scip, lpinput) );
938 break;
939
940 case LP_OBJECTIVE:
941 SCIP_CALL( readObjective(scip, lpinput) );
942 break;
943
944 case LP_END: /* this is already handled in the while() loop */
945 default:
946 SCIPerrorMessage("invalid Diff file section <%d>\n", lpinput->section);
947 return SCIP_INVALIDDATA;
948 }
949 }
950
951 /* close file */
952 SCIPfclose(lpinput->file);
953
954 return SCIP_OKAY;
955}
956
957/*
958 * Callback methods of reader
959 */
960
961/** copy method for reader plugins (called when SCIP copies plugins) */
962static
963SCIP_DECL_READERCOPY(readerCopyDiff)
964{ /*lint --e{715}*/
965 assert(scip != NULL);
966 assert(reader != NULL);
967 assert(strcmp(SCIPreaderGetName(reader), READER_NAME) == 0);
968
969 /* call inclusion method of reader */
971
972 return SCIP_OKAY;
973}
974
975/** destructor of reader to free user data (called when SCIP is exiting) */
976static
977SCIP_DECL_READERFREE(readerFreeDiff)
978{ /*lint --e{715}*/
979 return SCIP_OKAY;
980}
981
982/** problem reading method of reader */
983static
984SCIP_DECL_READERREAD(readerReadDiff)
985{ /*lint --e{715}*/
986
987 SCIP_CALL( SCIPreadDiff(scip, reader, filename, result) );
988
989 return SCIP_OKAY;
990}
991
992/*
993 * reader specific interface methods
994 */
995
996/** includes the lp file reader in SCIP */
998 SCIP* scip /**< SCIP data structure */
999 )
1000{
1001 SCIP_READER* reader;
1002
1003 /* include reader */
1005
1006 /* set non fundamental callbacks via setter functions */
1007 SCIP_CALL( SCIPsetReaderCopy(scip, reader, readerCopyDiff) );
1008 SCIP_CALL( SCIPsetReaderFree(scip, reader, readerFreeDiff) );
1009 SCIP_CALL( SCIPsetReaderRead(scip, reader, readerReadDiff) );
1010
1011 return SCIP_OKAY;
1012}
1013
1014
1015/** reads problem from file */
1017 SCIP* scip, /**< SCIP data structure */
1018 SCIP_READER* reader, /**< the file reader itself */
1019 const char* filename, /**< full path and name of file to read, or NULL if stdin should be used */
1020 SCIP_RESULT* result /**< pointer to store the result of the file reading call */
1021 )
1022{ /*lint --e{715}*/
1023 LPINPUT lpinput;
1024 int i;
1025
1026 assert(scip != NULL);
1027 assert(reader != NULL);
1028
1029 /* initialize LP input data */
1030 lpinput.file = NULL;
1032 lpinput.linebuf[0] = '\0';
1033 lpinput.linebufsize = LP_MAX_LINELEN;
1034 lpinput.probname[0] = '\0';
1035 lpinput.objname[0] = '\0';
1036 SCIP_CALL( SCIPallocBlockMemoryArray(scip, &lpinput.token, LP_MAX_LINELEN) ); /*lint !e506*/
1037 lpinput.token[0] = '\0';
1038 SCIP_CALL( SCIPallocBlockMemoryArray(scip, &lpinput.tokenbuf, LP_MAX_LINELEN) ); /*lint !e506*/
1039 lpinput.tokenbuf[0] = '\0';
1040 for( i = 0; i < LP_MAX_PUSHEDTOKENS; ++i )
1041 {
1042 SCIP_CALL( SCIPallocBlockMemoryArray(scip, &(lpinput.pushedtokens[i]), LP_MAX_LINELEN) ); /*lint !e866 !e506*/
1043 }
1044
1045 lpinput.npushedtokens = 0;
1046 lpinput.linenumber = 0;
1047 lpinput.linepos = 0;
1048 lpinput.section = LP_START;
1049 lpinput.objsense = SCIP_OBJSENSE_MINIMIZE;
1050 lpinput.haserror = FALSE;
1051
1052 /* read the file */
1053 SCIP_CALL( readDiffFile(scip, &lpinput, filename) );
1054
1055 /* free dynamically allocated memory */
1056 for( i = 0; i < LP_MAX_PUSHEDTOKENS; ++i )
1057 {
1058 SCIPfreeBlockMemoryArray(scip, &lpinput.pushedtokens[i], LP_MAX_LINELEN);
1059 }
1060 SCIPfreeBlockMemoryArray(scip, &lpinput.tokenbuf, LP_MAX_LINELEN);
1062 SCIPfreeBlockMemoryArray(scip, &lpinput.linebuf, lpinput.linebufsize);
1063
1064 /* evaluate the result */
1065 if( lpinput.haserror )
1066 return SCIP_READERROR;
1067
1068 *result = SCIP_SUCCESS;
1069
1070 return SCIP_OKAY;
1071}
#define NULL
Definition: def.h:267
#define SCIP_Bool
Definition: def.h:91
#define SCIP_Real
Definition: def.h:173
#define TRUE
Definition: def.h:93
#define FALSE
Definition: def.h:94
#define MAX(x, y)
Definition: def.h:239
#define SCIP_CALL_ABORT(x)
Definition: def.h:353
#define SCIP_CALL(x)
Definition: def.h:374
SCIP_FILE * SCIPfopen(const char *path, const char *mode)
Definition: fileio.c:153
int SCIPfclose(SCIP_FILE *fp)
Definition: fileio.c:232
char * SCIPfgets(char *s, int size, SCIP_FILE *stream)
Definition: fileio.c:200
SCIP_RETCODE SCIPreadDiff(SCIP *scip, SCIP_READER *reader, const char *filename, SCIP_RESULT *result)
Definition: reader_diff.c:1016
SCIP_RETCODE SCIPincludeReaderDiff(SCIP *scip)
Definition: reader_diff.c:997
SCIP_STAGE SCIPgetStage(SCIP *scip)
Definition: scip_general.c:380
SCIP_RETCODE SCIPchgReoptObjective(SCIP *scip, SCIP_OBJSENSE objsense, SCIP_VAR **vars, SCIP_Real *coefs, int nvars)
Definition: scip_prob.c:1119
SCIP_VAR * SCIPfindVar(SCIP *scip, const char *name)
Definition: scip_prob.c:2685
void SCIPverbMessage(SCIP *scip, SCIP_VERBLEVEL msgverblevel, FILE *file, const char *formatstr,...)
Definition: scip_message.c:225
#define SCIPdebugMsg
Definition: scip_message.h:78
void SCIPwarningMessage(SCIP *scip, const char *formatstr,...)
Definition: scip_message.c:120
#define SCIPfreeBlockMemoryArray(scip, ptr, num)
Definition: scip_mem.h:110
int SCIPcalcMemGrowSize(SCIP *scip, int num)
Definition: scip_mem.c:139
#define SCIPallocBlockMemoryArray(scip, ptr, num)
Definition: scip_mem.h:93
#define SCIPreallocBlockMemoryArray(scip, ptr, oldnum, newnum)
Definition: scip_mem.h:99
#define SCIPfreeBlockMemoryArrayNull(scip, ptr, num)
Definition: scip_mem.h:111
SCIP_RETCODE SCIPincludeReaderBasic(SCIP *scip, SCIP_READER **readerptr, const char *name, const char *desc, const char *extension, SCIP_READERDATA *readerdata)
Definition: scip_reader.c:109
SCIP_RETCODE SCIPsetReaderCopy(SCIP *scip, SCIP_READER *reader, SCIP_DECL_READERCOPY((*readercopy)))
Definition: scip_reader.c:147
SCIP_RETCODE SCIPsetReaderFree(SCIP *scip, SCIP_READER *reader, SCIP_DECL_READERFREE((*readerfree)))
Definition: scip_reader.c:171
const char * SCIPreaderGetName(SCIP_READER *reader)
Definition: reader.c:557
SCIP_RETCODE SCIPsetReaderRead(SCIP *scip, SCIP_READER *reader, SCIP_DECL_READERREAD((*readerread)))
Definition: scip_reader.c:195
SCIP_Bool SCIPisReoptEnabled(SCIP *scip)
Definition: scip_solve.c:3498
SCIP_RETCODE SCIPfreeReoptSolve(SCIP *scip)
Definition: scip_solve.c:3281
SCIP_RETCODE SCIPfreeTransform(SCIP *scip)
Definition: scip_solve.c:3344
SCIP_Real SCIPinfinity(SCIP *scip)
SCIP_Bool SCIPisZero(SCIP *scip, SCIP_Real val)
const char * SCIPvarGetName(SCIP_VAR *var)
Definition: var.c:17419
int SCIPsnprintf(char *t, int len, const char *s,...)
Definition: misc.c:10877
void SCIPprintSysError(const char *message)
Definition: misc.c:10769
int SCIPmemccpy(char *dest, const char *src, char stop, unsigned int cnt)
Definition: misc.c:10744
#define BMSclearMemoryArray(ptr, num)
Definition: memory.h:130
wrapper functions to map file i/o to standard or zlib file i/o
struct SCIP_File SCIP_FILE
Definition: pub_fileio.h:43
public methods for message output
#define SCIPerrorMessage
Definition: pub_message.h:64
public data structures and miscellaneous methods
public methods for input file readers
public methods for problem variables
#define LP_INIT_COEFSSIZE
Definition: reader_diff.c:74
static SCIP_DECL_READERCOPY(readerCopyDiff)
Definition: reader_diff.c:963
static SCIP_Bool isSign(LPINPUT *lpinput, int *sign)
Definition: reader_diff.c:546
static SCIP_Bool isNewSection(SCIP *scip, LPINPUT *lpinput)
Definition: reader_diff.c:468
static SCIP_Bool hasError(LPINPUT *lpinput)
Definition: reader_diff.c:151
static void pushToken(LPINPUT *lpinput)
Definition: reader_diff.c:431
static SCIP_Bool getNextLine(SCIP *scip, LPINPUT *lpinput)
Definition: reader_diff.c:251
static SCIP_RETCODE getVariable(SCIP *scip, char *name, SCIP_VAR **var)
Definition: reader_diff.c:634
static void swapTokenBuffer(LPINPUT *lpinput)
Definition: reader_diff.c:457
enum LpExpType LPEXPTYPE
Definition: reader_diff.c:87
struct LpInput LPINPUT
Definition: reader_diff.c:113
LpExpType
Definition: reader_diff.c:84
@ LP_EXP_UNSIGNED
Definition: reader_diff.c:85
@ LP_EXP_SIGNED
Definition: reader_diff.c:85
@ LP_EXP_NONE
Definition: reader_diff.c:85
static SCIP_Bool getNextToken(SCIP *scip, LPINPUT *lpinput)
Definition: reader_diff.c:323
static const char commentchars[]
Definition: reader_diff.c:115
static SCIP_Bool isValueChar(char c, char nextc, SCIP_Bool firstchar, SCIP_Bool *hasdot, LPEXPTYPE *exptype)
Definition: reader_diff.c:207
#define LP_MAX_LINELEN
Definition: reader_diff.c:72
#define READER_DESC
Definition: reader_diff.c:66
#define LP_MAX_PUSHEDTOKENS
Definition: reader_diff.c:73
LpSection
Definition: reader_diff.c:78
@ LP_END
Definition: reader_diff.c:79
@ LP_OBJECTIVE
Definition: reader_diff.c:79
@ LP_START
Definition: reader_diff.c:79
static SCIP_DECL_READERREAD(readerReadDiff)
Definition: reader_diff.c:984
#define READER_EXTENSION
Definition: reader_diff.c:67
static SCIP_RETCODE readObjective(SCIP *scip, LPINPUT *lpinput)
Definition: reader_diff.c:874
static SCIP_Bool isValue(SCIP *scip, LPINPUT *lpinput, SCIP_Real *value)
Definition: reader_diff.c:571
static void syntaxError(SCIP *scip, LPINPUT *lpinput, const char *msg)
Definition: reader_diff.c:124
static void pushBufferToken(LPINPUT *lpinput)
Definition: reader_diff.c:444
static SCIP_RETCODE readCoefficients(SCIP *scip, LPINPUT *lpinput, SCIP_Bool isobjective, char *name, int *coefssize, SCIP_VAR ***vars, SCIP_Real **coefs, int *ncoefs, SCIP_Bool *newsection)
Definition: reader_diff.c:674
enum LpSection LPSECTION
Definition: reader_diff.c:81
#define READER_NAME
Definition: reader_diff.c:65
static SCIP_Bool isSense(LPINPUT *lpinput, LPSENSE *sense)
Definition: reader_diff.c:603
static SCIP_Bool isDelimChar(char c)
Definition: reader_diff.c:162
static void swapPointers(char **pointer1, char **pointer2)
Definition: reader_diff.c:309
static SCIP_DECL_READERFREE(readerFreeDiff)
Definition: reader_diff.c:977
enum LpSense LPSENSE
Definition: reader_diff.c:93
static SCIP_RETCODE readStart(SCIP *scip, LPINPUT *lpinput)
Definition: reader_diff.c:653
static SCIP_RETCODE readDiffFile(SCIP *scip, LPINPUT *lpinput, const char *filename)
Definition: reader_diff.c:903
LpSense
Definition: reader_diff.c:90
@ LP_SENSE_LE
Definition: reader_diff.c:91
@ LP_SENSE_GE
Definition: reader_diff.c:91
@ LP_SENSE_EQ
Definition: reader_diff.c:91
static SCIP_Bool isTokenChar(char c)
Definition: reader_diff.c:183
diff file reader
general public methods
public methods for memory management
public methods for message handling
public methods for numerical tolerances
public methods for global and local (sub)problems
public methods for reader plugins
public solving methods
@ SCIP_VERBLEVEL_MINIMAL
Definition: type_message.h:54
@ SCIP_OBJSENSE_MAXIMIZE
Definition: type_prob.h:47
@ SCIP_OBJSENSE_MINIMIZE
Definition: type_prob.h:48
enum SCIP_Objsense SCIP_OBJSENSE
Definition: type_prob.h:50
@ SCIP_SUCCESS
Definition: type_result.h:58
enum SCIP_Result SCIP_RESULT
Definition: type_result.h:61
@ SCIP_NOFILE
Definition: type_retcode.h:47
@ SCIP_READERROR
Definition: type_retcode.h:45
@ SCIP_INVALIDDATA
Definition: type_retcode.h:52
@ SCIP_OKAY
Definition: type_retcode.h:42
enum SCIP_Retcode SCIP_RETCODE
Definition: type_retcode.h:63
@ SCIP_STAGE_PROBLEM
Definition: type_set.h:45