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.c
26   	 * @ingroup OTHER_CFILES
27   	 * @brief  interface for input file readers
28   	 * @author Tobias Achterberg
29   	 */
30   	
31   	/*---+----1----+----2----+----3----+----4----+----5----+----6----+----7----+----8----+----9----+----0----+----1----+----2*/
32   	
33   	#include <assert.h>
34   	#include <string.h>
35   	#if defined(_WIN32) || defined(_WIN64)
36   	#else
37   	#include <strings.h> /*lint --e{766}*/
38   	#endif
39   	#include <math.h>
40   	
41   	#include "scip/def.h"
42   	#include "blockmemshell/memory.h"
43   	#include "scip/set.h"
44   	#include "scip/clock.h"
45   	#include "scip/pub_misc.h"
46   	#include "scip/reader.h"
47   	#include "scip/prob.h"
48   	#include "scip/pub_var.h"
49   	#include "scip/var.h"
50   	#include "scip/pub_cons.h"
51   	#include "scip/cons.h"
52   	#include "scip/pub_message.h"
53   	
54   	#include "scip/struct_reader.h"
55   	
56   	
57   	/** copies the given reader to a new scip */
58   	SCIP_RETCODE SCIPreaderCopyInclude(
59   	   SCIP_READER*          reader,             /**< reader */
60   	   SCIP_SET*             set                 /**< SCIP_SET of SCIP to copy to */
61   	   )
62   	{
63   	   assert(reader != NULL);
64   	   assert(set != NULL);
65   	   assert(set->scip != NULL);
66   	
67   	   if( reader->readercopy != NULL )
68   	   {
69   	      SCIPsetDebugMsg(set, "including reader %s in subscip %p\n", SCIPreaderGetName(reader), (void*)set->scip);
70   	      SCIP_CALL( reader->readercopy(set->scip, reader) );
71   	   }
72   	   return SCIP_OKAY;
73   	}
74   	
75   	/** internal method to create a reader */
76   	static
77   	SCIP_RETCODE doReaderCreate(
78   	   SCIP_READER**         reader,             /**< pointer to store reader */
79   	   const char*           name,               /**< name of reader */
80   	   const char*           desc,               /**< description of reader */
81   	   const char*           extension,          /**< file extension that reader processes */
82   	   SCIP_DECL_READERCOPY  ((*readercopy)),    /**< copy method of reader or NULL if you don't want to copy your plugin into sub-SCIPs */
83   	   SCIP_DECL_READERFREE  ((*readerfree)),    /**< destructor of reader */
84   	   SCIP_DECL_READERREAD  ((*readerread)),    /**< read method */
85   	   SCIP_DECL_READERWRITE ((*readerwrite)),   /**< write method */
86   	   SCIP_READERDATA*      readerdata          /**< reader data */
87   	   )
88   	{
89   	   assert(reader != NULL);
90   	   assert(name != NULL);
91   	   assert(desc != NULL);
92   	   assert(extension != NULL);
93   	
94   	   SCIP_ALLOC( BMSallocMemory(reader) );
95   	   BMSclearMemory(*reader);
96   	
97   	   SCIP_ALLOC( BMSduplicateMemoryArray(&(*reader)->name, name, strlen(name)+1) );
98   	   SCIP_ALLOC( BMSduplicateMemoryArray(&(*reader)->desc, desc, strlen(desc)+1) );
99   	   SCIP_ALLOC( BMSduplicateMemoryArray(&(*reader)->extension, extension, strlen(extension)+1) );
100  	   (*reader)->readercopy = readercopy;
101  	   (*reader)->readerfree = readerfree;
102  	   (*reader)->readerread = readerread;
103  	   (*reader)->readerwrite = readerwrite;
104  	   (*reader)->readerdata = readerdata;
105  	
106  	   /* create reading clock */
107  	   SCIP_CALL( SCIPclockCreate(&(*reader)->readingtime, SCIP_CLOCKTYPE_DEFAULT) );
108  	
109  	   return SCIP_OKAY;
110  	}
111  	
112  	/** creates a reader */
113  	SCIP_RETCODE SCIPreaderCreate(
114  	   SCIP_READER**         reader,             /**< pointer to store reader */
115  	   SCIP_SET*             set,                /**< global SCIP settings */
116  	   const char*           name,               /**< name of reader */
117  	   const char*           desc,               /**< description of reader */
118  	   const char*           extension,          /**< file extension that reader processes */
119  	   SCIP_DECL_READERCOPY  ((*readercopy)),    /**< copy method of reader or NULL if you don't want to copy your plugin into sub-SCIPs */
120  	   SCIP_DECL_READERFREE  ((*readerfree)),    /**< destructor of reader */
121  	   SCIP_DECL_READERREAD  ((*readerread)),    /**< read method */
122  	   SCIP_DECL_READERWRITE ((*readerwrite)),   /**< write method */
123  	   SCIP_READERDATA*      readerdata          /**< reader data */
124  	   )
125  	{
126  	   assert(reader != NULL);
127  	   assert(set != NULL);
128  	   assert(name != NULL);
129  	   assert(desc != NULL);
130  	   assert(extension != NULL);
131  	
132  	   SCIP_CALL_FINALLY( doReaderCreate(reader, name, desc, extension, readercopy, readerfree, readerread, readerwrite,
133  	      readerdata), (void) SCIPreaderFree(reader, set) );
134  	
135  	   return SCIP_OKAY;
136  	}
137  	
138  	/** frees memory of reader */
139  	SCIP_RETCODE SCIPreaderFree(
140  	   SCIP_READER**         reader,             /**< pointer to reader data structure */
141  	   SCIP_SET*             set                 /**< global SCIP settings */
142  	   )
143  	{
144  	   assert(reader != NULL);
145  	   assert(set != NULL);
146  	
147  	   if( *reader == NULL )
148  	      return SCIP_OKAY;
149  	
150  	   /* call destructor of reader */
151  	   if( (*reader)->readerfree != NULL )
152  	   {
153  	      SCIP_CALL( (*reader)->readerfree(set->scip, *reader) );
154  	   }
155  	
156  	   BMSfreeMemoryArrayNull(&(*reader)->name);
157  	   BMSfreeMemoryArrayNull(&(*reader)->desc);
158  	   BMSfreeMemoryArrayNull(&(*reader)->extension);
159  	
160  	   /* free clock */
161  	   SCIPclockFree(&(*reader)->readingtime);
162  	
163  	   BMSfreeMemory(reader);
164  	
165  	   return SCIP_OKAY;
166  	}
167  	
168  	/** returns TRUE, if reader is responsible for files with the given extension */
169  	static
170  	SCIP_Bool readerIsApplicable(
171  	   SCIP_READER*          reader,             /**< reader */
172  	   const char*           extension           /**< extension of the input file name */
173  	   )
174  	{
175  	   assert(reader != NULL);
176  	   assert(reader->extension != NULL);
177  	
178  	   return (extension != NULL && strcasecmp(reader->extension, extension) == 0)
179  	      || (extension == NULL && *(reader->extension) == '\0');
180  	}
181  	
182  	/** reads problem data from file with given reader or returns SCIP_DIDNOTRUN */
183  	SCIP_RETCODE SCIPreaderRead(
184  	   SCIP_READER*          reader,             /**< reader */
185  	   SCIP_SET*             set,                /**< global SCIP settings */
186  	   const char*           filename,           /**< name of the input file */
187  	   const char*           extension,          /**< extension of the input file name */
188  	   SCIP_RESULT*          result              /**< pointer to store the result of the callback method */
189  	   )
190  	{
191  	   SCIP_RETCODE retcode;
192  	
193  	   assert(reader != NULL);
194  	   assert(set != NULL);
195  	   assert(filename != NULL);
196  	   assert(result != NULL);
197  	
198  	   /* check, if reader is applicable on the given file */
199  	   if( readerIsApplicable(reader, extension) && reader->readerread != NULL )
200  	   {
201  	      SCIP_CLOCK* readingtime;
202  	
203  	      /**@note we need temporary clock to measure the reading time correctly since in case of creating a new problem
204  	       *       within the reader all clocks are reset (including the reader clocks); this resetting is necessary for
205  	       *       example for those case we people solve several problems using the (same) interactive shell
206  	       */
207  	
208  	      assert(!SCIPclockIsRunning(reader->readingtime));
209  	
210  	      /* create a temporary clock for measuring the reading time */
211  	      SCIP_CALL( SCIPclockCreate(&readingtime, SCIP_CLOCKTYPE_DEFAULT) );
212  	
213  	      /* start timing */
214  	      SCIPclockStart(readingtime, set);
215  	
216  	      /* call reader to read problem */
217  	      retcode = reader->readerread(set->scip, reader, filename, result);
218  	
219  	      /* stop timing */
220  	      SCIPclockStop(readingtime, set);
221  	
222  	      /* add time to reader reading clock */
223  	      SCIPclockSetTime(reader->readingtime, SCIPclockGetTime(reader->readingtime) + SCIPclockGetTime(readingtime));
224  	
225  	      /* free the temporary clock */
226  	      SCIPclockFree(&readingtime);
227  	   }
228  	   else
229  	   {
230  	      *result = SCIP_DIDNOTRUN;
231  	      retcode = SCIP_OKAY;
232  	   }
233  	
234  	   /* check for reader errors */
235  	   if( retcode == SCIP_NOFILE || retcode == SCIP_READERROR )
236  	      return retcode;
237  	
238  	   /* check if the result code is valid in case no reader error occurred */
239  	   assert( *result == SCIP_DIDNOTRUN || *result == SCIP_SUCCESS );
240  	
241  	   SCIP_CALL( retcode );
242  	
243  	   return SCIP_OKAY;
244  	}
245  	
246  	
247  	/* reset the variable name to the given one */
248  	static
249  	void resetVarname(
250  	   SCIP_VAR*             var,                /**< variable */
251  	   SCIP_SET*             set,                /**< global SCIP settings */
252  	   const char*           name                /**< variable name */
253  	   )
254  	{
255  	   const char * oldname;
256  	
257  	   assert( var != NULL );
258  	   assert( name != NULL );
259  	
260  	   /* get pointer to temporary generic name and free the memory */
261  	   oldname = SCIPvarGetName(var);
262  	   SCIPsetFreeBufferArray(set, &oldname);
263  	
264  	   /* reset name */
265  	   SCIPvarSetNamePointer(var, name);
266  	}
267  	
268  	
269  	/** writes problem data to file with given reader or returns SCIP_DIDNOTRUN */
270  	SCIP_RETCODE SCIPreaderWrite(
271  	   SCIP_READER*          reader,             /**< reader */
272  	   SCIP_PROB*            prob,               /**< problem data */
273  	   SCIP_SET*             set,                /**< global SCIP settings */
274  	   FILE*                 file,               /**< output file (or NULL for standard output) */
275  	   const char*           extension,          /**< file format */
276  	   SCIP_Bool             genericnames,       /**< using generic variable and constraint names? */
277  	   SCIP_RESULT*          result              /**< pointer to store the result of the callback method */
278  	   )
279  	{
280  	   SCIP_RETCODE retcode;
281  	
282  	   assert(reader != NULL);
283  	   assert(set != NULL);
284  	   assert(set->buffer != NULL);
285  	   assert(extension != NULL);
286  	   assert(result != NULL);
287  	
288  	   /* check, if reader is applicable on the given file */
289  	   if( readerIsApplicable(reader, extension) && reader->readerwrite != NULL )
290  	   {
291  	      const char* consname;
292  	      const char** varnames = NULL;
293  	      const char** fixedvarnames = NULL;
294  	      const char** consnames = NULL;
295  	      SCIP_VAR** vars;
296  	      SCIP_VAR** fixedvars;
297  	      SCIP_CONS** conss;
298  	      SCIP_CONS* cons;
299  	      SCIP_Real objscale;
300  	      char* name;
301  	      int nfixedvars;
302  	      int nconss;
303  	      int nvars;
304  	      int i;
305  	
306  	      vars = prob->vars;
307  	      nvars = prob->nvars;
308  	      fixedvars = prob->fixedvars;
309  	      nfixedvars = prob->nfixedvars;
310  	
311  	      /* case of the transformed problem, we want to write currently valid problem */
312  	      if( prob->transformed )
313  	      {
314  	         SCIP_CONSHDLR** conshdlrs;
315  	         int nconshdlrs;
316  	
317  	         conshdlrs = set->conshdlrs;
318  	         nconshdlrs = set->nconshdlrs;
319  	
320  	         /* collect number of constraints which have to be enforced; these are the constraints which currency (locally)
321  	          * enabled; these also includes the local constraints
322  	          */
323  	         nconss = 0;
324  	         for( i = 0; i < nconshdlrs; ++i )
325  	         {
326  	            /* check if all constraints of the constraint handler should be written */
327  	            if( set->write_allconss )
328  	               nconss += SCIPconshdlrGetNConss(conshdlrs[i]);
329  	            else
330  	               nconss += SCIPconshdlrGetNEnfoConss(conshdlrs[i]);
331  	         }
332  	
333  	         SCIPsetDebugMsg(set, "Writing %d constraints.\n", nconss);
334  	
335  	         SCIP_CALL( SCIPsetAllocBufferArray(set, &conss, nconss) );
336  	
337  	         /* copy the constraints */
338  	         nconss = 0;
339  	         for( i = 0; i < nconshdlrs; ++i )
340  	         {
341  	            SCIP_CONS** conshdlrconss;
342  	            int nconshdlrconss;
343  	            int c;
344  	
345  	            /* check if all constraints of the constraint handler should be written */
346  	            if( set->write_allconss )
347  	            {
348  	               conshdlrconss = SCIPconshdlrGetConss(conshdlrs[i]);
349  	               nconshdlrconss = SCIPconshdlrGetNConss(conshdlrs[i]);
350  	            }
351  	            else
352  	            {
353  	               conshdlrconss = SCIPconshdlrGetEnfoConss(conshdlrs[i]);
354  	               nconshdlrconss = SCIPconshdlrGetNEnfoConss(conshdlrs[i]);
355  	            }
356  	
357  	            SCIPsetDebugMsg(set, "Conshdlr <%s> has %d constraints to write from all in all %d constraints.\n", SCIPconshdlrGetName(conshdlrs[i]), nconshdlrconss, SCIPconshdlrGetNConss(conshdlrs[i]));
358  	
359  	            for( c = 0; c < nconshdlrconss; ++c )
360  	            {
361  	               conss[nconss] = conshdlrconss[c];
362  	               nconss++;
363  	            }
364  	         }
365  	      }
366  	      else
367  	      {
368  	         conss = prob->conss;
369  	         nconss = prob->nconss;
370  	      }
371  	
372  	      if( genericnames )
373  	      {
374  	         SCIP_VAR* var;
375  	         int size;
376  	
377  	         /* save variable and constraint names and replace these names by generic names */
378  	
379  	         /* allocate memory for saving the original variable and constraint names */
380  	         SCIP_CALL( SCIPsetAllocBufferArray(set, &varnames, nvars) );
381  	         SCIP_CALL( SCIPsetAllocBufferArray(set, &fixedvarnames, nfixedvars) );
382  	         SCIP_CALL( SCIPsetAllocBufferArray(set, &consnames, nconss) );
383  	
384  	         /* compute length of the generic variable names:
385  	          * - nvars + 1 to avoid log of zero
386  	          * - +3 (zero at end + 'x' + 1 because we round down)
387  	          * Example: 10 -> need 4 chars ("x10\0") 
388  	          */
389  	         size = (int) log10(nvars+1.0) + 3;
390  	
391  	         for( i = 0; i < nvars; ++i )
392  	         {
393  	            var = vars[i];
394  	            varnames[i] = SCIPvarGetName(var);
395  	
396  	            SCIP_CALL( SCIPsetAllocBufferArray(set, &name, size) );
397  	            (void) SCIPsnprintf(name, size, "x%d", i + set->write_genoffset);
398  	            SCIPvarSetNamePointer(var, name);
399  	         }  
400  	
401  	         /* compute length of the generic variable names */
402  	         size = (int) log10(nfixedvars+1.0) + 3;
403  	
404  	         for( i = 0; i < nfixedvars; ++i )
405  	         {
406  	            var = fixedvars[i];
407  	            fixedvarnames[i] = SCIPvarGetName(var);
408  	
409  	            SCIP_CALL( SCIPsetAllocBufferArray(set, &name, size) );
410  	            (void) SCIPsnprintf(name, size, "y%d", i);
411  	            SCIPvarSetNamePointer(var, name);
412  	         }
413  	
414  	         /* compute length of the generic constraint names */
415  	         size = (int) log10(nconss+1.0) + 3;
416  	
417  	         for( i = 0; i < nconss; ++i )
418  	         {
419  	            cons = conss[i];
420  	            consnames[i] = SCIPconsGetName(cons);
421  	
422  	            SCIP_CALL( SCIPsetAllocBufferArray(set, &name, size) );
423  	            (void) SCIPsnprintf(name, size, "c%d", i);
424  	            SCIPconsSetNamePointer(cons, name);
425  	         }
426  	      }
427  	
428  	      /* adapt objective scale for transformed problem (for the original no change is necessary) */
429  	      objscale = prob->objscale;
430  	      if( prob->transformed && prob->objsense == SCIP_OBJSENSE_MAXIMIZE )
431  	         objscale *= -1.0;
432  	
433  	      /* call reader to write problem */
434  	      retcode = reader->readerwrite(set->scip, reader, file, prob->name, prob->probdata, prob->transformed,
435  	         prob->objsense, objscale, prob->objoffset,
436  	         vars, nvars, prob->nbinvars, prob->nintvars, prob->nimplvars, prob->ncontvars,
437  	         fixedvars, nfixedvars, prob->startnvars,
438  	         conss, nconss, prob->maxnconss, prob->startnconss, genericnames, result);
439  	
440  	      /* reset variable and constraint names to original names */
441  	      if( genericnames )
442  	      {  
443  	         assert(varnames != NULL);
444  	         assert(fixedvarnames != NULL);
445  	         assert(consnames != NULL);
446  	         for( i = nconss - 1; i >= 0; --i )
447  	         {
448  	            cons = conss[i];
449  	
450  	            /* get pointer to temporary generic name and free the memory */
451  	            consname = SCIPconsGetName(cons);
452  	            SCIPsetFreeBufferArray(set, &consname);
453  	
454  	            /* reset name */
455  	            SCIPconsSetNamePointer(cons, consnames[i]);
456  	         }
457  	
458  	         for( i = nfixedvars - 1; i >= 0; --i )
459  	            resetVarname(fixedvars[i], set, fixedvarnames[i]);
460  	
461  	         for( i = nvars - 1; i >= 0; --i )
462  	            resetVarname(vars[i], set, varnames[i]);
463  	
464  	         /* free memory */
465  	         SCIPsetFreeBufferArray(set, &consnames);
466  	         SCIPsetFreeBufferArray(set, &fixedvarnames);
467  	         SCIPsetFreeBufferArray(set, &varnames);
468  	      }
469  	
470  	      if( prob->transformed )
471  	      {
472  	         /* free memory */
473  	         SCIPsetFreeBufferArray(set, &conss);
474  	      }
475  	   }
476  	   else
477  	   {
478  	      *result = SCIP_DIDNOTRUN;
479  	      retcode = SCIP_OKAY;
480  	   }
481  	
482  	   /* check for reader errors */
483  	   if( retcode == SCIP_WRITEERROR )
484  	      return retcode;
485  	
486  	   SCIP_CALL( retcode );
487  	
488  	   return SCIP_OKAY;
489  	}
490  	
491  	/** gets user data of reader */
492  	SCIP_READERDATA* SCIPreaderGetData(
493  	   SCIP_READER*          reader              /**< reader */
494  	   )
495  	{
496  	   assert(reader != NULL);
497  	
498  	   return reader->readerdata;
499  	}
500  	
501  	/** sets user data of reader; user has to free old data in advance! */
502  	void SCIPreaderSetData(
503  	   SCIP_READER*          reader,             /**< reader */
504  	   SCIP_READERDATA*      readerdata          /**< new reader user data */
505  	   )
506  	{
507  	   assert(reader != NULL);
508  	
509  	   reader->readerdata = readerdata;
510  	}
511  	
512  	/** sets copy method of reader */
513  	void SCIPreaderSetCopy(
514  	   SCIP_READER*          reader,             /**< reader */
515  	   SCIP_DECL_READERCOPY  ((*readercopy))     /**< copy method of reader or NULL if you don't want to copy your plugin into sub-SCIPs */
516  	   )
517  	{
518  	   assert(reader != NULL);
519  	
520  	   reader->readercopy = readercopy;
521  	}
522  	
523  	/** sets destructor of reader */
524  	void SCIPreaderSetFree(
525  	   SCIP_READER*          reader,             /**< reader */
526  	   SCIP_DECL_READERFREE  ((*readerfree))     /**< destructor of reader */
527  	   )
528  	{
529  	   assert(reader != NULL);
530  	
531  	   reader->readerfree = readerfree;
532  	}
533  	
534  	/** sets read method of reader */
535  	void SCIPreaderSetRead(
536  	   SCIP_READER*          reader,             /**< reader */
537  	   SCIP_DECL_READERREAD  ((*readerread))     /**< read method */
538  	   )
539  	{
540  	   assert(reader != NULL);
541  	
542  	   reader->readerread = readerread;
543  	}
544  	
545  	/** sets write method of reader */
546  	void SCIPreaderSetWrite(
547  	   SCIP_READER*          reader,             /**< reader */
548  	   SCIP_DECL_READERWRITE ((*readerwrite))    /**< write method */
549  	   )
550  	{
551  	   assert(reader != NULL);
552  	
553  	   reader->readerwrite = readerwrite;
554  	}
555  	
556  	/** gets name of reader */
557  	const char* SCIPreaderGetName(
558  	   SCIP_READER*          reader              /**< reader */
559  	   )
560  	{
561  	   assert(reader != NULL);
562  	
563  	   return reader->name;
564  	}
565  	
566  	/** gets description of reader */
567  	const char* SCIPreaderGetDesc(
568  	   SCIP_READER*          reader              /**< reader */
569  	   )
570  	{
571  	   assert(reader != NULL);
572  	
573  	   return reader->desc;
574  	}
575  	
576  	/** gets file extension of reader */
577  	const char* SCIPreaderGetExtension(
578  	   SCIP_READER*          reader              /**< reader */
579  	   )
580  	{
581  	   assert(reader != NULL);
582  	
583  	   return reader->extension;
584  	}
585  	
586  	/** return whether the reader can read files */
587  	SCIP_Bool SCIPreaderCanRead(
588  	   SCIP_READER*          reader              /**< reader */
589  	   )
590  	{
591  	   assert(reader != NULL);
592  	
593  	   return (reader->readerread != NULL);
594  	}
595  	
596  	/** return whether the reader can write files */
597  	SCIP_Bool SCIPreaderCanWrite(
598  	   SCIP_READER*          reader              /**< reader */
599  	   )
600  	{
601  	   assert(reader != NULL);
602  	
603  	   return (reader->readerwrite != NULL);
604  	}
605  	
606  	/** gets time in seconds used in this reader for reading */
607  	SCIP_Real SCIPreaderGetReadingTime(
608  	   SCIP_READER*          reader              /**< reader */
609  	   )
610  	{
611  	   assert(reader != NULL);
612  	
613  	   return SCIPclockGetTime(reader->readingtime);
614  	}
615  	
616  	/** enables or disables all clocks of \p reader, depending on the value of the flag */
617  	void SCIPreaderEnableOrDisableClocks(
618  	   SCIP_READER*          reader,             /**< the reader for which all clocks should be enabled or disabled */
619  	   SCIP_Bool             enable              /**< should the clocks be enabled? */
620  	   )
621  	{
622  	   assert(reader != NULL);
623  	
624  	   SCIPclockEnableOrDisable(reader->readingtime, enable);
625  	}
626  	
627  	/** resets reading time of reader */
628  	SCIP_RETCODE SCIPreaderResetReadingTime(
629  	   SCIP_READER*          reader              /**< reader */
630  	   )
631  	{
632  	   assert(reader != NULL);
633  	
634  	   /* reset reading time/clock */
635  	   SCIPclockReset(reader->readingtime);
636  	
637  	   return SCIP_OKAY;
638  	}
639  	
640