1    	/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2    	/*                                                                           */
3    	/*                  This file is part of the program and library             */
4    	/*         SCIP --- Solving Constraint Integer Programs                      */
5    	/*                                                                           */
6    	/*  Copyright (c) 2002-2023 Zuse Institute Berlin (ZIB)                      */
7    	/*                                                                           */
8    	/*  Licensed under the Apache License, Version 2.0 (the "License");          */
9    	/*  you may not use this file except in compliance with the License.         */
10   	/*  You may obtain a copy of the License at                                  */
11   	/*                                                                           */
12   	/*      http://www.apache.org/licenses/LICENSE-2.0                           */
13   	/*                                                                           */
14   	/*  Unless required by applicable law or agreed to in writing, software      */
15   	/*  distributed under the License is distributed on an "AS IS" BASIS,        */
16   	/*  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. */
17   	/*  See the License for the specific language governing permissions and      */
18   	/*  limitations under the License.                                           */
19   	/*                                                                           */
20   	/*  You should have received a copy of the Apache-2.0 license                */
21   	/*  along with SCIP; see the file LICENSE. If not visit scipopt.org.         */
22   	/*                                                                           */
23   	/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
24   	
25   	/**@file   reader_tim.c
26   	 * @ingroup DEFPLUGINS_READER
27   	 * @brief  TIM file reader - the stage information for a stochastic programming instance in SMPS format
28   	 * @author Stephen J. Maher
29   	 */
30   	
31   	/*---+----1----+----2----+----3----+----4----+----5----+----6----+----7----+----8----+----9----+----0----+----1----+----2*/
32   	
33   	#include "scip/pub_cons.h"
34   	#include "scip/pub_fileio.h"
35   	#include "scip/pub_message.h"
36   	#include "scip/pub_misc.h"
37   	#include "scip/pub_reader.h"
38   	#include "scip/reader_cor.h"
39   	#include "scip/reader_tim.h"
40   	#include "scip/scip_mem.h"
41   	#include "scip/scip_message.h"
42   	#include "scip/scip_numerics.h"
43   	#include "scip/scip_prob.h"
44   	#include "scip/scip_reader.h"
45   	#include <string.h>
46   	
47   	#define READER_NAME             "timreader"
48   	#define READER_DESC             "file reader for the TIME file of a stochastic program in SMPS format"
49   	#define READER_EXTENSION        "tim"
50   	
51   	/*
52   	 * tim reader internal methods
53   	 */
54   	
55   	#define TIM_MAX_LINELEN       1025
56   	#define TIM_MAX_NAMELEN        256
57   	#define TIM_DEFAULT_STAGESIZE   10
58   	#define TIM_DEFAULT_ARRAYSIZE  100
59   	
60   	#define BLANK         ' '
61   	
62   	struct TimStage
63   	{
64   	   SCIP_VAR**            vars;
65   	   SCIP_CONS**           conss;
66   	   SCIP_HASHMAP*         varnametovar;
67   	   SCIP_HASHMAP*         consnametocons;
68   	   int                   nvars;
69   	   int                   nconss;
70   	   int                   varssize;
71   	   int                   conssize;
72   	};
73   	typedef struct TimStage TIMSTAGE;
74   	
75   	/** TIM reading data */
76   	struct SCIP_ReaderData
77   	{
78   	   SCIP_Bool             read;               /**< flag to indicate whether the time file has been read */
79   	   int                   nstages;            /**< the number of stages in the stochastic program */
80   	   const char**          stagestartvars;     /**< the variables that start each stage */
81   	   const char**          stagestartcons;     /**< the constraints that start each stage */
82   	   const char**          stagenames;         /**< the name of the stage */
83   	   TIMSTAGE**            stages;             /**< the stages for the stochastic program */
84   	};
85   	
86   	/** enum containing all tim sections */
87   	enum TimSection
88   	{
89   	   TIM_TIME,
90   	   TIM_PERIODS,
91   	   TIM_ENDATA
92   	};
93   	typedef enum TimSection TIMSECTION;
94   	
95   	/** tim input structure */
96   	struct TimInput
97   	{
98   	   TIMSECTION            section;
99   	   SCIP_FILE*            fp;
100  	   int                   lineno;
101  	   SCIP_Bool             haserror;
102  	   char                  buf[TIM_MAX_LINELEN];
103  	   const char*           f0;
104  	   const char*           f1;
105  	   const char*           f2;
106  	   const char*           f3;
107  	   char                  probname[TIM_MAX_NAMELEN];
108  	   const char**          stagestartvars;
109  	   const char**          stagestartcons;
110  	   const char**          stagenames;
111  	   int                   nstages;
112  	   int                   stagesize;
113  	};
114  	typedef struct TimInput TIMINPUT;
115  	
116  	/** adds the variable to the given stage */
117  	static
118  	SCIP_RETCODE addVariableToStage(
119  	   SCIP*                 scip,               /**< SCIP data structure */
120  	   TIMSTAGE*             stage,              /**< the stage structure */
121  	   const char*           varname             /**< the name of the variable to add to the stage */
122  	   )
123  	{
124  	   SCIP_VAR* var;
125  	
126  	   assert(scip != NULL);
127  	   assert(stage != NULL);
128  	
129  	   var = SCIPfindVar(scip, varname);
130  	
131  	   if( var == NULL )
132  	   {
133  	      SCIPwarningMessage(scip, "This is an error. All variables should in the problem.\n");
134  	      return SCIP_OKAY;
135  	   }
136  	
137  	   /* adding the variable to the hashmap */
138  	   SCIP_CALL( SCIPhashmapInsert(stage->varnametovar, (void*) varname, var) );
139  	
140  	   /* adding the variable to the variable storage */
141  	   SCIP_CALL( SCIPensureBlockMemoryArray(scip, &stage->vars, &stage->varssize, stage->nvars + 1) );
142  	   stage->vars[stage->nvars] = var;
143  	   stage->nvars++;
144  	
145  	   return SCIP_OKAY;
146  	}
147  	
148  	/** adds the constraint to the given stage */
149  	static
150  	SCIP_RETCODE addConstraintToStage(
151  	   SCIP*                 scip,               /**< SCIP data structure */
152  	   TIMSTAGE*             stage,              /**< the stage structure */
153  	   const char*           consname            /**< the name of the constraint to add to the stage */
154  	   )
155  	{
156  	   SCIP_CONS* cons;
157  	
158  	   assert(scip != NULL);
159  	   assert(stage != NULL);
160  	
161  	   cons = SCIPfindCons(scip, consname);
162  	
163  	   if( cons == NULL )
164  	   {
165  	      SCIPwarningMessage(scip, "This is an error. All constraints should in the problem.\n");
166  	      return SCIP_OKAY;
167  	   }
168  	
169  	   /* adding the constraint to the hashmap */
170  	   SCIP_CALL( SCIPhashmapInsert(stage->consnametocons, (void*) consname, cons) );
171  	
172  	   /* adding the constraint to the constraint storage */
173  	   SCIP_CALL( SCIPensureBlockMemoryArray(scip, &stage->conss, &stage->conssize, stage->nconss + 1) );
174  	   stage->conss[stage->nconss] = cons;
175  	   stage->nconss++;
176  	
177  	   return SCIP_OKAY;
178  	}
179  	
180  	/** creates the stage data */
181  	static
182  	SCIP_RETCODE createStages(
183  	   SCIP*                 scip,               /**< SCIP data structure */
184  	   SCIP_READER*          reader,             /**< the reader structure */
185  	   SCIP_READER*          correader           /**< the reader structure for the core file */
186  	   )
187  	{
188  	   SCIP_READERDATA* readerdata;
189  	   int stage;
190  	   int i;
191  	
192  	   assert(scip != NULL);
193  	   assert(reader != NULL);
194  	   assert(correader != NULL);
195  	
196  	   readerdata = SCIPreaderGetData(reader);
197  	   assert(readerdata != NULL);
198  	
199  	   stage = 0;
200  	
201  	   /* assigning the variables to the stages */
202  	   for( i = 0; i < SCIPcorGetNVarNames(correader); i++ )
203  	   {
204  	      /* the first variable in the var names list should be the start of the first stage */
205  	      assert((stage == 0 && i == 0 && strcmp(SCIPcorGetVarName(correader, i), readerdata->stagestartvars[stage]) == 0)
206  	         || i > 0);
207  	      /* checking whether the next stage has been found */
208  	      if( i > 0 && stage < readerdata->nstages - 1
209  	         && strcmp(SCIPcorGetVarName(correader, i), readerdata->stagestartvars[stage + 1]) == 0 )
210  	         stage++;
211  	
212  	      /* adding the variable to the stage */
213  	      SCIP_CALL( addVariableToStage(scip, readerdata->stages[stage], SCIPcorGetVarName(correader, i)) );
214  	   }
215  	
216  	   stage = 0;
217  	
218  	   /* assigning the constraint to the stages */
219  	   for( i = 0; i < SCIPcorGetNConsNames(correader); i++ )
220  	   {
221  	      /* checking whether the next stage has been found */
222  	      if( i > 0 && stage < readerdata->nstages - 1
223  	         && strcmp(SCIPcorGetConsName(correader, i), readerdata->stagestartcons[stage + 1]) == 0 )
224  	         stage++;
225  	
226  	      /* adding the consiable to the stage */
227  	      SCIP_CALL( addConstraintToStage(scip, readerdata->stages[stage], SCIPcorGetConsName(correader, i)) );
228  	   }
229  	
230  	   return SCIP_OKAY;
231  	}
232  	
233  	/** creates the reader data for the time input data */
234  	static
235  	SCIP_RETCODE createReaderdata(
236  	   SCIP*                 scip,               /**< SCIP data structure */
237  	   SCIP_READER*          reader,             /**< the reader structure */
238  	   TIMINPUT*             timi                /**< tim input structure */
239  	   )
240  	{
241  	   SCIP_READERDATA* readerdata;
242  	   int hashmapsize;
243  	   int nvars;
244  	   int i;
245  	
246  	   assert(scip != NULL);
247  	   assert(reader != NULL);
248  	   assert(timi != NULL);
249  	
250  	   readerdata = SCIPreaderGetData(reader);
251  	
252  	   assert(readerdata != NULL);
253  	
254  	   /* getting the total number of variables in the problem. The hash maps will be of size nvars/nstages. */
255  	   nvars = SCIPgetNVars(scip);
256  	
257  	   readerdata->read = TRUE;
258  	   readerdata->nstages = timi->nstages;
259  	
260  	   SCIP_CALL( SCIPallocBlockMemoryArray(scip, &readerdata->stagestartvars, readerdata->nstages) );
261  	   SCIP_CALL( SCIPallocBlockMemoryArray(scip, &readerdata->stagestartcons, readerdata->nstages) );
262  	   SCIP_CALL( SCIPallocBlockMemoryArray(scip, &readerdata->stagenames, readerdata->nstages) );
263  	   SCIP_CALL( SCIPallocBlockMemoryArray(scip, &readerdata->stages, readerdata->nstages) );
264  	
265  	   for( i = 0; i < readerdata->nstages; i++ )
266  	   {
267  	      SCIP_CALL( SCIPduplicateBlockMemoryArray(scip, &readerdata->stagestartvars[i],
268  	            timi->stagestartvars[i], strlen(timi->stagestartvars[i]) + 1) );  /*lint !e866*/
269  	      SCIP_CALL( SCIPduplicateBlockMemoryArray(scip, &readerdata->stagestartcons[i],
270  	            timi->stagestartcons[i], strlen(timi->stagestartcons[i]) + 1) );  /*lint !e866*/
271  	      SCIP_CALL( SCIPduplicateBlockMemoryArray(scip, &readerdata->stagenames[i],
272  	            timi->stagenames[i], strlen(timi->stagenames[i]) + 1) );          /*lint !e866*/
273  	
274  	      /* creating the data for the stages */
275  	      SCIP_CALL( SCIPallocBlockMemory(scip, &readerdata->stages[i]) );        /*lint !e866*/
276  	      readerdata->stages[i]->nvars = 0;
277  	      readerdata->stages[i]->nconss = 0;
278  	      readerdata->stages[i]->varssize = TIM_DEFAULT_ARRAYSIZE;
279  	      readerdata->stages[i]->conssize = TIM_DEFAULT_ARRAYSIZE;
280  	      SCIP_CALL( SCIPallocBlockMemoryArray(scip, &readerdata->stages[i]->vars, readerdata->stages[i]->varssize) );      /*lint !e866*/
281  	      SCIP_CALL( SCIPallocBlockMemoryArray(scip, &readerdata->stages[i]->conss, readerdata->stages[i]->conssize) );     /*lint !e866*/
282  	
283  	      /* creating the hashmaps */
284  	      hashmapsize = (int) SCIPceil(scip, (SCIP_Real) nvars/(SCIP_Real) readerdata->nstages);
285  	      SCIP_CALL( SCIPhashmapCreate(&readerdata->stages[i]->varnametovar, SCIPblkmem(scip), hashmapsize) );
286  	      SCIP_CALL( SCIPhashmapCreate(&readerdata->stages[i]->consnametocons, SCIPblkmem(scip), hashmapsize) );
287  	   }
288  	
289  	   return SCIP_OKAY;
290  	}
291  	
292  	/** free the reader data */
293  	static
294  	void freeReaderdata(
295  	   SCIP*                 scip,               /**< SCIP data structure */
296  	   SCIP_READER*          reader              /**< the reader structure */
297  	   )
298  	{
299  	   SCIP_READERDATA* readerdata;
300  	   int i;
301  	
302  	   assert(scip != NULL);
303  	   assert(reader != NULL);
304  	
305  	   readerdata = SCIPreaderGetData(reader);
306  	
307  	   assert(readerdata != NULL);
308  	
309  	   /* only free the reader data is a file has been read */
310  	   if( readerdata->read )
311  	   {
312  	      for( i = 0; i < readerdata->nstages; i++ )
313  	      {
314  	         /* freeing the hashmaps */
315  	         SCIPhashmapFree(&readerdata->stages[i]->consnametocons);
316  	         SCIPhashmapFree(&readerdata->stages[i]->varnametovar);
317  	
318  	         SCIPfreeBlockMemoryArray(scip, &readerdata->stagestartvars[i], strlen(readerdata->stagestartvars[i]) + 1);
319  	         SCIPfreeBlockMemoryArray(scip, &readerdata->stagestartcons[i], strlen(readerdata->stagestartcons[i]) + 1);
320  	         SCIPfreeBlockMemoryArray(scip, &readerdata->stagenames[i], strlen(readerdata->stagenames[i]) + 1);
321  	
322  	         /* freeing the memory for the stage data */
323  	         SCIPfreeBlockMemoryArray(scip, &readerdata->stages[i]->vars, readerdata->stages[i]->varssize);
324  	         SCIPfreeBlockMemoryArray(scip, &readerdata->stages[i]->conss, readerdata->stages[i]->conssize);
325  	         SCIPfreeBlockMemory(scip, &readerdata->stages[i]);    /*lint !e866*/
326  	      }
327  	
328  	      SCIPfreeBlockMemoryArray(scip, &readerdata->stages, readerdata->nstages);
329  	      SCIPfreeBlockMemoryArray(scip, &readerdata->stagenames, readerdata->nstages);
330  	      SCIPfreeBlockMemoryArray(scip, &readerdata->stagestartcons, readerdata->nstages);
331  	      SCIPfreeBlockMemoryArray(scip, &readerdata->stagestartvars, readerdata->nstages);
332  	   }
333  	
334  	   SCIPfreeBlockMemory(scip, &readerdata);
335  	}
336  	
337  	
338  	/** creates the tim input structure */
339  	static
340  	SCIP_RETCODE timinputCreate(
341  	   SCIP*                 scip,               /**< SCIP data structure */
342  	   TIMINPUT**            timi,               /**< tim input structure */
343  	   SCIP_FILE*            fp                  /**< file object for the input file */
344  	   )
345  	{
346  	   assert(timi != NULL);
347  	   assert(fp != NULL);
348  	
349  	   SCIP_CALL( SCIPallocBlockMemory(scip, timi) );
350  	
351  	   (*timi)->section     = TIM_TIME;
352  	   (*timi)->fp          = fp;
353  	   (*timi)->lineno      = 0;
354  	   (*timi)->haserror    = FALSE;
355  	   (*timi)->buf     [0] = '\0';
356  	   (*timi)->probname[0] = '\0';
357  	   (*timi)->f0          = NULL;
358  	   (*timi)->f1          = NULL;
359  	   (*timi)->f2          = NULL;
360  	   (*timi)->f3          = NULL;
361  	   (*timi)->nstages     = 0;
362  	   (*timi)->stagesize   = TIM_DEFAULT_STAGESIZE;
363  	
364  	   SCIP_CALL( SCIPallocBlockMemoryArray(scip, &(*timi)->stagestartvars, (*timi)->stagesize) );
365  	   SCIP_CALL( SCIPallocBlockMemoryArray(scip, &(*timi)->stagestartcons, (*timi)->stagesize) );
366  	   SCIP_CALL( SCIPallocBlockMemoryArray(scip, &(*timi)->stagenames, (*timi)->stagesize) );
367  	
368  	   return SCIP_OKAY;
369  	}
370  	
371  	/** free the tim input structure */
372  	static
373  	void timinputFree(
374  	   SCIP*                 scip,               /**< SCIP data structure */
375  	   TIMINPUT**            timi                /**< tim input structure */
376  	   )
377  	{
378  	   int i;
379  	
380  	   for( i = 0; i < (*timi)->nstages; i++ )
381  	   {
382  	      SCIPfreeBlockMemoryArray(scip, &(*timi)->stagestartvars[i], strlen((*timi)->stagestartvars[i]) + 1);
383  	      SCIPfreeBlockMemoryArray(scip, &(*timi)->stagestartcons[i], strlen((*timi)->stagestartcons[i]) + 1);
384  	      SCIPfreeBlockMemoryArray(scip, &(*timi)->stagenames[i], strlen((*timi)->stagenames[i]) + 1);
385  	   }
386  	
387  	   SCIPfreeBlockMemoryArray(scip, &(*timi)->stagestartvars, (*timi)->stagesize);
388  	   SCIPfreeBlockMemoryArray(scip, &(*timi)->stagestartcons, (*timi)->stagesize);
389  	   SCIPfreeBlockMemoryArray(scip, &(*timi)->stagenames, (*timi)->stagesize);
390  	
391  	   SCIPfreeBlockMemory(scip, timi);
392  	}
393  	
394  	/** returns the current section */
395  	static
396  	TIMSECTION timinputSection(
397  	   const TIMINPUT*       timi                /**< tim input structure */
398  	   )
399  	{
400  	   assert(timi != NULL);
401  	
402  	   return timi->section;
403  	}
404  	
405  	/** return the current value of field 0 */
406  	static
407  	const char* timinputField0(
408  	   const TIMINPUT*       timi                /**< tim input structure */
409  	   )
410  	{
411  	   assert(timi != NULL);
412  	
413  	   return timi->f0;
414  	}
415  	
416  	/** return the current value of field 1 */
417  	static
418  	const char* timinputField1(
419  	   const TIMINPUT*       timi                /**< tim input structure */
420  	   )
421  	{
422  	   assert(timi != NULL);
423  	
424  	   return timi->f1;
425  	}
426  	
427  	/** return the current value of field 2 */
428  	static
429  	const char* timinputField2(
430  	   const TIMINPUT*       timi                /**< tim input structure */
431  	   )
432  	{
433  	   assert(timi != NULL);
434  	
435  	   return timi->f2;
436  	}
437  	
438  	/** return the current value of field 3 */
439  	static
440  	const char* timinputField3(
441  	   const TIMINPUT*       timi                /**< tim input structure */
442  	   )
443  	{
444  	   assert(timi != NULL);
445  	
446  	   return timi->f3;
447  	}
448  	
449  	/** returns if an error was detected */
450  	static
451  	SCIP_Bool timinputHasError(
452  	   const TIMINPUT*       timi                /**< tim input structure */
453  	   )
454  	{
455  	   assert(timi != NULL);
456  	
457  	   return timi->haserror;
458  	}
459  	
460  	/** set the section in the tim input structure to given section */
461  	static
462  	void timinputSetSection(
463  	   TIMINPUT*             timi,               /**< tim input structure */
464  	   TIMSECTION            section             /**< section that is set */
465  	   )
466  	{
467  	   assert(timi != NULL);
468  	
469  	   timi->section = section;
470  	}
471  	
472  	/** set the problem name in the tim input structure to given problem name */
473  	static
474  	void timinputSetProbname(
475  	   TIMINPUT*             timi,               /**< tim input structure */
476  	   const char*           probname            /**< name of the problem to set */
477  	   )
478  	{
479  	   assert(timi     != NULL);
480  	   assert(probname != NULL);
481  	   assert(strlen(probname) < sizeof(timi->probname));
482  	
483  	   (void)SCIPmemccpy(timi->probname, probname, '\0', TIM_MAX_NAMELEN - 1);
484  	}
485  	
486  	/** set the problem var name that starts a stage in the tim input structure to given objective name */
487  	static
488  	SCIP_RETCODE timinputSetStageStartVar(
489  	   TIMINPUT*             timi,               /**< tim input structure */
490  	   SCIP*                 scip,               /**< SCIP data structure */
491  	   const char*           varname,            /**< name of the variable that starts the stage */
492  	   int                   stagenum            /**< the stage number the variable starts */
493  	   )
494  	{
495  	   assert(timi != NULL);
496  	   assert(varname != NULL);
497  	
498  	   SCIP_CALL( SCIPduplicateBlockMemoryArray(scip, &timi->stagestartvars[stagenum], varname, strlen(varname) + 1) );  /*lint !e866*/
499  	
500  	   return SCIP_OKAY;
501  	}
502  	
503  	/** set the problem constraint name that starts a stage in the tim input structure to given objective name */
504  	static
505  	SCIP_RETCODE timinputSetStageStartCons(
506  	   TIMINPUT*             timi,               /**< tim input structure */
507  	   SCIP*                 scip,               /**< SCIP data structure */
508  	   const char*           consname,           /**< name of the constraint that starts the stage */
509  	   int                   stagenum            /**< the stage number the constraint starts */
510  	   )
511  	{
512  	   assert(timi != NULL);
513  	   assert(consname != NULL);
514  	
515  	   SCIP_CALL( SCIPduplicateBlockMemoryArray(scip, &timi->stagestartcons[stagenum], consname, strlen(consname) + 1) );   /*lint !e866*/
516  	
517  	   return SCIP_OKAY;
518  	}
519  	
520  	/** set the stage name in the tim input structure to given objective name */
521  	static
522  	SCIP_RETCODE timinputSetStageName(
523  	   TIMINPUT*             timi,               /**< tim input structure */
524  	   SCIP*                 scip,               /**< SCIP data structure */
525  	   const char*           stagename,          /**< name of the stage */
526  	   int                   stagenum            /**< the stage number the constraint starts */
527  	   )
528  	{
529  	   assert(timi != NULL);
530  	   assert(stagename != NULL);
531  	
532  	   SCIP_CALL( SCIPduplicateBlockMemoryArray(scip, &timi->stagenames[stagenum], stagename, strlen(stagename) + 1) );  /*lint !e866*/
533  	
534  	   return SCIP_OKAY;
535  	}
536  	
537  	static
538  	void timinputSyntaxerror(
539  	   TIMINPUT*             timi                /**< tim input structure */
540  	   )
541  	{
542  	   assert(timi != NULL);
543  	
544  	   SCIPerrorMessage("Syntax error in line %d\n", timi->lineno);
545  	   timi->section  = TIM_ENDATA;
546  	   timi->haserror = TRUE;
547  	}
548  	
549  	/** fill the line from \p pos up to column 80 with blanks. */
550  	static
551  	void clearFrom(
552  	   char*                 buf,                /**< buffer to clear */
553  	   unsigned int          pos                 /**< position to start the clearing process */
554  	   )
555  	{
556  	   unsigned int i;
557  	
558  	   for(i = pos; i < 80; i++)
559  	      buf[i] = BLANK;
560  	   buf[80] = '\0';
561  	}
562  	
563  	/** read a tim format data line and parse the fields. */
564  	static
565  	SCIP_Bool timinputReadLine(
566  	   TIMINPUT*             timi                /**< tim input structure */
567  	   )
568  	{
569  	   unsigned int len;
570  	   unsigned int i;
571  	   char* s;
572  	   SCIP_Bool is_empty;
573  	   char* nexttok;
574  	
575  	   do
576  	   {
577  	      timi->f0 = timi->f1 = timi->f2 = timi->f3 = 0;
578  	
579  	      /* Read until we have not a comment line. */
580  	      do
581  	      {
582  	         timi->buf[TIM_MAX_LINELEN-1] = '\0';
583  	         if( NULL == SCIPfgets(timi->buf, (int) sizeof(timi->buf), timi->fp) )
584  	            return FALSE;
585  	         timi->lineno++;
586  	      }
587  	      while( *timi->buf == '*' );   /* coverity[a_loop_bound] */
588  	
589  	      /* Normalize line */
590  	      len = (unsigned int) strlen(timi->buf);
591  	
592  	      for( i = 0; i < len; i++ )
593  	         if( (timi->buf[i] == '\t') || (timi->buf[i] == '\n') || (timi->buf[i] == '\r') )
594  	            timi->buf[i] = BLANK;
595  	
596  	      if( len < 80 )
597  	         clearFrom(timi->buf, len);
598  	
599  	      SCIPdebugMessage("line %d: <%s>\n", timi->lineno, timi->buf);
600  	
601  	      assert(strlen(timi->buf) >= 80);
602  	
603  	      /* Look for new section */
604  	      if( *timi->buf != BLANK )
605  	      {
606  	         timi->f0 = SCIPstrtok(&timi->buf[0], " ", &nexttok);
607  	
608  	         assert(timi->f0 != 0);
609  	
610  	         timi->f1 = SCIPstrtok(NULL, " ", &nexttok);
611  	
612  	         return TRUE;
613  	      }
614  	
615  	      s = &timi->buf[1];
616  	
617  	      /* At this point it is not clear if we have a indicator field.
618  	       * If there is none (e.g. empty) f1 will be the first name field.
619  	       * If there is one, f2 will be the first name field.
620  	       *
621  	       * Initially comment marks '$' are only allowed in the beginning
622  	       * of the 2nd and 3rd name field. We test all fields but the first.
623  	       * This makes no difference, since if the $ is at the start of a value
624  	       * field, the line will be erroneous anyway.
625  	       */
626  	      do
627  	      {
628  	         if( NULL == (timi->f1 = SCIPstrtok(s, " ", &nexttok)) )
629  	            break;
630  	
631  	         if( (NULL == (timi->f2 = SCIPstrtok(NULL, " ", &nexttok))) || (*timi->f2 == '$') )
632  	         {
633  	            timi->f2 = 0;
634  	            break;
635  	         }
636  	
637  	         if( (NULL == (timi->f3 = SCIPstrtok(NULL, " ", &nexttok))) || (*timi->f3 == '$') )
638  	         {
639  	            timi->f3 = 0;
640  	            break;
641  	         }
642  	      }
643  	      while( FALSE );
644  	
645  	      /* check for empty lines */
646  	      is_empty = (timi->f0 == NULL && timi->f1 == NULL);
647  	   }
648  	   while( is_empty );
649  	
650  	   return TRUE;
651  	}
652  	
653  	/** Process TIME section. */
654  	static
655  	SCIP_RETCODE readTime(
656  	   SCIP*                 scip,               /**< SCIP data structure */
657  	   TIMINPUT*             timi                /**< tim input structure */
658  	   )
659  	{
660  	   SCIPdebugMsg(scip, "read problem name from TIME section\n");
661  	
662  	   /* This has to be the Line with the TIME section. */
663  	   if( !timinputReadLine(timi) || timinputField0(timi) == NULL || strcmp(timinputField0(timi), "TIME") )
664  	   {
665  	      timinputSyntaxerror(timi);
666  	      return SCIP_OKAY;
667  	   }
668  	
669  	   /* Sometimes the name is omitted. */
670  	   timinputSetProbname(timi, (timinputField1(timi) == 0) ? "_TIM_" : timinputField1(timi));
671  	
672  	   /* This has to be a new section */
673  	   /* coverity[tainted_data] */
674  	   if( !timinputReadLine(timi) || (timinputField0(timi) == NULL) )
675  	   {
676  	      timinputSyntaxerror(timi);
677  	      return SCIP_OKAY;
678  	   }
679  	
680  	   if( strncmp(timinputField0(timi), "PERIODS", 7) == 0 )
681  	      timinputSetSection(timi, TIM_PERIODS);
682  	   else
683  	   {
684  	      timinputSyntaxerror(timi);
685  	      return SCIP_OKAY;
686  	   }
687  	
688  	   return SCIP_OKAY;
689  	}
690  	
691  	/** Process PERIODS section. */
692  	static
693  	SCIP_RETCODE readPeriods(
694  	   TIMINPUT*             timi,               /**< tim input structure */
695  	   SCIP*                 scip                /**< SCIP data structure */
696  	   )
697  	{
698  	   SCIPdebugMsg(scip, "read Periods\n");
699  	
700  	   /* coverity[tainted_data_sink_lv_call] */
701  	   /* coverity[tainted_data] */
702  	   while( timinputReadLine(timi) )
703  	   {
704  	      if( timinputField0(timi) != NULL )
705  	      {
706  	         if( strcmp(timinputField0(timi), "PERIODS") == 0 )
707  	            timinputSetSection(timi, TIM_PERIODS);
708  	         else if( strcmp(timinputField0(timi), "ENDATA") == 0 )
709  	            timinputSetSection(timi, TIM_ENDATA);
710  	         else
711  	            timinputSyntaxerror(timi);
712  	
713  	         return SCIP_OKAY;
714  	      }
715  	
716  	      if( timi->nstages + 1 >= timi->stagesize )
717  	      {
718  	         SCIP_CALL( SCIPensureBlockMemoryArray(scip, &timi->stagestartvars, &timi->stagesize, timi->nstages + 1) );
719  	         SCIP_CALL( SCIPensureBlockMemoryArray(scip, &timi->stagestartcons, &timi->stagesize, timi->nstages + 1) );
720  	         SCIP_CALL( SCIPensureBlockMemoryArray(scip, &timi->stagenames, &timi->stagesize, timi->nstages + 1) );
721  	      }
722  	
723  	      SCIP_CALL( timinputSetStageStartVar(timi, scip, timinputField1(timi), timi->nstages) );
724  	      SCIP_CALL( timinputSetStageStartCons(timi, scip, timinputField2(timi), timi->nstages) );
725  	      SCIP_CALL( timinputSetStageName(timi, scip, timinputField3(timi), timi->nstages) );
726  	
727  	      timi->nstages++;
728  	   }
729  	   timinputSyntaxerror(timi);
730  	
731  	   return SCIP_OKAY;
732  	}
733  	
734  	
735  	/** Read time data for the SMPS file format. */
736  	static
737  	SCIP_RETCODE readTim(
738  	   SCIP*                 scip,               /**< SCIP data structure */
739  	   SCIP_READER*          reader,             /**< the file reader itself */
740  	   const char*           filename            /**< name of the input file */
741  	   )
742  	{
743  	   SCIP_FILE* fp;
744  	   TIMINPUT* timi;
745  	   SCIP_RETCODE retcode;
746  	   SCIP_Bool error = TRUE;
747  	
748  	   assert(scip != NULL);
749  	   assert(filename != NULL);
750  	
751  	   fp = SCIPfopen(filename, "r");
752  	   if( fp == NULL )
753  	   {
754  	      SCIPerrorMessage("cannot open file <%s> for reading\n", filename);
755  	      SCIPprintSysError(filename);
756  	
757  	      return SCIP_NOFILE;
758  	   }
759  	
760  	   SCIP_CALL_FINALLY( timinputCreate(scip, &timi, fp), SCIPfclose(fp) );
761  	
762  	   SCIP_CALL_TERMINATE( retcode, readTime(scip, timi), TERMINATE );
763  	
764  	   while( timinputSection(timi) == TIM_PERIODS )
765  	   {
766  	      /* coverity[tainted_data] */
767  	      SCIP_CALL_TERMINATE( retcode, readPeriods(timi, scip), TERMINATE );
768  	   }
769  	   if( timinputSection(timi) != TIM_ENDATA )
770  	      timinputSyntaxerror(timi);
771  	
772  	   error = timinputHasError(timi);
773  	
774  	   if( !error )
775  	   {
776  	      SCIP_CALL_TERMINATE( retcode, createReaderdata(scip, reader, timi), TERMINATE );
777  	   }
778  	
779  	 /* cppcheck-suppress unusedLabel */
780  	 TERMINATE:
781  	   timinputFree(scip, &timi);
782  	   SCIPfclose(fp);
783  	
784  	   if( error )
785  	      return SCIP_READERROR;
786  	   else
787  	      return SCIP_OKAY;
788  	}
789  	
790  	/*
791  	 * Callback methods of reader
792  	 */
793  	
794  	/** copy method for reader plugins (called when SCIP copies plugins) */
795  	static
796  	SCIP_DECL_READERCOPY(readerCopyTim)
797  	{  /*lint --e{715}*/
798  	   assert(scip != NULL);
799  	   assert(reader != NULL);
800  	   assert(strcmp(SCIPreaderGetName(reader), READER_NAME) == 0);
801  	
802  	   /* call inclusion method of reader */
803  	   SCIP_CALL( SCIPincludeReaderTim(scip) );
804  	
805  	   return SCIP_OKAY;
806  	}
807  	
808  	/** destructor of reader to free user data (called when SCIP is exiting) */
809  	static
810  	SCIP_DECL_READERFREE(readerFreeTim)
811  	{
812  	   freeReaderdata(scip, reader);
813  	
814  	   return SCIP_OKAY;
815  	}
816  	
817  	/** reads the stage information for a stochastic programming instance in SMPS format */
818  	static
819  	SCIP_DECL_READERREAD(readerReadTim)
820  	{  /*lint --e{715}*/
821  	   SCIP_READER* correader;
822  	
823  	   assert(reader != NULL);
824  	   assert(strcmp(SCIPreaderGetName(reader), READER_NAME) == 0);
825  	
826  	   correader = SCIPfindReader(scip, "correader");
827  	
828  	   if( correader == NULL )
829  	   {
830  	      SCIPwarningMessage(scip, "It is necessary to include the \"cor\" reader\n");
831  	      (*result) = SCIP_DIDNOTRUN;
832  	      return SCIP_OKAY;
833  	   }
834  	
835  	   /* checking whether the cor file has been read */
836  	   if( !SCIPcorHasRead(correader) )
837  	   {
838  	      SCIPwarningMessage(scip, "The core file must be read before the time and stochastic files.\n");
839  	      (*result) = SCIP_DIDNOTRUN;
840  	      return SCIP_OKAY;
841  	   }
842  	
843  	   SCIP_CALL( SCIPreadTim(scip, filename, result) );
844  	
845  	   return SCIP_OKAY;
846  	}
847  	
848  	
849  	/*
850  	 * tim file reader specific interface methods
851  	 */
852  	
853  	/** includes the tim file reader in SCIP */
854  	SCIP_RETCODE SCIPincludeReaderTim(
855  	   SCIP*                 scip                /**< SCIP data structure */
856  	   )
857  	{
858  	   SCIP_READERDATA* readerdata;
859  	   SCIP_READER* reader;
860  	
861  	   /* create reader data */
862  	   SCIP_CALL( SCIPallocBlockMemory(scip, &readerdata) );
863  	   readerdata->read = FALSE;
864  	
865  	   /* include reader */
866  	   SCIP_CALL( SCIPincludeReaderBasic(scip, &reader, READER_NAME, READER_DESC, READER_EXTENSION, readerdata) );
867  	
868  	   /* set non fundamental callbacks via setter functions */
869  	   SCIP_CALL( SCIPsetReaderCopy(scip, reader, readerCopyTim) );
870  	   SCIP_CALL( SCIPsetReaderFree(scip, reader, readerFreeTim) );
871  	   SCIP_CALL( SCIPsetReaderRead(scip, reader, readerReadTim) );
872  	
873  	   return SCIP_OKAY;
874  	}
875  	
876  	
877  	/** reads problem from file */
878  	SCIP_RETCODE SCIPreadTim(
879  	   SCIP*                 scip,               /**< SCIP data structure */
880  	   const char*           filename,           /**< full path and name of file to read, or NULL if stdin should be used */
881  	   SCIP_RESULT*          result              /**< pointer to store the result of the file reading call */
882  	   )
883  	{
884  	   SCIP_READER* reader;
885  	   SCIP_RETCODE retcode;
886  	   SCIP_READERDATA* readerdata;
887  	
888  	   assert(scip != NULL);
889  	   assert(result != NULL);
890  	
891  	   reader = SCIPfindReader(scip, READER_NAME);
892  	   assert(reader != NULL);
893  	
894  	   retcode = readTim(scip, reader, filename);
895  	
896  	   if( retcode == SCIP_PLUGINNOTFOUND )
897  	      retcode = SCIP_READERROR;
898  	
899  	   if( retcode == SCIP_NOFILE || retcode == SCIP_READERROR )
900  	      return retcode;
901  	
902  	   SCIP_CALL( retcode );
903  	
904  	   /* creating the stages */
905  	   SCIP_CALL( createStages(scip, reader, SCIPfindReader(scip, "correader")) );
906  	
907  	   /* setting the read flag to TRUE */
908  	   readerdata = SCIPreaderGetData(reader);
909  	   readerdata->read = TRUE;
910  	
911  	   *result = SCIP_SUCCESS;
912  	
913  	   return SCIP_OKAY;
914  	}
915  	
916  	/*
917  	 * Interface methods for the cor and sto files
918  	 */
919  	
920  	/* return whether the tim file has been read */
921  	SCIP_Bool SCIPtimHasRead(
922  	   SCIP_READER*          reader              /**< the file reader itself */
923  	   )
924  	{
925  	   SCIP_READERDATA* readerdata;
926  	
927  	   assert(reader != NULL);
928  	   assert(strcmp(SCIPreaderGetName(reader), READER_NAME) == 0);
929  	
930  	   readerdata = SCIPreaderGetData(reader);
931  	   assert(readerdata != NULL);
932  	
933  	   return readerdata->read;
934  	}
935  	
936  	
937  	/* returns the number of stages */
938  	int SCIPtimGetNStages(
939  	   SCIP*                 scip                /**< SCIP data structure */
940  	   )
941  	{
942  	   SCIP_READER* reader;
943  	   SCIP_READERDATA* readerdata;
944  	
945  	   reader = SCIPfindReader(scip, READER_NAME);
946  	
947  	   assert(reader != NULL);
948  	   assert(strcmp(SCIPreaderGetName(reader), READER_NAME) == 0);
949  	
950  	   readerdata = SCIPreaderGetData(reader);
951  	   assert(readerdata != NULL);
952  	
953  	   return readerdata->nstages;
954  	}
955  	
956  	/* returns the name for a given stage */
957  	const char* SCIPtimGetStageName(
958  	   SCIP*                 scip,               /**< SCIP data structure */
959  	   int                   stagenum            /**< the number of the requested stage */
960  	   )
961  	{
962  	   SCIP_READER* reader;
963  	   SCIP_READERDATA* readerdata;
964  	
965  	   reader = SCIPfindReader(scip, READER_NAME);
966  	
967  	   assert(reader != NULL);
968  	   assert(strcmp(SCIPreaderGetName(reader), READER_NAME) == 0);
969  	
970  	   readerdata = SCIPreaderGetData(reader);
971  	   assert(readerdata != NULL);
972  	   assert(stagenum >= 0 && stagenum < readerdata->nstages);
973  	
974  	   return readerdata->stagenames[stagenum];
975  	}
976  	
977  	/* returns the stage name for a given constraint name */
978  	const char* SCIPtimConsGetStageName(
979  	   SCIP*                 scip,               /**< SCIP data structure */
980  	   const char*           consname            /**< the constraint to search for */
981  	   )
982  	{
983  	   SCIP_READER* reader;
984  	   SCIP_READERDATA* readerdata;
985  	   int stagenum;
986  	   int i;
987  	   int j;
988  	
989  	   reader = SCIPfindReader(scip, READER_NAME);
990  	
991  	   assert(reader != NULL);
992  	   assert(strcmp(SCIPreaderGetName(reader), READER_NAME) == 0);
993  	
994  	   readerdata = SCIPreaderGetData(reader);
995  	   assert(readerdata != NULL);
996  	
997  	   /* looping over all stages to find the provided constraint */
998  	   stagenum = -1;
999  	   for( i = 0; i < readerdata->nstages; i++ )
1000 	   {
1001 	      for( j = 0; j < readerdata->stages[i]->nconss; j++ )
1002 	      {
1003 	         if( strcmp(SCIPconsGetName(readerdata->stages[i]->conss[j]), consname) == 0 )
1004 	         {
1005 	            stagenum = i;
1006 	            break;
1007 	         }
1008 	      }
1009 	
1010 	      if( stagenum >= 0 )
1011 	         break;
1012 	   }
1013 	   assert(stagenum >= 0 && stagenum < readerdata->nstages);
1014 	
1015 	   return readerdata->stagenames[stagenum];
1016 	}
1017 	
1018 	/* returns the number for a given stage */
1019 	int SCIPtimFindStage(
1020 	   SCIP*                 scip,               /**< SCIP data structure */
1021 	   const char*           stage               /**< the name of the requested stage */
1022 	   )
1023 	{
1024 	   SCIP_READER* reader;
1025 	   SCIP_READERDATA* readerdata;
1026 	   int i;
1027 	   int stagenum;
1028 	
1029 	   reader = SCIPfindReader(scip, READER_NAME);
1030 	
1031 	   assert(reader != NULL);
1032 	   assert(strcmp(SCIPreaderGetName(reader), READER_NAME) == 0);
1033 	
1034 	   readerdata = SCIPreaderGetData(reader);
1035 	   assert(readerdata != NULL);
1036 	
1037 	   stagenum = -1;
1038 	   for( i = 0; i < readerdata->nstages; i++ )
1039 	   {
1040 	      if( strcmp(readerdata->stagenames[i], stage) == 0 )
1041 	      {
1042 	         stagenum = i;
1043 	         break;
1044 	      }
1045 	   }
1046 	
1047 	   if( stagenum < 0 )
1048 	   {
1049 	      SCIPerrorMessage("Stage <%s> was not found in the TIM file. Check the SMPS files (COR, TIM and STO)\n", stage);
1050 	      SCIPABORT();
1051 	   }
1052 	
1053 	   return stagenum;
1054 	}
1055 	
1056 	/* returns the array of variables for a given stage */
1057 	SCIP_VAR** SCIPtimGetStageVars(
1058 	   SCIP*                 scip,               /**< SCIP data structure */
1059 	   int                   stagenum            /**< the number of the requested stage */
1060 	   )
1061 	{
1062 	   SCIP_READER* reader;
1063 	   SCIP_READERDATA* readerdata;
1064 	
1065 	   reader = SCIPfindReader(scip, READER_NAME);
1066 	
1067 	   assert(reader != NULL);
1068 	   assert(strcmp(SCIPreaderGetName(reader), READER_NAME) == 0);
1069 	
1070 	   readerdata = SCIPreaderGetData(reader);
1071 	   assert(readerdata != NULL);
1072 	   assert(stagenum >= 0 && stagenum < readerdata->nstages);
1073 	
1074 	   return readerdata->stages[stagenum]->vars;
1075 	}
1076 	
1077 	/* returns an array of constraints for a given stage */
1078 	SCIP_CONS** SCIPtimGetStageConss(
1079 	   SCIP*                 scip,               /**< SCIP data structure */
1080 	   int                   stagenum            /**< the number of the requested stage */
1081 	   )
1082 	{
1083 	   SCIP_READER* reader;
1084 	   SCIP_READERDATA* readerdata;
1085 	
1086 	   reader = SCIPfindReader(scip, READER_NAME);
1087 	
1088 	   assert(reader != NULL);
1089 	   assert(strcmp(SCIPreaderGetName(reader), READER_NAME) == 0);
1090 	
1091 	   readerdata = SCIPreaderGetData(reader);
1092 	   assert(readerdata != NULL);
1093 	   assert(stagenum >= 0 && stagenum < readerdata->nstages);
1094 	
1095 	   return readerdata->stages[stagenum]->conss;
1096 	}
1097 	
1098 	/* returns the number of variables for a given stage */
1099 	int SCIPtimGetStageNVars(
1100 	   SCIP*                 scip,               /**< SCIP data structure */
1101 	   int                   stagenum            /**< the number of the requested stage */
1102 	   )
1103 	{
1104 	   SCIP_READER* reader;
1105 	   SCIP_READERDATA* readerdata;
1106 	
1107 	   reader = SCIPfindReader(scip, READER_NAME);
1108 	
1109 	   assert(reader != NULL);
1110 	   assert(strcmp(SCIPreaderGetName(reader), READER_NAME) == 0);
1111 	
1112 	   readerdata = SCIPreaderGetData(reader);
1113 	   assert(readerdata != NULL);
1114 	   assert(stagenum >= 0 && stagenum < readerdata->nstages);
1115 	
1116 	   return readerdata->stages[stagenum]->nvars;
1117 	}
1118 	
1119 	/* returns the number of constraints for a given stage */
1120 	int SCIPtimGetStageNConss(
1121 	   SCIP*                 scip,               /**< SCIP data structure */
1122 	   int                   stagenum            /**< the number of the requested stage */
1123 	   )
1124 	{
1125 	   SCIP_READER* reader;
1126 	   SCIP_READERDATA* readerdata;
1127 	
1128 	   reader = SCIPfindReader(scip, READER_NAME);
1129 	
1130 	   assert(reader != NULL);
1131 	   assert(strcmp(SCIPreaderGetName(reader), READER_NAME) == 0);
1132 	
1133 	   readerdata = SCIPreaderGetData(reader);
1134 	   assert(readerdata != NULL);
1135 	   assert(stagenum >= 0 && stagenum < readerdata->nstages);
1136 	
1137 	   return readerdata->stages[stagenum]->nconss;
1138 	}
1139