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_zpl.c
26   	 * @ingroup DEFPLUGINS_READER
27   	 * @brief  ZIMPL model file reader
28   	 * @author Tobias Achterberg
29   	 * @author Timo Berthold
30   	 */
31   	
32   	/*---+----1----+----2----+----3----+----4----+----5----+----6----+----7----+----8----+----9----+----0----+----1----+----2*/
33   	
34   	#include "scip/reader_zpl.h"
35   	
36   	#ifdef SCIP_WITH_ZIMPL
37   	
38   	#include <unistd.h>
39   	#include <stdbool.h>
40   	#include <string.h>
41   	
42   	#include "scip/cons_indicator.h"
43   	#include "scip/cons_linear.h"
44   	#include "scip/cons_sos1.h"
45   	#include "scip/cons_sos2.h"
46   	#include "scip/pub_misc.h"
47   	#include "scip/pub_nlp.h"
48   	#include "scip/pub_reader.h"
49   	#include "scip/pub_var.h"
50   	#include "scip/scip_cons.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_param.h"
56   	#include "scip/scip_prob.h"
57   	#include "scip/scip_reader.h"
58   	#include "scip/scip_sol.h"
59   	#include "scip/scip_var.h"
60   	#include "scip/cons_nonlinear.h"
61   	#include "scip/struct_misc.h"
62   	#include "scip/expr_pow.h"
63   	#include "scip/expr_log.h"
64   	#include "scip/expr_exp.h"
65   	#include "scip/expr_abs.h"
66   	#include "scip/expr_sum.h"
67   	#include "scip/expr_trig.h"
68   	#include "scip/expr_product.h"
69   	#include "scip/pub_expr.h"
70   	#include "scip/type_reader.h"
71   	
72   	#ifdef __cplusplus
73   	extern "C" {
74   	#endif
75   	
76   	/* @Note: Due to dependencies we need the following order. */
77   	/* include the ZIMPL headers necessary to define the LP and MINLP construction interface */
78   	#include "zimpl/attribute.h"
79   	#include "zimpl/ratlptypes.h"
80   	#include "zimpl/lint.h"
81   	#include "zimpl/mme.h"
82   	
83   	#include "zimpl/numb.h"
84   	#include "zimpl/bound.h"
85   	#include "zimpl/mono.h"
86   	#include "zimpl/term.h"
87   	
88   	#include "zimpl/xlpglue.h"
89   	#include "zimpl/zimpllib.h"
90   	
91   	#ifdef __cplusplus
92   	}
93   	#endif
94   	
95   	#define READER_NAME             "zplreader"
96   	#define READER_DESC             "file reader for ZIMPL model files"
97   	#define READER_EXTENSION        "zpl"
98   	
99   	/*
100  	 * LP construction interface of ZIMPL
101  	 */
102  	
103  	/* we only support ZIMPL with a version higher than 3.4.1 */
104  	#if (ZIMPL_VERSION >= 341)
105  	
106  	/* ZIMPL does not support user data in callbacks - we have to use static variables */
107  	struct
108  	SCIP_ReaderData
109  	{
110  	   SCIP*                 scip;               /**< scip data structure */
111  	   SCIP_SOL*             sol;                /**< primal solution candidate */
112  	   SCIP_Bool             valid;              /**< is the primal solution candidate valid */
113  	   SCIP_Bool             branchpriowarning;  /**< store if the waring regarding fractional value for the branching
114  	                                              *   priority was already posted */
115  	   SCIP_Bool             initialconss;       /**< should model constraints be marked as initial? */
116  	   SCIP_Bool             dynamicconss;       /**< should model constraints be subject to aging? */
117  	   SCIP_Bool             dynamiccols;        /**< should columns be added and removed dynamically to the LP? */
118  	   SCIP_Bool             dynamicrows;        /**< should rows be added and removed dynamically to the LP? */
119  	   SCIP_Bool             readerror;          /**< was a reading error be discovered */
120  	   SCIP_RETCODE          retcode;            /**< store a none SCIP_OKAY return code if an error occurred */
121  	};
122  	
123  	/** create problem */
124  	static
125  	SCIP_RETCODE createProb(
126  	   SCIP*                 scip,               /**< SCIP data structure */
127  	   SCIP_READERDATA*      readerdata,         /**< reader data */
128  	   const char*           name                /**< name of the problem */
129  	   )
130  	{
131  	   SCIP_Bool usestartsol;
132  	
133  	   /* create problem */
134  	   SCIP_CALL( SCIPcreateProb(scip, name, NULL, NULL, NULL, NULL, NULL, NULL, NULL) );
135  	
136  	   /* check if are interested in the primal solution candidate */
137  	   SCIP_CALL( SCIPgetBoolParam(scip, "reading/zplreader/usestartsol", &usestartsol) );
138  	
139  	   if( usestartsol )
140  	   {
141  	      /* create primal solution */
142  	      SCIP_CALL( SCIPcreateSol(scip, &readerdata->sol, NULL) );
143  	      readerdata->valid = TRUE;
144  	   }
145  	
146  	   return SCIP_OKAY;
147  	}
148  	
149  	/** Allocate storage for the mathematical program instance generated by ZIMPL. xlp_alloc() is the first xlpglue routine
150  	 *  that will be called by ZIMPL. The user_data pointer may hold an arbitray value.
151  	 */
152  	Lps* xlp_alloc(
153  	   const char*           name,               /**< name of the problem */
154  	   bool                  need_startval,      /**< does ZIMPL provides a primal solution candidate */
155  	   void*                 user_data           /**< user data which was previously passed to ZIMPL */
156  	   )
157  	{  /*lint --e{715}*/
158  	   SCIP* scip;
159  	   SCIP_READERDATA* readerdata;
160  	
161  	   readerdata = (SCIP_READERDATA*)user_data;
162  	   assert(readerdata != NULL);
163  	   assert(readerdata->retcode == SCIP_OKAY);
164  	   assert(!readerdata->readerror);
165  	
166  	   scip = readerdata->scip;
167  	   assert(scip != NULL);
168  	
169  	   readerdata->retcode = createProb(scip, readerdata, name);
170  	
171  	   /* return the reader data pointer to receive it all other ZIMPL call backs */
172  	   return (Lps*) readerdata;
173  	}
174  	
175  	/** free storage for mathematical program. xlp_free() is the last xlpglue routine that will be called by Zimpl */
176  	void xlp_free(
177  	   Lps*                  data                /**< pointer to reader data */
178  	   )
179  	{  /*lint --e{715}*/
180  	   /* nothing to be done here */
181  	}
182  	
183  	/** does there already exists a constraint with the given name? */
184  	bool xlp_conname_exists(
185  	   const Lps*            data,               /**< pointer to reader data */
186  	   const char*           name                /**< constraint name to check */
187  	   )
188  	{
189  	   SCIP_READERDATA* readerdata;
190  	
191  	   readerdata = (SCIP_READERDATA*)data;
192  	   assert(readerdata != NULL);
193  	
194  	   /* check if constraint with the given name already exists */
195  	   return (SCIPfindCons(readerdata->scip, name) != NULL);
196  	}
197  	
198  	/** create a SCIP expression from a ZIMPL term
199  	 *
200  	 * Returns *expr == NULL if could not create expression due to unsupported ZIMPL functions.
201  	 */
202  	static
203  	SCIP_RETCODE createExpr(
204  	   SCIP*                 scip,               /**< SCIP data structure */
205  	   SCIP_READERDATA*      readerdata,         /**< reader data */
206  	   SCIP_EXPR**           expr,               /**< buffer to store expression */
207  	   const Term*           term                /**< term to convert to expression */
208  	   )
209  	{
210  	   assert(scip != NULL);
211  	   assert(readerdata != NULL);
212  	   assert(expr != NULL);
213  	   assert(term != NULL);
214  	
215  	   *expr = NULL;
216  	
217  	   if( term_get_degree(term) == 2 )
218  	   {
219  	      int        nlinvars;
220  	      int        nquadterms;
221  	      SCIP_VAR** linvars;
222  	      SCIP_VAR** quadvar1;
223  	      SCIP_VAR** quadvar2;
224  	      SCIP_Real* lincoefs;
225  	      SCIP_Real* quadcoefs;
226  	      Mono*      monom;
227  	      int i;
228  	
229  	      nlinvars   = 0;
230  	      nquadterms = 0;
231  	
232  	      SCIP_CALL( SCIPallocBufferArray(scip, &linvars,   term_get_elements(term)) );
233  	      SCIP_CALL( SCIPallocBufferArray(scip, &quadvar1,  term_get_elements(term)) );
234  	      SCIP_CALL( SCIPallocBufferArray(scip, &quadvar2,  term_get_elements(term)) );
235  	      SCIP_CALL( SCIPallocBufferArray(scip, &lincoefs,  term_get_elements(term)) );
236  	      SCIP_CALL( SCIPallocBufferArray(scip, &quadcoefs, term_get_elements(term)) );
237  	
238  	      for( i = 0; i < term_get_elements(term); ++i )
239  	      {
240  	         monom = term_get_element(term, i);
241  	         assert(!numb_equal(mono_get_coeff(monom), numb_zero()));
242  	         assert(mono_get_degree(monom) <= 2);
243  	         assert(mono_get_degree(monom) > 0);
244  	         if (mono_get_degree(monom) == 1)
245  	         {
246  	            linvars [nlinvars] = (SCIP_VAR*)mono_get_var(monom, 0);
247  	            lincoefs[nlinvars] = numb_todbl(mono_get_coeff(monom));
248  	            ++nlinvars;
249  	         }
250  	         else
251  	         {
252  	            assert(mono_get_degree(monom) == 2);
253  	            quadvar1 [nquadterms] = (SCIP_VAR*)mono_get_var(monom, 0);
254  	            quadvar2 [nquadterms] = (SCIP_VAR*)mono_get_var(monom, 1);
255  	            quadcoefs[nquadterms] = numb_todbl(mono_get_coeff(monom));
256  	            ++nquadterms;
257  	         }
258  	      }
259  	
260  	      SCIP_CALL( SCIPcreateExprQuadratic(scip, expr, nlinvars, linvars, lincoefs, nquadterms, quadvar1, quadvar2, quadcoefs, NULL, NULL) );
261  	
262  	      SCIPfreeBufferArray(scip, &linvars);
263  	      SCIPfreeBufferArray(scip, &quadvar1);
264  	      SCIPfreeBufferArray(scip, &quadvar2);
265  	      SCIPfreeBufferArray(scip, &lincoefs);
266  	      SCIPfreeBufferArray(scip, &quadcoefs);
267  	   }
268  	   else
269  	   {
270  	      SCIP_VAR** polyvars;
271  	      SCIP_Real* polyexps;
272  	      SCIP_HASHMAP* varexpmap;
273  	      SCIP_EXPR** monomials;
274  	      int        nmonomials;
275  	      int        monomialssize;
276  	      SCIP_Real* coefs;
277  	      Mono*      monomial;
278  	      SCIP_EXPR* monomialexpr;
279  	      SCIP_Bool created;
280  	      int varpos;
281  	      int i;
282  	      int j;
283  	
284  	      polyvars = NULL;
285  	      polyexps = NULL;
286  	
287  	      monomials = NULL;
288  	      nmonomials = 0;
289  	      monomialssize = 0;
290  	      coefs = NULL;
291  	      created = TRUE;
292  	
293  	      SCIP_CALL( SCIPhashmapCreate(&varexpmap, SCIPblkmem(scip), SCIPcalcMemGrowSize(scip, 10)) );
294  	
295  	      for( i = 0; i < term_get_elements(term); ++i )
296  	      {
297  	         monomial = term_get_element(term, i);
298  	         assert(monomial != NULL);
299  	         assert(!numb_equal(mono_get_coeff(monomial), numb_zero()));
300  	         assert(mono_get_degree(monomial) > 0);
301  	
302  	         /* allocate space in the monomials array */
303  	         if( monomialssize == 0 )
304  	         {
305  	            monomialssize = SCIPcalcMemGrowSize(scip, 1);
306  	            SCIP_CALL( SCIPallocBufferArray(scip, &monomials, monomialssize) );
307  	            SCIP_CALL( SCIPallocBufferArray(scip, &coefs, monomialssize) );
308  	         }
309  	         else if( monomialssize < nmonomials + 1 )
310  	         {
311  	            monomialssize = SCIPcalcMemGrowSize(scip, nmonomials+1);
312  	            SCIP_CALL( SCIPreallocBufferArray(scip, &monomials, monomialssize) );
313  	            SCIP_CALL( SCIPreallocBufferArray(scip, &coefs, monomialssize) );
314  	         }
315  	         assert(monomials != NULL);
316  	         assert(coefs != NULL);
317  	
318  	         /* create SCIP monomial expression */
319  	         for( j = 0; j < mono_get_degree(monomial); ++j )
320  	         {
321  	            SCIP_Real exponent;
322  	
323  	            exponent = SCIPhashmapGetImageReal(varexpmap, (void*)mono_get_var(monomial, j));
324  	            exponent = exponent == SCIP_INVALID ? 1.0 : exponent + 1.0;
325  	
326  	            SCIP_CALL( SCIPhashmapSetImageReal(varexpmap, (void*)mono_get_var(monomial, j), exponent) );
327  	         }
328  	
329  	         SCIP_CALL( SCIPallocBufferArray(scip, &polyvars, SCIPhashmapGetNElements(varexpmap)) );
330  	         SCIP_CALL( SCIPallocBufferArray(scip, &polyexps, SCIPhashmapGetNElements(varexpmap)) );
331  	
332  	         varpos = 0;
333  	
334  	         for( j = 0; j < SCIPhashmapGetNEntries(varexpmap); ++j )
335  	         {
336  	            SCIP_HASHMAPENTRY* entry;
337  	
338  	            entry = SCIPhashmapGetEntry(varexpmap, j);
339  	            if( entry == NULL )
340  	               continue;
341  	
342  	            polyvars[varpos] = (SCIP_VAR*) SCIPhashmapEntryGetOrigin(entry);
343  	            polyexps[varpos] = SCIPhashmapEntryGetImageReal(entry);
344  	            ++varpos;
345  	         }
346  	         assert(varpos == SCIPhashmapGetNElements(varexpmap));
347  	         SCIPhashmapRemoveAll(varexpmap);
348  	
349  	         SCIP_CALL( SCIPcreateExprMonomial(scip, &monomialexpr, varpos, polyvars, polyexps, NULL, NULL) );
350  	
351  	         SCIPfreeBufferArrayNull(scip, &polyexps);
352  	         SCIPfreeBufferArrayNull(scip, &polyvars);
353  	
354  	         /* add monomial to array, possibly with an extra function around it */
355  	         if( mono_get_function(monomial) == MFUN_NONE )
356  	         {
357  	            monomials[nmonomials] = monomialexpr;
358  	            coefs[nmonomials] = numb_todbl(mono_get_coeff(monomial));
359  	         }
360  	         else
361  	         {
362  	            SCIP_EXPR* cosexpr;
363  	            SCIP_EXPR* prodchildren[2];
364  	
365  	            coefs[nmonomials] = 1.0;
366  	
367  	            /* nonlinear monomial with an extra function around it */
368  	            switch( mono_get_function(monomial) )
369  	            {
370  	            case MFUN_SQRT:
371  	               SCIP_CALL( SCIPcreateExprPow(scip, &monomials[nmonomials], monomialexpr, 0.5, NULL, NULL) );
372  	               break;
373  	            case MFUN_LOG:
374  	               /* log10(x) = ln(x) / ln(10.0) */
375  	               coefs[nmonomials] = 1.0 / log(10.0);
376  	               SCIP_CALL( SCIPcreateExprLog(scip, &monomials[nmonomials], monomialexpr, NULL, NULL) );
377  	               break;
378  	            case MFUN_EXP:
379  	               SCIP_CALL( SCIPcreateExprExp(scip, &monomials[nmonomials], monomialexpr, NULL, NULL) );
380  	               break;
381  	            case MFUN_LN:
382  	               SCIP_CALL( SCIPcreateExprLog(scip, &monomials[nmonomials], monomialexpr, NULL, NULL) );
383  	               break;
384  	            case MFUN_SIN:
385  	               SCIP_CALL( SCIPcreateExprSin(scip, &monomials[nmonomials], monomialexpr, NULL, NULL) );
386  	               break;
387  	            case MFUN_COS:
388  	               SCIP_CALL( SCIPcreateExprCos(scip, &monomials[nmonomials], monomialexpr, NULL, NULL) );
389  	               break;
390  	            case MFUN_TAN:
391  	               SCIP_CALL( SCIPcreateExprSin(scip, &prodchildren[0], monomialexpr, NULL, NULL) );
392  	               SCIP_CALL( SCIPcreateExprCos(scip, &cosexpr, monomialexpr, NULL, NULL) );
393  	               SCIP_CALL( SCIPcreateExprPow(scip, &prodchildren[1], cosexpr, -1.0, NULL, NULL) );
394  	               SCIP_CALL( SCIPcreateExprProduct(scip, &monomials[nmonomials], 2, prodchildren, 1.0, NULL, NULL) );
395  	
396  	               SCIP_CALL( SCIPreleaseExpr(scip, &prodchildren[1]) );
397  	               SCIP_CALL( SCIPreleaseExpr(scip, &cosexpr) );
398  	               SCIP_CALL( SCIPreleaseExpr(scip, &prodchildren[0]) );
399  	
400  	               break;
401  	            case MFUN_ABS:
402  	               SCIP_CALL( SCIPcreateExprAbs(scip, &monomials[nmonomials], monomialexpr, NULL, NULL) );
403  	               break;
404  	            case MFUN_POW:
405  	               SCIP_CALL( SCIPcreateExprPow(scip, &monomials[nmonomials], monomialexpr,
406  	                     numb_todbl(mono_get_coeff(monomial)), NULL, NULL) );
407  	               break;
408  	            case MFUN_SGNPOW:
409  	               SCIP_CALL( SCIPcreateExprSignpower(scip, &monomials[nmonomials], monomialexpr,
410  	                     numb_todbl(mono_get_coeff(monomial)), NULL, NULL) );
411  	               break;
412  	            case MFUN_NONE:
413  	            case MFUN_TRUE:
414  	            case MFUN_FALSE:
415  	               SCIPerrorMessage("ZIMPL function %d invalid here.\n", mono_get_function(monomial));
416  	               created = FALSE;
417  	               break;
418  	            default:
419  	               SCIPerrorMessage("ZIMPL function %d not supported\n", mono_get_function(monomial));
420  	               created = FALSE;
421  	               break;
422  	            }  /*lint !e788*/
423  	
424  	            SCIP_CALL( SCIPreleaseExpr(scip, &monomialexpr) );
425  	         }
426  	
427  	         ++nmonomials;
428  	
429  	         if( !created )
430  	            break;
431  	      }
432  	
433  	      if( created )
434  	      {
435  	         SCIP_CALL( SCIPcreateExprSum(scip, expr, nmonomials, monomials, coefs, 0.0, NULL, NULL) );
436  	      }
437  	
438  	      /* free memory */
439  	      for( j = nmonomials - 1; j >= 0; --j )
440  	      {
441  	         if( monomials[j] != NULL )
442  	         {
443  	            SCIP_CALL( SCIPreleaseExpr(scip, &monomials[j]) );
444  	         }
445  	      }
446  	
447  	      SCIPfreeBufferArrayNull(scip, &coefs);
448  	      SCIPfreeBufferArrayNull(scip, &monomials);
449  	      SCIPhashmapFree(&varexpmap);
450  	   }
451  	
452  	   return SCIP_OKAY;
453  	}
454  	
455  	/** method creates a constraint and is called directly from ZIMPL
456  	 *
457  	 *  @note this method is used by ZIMPL beginning from version 3.00
458  	 */
459  	static
460  	SCIP_RETCODE addConsTerm(
461  	   SCIP*                 scip,               /**< SCIP data structure */
462  	   SCIP_READERDATA*      readerdata,         /**< reader data */
463  	   const char*           name,               /**< constraint name */
464  	   ConType               type,               /**< constraint type (LHS, RHS, EQUAL, RANGE, etc) */
465  	   const Numb*           lhs,                /**< left hand side */
466  	   const Numb*           rhs,                /**< right hand side */
467  	   unsigned int          flags,              /**< special constraint flags, see ratlptypes.h */
468  	   const Term*           term,               /**< term to use */
469  	   SCIP_Bool*            created             /**< pointer to store if a constraint was created */
470  	   )
471  	{
472  	   SCIP_CONS* cons;
473  	   SCIP_Real sciplhs;
474  	   SCIP_Real sciprhs;
475  	   SCIP_Bool initial;
476  	   SCIP_Bool separate;
477  	   SCIP_Bool enforce;
478  	   SCIP_Bool check;
479  	   SCIP_Bool propagate;
480  	   SCIP_Bool local;
481  	   SCIP_Bool modifiable;
482  	   SCIP_Bool usercut;
483  	   SCIP_Bool lazycut;
484  	   int i;
485  	
486  	   switch( type )
487  	   {
488  	   case CON_FREE:
489  	      sciplhs = -SCIPinfinity(scip);
490  	      sciprhs = SCIPinfinity(scip);
491  	      break;
492  	   case CON_LHS:
493  	      sciplhs = (SCIP_Real)numb_todbl(lhs);
494  	      sciprhs = SCIPinfinity(scip);
495  	      break;
496  	   case CON_RHS:
497  	      sciplhs = -SCIPinfinity(scip);
498  	      sciprhs = (SCIP_Real)numb_todbl(rhs);
499  	      break;
500  	   case CON_RANGE:
501  	      sciplhs = (SCIP_Real)numb_todbl(lhs);
502  	      sciprhs = (SCIP_Real)numb_todbl(rhs);
503  	      break;
504  	   case CON_EQUAL:
505  	      sciplhs = (SCIP_Real)numb_todbl(lhs);
506  	      sciprhs = (SCIP_Real)numb_todbl(rhs);
507  	      assert(sciplhs == sciprhs);  /*lint !e777*/
508  	      break;
509  	   default:
510  	      SCIPwarningMessage(scip, "invalid constraint type <%d> in ZIMPL callback xlp_addcon()\n", type);
511  	      sciplhs = (SCIP_Real)numb_todbl(lhs);
512  	      sciprhs = (SCIP_Real)numb_todbl(rhs);
513  	      readerdata->readerror = TRUE;
514  	      break;
515  	   }
516  	
517  	   cons = NULL;
518  	
519  	   /* default values */
520  	   initial = readerdata->initialconss;
521  	   separate = TRUE;
522  	   propagate = TRUE;
523  	   enforce = TRUE;
524  	   check = TRUE;
525  	   local = FALSE;
526  	   modifiable = FALSE;
527  	
528  	   usercut = (flags & LP_FLAG_CON_SEPAR) != 0;
529  	   lazycut = (flags & LP_FLAG_CON_CHECK) != 0;
530  	
531  	   /* evaluate constraint flags */
532  	   if( usercut && lazycut )
533  	   {
534  	      initial = FALSE;
535  	      separate = TRUE;
536  	      check = TRUE;
537  	   }
538  	   else if( usercut )
539  	   {
540  	      initial = FALSE;
541  	      separate = TRUE;
542  	      check = FALSE;
543  	   }
544  	   else if( lazycut )
545  	   {
546  	      initial = FALSE;
547  	      separate = FALSE;
548  	      check = TRUE;
549  	   }
550  	
551  	   if( term_is_linear(term) )
552  	   {
553  	      /* if the constraint gives an indicator constraint */
554  	      if ( flags & LP_FLAG_CON_INDIC )
555  	      {
556  	         bool lhsIndCons = FALSE;  /* generate lhs form for indicator constraints */
557  	         bool rhsIndCons = FALSE;  /* generate rhs form for indicator constraints */
558  	
559  	         /* currently indicator constraints can only handle "<=" constraints */
560  	         switch( type )
561  	         {
562  	         case CON_LHS:
563  	            lhsIndCons = TRUE;
564  	            break;
565  	         case CON_RHS:
566  	            rhsIndCons = TRUE;
567  	            break;
568  	         case CON_RANGE:
569  	         case CON_EQUAL:
570  	            lhsIndCons = TRUE;
571  	            rhsIndCons = TRUE;
572  	            break;
573  	         case CON_FREE:
574  	            /*lint -fallthrough*/
575  	         default:
576  	            SCIPerrorMessage("invalid constraint type <%d> in ZIMPL callback xlp_addcon()\n", type);
577  	            readerdata->readerror = TRUE;
578  	            break;
579  	         }
580  	
581  	         /* insert lhs form of indicator */
582  	         if ( lhsIndCons )
583  	         {
584  	            SCIP_CALL( SCIPcreateConsIndicator(scip, &cons, name, NULL, 0, NULL, NULL, -sciplhs,
585  	                  initial, separate, enforce, check, propagate, local, readerdata->dynamicconss, readerdata->dynamicrows, FALSE) );
586  	            SCIP_CALL( SCIPaddCons(scip, cons) );
587  	
588  	            for( i = 0; i < term_get_elements(term); i++ )
589  	            {
590  	               SCIP_VAR* scipvar;
591  	               SCIP_Real scipval;
592  	               const Mono* mono = term_get_element(term, i);
593  	               MFun mfun;
594  	
595  	               scipvar = (SCIP_VAR*)mono_get_var(mono, 0);
596  	
597  	               /* check whether variable is the binary variable */
598  	               mfun = mono_get_function(mono);
599  	               if (mfun == MFUN_TRUE || mfun == MFUN_FALSE)
600  	               {
601  	                  scipvar = (SCIP_VAR*)mono_get_var(mono, 0);
602  	                  SCIP_CALL( SCIPsetBinaryVarIndicator(scip, cons, scipvar) );
603  	               }
604  	               else
605  	               {
606  	                  assert(!numb_equal(mono_get_coeff(mono), numb_zero()));
607  	                  assert(mono_is_linear(mono));
608  	
609  	                  scipval = -numb_todbl(mono_get_coeff(mono));
610  	                  SCIP_CALL( SCIPaddVarIndicator(scip, cons, scipvar, scipval) );
611  	               }
612  	            }
613  	
614  	            (*created) = TRUE;
615  	         }
616  	
617  	         /* insert rhs form of indicator */
618  	         if ( rhsIndCons )
619  	         {
620  	            SCIP_CALL( SCIPcreateConsIndicator(scip, &cons, name, NULL, 0, NULL, NULL, sciprhs,
621  	                  initial, separate, enforce, check, propagate, local, readerdata->dynamicconss, readerdata->dynamicrows, FALSE) );
622  	            SCIP_CALL( SCIPaddCons(scip, cons) );
623  	
624  	            for( i = 0; i < term_get_elements(term); i++ )
625  	            {
626  	               SCIP_VAR* scipvar;
627  	               SCIP_Real scipval;
628  	               const Mono* mono = term_get_element(term, i);
629  	               MFun mfun;
630  	
631  	               scipvar = (SCIP_VAR*)mono_get_var(mono, 0);
632  	
633  	               /* check whether variable is the binary variable */
634  	               mfun = mono_get_function(mono);
635  	               if (mfun == MFUN_TRUE || mfun == MFUN_FALSE)
636  	               {
637  	                  scipvar = (SCIP_VAR*)mono_get_var(mono, 0);
638  	                  SCIP_CALL( SCIPsetBinaryVarIndicator(scip, cons, scipvar) );
639  	               }
640  	               else
641  	               {
642  	                  assert(!numb_equal(mono_get_coeff(mono), numb_zero()));
643  	                  assert(mono_is_linear(mono));
644  	
645  	                  scipval = numb_todbl(mono_get_coeff(mono));
646  	                  SCIP_CALL( SCIPaddVarIndicator(scip, cons, scipvar, scipval) );
647  	               }
648  	            }
649  	
650  	            (*created) = TRUE;
651  	         }
652  	      }
653  	      else
654  	      {
655  	         SCIP_CALL( SCIPcreateConsLinear(scip, &cons, name, 0, NULL, NULL, sciplhs, sciprhs,
656  	               initial, separate, enforce, check, propagate, local, modifiable, readerdata->dynamicconss, readerdata->dynamicrows, FALSE) );
657  	         SCIP_CALL( SCIPaddCons(scip, cons) );
658  	
659  	         for( i = 0; i < term_get_elements(term); i++ )
660  	         {
661  	            SCIP_VAR* scipvar;
662  	            SCIP_Real scipval;
663  	
664  	            assert(!numb_equal(mono_get_coeff(term_get_element(term, i)), numb_zero()));
665  	            assert(mono_is_linear(term_get_element(term, i)));
666  	
667  	            scipvar = (SCIP_VAR*)mono_get_var(term_get_element(term, i), 0);
668  	            scipval = numb_todbl(mono_get_coeff(term_get_element(term, i)));
669  	
670  	            SCIP_CALL( SCIPaddCoefLinear(scip, cons, scipvar, scipval) );
671  	         }
672  	
673  	         (*created) = TRUE;
674  	      }
675  	   }
676  	   else
677  	   {
678  	      SCIP_EXPR* expr;
679  	
680  	      /* convert term into expression */
681  	      SCIP_CALL( createExpr(scip, readerdata, &expr, term) );
682  	
683  	      if( expr == NULL )
684  	      {
685  	         /* ZIMPL term could not be represented as SCIP expression */
686  	         (*created) = FALSE;
687  	      }
688  	      else
689  	      {
690  	         /* create constraint with expression */
691  	         SCIP_CALL( SCIPcreateConsNonlinear(scip, &cons, name, expr, sciplhs, sciprhs,
692  	            initial, separate, enforce, check, propagate, local, modifiable, readerdata->dynamicconss, readerdata->dynamicrows) );
693  	         SCIP_CALL( SCIPaddCons(scip, cons) );
694  	
695  	         SCIP_CALL( SCIPreleaseExpr(scip, &expr) );
696  	
697  	         (*created) = TRUE;
698  	      }
699  	   }
700  	
701  	   if( cons != NULL )
702  	   {
703  	      SCIP_CALL( SCIPreleaseCons(scip, &cons) );
704  	   }
705  	
706  	   return SCIP_OKAY;
707  	}
708  	
709  	/** method adds objective term and is called directly from ZIMPL
710  	 *
711  	 *  @note this method is used by ZIMPL beginning from version 3.4.1
712  	 */
713  	static
714  	SCIP_RETCODE addObjTerm(
715  	   SCIP*                 scip,               /**< SCIP data structure */
716  	   SCIP_READERDATA*      readerdata,         /**< reader data */
717  	   const Term*           term                /**< term to use */
718  	   )
719  	{
720  	   SCIP_Real objoffset;
721  	
722  	   if( term_is_linear(term) )
723  	   {
724  	      int i;
725  	      for( i = 0; i < term_get_elements(term); i++ )
726  	      {
727  	         SCIP_VAR* scipvar;
728  	         SCIP_Real scipval;
729  	
730  	         assert(!numb_equal(mono_get_coeff(term_get_element(term, i)), numb_zero()));
731  	         assert(mono_is_linear(term_get_element(term, i)));
732  	
733  	         scipvar = (SCIP_VAR*)mono_get_var(term_get_element(term, i), 0);
734  	         scipval = numb_todbl(mono_get_coeff(term_get_element(term, i)));
735  	
736  	         SCIP_CALL( SCIPaddVarObj(scip, scipvar, scipval) );
737  	      }
738  	   }
739  	   else
740  	   {
741  	      /* create variable objvar, add 1*objvar to objective, and add constraint term - objvar = 0 */
742  	      SCIP_EXPR* expr;
743  	      SCIP_CONS* cons;
744  	      SCIP_VAR* objvar;
745  	
746  	      SCIP_CALL( createExpr(scip, readerdata, &expr, term) );
747  	
748  	      if( expr == NULL )
749  	      {
750  	         SCIPerrorMessage("Could not convert ZIMPL objective term into SCIP expression due to unsupported ZIMPL function.\n");
751  	         return SCIP_READERROR;
752  	      }
753  	
754  	      SCIP_CALL( SCIPcreateConsNonlinear(scip, &cons, "obj", expr,
755  	         SCIPgetObjsense(scip) == SCIP_OBJSENSE_MINIMIZE ? -SCIPinfinity(scip) : 0.0,
756  	         SCIPgetObjsense(scip) == SCIP_OBJSENSE_MAXIMIZE ?  SCIPinfinity(scip) : 0.0,
757  	         readerdata->initialconss, TRUE, TRUE, TRUE, TRUE, FALSE, FALSE, readerdata->dynamicconss, FALSE) );
758  	
759  	      SCIP_CALL( SCIPcreateVarBasic(scip, &objvar, "objvar", -SCIPinfinity(scip), SCIPinfinity(scip), 1.0, SCIP_VARTYPE_CONTINUOUS) );
760  	      SCIP_CALL( SCIPaddLinearVarNonlinear(scip, cons, objvar, -1.0) );
761  	
762  	      SCIP_CALL( SCIPaddVar(scip, objvar) );
763  	      SCIP_CALL( SCIPaddCons(scip, cons) );
764  	
765  	      SCIP_CALL( SCIPreleaseExpr(scip, &expr) );
766  	      SCIP_CALL( SCIPreleaseCons(scip, &cons) );
767  	      SCIP_CALL( SCIPreleaseVar(scip, &objvar) );
768  	   }
769  	
770  	   objoffset = numb_todbl(term_get_constant(term));
771  	   SCIP_CALL( SCIPaddOrigObjoffset(scip, objoffset) );
772  	
773  	   return SCIP_OKAY;
774  	}
775  	
776  	/** method creates a constraint and is called directly from ZIMPL
777  	 *
778  	 *  @note this method is used by ZIMPL beginning from version 3.00
779  	 */
780  	bool xlp_addcon_term(
781  	   Lps*                  data,               /**< pointer to reader data */
782  	   const char*           name,               /**< constraint name */
783  	   ConType               type,               /**< constraint type (LHS, RHS, EQUAL, RANGE, etc) */
784  	   const Numb*           lhs,                /**< left hand side */
785  	   const Numb*           rhs,                /**< right hand side */
786  	   unsigned int          flags,              /**< special constraint flags, see ratlptypes.h */
787  	   const Term*           term                /**< term to use */
788  	   )
789  	{
790  	   SCIP* scip;
791  	   SCIP_READERDATA* readerdata;
792  	   SCIP_Bool created = FALSE;
793  	
794  	   readerdata = (SCIP_READERDATA*)data;
795  	   assert(readerdata != NULL);
796  	
797  	   scip = readerdata->scip;
798  	   assert(scip != NULL);
799  	
800  	   if( readerdata->retcode != SCIP_OKAY || readerdata->readerror )
801  	      return TRUE;
802  	
803  	   readerdata->retcode = addConsTerm(scip, readerdata, name, type, lhs, rhs, flags, term, &created);
804  	
805  	   return !created;
806  	}
807  	
808  	/** adde variable */
809  	static
810  	SCIP_RETCODE addVar(
811  	   SCIP*                 scip,               /**< SCIP data structure */
812  	   SCIP_READERDATA*      readerdata,         /**< reader data */
813  	   const char*           name,               /**< variable name */
814  	   VarClass              usevarclass,        /**< variable type */
815  	   const Bound*          lower,              /**< lower bound */
816  	   const Bound*          upper,              /**< upper bound */
817  	   const Numb*           priority,           /**< branching priority */
818  	   const Numb*           startval,           /**< start value for the variable within in the start solution */
819  	   Var**                 zplvar              /**< pointer to store the created variable */
820  	   )
821  	{
822  	   SCIP_VAR* var;
823  	   SCIP_Real lb;
824  	   SCIP_Real ub;
825  	   SCIP_VARTYPE vartype;
826  	   SCIP_Bool initial;
827  	   SCIP_Bool removable;
828  	   int branchpriority;
829  	
830  	   switch( bound_get_type(lower) )
831  	   {
832  	   case BOUND_VALUE:
833  	      lb = (SCIP_Real)numb_todbl(bound_get_value(lower));
834  	      break;
835  	   case BOUND_INFTY:
836  	      lb = SCIPinfinity(scip);
837  	      break;
838  	   case BOUND_MINUS_INFTY:
839  	      lb = -SCIPinfinity(scip);
840  	      break;
841  	   case BOUND_ERROR:
842  	   default:
843  	      SCIPerrorMessage("invalid lower bound type <%d> in ZIMPL reader\n", bound_get_type(lower));
844  	      lb = 0.0;
845  	      break;
846  	   }
847  	
848  	   switch( bound_get_type(upper) )
849  	   {
850  	   case BOUND_VALUE:
851  	      ub = (SCIP_Real)numb_todbl(bound_get_value(upper));
852  	      break;
853  	   case BOUND_INFTY:
854  	      ub = SCIPinfinity(scip);
855  	      break;
856  	   case BOUND_MINUS_INFTY:
857  	      ub = -SCIPinfinity(scip);
858  	      break;
859  	   case BOUND_ERROR:
860  	   default:
861  	      SCIPerrorMessage("invalid upper bound type <%d> in ZIMPL reader\n", bound_get_type(upper));
862  	      ub = 0.0;
863  	      break;
864  	   }
865  	
866  	   switch( usevarclass )
867  	   {
868  	   case VAR_CON:
869  	      vartype = SCIP_VARTYPE_CONTINUOUS;
870  	      break;
871  	   case VAR_INT:
872  	      vartype = SCIP_VARTYPE_INTEGER;
873  	      break;
874  	   case VAR_IMP:
875  	      vartype = SCIP_VARTYPE_IMPLINT;
876  	      break;
877  	   default:
878  	      SCIPwarningMessage(scip, "invalid variable class <%d> in ZIMPL callback xlp_addvar()\n", usevarclass);
879  	      vartype = SCIP_VARTYPE_CONTINUOUS;
880  	      readerdata->readerror = TRUE;
881  	      break;
882  	   }
883  	   initial = !(readerdata->dynamiccols);
884  	   removable = readerdata->dynamiccols;
885  	
886  	   /* create variable */
887  	   SCIP_CALL( SCIPcreateVar(scip, &var, name, lb, ub, 0.0, vartype, initial, removable, NULL, NULL, NULL, NULL, NULL) );
888  	
889  	   /* add variable to the problem; we are releasing the variable later */
890  	   SCIP_CALL( SCIPaddVar(scip, var) );
891  	
892  	   if( !numb_equal(priority, numb_unknown()) )
893  	   {
894  	      if( numb_is_int(priority) )
895  		 branchpriority = numb_toint(priority);
896  	      else
897  	      {
898  		 if( !readerdata->branchpriowarning )
899  		 {
900  		    SCIPverbMessage(scip, SCIP_VERBLEVEL_MINIMAL, NULL,
901  		       "ZIMPL reader: fractional branching priorities in input - rounding down to integer values\n");
902  		    readerdata->branchpriowarning = TRUE;
903  		 }
904  		 branchpriority = (int)numb_todbl(priority);
905  	      }
906  	
907  	      /* change the branching priority of the variable */
908  	      SCIP_CALL( SCIPchgVarBranchPriority(scip, var, branchpriority) );
909  	   }
910  	
911  	   /* check if we are willing to except a primal solution candidate */
912  	   if( readerdata->valid )
913  	   {
914  	      /* if the number is unknown we have no valid primal solution candidate */
915  	      if( numb_equal(startval, numb_unknown()) )
916  	      {
917  	         SCIPdebugMsg(scip, "primal solution candidate contains an unknown value for variable <%s>(%g)\n",
918  	            SCIPvarGetName(var), (SCIP_Real)numb_todbl(startval));
919  	         readerdata->valid = FALSE;
920  	      }
921  	      else
922  	      {
923  	         assert(readerdata->sol != NULL);
924  	         SCIPdebugMsg(scip, "change solution solution <%p>: <%s> = <%g>\n",
925  	            (void*)readerdata->sol, SCIPvarGetName(var), (SCIP_Real)numb_todbl(startval));
926  	
927  	         /* set value within the primal solution candidate */
928  	         SCIP_CALL( SCIPsetSolVal(scip, readerdata->sol, var, (SCIP_Real)numb_todbl(startval)) );
929  	      }
930  	   }
931  	
932  	   /* copy the variable pointer before we release the variable */
933  	   (*zplvar) = (Var*)var;
934  	
935  	   /* release variable */
936  	   SCIP_CALL( SCIPreleaseVar(scip, &var) );
937  	
938  	   return SCIP_OKAY;
939  	}
940  	
941  	/** method adds a variable; is called directly by ZIMPL */
942  	Var* xlp_addvar(
943  	   Lps*                  data,               /**< pointer to reader data */
944  	   const char*           name,               /**< variable name */
945  	   VarClass              usevarclass,        /**< variable type */
946  	   const Bound*          lower,              /**< lower bound */
947  	   const Bound*          upper,              /**< upper bound */
948  	   const Numb*           priority,           /**< branching priority */
949  	   const Numb*           startval            /**< start value for the variable within in the start solution */
950  	   )
951  	{  /*lint --e{715}*/
952  	   SCIP* scip;
953  	   SCIP_READERDATA* readerdata;
954  	   Var* zplvar;
955  	
956  	   readerdata = (SCIP_READERDATA*)data;
957  	   assert(readerdata != NULL);
958  	
959  	   scip = readerdata->scip;
960  	   assert(scip != NULL);
961  	
962  	   zplvar = NULL;
963  	
964  	   if( readerdata->retcode != SCIP_OKAY || readerdata->readerror )
965  	      return NULL;
966  	
967  	   readerdata->retcode = addVar(scip, readerdata, name, usevarclass, lower, upper, priority, startval, &zplvar);
968  	
969  	   return zplvar;
970  	}
971  	
972  	/** add a SOS constraint. Add a given a Zimpl term as an SOS constraint to the mathematical program */
973  	static
974  	SCIP_RETCODE addSOS(
975  	   SCIP*                 scip,               /**< SCIP data structure */
976  	   SCIP_READERDATA*      readerdata,         /**< reader data */
977  	   const char*           name,               /**< constraint name */
978  	   SosType               type,               /**< SOS type */
979  	   const Term*           term                /**< terms indicating sos */
980  	   )
981  	{
982  	   SCIP_CONS* cons;
983  	   SCIP_Bool separate;
984  	   SCIP_Bool enforce;
985  	   SCIP_Bool check;
986  	   SCIP_Bool propagate;
987  	   SCIP_Bool local;
988  	   int i;
989  	
990  	   switch( type )
991  	   {
992  	   case SOS_TYPE1:
993  	      separate = TRUE;
994  	      enforce = TRUE;
995  	      check = enforce;
996  	      propagate = TRUE;
997  	      local = FALSE;
998  	
999  	      SCIP_CALL( SCIPcreateConsSOS1(scip, &cons, name, 0, NULL, NULL,
1000 	            readerdata->initialconss, separate, enforce, check, propagate, local, readerdata->dynamicconss, readerdata->dynamicrows, FALSE) );
1001 	      SCIP_CALL( SCIPaddCons(scip, cons) );
1002 	
1003 	      for( i = 0; i < term_get_elements(term); i++ )
1004 	      {
1005 	         SCIP_VAR* var;
1006 	         SCIP_Real weight;
1007 	
1008 	         assert( mono_is_linear(term_get_element(term, i)) );
1009 	
1010 	         var = (SCIP_VAR*) mono_get_var(term_get_element(term, i), 0);
1011 	         weight = numb_todbl(mono_get_coeff(term_get_element(term, i)));
1012 	
1013 	         SCIP_CALL( SCIPaddVarSOS1(scip, cons, var, weight) );
1014 	      }
1015 	      SCIP_CALL( SCIPreleaseCons(scip, &cons) );
1016 	      break;
1017 	   case SOS_TYPE2:
1018 	      separate = TRUE;
1019 	      enforce = TRUE;
1020 	      check = enforce;
1021 	      propagate = TRUE;
1022 	      local = FALSE;
1023 	
1024 	      SCIP_CALL( SCIPcreateConsSOS2(scip, &cons, name, 0, NULL, NULL,
1025 	            readerdata->initialconss, separate, enforce, check, propagate, local, readerdata->dynamicconss, readerdata->dynamicrows, FALSE) );
1026 	      SCIP_CALL( SCIPaddCons(scip, cons) );
1027 	      for( i = 0; i < term_get_elements(term); i++ )
1028 	      {
1029 	         SCIP_VAR* var;
1030 	         SCIP_Real weight;
1031 	
1032 	         assert( mono_is_linear(term_get_element(term, i)) );
1033 	
1034 	         var = (SCIP_VAR*) mono_get_var(term_get_element(term, i), 0);
1035 	         weight = numb_todbl(mono_get_coeff(term_get_element(term, i)));
1036 	
1037 	         SCIP_CALL( SCIPaddVarSOS2(scip, cons, var, weight) );
1038 	      }
1039 	      SCIP_CALL( SCIPreleaseCons(scip, &cons) );
1040 	      break;
1041 	   case SOS_ERR:
1042 	      /*lint -fallthrough*/
1043 	   default:
1044 	      SCIPerrorMessage("invalid SOS type <%d> in ZIMPL callback xlp_addsos_term()\n", type);
1045 	      readerdata->readerror = TRUE;
1046 	      break;
1047 	   }
1048 	
1049 	   return SCIP_OKAY;
1050 	}
1051 	
1052 	/** add a SOS constraint. Add a given a Zimpl term as an SOS constraint to the mathematical program */
1053 	int xlp_addsos_term(
1054 	   Lps*                  data,               /**< pointer to reader data */
1055 	   const char*           name,               /**< constraint name */
1056 	   SosType               type,               /**< SOS type */
1057 	   const Numb*           priority,           /**< priority */
1058 	   const Term*           term                /**< terms indicating sos */
1059 	   )
1060 	{
1061 	   /*lint --e{715}*/
1062 	   SCIP* scip;
1063 	   SCIP_READERDATA* readerdata;
1064 	
1065 	   readerdata = (SCIP_READERDATA*)data;
1066 	   assert(readerdata != NULL);
1067 	
1068 	   scip = readerdata->scip;
1069 	   assert(scip != NULL);
1070 	
1071 	   if( readerdata->retcode != SCIP_OKAY || readerdata->readerror )
1072 	      return TRUE;
1073 	
1074 	   readerdata->retcode = addSOS(scip, readerdata, name, type, term);
1075 	
1076 	   return 0;
1077 	}
1078 	
1079 	/** returns the variable name */
1080 	const char* xlp_getvarname(
1081 	   const Lps*            data,               /**< pointer to reader data */
1082 	   const Var*            var                 /**< variable */
1083 	   )
1084 	{
1085 	#ifndef NDEBUG
1086 	   SCIP* scip;
1087 	   SCIP_READERDATA* readerdata;
1088 	
1089 	   readerdata = (SCIP_READERDATA*)data;
1090 	   assert(readerdata != NULL);
1091 	
1092 	   scip = readerdata->scip;
1093 	   assert(scip != NULL);
1094 	#endif
1095 	
1096 	   return SCIPvarGetName((SCIP_VAR*)var);
1097 	}
1098 	
1099 	/** return variable type */
1100 	VarClass xlp_getclass(
1101 	   const Lps*            data,               /**< pointer to reader data */
1102 	   const Var*            var                 /**< variable */
1103 	   )
1104 	{
1105 	   SCIP_READERDATA* readerdata;
1106 	   SCIP_VAR* scipvar;
1107 	
1108 	   readerdata = (SCIP_READERDATA*)data;
1109 	   assert(readerdata != NULL);
1110 	
1111 	   scipvar = (SCIP_VAR*)var;
1112 	   switch( SCIPvarGetType(scipvar) )
1113 	   {
1114 	   case SCIP_VARTYPE_BINARY:
1115 	   case SCIP_VARTYPE_INTEGER:
1116 	      return VAR_INT;
1117 	   case SCIP_VARTYPE_IMPLINT:
1118 	      return VAR_IMP;
1119 	   case SCIP_VARTYPE_CONTINUOUS:
1120 	      return VAR_CON;
1121 	   default:
1122 	      SCIPerrorMessage("invalid SCIP variable type <%d> in ZIMPL callback xlp_getclass()\n", SCIPvarGetType(scipvar));
1123 	      readerdata->readerror = TRUE;
1124 	      break;
1125 	   }
1126 	
1127 	   return VAR_CON;
1128 	}
1129 	
1130 	/** returns lower bound */
1131 	Bound* xlp_getlower(
1132 	   const Lps*            data,               /**< pointer to reader data */
1133 	   const Var*            var                 /**< variable */
1134 	   )
1135 	{
1136 	   SCIP* scip;
1137 	   SCIP_READERDATA* readerdata;
1138 	   SCIP_VAR* scipvar;
1139 	   SCIP_Real lb;
1140 	   char s[SCIP_MAXSTRLEN];
1141 	   BoundType boundtype;
1142 	   Numb* numb;
1143 	   Bound* bound;
1144 	
1145 	   readerdata = (SCIP_READERDATA*)data;
1146 	   assert(readerdata != NULL);
1147 	
1148 	   scip = readerdata->scip;
1149 	   assert(scip != NULL);
1150 	
1151 	   scipvar = (SCIP_VAR*)var;
1152 	   assert(scipvar != NULL);
1153 	
1154 	   /* collect lower bound */
1155 	   lb = SCIPvarGetLbGlobal(scipvar);
1156 	   numb = NULL;
1157 	
1158 	   /* check if lower bound is infinity */
1159 	   if( SCIPisInfinity(scip, -lb) )
1160 	      boundtype = BOUND_MINUS_INFTY;
1161 	   else if( SCIPisInfinity(scip, lb) )
1162 	      boundtype = BOUND_INFTY;
1163 	   else
1164 	   {
1165 	      boundtype = BOUND_VALUE;
1166 	
1167 	      /* create double form string */
1168 	      (void) SCIPsnprintf(s, SCIP_MAXSTRLEN, "%.20f", lb);
1169 	      numb = numb_new_ascii(s);
1170 	   }
1171 	
1172 	   /* create bound */
1173 	   bound = bound_new(boundtype, numb);
1174 	
1175 	   if( numb != NULL )
1176 	      numb_free(numb);
1177 	
1178 	   return bound;
1179 	}
1180 	
1181 	/** returns upper bound */
1182 	Bound* xlp_getupper(
1183 	   const Lps*            data,               /**< pointer to reader data */
1184 	   const Var*            var                 /**< variable */
1185 	   )
1186 	{
1187 	   SCIP* scip;
1188 	   SCIP_READERDATA* readerdata;
1189 	   SCIP_VAR* scipvar;
1190 	   SCIP_Real ub;
1191 	   char s[SCIP_MAXSTRLEN];
1192 	   BoundType boundtype;
1193 	   Numb* numb;
1194 	   Bound* bound;
1195 	
1196 	   readerdata = (SCIP_READERDATA*)data;
1197 	   assert(readerdata != NULL);
1198 	
1199 	   scip = readerdata->scip;
1200 	   assert(scip != NULL);
1201 	
1202 	   scipvar = (SCIP_VAR*)var;
1203 	   assert(scipvar != NULL);
1204 	
1205 	   /* collect upper bound */
1206 	   ub = SCIPvarGetUbGlobal(scipvar);
1207 	   numb = NULL;
1208 	
1209 	   /* check if upper bound is infinity */
1210 	   if( SCIPisInfinity(scip, -ub) )
1211 	      boundtype = BOUND_MINUS_INFTY;
1212 	   else if( SCIPisInfinity(scip, ub) )
1213 	      boundtype = BOUND_INFTY;
1214 	   else
1215 	   {
1216 	      boundtype = BOUND_VALUE;
1217 	      (void) SCIPsnprintf(s, SCIP_MAXSTRLEN, "%.20f", ub);
1218 	      numb = numb_new_ascii(s);
1219 	   }
1220 	
1221 	   /* create ZIMPL bound */
1222 	   bound = bound_new(boundtype, numb);
1223 	
1224 	   if (numb != NULL)
1225 	      numb_free(numb);
1226 	
1227 	   return bound;
1228 	}
1229 	
1230 	/** Set the name and direction of the objective function, i.e. minimization or maximization
1231 	 *  Coefficents of the objective function will be set to all zero.
1232 	 */
1233 	bool xlp_setobj(
1234 	   Lps*                  data,               /**< pointer to reader data */
1235 	   const char*           name,               /**< name of the objective function */
1236 	   bool                  minimize            /**< True if the problem should be minimized, False if it should be maximized  */
1237 	   )
1238 	{
1239 	   SCIP* scip;
1240 	   SCIP_READERDATA* readerdata;
1241 	   SCIP_OBJSENSE objsense;
1242 	
1243 	   readerdata = (SCIP_READERDATA*)data;
1244 	   assert(readerdata != NULL);
1245 	
1246 	   scip = readerdata->scip;
1247 	   assert(scip != NULL);
1248 	
1249 	   if( readerdata->retcode != SCIP_OKAY || readerdata->readerror )
1250 	      return FALSE;
1251 	
1252 	   objsense = (minimize ? SCIP_OBJSENSE_MINIMIZE : SCIP_OBJSENSE_MAXIMIZE);
1253 	   readerdata->retcode = SCIPsetObjsense(scip, objsense);
1254 	
1255 	   return FALSE;
1256 	}
1257 	
1258 	/** adds objective function */
1259 	void xlp_addtoobj(
1260 	   Lps*                  data,               /**< pointer to reader data */
1261 	   const Term*           term                /**< objective term */
1262 	   )
1263 	{
1264 	   SCIP* scip;
1265 	   SCIP_READERDATA* readerdata;
1266 	
1267 	   readerdata = (SCIP_READERDATA*)data;
1268 	   assert(readerdata != NULL);
1269 	
1270 	   scip = readerdata->scip;
1271 	   assert(scip != NULL);
1272 	
1273 	   if( readerdata->retcode != SCIP_OKAY || readerdata->readerror )
1274 	      return;
1275 	
1276 	   readerdata->retcode = addObjTerm(scip, readerdata, term);
1277 	}
1278 	
1279 	/*
1280 	 * Callback methods of reader
1281 	 */
1282 	
1283 	/** copy method for reader plugins (called when SCIP copies plugins) */
1284 	static
1285 	SCIP_DECL_READERCOPY(readerCopyZpl)
1286 	{  /*lint --e{715}*/
1287 	   assert(scip != NULL);
1288 	   assert(reader != NULL);
1289 	   assert(strcmp(SCIPreaderGetName(reader), READER_NAME) == 0);
1290 	
1291 	   /* call inclusion method of reader */
1292 	   SCIP_CALL( SCIPincludeReaderZpl(scip) );
1293 	
1294 	   return SCIP_OKAY;
1295 	}
1296 	
1297 	
1298 	/** problem reading method of reader */
1299 	static
1300 	SCIP_DECL_READERREAD(readerReadZpl)
1301 	{  /*lint --e{715}*/
1302 	   SCIP_READERDATA* readerdata;
1303 	   SCIP_RETCODE retcode;
1304 	   char oldpath[SCIP_MAXSTRLEN];
1305 	   char buffer[SCIP_MAXSTRLEN];
1306 	   char compextension[SCIP_MAXSTRLEN];
1307 	   char namewithoutpath[SCIP_MAXSTRLEN];
1308 	   char* path;
1309 	   char* name;
1310 	   char* extension;
1311 	   char* compression;
1312 	   char* paramstr;
1313 	
1314 	   SCIP_Bool changedir;
1315 	   int i;
1316 	
1317 	   SCIP_CALL( SCIPgetBoolParam(scip, "reading/zplreader/changedir", &changedir) );
1318 	
1319 	   path = NULL;
1320 	   oldpath[0] = '\0';
1321 	   if( changedir )
1322 	   {
1323 	      /* change to the directory of the ZIMPL file, s.t. paths of data files read by the ZIMPL model are relative to
1324 	       * the location of the ZIMPL file
1325 	       */
1326 	      (void)SCIPstrncpy(buffer, filename, SCIP_MAXSTRLEN);
1327 	      SCIPsplitFilename(buffer, &path, &name, &extension, &compression);
1328 	      if( compression != NULL )
1329 	         (void) SCIPsnprintf(compextension, SCIP_MAXSTRLEN, ".%s", compression);
1330 	      else
1331 	         *compextension = '\0';
1332 	      (void) SCIPsnprintf(namewithoutpath, SCIP_MAXSTRLEN, "%s.%s%s", name, extension, compextension);
1333 	      if( (char*)getcwd(oldpath, SCIP_MAXSTRLEN) == NULL )
1334 	      {
1335 	         SCIPerrorMessage("error getting the current path\n");
1336 	         return SCIP_READERROR;
1337 	      }
1338 	      if( path != NULL )
1339 	      {
1340 	         if( chdir(path) != 0 )
1341 	         {
1342 	            SCIPerrorMessage("error changing to directory <%s>\n", path);
1343 	            return SCIP_NOFILE;
1344 	         }
1345 	      }
1346 	      filename = namewithoutpath;
1347 	   }
1348 	
1349 	   /* get current path for output */
1350 	   if( SCIPgetVerbLevel(scip) >= SCIP_VERBLEVEL_NORMAL )
1351 	   {
1352 	      char currentpath[SCIP_MAXSTRLEN];
1353 	      if( (char*)getcwd(currentpath, SCIP_MAXSTRLEN) == NULL )
1354 	      {
1355 	         SCIPerrorMessage("error getting the current path\n");
1356 	         return SCIP_READERROR;
1357 	      }
1358 	      /* an extra blank line should be printed separately since the buffer message handler only handle up to one line
1359 	       *  correctly */
1360 	      SCIPverbMessage(scip, SCIP_VERBLEVEL_NORMAL, NULL, "\n");
1361 	      SCIPverbMessage(scip, SCIP_VERBLEVEL_NORMAL, NULL, "base directory for ZIMPL parsing: <%s>\n", currentpath);
1362 	      /* an extra blank line should be printed separately since the buffer message handler only handle up to one line
1363 	       *  correctly */
1364 	      SCIPverbMessage(scip, SCIP_VERBLEVEL_NORMAL, NULL, "\n");
1365 	   }
1366 	
1367 	   /* allocate storage */
1368 	   SCIP_CALL( SCIPallocBuffer(scip, &readerdata) );
1369 	
1370 	   readerdata->scip = scip;
1371 	   readerdata->sol = NULL;
1372 	   readerdata->valid = FALSE;
1373 	   readerdata->branchpriowarning = FALSE;
1374 	   readerdata->readerror = FALSE;
1375 	   readerdata->retcode = SCIP_OKAY;
1376 	   SCIP_CALL( SCIPgetBoolParam(scip, "reading/initialconss", &(readerdata->initialconss)) );
1377 	   SCIP_CALL( SCIPgetBoolParam(scip, "reading/dynamicconss", &(readerdata->dynamicconss)) );
1378 	   SCIP_CALL( SCIPgetBoolParam(scip, "reading/dynamiccols", &(readerdata->dynamiccols)) );
1379 	   SCIP_CALL( SCIPgetBoolParam(scip, "reading/dynamicrows", &(readerdata->dynamicrows)) );
1380 	
1381 	   /* get the parameter string */
1382 	   SCIP_CALL( SCIPgetStringParam(scip, "reading/zplreader/parameters", &paramstr) );
1383 	   if( strcmp(paramstr, "-") == 0 )
1384 	   {
1385 	      /* call ZIMPL parser without arguments */
1386 	      if( !zpl_read(filename, TRUE, (void*)readerdata) )
1387 	         readerdata->readerror = TRUE;
1388 	      else
1389 	      {
1390 	         /* evaluate retcode */
1391 	         if ( readerdata->retcode != SCIP_OKAY )
1392 	         {
1393 	            SCIPfreeBuffer(scip, &readerdata);
1394 	            return readerdata->retcode;
1395 	         }
1396 	      }
1397 	   }
1398 	   else
1399 	   {
1400 	      char dummy[2] = "x";
1401 	      char** argv;
1402 	      int argc;
1403 	      int p;
1404 	      int len;
1405 	
1406 	      len = (int) strlen(paramstr);
1407 	      SCIP_CALL( SCIPallocBufferArray(scip, &argv, len+1) );
1408 	      argv[0] = dummy; /* argument 0 is irrelevant */
1409 	      argc = 1;
1410 	      p = 0;
1411 	      while( p < len )
1412 	      {
1413 	         int arglen;
1414 	
1415 	         /* process next argument */
1416 	         SCIP_CALL( SCIPallocBufferArray(scip, &argv[argc], len+1) );  /*lint !e866*/
1417 	         arglen = 0;
1418 	
1419 	         /* skip spaces */
1420 	         while( p < len && paramstr[p] == ' ' )
1421 	            p++;
1422 	
1423 	         /* process characters */
1424 	         while( p < len && paramstr[p] != ' ' )
1425 	         {
1426 	            switch( paramstr[p] )
1427 	            {
1428 	            case '"':
1429 	               p++;
1430 	               /* read characters as they are until the next " */
1431 	               while( p < len && paramstr[p] != '"' )
1432 	               {
1433 	                  argv[argc][arglen] = paramstr[p];
1434 	                  arglen++;
1435 	                  p++;
1436 	               }
1437 	               p++; /* skip final " */
1438 	               break;
1439 	            case '\\':
1440 	               /* read next character as it is */
1441 	               p++;
1442 	               argv[argc][arglen] = paramstr[p];
1443 	               arglen++;
1444 	               p++;
1445 	               break;
1446 	            default:
1447 	               argv[argc][arglen] = paramstr[p];
1448 	               arglen++;
1449 	               p++;
1450 	               break;
1451 	            }
1452 	         }
1453 	         argv[argc][arglen] = '\0';
1454 	
1455 	         /* check for empty argument */
1456 	         if( arglen == 0 )
1457 	         {
1458 	            SCIPfreeBufferArray(scip, &argv[argc]);
1459 	         }
1460 	         else
1461 	            argc++;
1462 	      }
1463 	
1464 	      /* append file name as last argument */
1465 	      SCIP_CALL( SCIPduplicateBufferArray(scip, &argv[argc], filename, (int) strlen(filename)+1) );  /*lint !e866*/
1466 	      argc++;
1467 	
1468 	      /* display parsed arguments */
1469 	      if( SCIPgetVerbLevel(scip) >= SCIP_VERBLEVEL_FULL )
1470 	      {
1471 	         SCIPverbMessage(scip, SCIP_VERBLEVEL_FULL, NULL, "ZIMPL arguments:\n");
1472 	         for( i = 1; i < argc; ++i )
1473 	         {
1474 	            SCIPverbMessage(scip, SCIP_VERBLEVEL_FULL, NULL, "%d: <%s>\n", i, argv[i]);
1475 	         }
1476 	      }
1477 	
1478 	      /* call ZIMPL parser with arguments */
1479 	      if( !zpl_read_with_args(argv, argc, TRUE, (void*)readerdata) )
1480 	         readerdata->readerror = TRUE;
1481 	
1482 	      /* free argument memory */
1483 	      for( i = argc - 1; i >= 1; --i )
1484 	      {
1485 	         SCIPfreeBufferArray(scip, &argv[i]);
1486 	      }
1487 	      SCIPfreeBufferArray(scip, &argv);
1488 	
1489 	      if ( readerdata->retcode != SCIP_OKAY )
1490 	      {
1491 	         SCIPfreeBuffer(scip, &readerdata);
1492 	         return readerdata->retcode;
1493 	      }
1494 	   }
1495 	
1496 	   if( changedir )
1497 	   {
1498 	      /* change directory back to old path */
1499 	      if( path != NULL )
1500 	      {
1501 	         if( chdir(oldpath) != 0 )
1502 	         {
1503 	            SCIPwarningMessage(scip, "error changing back to directory <%s>\n", oldpath);
1504 	         }
1505 	      }
1506 	   }
1507 	
1508 	   if( readerdata->valid )
1509 	   {
1510 	      SCIP_Bool stored;
1511 	
1512 	      assert(readerdata->sol != NULL);
1513 	
1514 	      stored = FALSE;
1515 	
1516 	      /* add primal solution to solution candidate storage, frees the solution afterwards */
1517 	      SCIP_CALL( SCIPaddSolFree(scip, &readerdata->sol, &stored) );
1518 	
1519 	      if( stored )
1520 	      {
1521 	         SCIPverbMessage(scip, SCIP_VERBLEVEL_FULL, NULL, "ZIMPL starting solution candidate accepted\n");
1522 	      }
1523 	   }
1524 	
1525 	   *result = SCIP_SUCCESS;
1526 	
1527 	   /* evaluate if a reading error occurred */
1528 	   if( readerdata->readerror )
1529 	      retcode = SCIP_READERROR;
1530 	   else
1531 	      retcode = SCIP_OKAY;
1532 	
1533 	   /* free primal solution candidate */
1534 	   if( readerdata->sol != NULL )
1535 	   {
1536 	      SCIP_CALL( SCIPfreeSol(scip, &readerdata->sol) );
1537 	   }
1538 	
1539 	   /* free reader data */
1540 	   SCIPfreeBuffer(scip, &readerdata);
1541 	
1542 	   return retcode;
1543 	}
1544 	
1545 	
1546 	#endif
1547 	#endif
1548 	
1549 	
1550 	/*
1551 	 * reader specific interface methods
1552 	 */
1553 	
1554 	/** includes the zpl file reader in SCIP */ /*lint --e{715}*/
1555 	SCIP_RETCODE SCIPincludeReaderZpl(
1556 	   SCIP*                 scip                /**< SCIP data structure */
1557 	   )
1558 	{ /*lint --e{715}*/
1559 	#ifdef SCIP_WITH_ZIMPL
1560 	#if (ZIMPL_VERSION >= 341)
1561 	   SCIP_READERDATA* readerdata;
1562 	   SCIP_READER* reader;
1563 	   char extcodename[SCIP_MAXSTRLEN];
1564 	
1565 	   assert(scip != NULL);
1566 	
1567 	   /* create zpl reader data */
1568 	   readerdata = NULL;
1569 	   reader = NULL;
1570 	   /* include zpl reader */
1571 	   SCIP_CALL( SCIPincludeReaderBasic(scip, &reader, READER_NAME, READER_DESC, READER_EXTENSION, readerdata) );
1572 	   assert(reader != NULL);
1573 	
1574 	   SCIP_CALL( SCIPsetReaderCopy(scip, reader, readerCopyZpl) );
1575 	   SCIP_CALL( SCIPsetReaderRead(scip, reader, readerReadZpl) );
1576 	
1577 	   /* add zpl reader parameters */
1578 	   SCIP_CALL( SCIPaddBoolParam(scip,
1579 	         "reading/zplreader/changedir", "should the current directory be changed to that of the ZIMPL file before parsing?",
1580 	         NULL, FALSE, TRUE, NULL, NULL) );
1581 	   SCIP_CALL( SCIPaddBoolParam(scip,
1582 	         "reading/zplreader/usestartsol", "should ZIMPL starting solutions be forwarded to SCIP?",
1583 	         NULL, FALSE, TRUE, NULL, NULL) );
1584 	   SCIP_CALL( SCIPaddStringParam(scip,
1585 	         "reading/zplreader/parameters", "additional parameter string passed to the ZIMPL parser (or - for no additional parameters)",
1586 	         NULL, FALSE, "-", NULL, NULL) );
1587 	
1588 	   (void) SCIPsnprintf(extcodename, SCIP_MAXSTRLEN, "ZIMPL %d.%d.%d", ZIMPL_VERSION/100, (ZIMPL_VERSION%100)/10, ZIMPL_VERSION%10); /*lint !e778*/
1589 	   SCIP_CALL( SCIPincludeExternalCodeInformation(scip, extcodename, "Zuse Institute Mathematical Programming Language developed by T. Koch (zimpl.zib.de)"));
1590 	#else
1591 	   assert(scip != NULL);
1592 	
1593 	   SCIPwarningMessage(scip, "SCIP does only support ZIMPL 3.4.1 and higher. Please update your ZIMPL version %d.%d.%d\n",
1594 	      ZIMPL_VERSION/100, (ZIMPL_VERSION%100)/10, ZIMPL_VERSION%10);
1595 	#endif
1596 	#endif
1597 	
1598 	   return SCIP_OKAY;
1599 	}
1600