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_fix.c
26   	 * @ingroup DEFPLUGINS_READER
27   	 * @brief  file reader for variable fixings
28   	 * @author Tobias Achterberg
29   	 *
30   	 * This reader allows to read a file containing fixation values for variables of the current problem. Each line of the
31   	 * file should have format
32   	 *
33   	 *    \<variable name\> \<value to fix\>
34   	 *
35   	 * Note that only a subset of the variables may need to appear in the file. Lines with unknown variable names are
36   	 * ignored. The writing functionality is currently not supported.
37   	 *
38   	 * @note The format is equal to the (not xml) solution format of SCIP.
39   	 *
40   	 */
41   	
42   	/*---+----1----+----2----+----3----+----4----+----5----+----6----+----7----+----8----+----9----+----0----+----1----+----2*/
43   	
44   	#include "scip/pub_fileio.h"
45   	#include "scip/pub_message.h"
46   	#include "scip/pub_misc.h"
47   	#include "scip/pub_reader.h"
48   	#include "scip/pub_var.h"
49   	#include "scip/reader_fix.h"
50   	#include "scip/scip_general.h"
51   	#include "scip/scip_message.h"
52   	#include "scip/scip_numerics.h"
53   	#include "scip/scip_prob.h"
54   	#include "scip/scip_reader.h"
55   	#include "scip/scip_solve.h"
56   	#include "scip/scip_var.h"
57   	#include <string.h>
58   	
59   	#if !defined(_WIN32) && !defined(_WIN64)
60   	#include <strings.h> /*lint --e{766}*/ /* needed for strncasecmp() */
61   	#endif
62   	
63   	
64   	
65   	#define READER_NAME             "fixreader"
66   	#define READER_DESC             "file reader for variable fixings"
67   	#define READER_EXTENSION        "fix"
68   	
69   	
70   	/*
71   	 * local methods
72   	 */
73   	
74   	/** reads the given solution file */
75   	static
76   	SCIP_RETCODE readSol(
77   	   SCIP*                 scip,               /**< SCIP data structure */   
78   	   const char*           filename            /**< name of the input file */
79   	   )
80   	{
81   	   SCIP_RETCODE retcode;
82   	   SCIP_FILE* file;
83   	   SCIP_Bool error;
84   	   SCIP_Bool unknownvariablemessage;
85   	   int lineno;
86   	   int nfixed;
87   	
88   	   assert(scip != NULL);
89   	   assert(filename != NULL);
90   	
91   	   /* open input file */
92   	   file = SCIPfopen(filename, "r");
93   	   if( file == NULL )
94   	   {
95   	      SCIPerrorMessage("cannot open file <%s> for reading\n", filename);
96   	      SCIPprintSysError(filename);
97   	      return SCIP_NOFILE;
98   	   }   
99   	
100  	   /* read the file */
101  	   error = FALSE;
102  	   unknownvariablemessage = FALSE;
103  	   lineno = 0;
104  	   nfixed = 0;
105  	   while( !SCIPfeof(file) && !error )
106  	   {
107  	      char buffer[SCIP_MAXSTRLEN];
108  	      char varname[SCIP_MAXSTRLEN];
109  	      char valuestring[SCIP_MAXSTRLEN];
110  	      char objstring[SCIP_MAXSTRLEN];
111  	      char format[SCIP_MAXSTRLEN];
112  	      SCIP_VAR* var;
113  	      SCIP_Real value;
114  	      SCIP_Bool infeasible;
115  	      SCIP_Bool fixed;
116  	      int nread;
117  	
118  	      /* get next line */
119  	      if( SCIPfgets(buffer, (int) sizeof(buffer), file) == NULL )
120  	         break;
121  	      lineno++;
122  	
123  	      /* the lines "solution status: ..." and "objective value: ..." may preceed the solution information */
124  	      if( strncasecmp(buffer, "solution status:", 16) == 0 || strncasecmp(buffer, "objective value:", 16) == 0 )
125  	         continue;
126  	
127  	      /* parse the line */
128  	      (void) SCIPsnprintf(format, SCIP_MAXSTRLEN, "%%%ds %%%ds %%%ds\n", SCIP_MAXSTRLEN, SCIP_MAXSTRLEN, SCIP_MAXSTRLEN);
129  	      nread = sscanf(buffer, format, varname, valuestring, objstring);
130  	      if( nread < 2 )
131  	      {
132  	         SCIPerrorMessage("invalid input line %d in solution file <%s>: <%s>\n", lineno, filename, buffer);
133  	         error = TRUE;
134  	         break;
135  	      }
136  	
137  	      /* find the variable */
138  	      var = SCIPfindVar(scip, varname);
139  	      if( var == NULL )
140  	      {
141  	         if( !unknownvariablemessage )
142  	         {
143  	            SCIPwarningMessage(scip, "unknown variable <%s> in line %d of solution file <%s>\n", varname, lineno, filename);
144  	            SCIPwarningMessage(scip, "  (further unknown variables are ignored)\n");
145  	            unknownvariablemessage = TRUE;
146  	         }
147  	         continue;
148  	      }
149  	
150  	      /* cast the value */
151  	      if( strncasecmp(valuestring, "inv", 3) == 0 )
152  	         continue;
153  	      else if( strncasecmp(valuestring, "+inf", 4) == 0 || strncasecmp(valuestring, "inf", 3) == 0 )
154  	         value = SCIPinfinity(scip);
155  	      else if( strncasecmp(valuestring, "-inf", 4) == 0 )
156  	         value = -SCIPinfinity(scip);
157  	      else
158  	      {
159  	         /* coverity[secure_coding] */
160  	         nread = sscanf(valuestring, "%lf", &value);
161  	         if( nread != 1 )
162  	         {
163  	            SCIPerrorMessage("invalid solution value <%s> for variable <%s> in line %d of solution file <%s>\n",
164  	               valuestring, varname, lineno, filename);
165  	            error = TRUE;
166  	            break;
167  	         }
168  	      }
169  	
170  	      /* fix the variable */
171  	      retcode = SCIPfixVar(scip, var, value, &infeasible, &fixed);
172  	      if( retcode != SCIP_OKAY )
173  	      {
174  	         SCIPerrorMessage("Error fixing variable <%s> to value %.15g in line %d of bounds file <%s>\n",
175  	            varname, value, lineno, filename);
176  	         error = TRUE;
177  	         break;
178  	      }
179  	      if( infeasible )
180  	      {
181  	         SCIPerrorMessage("infeasible solution value of <%s>[%.15g,%.15g] to %.15g in line %d of solution file <%s>\n",
182  	            varname, SCIPvarGetLbGlobal(var), SCIPvarGetUbGlobal(var), value, lineno, filename);
183  	         error = TRUE;
184  	         break;
185  	      }
186  	      if( fixed )
187  	         nfixed++;
188  	   }
189  	
190  	   /* close input file */
191  	   SCIPfclose(file);
192  	
193  	   /* display result */
194  	   SCIPverbMessage(scip, SCIP_VERBLEVEL_NORMAL, NULL, "fixed %d variables from solution file <%s>\n", nfixed, filename);
195  	
196  	   if( error )
197  	      return SCIP_READERROR;
198  	   else
199  	      return SCIP_OKAY;
200  	}
201  	
202  	/*
203  	 * Callback methods of reader
204  	 */
205  	
206  	/** copy method for reader plugins (called when SCIP copies plugins) */
207  	static
208  	SCIP_DECL_READERCOPY(readerCopyFix)
209  	{  /*lint --e{715}*/
210  	   assert(scip != NULL);
211  	   assert(reader != NULL);
212  	   assert(strcmp(SCIPreaderGetName(reader), READER_NAME) == 0);
213  	
214  	   /* call inclusion method of reader */
215  	   SCIP_CALL( SCIPincludeReaderFix(scip) );
216  	
217  	   return SCIP_OKAY;
218  	}
219  	
220  	/** problem reading method of reader */
221  	static
222  	SCIP_DECL_READERREAD(readerReadFix)
223  	{  /*lint --e{715}*/
224  	   assert(reader != NULL);
225  	   assert(strcmp(SCIPreaderGetName(reader), READER_NAME) == 0);
226  	   assert(result != NULL);
227  	
228  	   *result = SCIP_DIDNOTRUN;
229  	
230  	   if( SCIPgetStage(scip) < SCIP_STAGE_PROBLEM )
231  	   {
232  	      SCIPerrorMessage("reading of fixing file is only possible after a problem was created\n");
233  	      return SCIP_READERROR;
234  	   }
235  	
236  	   /* free transformed problem, s.t. fixings are applied to the original problem */
237  	   SCIP_CALL( SCIPfreeTransform(scip) );
238  	
239  	   /* read (partial) solution from fixing file */
240  	   SCIP_CALL( readSol(scip, filename) );
241  	
242  	   *result = SCIP_SUCCESS;
243  	
244  	   return SCIP_OKAY;
245  	}
246  	
247  	/*
248  	 * fix file reader specific interface methods
249  	 */
250  	
251  	/** includes the fix file reader in SCIP */
252  	SCIP_RETCODE SCIPincludeReaderFix(
253  	   SCIP*                 scip                /**< SCIP data structure */
254  	   )
255  	{
256  	   SCIP_READER* reader;
257  	
258  	   /* include reader */
259  	   SCIP_CALL( SCIPincludeReaderBasic(scip, &reader, READER_NAME, READER_DESC, READER_EXTENSION, NULL) );
260  	
261  	   /* set non fundamental callbacks via setter functions */
262  	   SCIP_CALL( SCIPsetReaderCopy(scip, reader, readerCopyFix) );
263  	   SCIP_CALL( SCIPsetReaderRead(scip, reader, readerReadFix) );
264  	
265  	   return SCIP_OKAY;
266  	}
267