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