1    	/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2    	/*                                                                           */
3    	/*                  This file is part of the class library                   */
4    	/*       SoPlex --- the Sequential object-oriented simPlex.                  */
5    	/*                                                                           */
6    	/*  Copyright (c) 1996-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 SoPlex; see the file LICENSE. If not email to soplex@zib.de.  */
22   	/*                                                                           */
23   	/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
24   	
25   	/**@file  spxlpbase_rational.hpp
26   	 * @brief Saving LPs with Rational values in a form suitable for SoPlex.
27   	 */
28   	
29   	#include <assert.h>
30   	#include <stdio.h>
31   	#include <ctype.h>
32   	#include <iostream>
33   	
34   	#include "soplex/spxdefines.h"
35   	#include "soplex/spxout.h"
36   	#include "soplex/mpsinput.h"
37   	#include "soplex/exceptions.h"
38   	#include "soplex/rational.h"
39   	
40   	#define SOPLEX_MAX_LINE_WRITE_LEN 65536   ///< maximum length allowed for writing lines
41   	
42   	namespace soplex
43   	{
44   	template<> inline
45   	void SPxLPBase<Rational>::computePrimalActivity(const VectorBase<Rational>& primal,
46   	      VectorBase<Rational>& activity, const bool unscaled) const
47   	{
48   	   if(primal.dim() != nCols())
49   	   {
50   	      throw SPxInternalCodeException("XSPXLP01 Primal vector for computing row activity has wrong dimension");
51   	   }
52   	
53   	   if(activity.dim() != nRows())
54   	   {
55   	      throw SPxInternalCodeException("XSPXLP03 Activity vector computing row activity has wrong dimension");
56   	   }
57   	
58   	   int c;
59   	
60   	   for(c = 0; c < nCols() && primal[c] == 0; c++)
61   	      ;
62   	
63   	   if(c >= nCols())
64   	   {
65   	      activity.clear();
66   	      return;
67   	   }
68   	
69   	   activity = colVector(c);
70   	
71   	   activity *= primal[c];
72   	   c++;
73   	
74   	   for(; c < nCols(); c++)
75   	   {
76   	      if(primal[c] != 0)
77   	      {
78   	         activity.multAdd(primal[c], colVector(c));
79   	      }
80   	   }
81   	}
82   	
83   	template<> inline
84   	void SPxLPBase<Rational>::computeDualActivity(const VectorBase<Rational>& dual,
85   	      VectorBase<Rational>& activity, const bool unscaled) const
86   	{
87   	   if(dual.dim() != nRows())
88   	   {
89   	      throw SPxInternalCodeException("XSPXLP02 Dual vector for computing dual activity has wrong dimension");
90   	   }
91   	
92   	   if(activity.dim() != nCols())
93   	   {
94   	      throw SPxInternalCodeException("XSPXLP04 Activity vector computing dual activity has wrong dimension");
95   	   }
96   	
97   	   int r;
98   	
99   	   for(r = 0; r < nRows() && dual[r] == 0; r++)
100  	      ;
101  	
102  	   if(r >= nRows())
103  	   {
104  	      activity.clear();
105  	      return;
106  	   }
107  	
108  	   activity = rowVector(r);
109  	
110  	   activity *= dual[r];
111  	   r++;
112  	
113  	   for(; r < nRows(); r++)
114  	   {
115  	      if(dual[r] != 0)
116  	      {
117  	         activity.multAdd(dual[r], rowVector(r));
118  	      }
119  	   }
120  	}
121  	
122  	template<> inline
123  	Rational SPxLPBase<Rational>::maxAbsNzo(bool /* unscaled */) const
124  	{
125  	   Rational maxi = Rational(0);
126  	
127  	   for(int i = 0; i < nCols(); ++i)
128  	   {
129  	      Rational m = colVector(i).maxAbs();
130  	
131  	      if(m > maxi)
132  	         maxi = m;
133  	   }
134  	
135  	   assert(maxi >= Rational(0));
136  	
137  	   return maxi;
138  	}
139  	
140  	template<> inline
141  	Rational SPxLPBase<Rational>::minAbsNzo(bool /* unscaled */) const
142  	{
143  	   Rational mini = infinity;
144  	
145  	   for(int i = 0; i < nCols(); ++i)
146  	   {
147  	      Rational m = colVector(i).minAbs();
148  	
149  	      if(m < mini)
150  	         mini = m;
151  	   }
152  	
153  	   assert(mini >= Rational(0));
154  	
155  	   return mini;
156  	}
157  	
158  	// ---------------------------------------------------------------------------------------------------------------------
159  	//  Specialization for reading LP format
160  	// ---------------------------------------------------------------------------------------------------------------------
161  	
162  	#define SOPLEX_LPF_MAX_LINE_LEN  8192     ///< maximum length of a line (8190 + \\n + \\0)
163  	
164  	/// Read the next number and advance \p pos.
165  	/** If only a sign is encountered, the number is assumed to be \c sign * 1.  This routine will not catch malformatted
166  	 *  numbers like .e10 !
167  	 */
168  	static Rational LPFreadValue(char*& pos, SPxOut* spxout, const int lineno = -1)
169  	{
170  	   assert(LPFisValue(pos));
171  	
172  	   char        tmp[SOPLEX_LPF_MAX_LINE_LEN];
173  	   const char* s = pos;
174  	   char*       t;
175  	   Rational        value = 1;
176  	   bool        has_digits = false;
177  	   bool        has_emptyexponent = false;
178  	   bool        has_dot = false;
179  	   bool        has_exponent = false;
180  	   bool        has_emptydivisor = false;
181  	
182  	   // 1. sign
183  	   if((*s == '+') || (*s == '-'))
184  	      s++;
185  	
186  	   // 2. Digits before the decimal dot
187  	   while((*s >= '0') && (*s <= '9'))
188  	   {
189  	      has_digits = true;
190  	      s++;
191  	   }
192  	
193  	   // 3. Decimal dot
194  	   if(*s == '.')
195  	   {
196  	      has_dot = true;
197  	      s++;
198  	
199  	      // 4. If there was a dot, possible digit behind it
200  	      while((*s >= '0') && (*s <= '9'))
201  	      {
202  	         has_digits = true;
203  	         s++;
204  	      }
205  	   }
206  	
207  	   // 5. Exponent
208  	   if(tolower(*s) == 'e')
209  	   {
210  	      has_exponent = true;
211  	      has_emptyexponent = true;
212  	      s++;
213  	
214  	      // 6. Exponent sign
215  	      if((*s == '+') || (*s == '-'))
216  	         s++;
217  	
218  	      // 7. Exponent digits
219  	      while((*s >= '0') && (*s <= '9'))
220  	      {
221  	         has_emptyexponent = false;
222  	         s++;
223  	      }
224  	   }
225  	
226  	   // 8. Division
227  	   if(*s == '/')
228  	   {
229  	      s++;
230  	      has_emptydivisor = true;
231  	
232  	      while((*s >= '0') && (*s <= '9'))
233  	      {
234  	         has_emptydivisor = false;
235  	         s++;
236  	      }
237  	
238  	      if(has_dot || has_exponent || has_emptydivisor ||
239  	            (*s == '.') || (*s == '+') || (*s == '-') || (tolower(*s) == 'e'))
240  	      {
241  	         SPX_MSG_WARNING((*spxout), (*spxout) << "WLPFRD03 Warning: In line " << lineno <<
242  	                         ": malformed rational value in LP file\n";)
243  	      }
244  	   }
245  	
246  	
247  	   assert(s != pos);
248  	
249  	   if(has_emptyexponent)
250  	   {
251  	      SPX_MSG_WARNING((*spxout), (*spxout) << "WLPFRD01 Warning: In line " << lineno <<
252  	                      ": found empty exponent in LP file - check for forbidden variable names with initial 'e' or 'E'\n");
253  	   }
254  	
255  	   if(!has_digits)
256  	      value = (*pos == '-') ? -1 : 1;
257  	   else
258  	   {
259  	      for(t = tmp; pos != s; pos++)
260  	         *t++ = *pos;
261  	
262  	      *t = '\0';
263  	
264  	      try
265  	      {
266  	         value = ratFromString(tmp);
267  	      }
268  	      catch(const std::exception& e)
269  	      {
270  	         SPX_MSG_WARNING((*spxout), (*spxout) << "WLPFRD04 Warning: In line " << lineno <<
271  	                         ": malformed rational value in LP file\n");
272  	         std::cerr << e.what() << '\n';
273  	      }
274  	   }
275  	
276  	   pos += s - pos;
277  	
278  	   assert(pos == s);
279  	
280  	   SPxOut::debug(spxout, "DLPFRD01 LPFreadValue = {}\n", value);
281  	
282  	   if(LPFisSpace(*pos))
283  	      pos++;
284  	
285  	   return value;
286  	}
287  	
288  	
289  	
290  	/// Read the next column name from the input.
291  	/** The name read is looked up and if not found \p emptycol
292  	 *  is added to \p colset. \p pos is advanced behind the name.
293  	 *  @return The Index of the named column.
294  	 */
295  	static int LPFreadColName(char*& pos, NameSet* colnames, LPColSetBase<Rational>& colset,
296  	                          const LPColBase<Rational>* emptycol, SPxOut* spxout)
297  	{
298  	   assert(LPFisColName(pos));
299  	   assert(colnames != 0);
300  	
301  	   char        name[SOPLEX_LPF_MAX_LINE_LEN];
302  	   const char* s = pos;
303  	   int         i;
304  	   int         colidx;
305  	
306  	   // These are the characters that are not allowed in a column name.
307  	   while((strchr("+-.<>= ", *s) == 0) && (*s != '\0'))
308  	      s++;
309  	
310  	   for(i = 0; pos != s; i++, pos++)
311  	      name[i] = *pos;
312  	
313  	   name[i] = '\0';
314  	
315  	   if((colidx = colnames->number(name)) < 0)
316  	   {
317  	      // We only add the name if we got an empty column.
318  	      if(emptycol == 0)
319  	         SPX_MSG_WARNING((*spxout), (*spxout) << "WLPFRD02 Unknown variable \"" << name << "\" ";)
320  	         else
321  	         {
322  	            colidx = colnames->num();
323  	            colnames->add(name);
324  	            colset.add(*emptycol);
325  	         }
326  	   }
327  	
328  	   SPxOut::debug(spxout, "DLPFRD03 LPFreadColName [{}] = {}\n", name, colidx);
329  	
330  	   if(LPFisSpace(*pos))
331  	      pos++;
332  	
333  	   return colidx;
334  	}
335  	
336  	static Rational LPFreadInfinity(char*& pos)
337  	{
338  	   assert(LPFisInfinity(pos));
339  	
340  	   Rational sense = (*pos == '-') ? -1 : 1;
341  	
342  	   (void) LPFhasKeyword(++pos, "inf[inity]");
343  	
344  	   sense *= Rational(infinity);
345  	   return sense;
346  	}
347  	
348  	/// Read LP in "CPLEX LP File Format".
349  	/** The specification is taken from the ILOG CPLEX 7.0 Reference Manual, Appendix E, Page 527.
350  	 *
351  	 *  This routine should read (most?) valid LP format files.  What it will not do, is find all cases where a file is ill
352  	 *  formed.  If this happens it may complain and read nothing or read "something".
353  	 *
354  	 *  Problem: A line ending in '+' or '-' followed by a line starting with a number, will be regarded as an error.
355  	 *
356  	 *  The reader will accept the keyword INT[egers] as a synonym for GEN[erals] which is an undocumented feature in CPLEX.
357  	 *
358  	 *  A difference to the CPLEX reader, is that no name for the objective row is required.
359  	 *
360  	 * The manual says the maximum allowed line length is 255 characters, but CPLEX does not complain if the lines are
361  	 * longer.
362  	 *
363  	 *  @return true if the file was read correctly
364  	 */
365  	template <> inline
366  	bool SPxLPBase<Rational>::readLPF(
367  	   std::istream& p_input,                ///< input stream.
368  	   NameSet*      p_rnames,               ///< row names.
369  	   NameSet*      p_cnames,               ///< column names.
370  	   DIdxSet*      p_intvars)              ///< integer variables.
371  	{
372  	   enum
373  	   {
374  	      START, OBJECTIVE, CONSTRAINTS, BOUNDS, INTEGERS, BINARIES
375  	   } section = START;
376  	
377  	   NameSet* rnames;                      ///< row names.
378  	   NameSet* cnames;                      ///< column names.
379  	
380  	   LPColSetBase<Rational> cset;              ///< the set of columns read.
381  	   LPRowSetBase<Rational> rset;              ///< the set of rows read.
382  	   LPColBase<Rational> emptycol;             ///< reusable empty column.
383  	   LPRowBase<Rational> row;                  ///< last assembled row.
(1) Event start: Starting defect path here.
384  	   DSVectorBase<Rational> vec;               ///< last assembled vector (from row).
385  	
386  	   Rational val = 1;
387  	   int colidx;
388  	   int sense = 0;
389  	
390  	   int lineno = 0;
391  	   bool unnamed = true;
392  	   bool finished = false;
393  	   bool other;
394  	   bool have_value = true;
395  	   int i;
396  	   int k;
397  	   int buf_size;
398  	   int buf_pos;
399  	   char* buf;
400  	   char* tmp;
401  	   char* line;
402  	   char* s;
403  	   char* pos;
404  	   char* pos_old = 0;
405  	
(2) Event cond_true: Condition "p_cnames", taking true branch.
406  	   if(p_cnames)
(3) Event if_fallthrough: Falling through to end of if statement.
407  	      cnames = p_cnames;
408  	   else
409  	   {
410  	      cnames = 0;
411  	      spx_alloc(cnames);
412  	      cnames = new(cnames) NameSet();
(4) Event if_end: End of if statement.
413  	   }
414  	
415  	   cnames->clear();
416  	
(5) Event cond_true: Condition "p_rnames", taking true branch.
417  	   if(p_rnames)
(6) Event if_fallthrough: Falling through to end of if statement.
418  	      rnames = p_rnames;
419  	   else
420  	   {
421  	      try
422  	      {
423  	         rnames = 0;
424  	         spx_alloc(rnames);
425  	         rnames = new(rnames) NameSet();
426  	      }
427  	      catch(const SPxMemoryException& x)
428  	      {
429  	         if(!p_cnames)
430  	         {
431  	            cnames->~NameSet();
432  	            spx_free(cnames);
433  	         }
434  	
435  	         throw x;
436  	      }
(7) Event if_end: End of if statement.
437  	   }
438  	
439  	   rnames->clear();
440  	
441  	   SPxLPBase<Rational>::clear(); // clear the LP.
442  	
443  	   //--------------------------------------------------------------------------
444  	   //--- Main Loop
445  	   //--------------------------------------------------------------------------
446  	   buf_size = SOPLEX_LPF_MAX_LINE_LEN;
(8) Event alloc_arg: "spx_alloc" allocates memory that is stored into "buf". [details]
Also see events: [noescape][noescape][var_assign][identity_transfer][noescape][var_assign][leaked_storage][leaked_storage][leaked_storage]
447  	   spx_alloc(buf, buf_size);
448  	   spx_alloc(tmp, buf_size);
449  	   spx_alloc(line, buf_size);
450  	
451  	   for(;;)
452  	   {
453  	      buf_pos = 0;
454  	
(9) Event noescape: Resource "buf + buf_pos" is not freed or pointed-to in "getline". [Note: The source code implementation of the function has been overridden by a builtin model.]
(10) Event cond_true: Condition "!p_input->getline(buf + buf_pos, buf_size - buf_pos)", taking true branch.
Also see events: [alloc_arg][noescape][var_assign][identity_transfer][noescape][var_assign][leaked_storage][leaked_storage][leaked_storage]
455  	      while(!p_input.getline(buf + buf_pos, buf_size - buf_pos))
456  	      {
457  	         p_input.clear();
458  	
(11) Event noescape: Resource "buf" is not freed or pointed-to in "strlen".
(12) Event cond_false: Condition "strlen(buf) == (size_t)buf_size - 1", taking false branch.
Also see events: [alloc_arg][noescape][var_assign][identity_transfer][noescape][var_assign][leaked_storage][leaked_storage][leaked_storage]
459  	         if(strlen(buf) == (size_t) buf_size - 1)
460  	         {
461  	            buf_pos = buf_size - 1;
462  	            buf_size = buf_size + SOPLEX_LPF_MAX_LINE_LEN;
463  	
464  	            if(buf_size >= INT_MAX)
465  	            {
466  	               SPX_MSG_ERROR(std::cerr << "ELPFRD16 Line longer than INT_MAX" << std::endl;)
467  	               finished = true;
468  	               break;
469  	            }
470  	
471  	            spx_realloc(buf, buf_size);
472  	         }
473  	         else
(13) Event else_branch: Reached else branch.
474  	         {
475  	            SPX_MSG_ERROR(std::cerr << "ELPFRD07 No 'End' marker found" << std::endl;)
476  	            finished = true;
(14) Event break: Breaking from loop.
477  	            break;
478  	         }
(15) Event loop_end: Reached end of loop.
479  	      }
480  	
(16) Event cond_true: Condition "(size_t)buf_size > 8UL /* sizeof (tmp) */", taking true branch.
481  	      if((size_t) buf_size > sizeof(tmp))
482  	      {
483  	         spx_realloc(tmp, buf_size);
484  	         spx_realloc(line, buf_size);
485  	      }
486  	
487  	      lineno++;
488  	      i   = 0;
(17) Event var_assign: Assigning: "pos" = "buf".
Also see events: [alloc_arg][noescape][noescape][identity_transfer][noescape][var_assign][leaked_storage][leaked_storage][leaked_storage]
489  	      pos = buf;
490  	
491  	      SPxOut::debug(spxout, "DLPFRD08 Reading line {} (pos={})\n", lineno, pos);
492  	
493  	      // 1. Remove comments.
(18) Event identity_transfer: Passing "buf" as argument 1 to function "strchr", which returns an offset off that argument. [Note: The source code implementation of the function has been overridden by a builtin model.]
(19) Event noescape: Resource "buf" is not freed or pointed-to in "strchr". [Note: The source code implementation of the function has been overridden by a builtin model.]
(20) Event var_assign: Assigning: "s" = storage returned from "strchr(buf, 92)".
(21) Event cond_true: Condition "NULL != (s = strchr(buf, '\\'))", taking true branch.
Also see events: [alloc_arg][noescape][noescape][var_assign][leaked_storage][leaked_storage][leaked_storage]
494  	      if(0 != (s = strchr(buf, '\\')))
495  	         * s = '\0';
496  	
497  	      // 2. Look for keywords.
(22) Event cond_false: Condition "section == START", taking false branch.
498  	      if(section == START)
499  	      {
500  	         if(LPFhasKeyword(pos, "max[imize]"))
501  	         {
502  	            changeSense(SPxLPBase<Rational>::MAXIMIZE);
503  	            section = OBJECTIVE;
504  	         }
505  	         else if(LPFhasKeyword(pos, "min[imize]"))
506  	         {
507  	            changeSense(SPxLPBase<Rational>::MINIMIZE);
508  	            section = OBJECTIVE;
509  	         }
510  	      }
(23) Event else_branch: Reached else branch.
(24) Event cond_false: Condition "section == OBJECTIVE", taking false branch.
511  	      else if(section == OBJECTIVE)
512  	      {
513  	         if(LPFhasKeyword(pos, "s[ubject][   ]t[o]")
514  	               || LPFhasKeyword(pos, "s[uch][    ]t[hat]")
515  	               || LPFhasKeyword(pos, "s[.][    ]t[.]")
516  	               || LPFhasKeyword(pos, "lazy con[straints]"))
517  	         {
518  	            // store objective vector
519  	            for(int j = vec.size() - 1; j >= 0; --j)
520  	               cset.maxObj_w(vec.index(j)) = vec.value(j);
521  	
522  	            // multiplication with -1 for minimization is done below
523  	            vec.clear();
524  	            have_value = true;
525  	            val = 1;
526  	            section = CONSTRAINTS;
527  	         }
528  	      }
(25) Event else_branch: Reached else branch.
(26) Event cond_true: Condition "section == CONSTRAINTS", taking true branch.
(27) Event cond_false: Condition "soplex::LPFhasKeyword(pos, "s[ubject][ ]t[o]")", taking false branch.
(28) Event cond_false: Condition "soplex::LPFhasKeyword(pos, "s[uch][ ]t[hat]")", taking false branch.
(29) Event cond_false: Condition "soplex::LPFhasKeyword(pos, "s[.][ ]t[.]")", taking false branch.
529  	      else if(section == CONSTRAINTS &&
530  	              (LPFhasKeyword(pos, "s[ubject][   ]t[o]")
531  	               || LPFhasKeyword(pos, "s[uch][    ]t[hat]")
532  	               || LPFhasKeyword(pos, "s[.][    ]t[.]")))
533  	      {
534  	         have_value = true;
535  	         val = 1;
536  	      }
537  	      else
(30) Event else_branch: Reached else branch.
538  	      {
(31) Event cond_false: Condition "soplex::LPFhasKeyword(pos, "lazy con[straints]")", taking false branch.
539  	         if(LPFhasKeyword(pos, "lazy con[straints]"))
540  	            ;
(32) Event else_branch: Reached else branch.
(33) Event cond_false: Condition "soplex::LPFhasKeyword(pos, "bound[s]")", taking false branch.
541  	         else if(LPFhasKeyword(pos, "bound[s]"))
542  	            section = BOUNDS;
(34) Event else_branch: Reached else branch.
(35) Event cond_false: Condition "soplex::LPFhasKeyword(pos, "bin[ary]")", taking false branch.
543  	         else if(LPFhasKeyword(pos, "bin[ary]"))
544  	            section = BINARIES;
(36) Event else_branch: Reached else branch.
(37) Event cond_false: Condition "soplex::LPFhasKeyword(pos, "bin[aries]")", taking false branch.
545  	         else if(LPFhasKeyword(pos, "bin[aries]"))
546  	            section = BINARIES;
(38) Event else_branch: Reached else branch.
(39) Event cond_false: Condition "soplex::LPFhasKeyword(pos, "gen[erals]")", taking false branch.
547  	         else if(LPFhasKeyword(pos, "gen[erals]"))
548  	            section = INTEGERS;
(40) Event else_branch: Reached else branch.
(41) Event cond_false: Condition "soplex::LPFhasKeyword(pos, "int[egers]")", taking false branch.
549  	         else if(LPFhasKeyword(pos, "int[egers]"))   // this is undocumented
550  	            section = INTEGERS;
(42) Event else_branch: Reached else branch.
(43) Event cond_true: Condition "soplex::LPFhasKeyword(pos, "end")", taking true branch.
551  	         else if(LPFhasKeyword(pos, "end"))
552  	         {
553  	            finished = true;
(44) Event break: Breaking from loop.
554  	            break;
555  	         }
556  	         else if(LPFhasKeyword(pos, "s[ubject][   ]t[o]")  // second time
557  	                 || LPFhasKeyword(pos, "s[uch][    ]t[hat]")
558  	                 || LPFhasKeyword(pos, "s[.][    ]t[.]")
559  	                 || LPFhasKeyword(pos, "lazy con[straints]"))
560  	         {
561  	            // In principle this has to checked for all keywords above,
562  	            // otherwise we just ignore any half finished constraint
563  	            if(have_value)
564  	               goto syntax_error;
565  	
566  	            have_value = true;
567  	            val = 1;
568  	         }
569  	      }
570  	
571  	      // 3a. Look for row names in objective and drop it.
572  	      if(section == OBJECTIVE)
573  	         LPFhasRowName(pos, 0);
574  	
575  	      // 3b. Look for row name in constraint and store it.
576  	      if(section == CONSTRAINTS)
577  	         if(LPFhasRowName(pos, rnames))
578  	            unnamed = false;
579  	
580  	      // 4a. Remove initial spaces.
581  	      while(LPFisSpace(pos[i]))
582  	         i++;
583  	
584  	      // 4b. remove spaces if they do not appear before the name of a vaiable.
585  	      for(k = 0; pos[i] != '\0'; i++)
586  	         if(!LPFisSpace(pos[i]) || LPFisColName(&pos[i + 1]))
587  	            tmp[k++] = pos[i];
588  	
589  	      tmp[k] = '\0';
590  	
591  	      // 5. Is this an empty line ?
592  	      if(tmp[0] == '\0')
593  	         continue;
594  	
595  	      // 6. Collapse sequences of '+' and '-'. e.g ++---+ => -
596  	      for(i = 0, k = 0; tmp[i] != '\0'; i++)
597  	      {
598  	         while(((tmp[i] == '+') || (tmp[i] == '-')) && ((tmp[i + 1] == '+') || (tmp[i + 1] == '-')))
599  	         {
600  	            if(tmp[i++] == '-')
601  	               tmp[i] = (tmp[i] == '-') ? '+' : '-';
602  	         }
603  	
604  	         line[k++] = tmp[i];
605  	      }
606  	
607  	      line[k] = '\0';
608  	
609  	      //-----------------------------------------------------------------------
610  	      //--- Line processing loop
611  	      //-----------------------------------------------------------------------
612  	      pos = line;
613  	
614  	      SPxOut::debug(spxout, "DLPFRD09 pos= {}\n", pos);
615  	
616  	      // 7. We have something left to process.
617  	      while((pos != 0) && (*pos != '\0'))
618  	      {
619  	         // remember our position, so we are sure we make progress.
620  	         pos_old = pos;
621  	
622  	         // now process the sections
623  	         switch(section)
624  	         {
625  	         case OBJECTIVE:
626  	            if(LPFisValue(pos))
627  	            {
628  	               Rational pre_sign = 1;
629  	
630  	               /* Already having here a value could only result from being the first number in a constraint, or a sign
631  	                * '+' or '-' as last token on the previous line.
632  	                */
633  	               if(have_value)
634  	               {
635  	                  if(spxAbs(val) != 1)
636  	                     goto syntax_error;
637  	
638  	                  if(val == -1)
639  	                     pre_sign = val;
640  	               }
641  	
642  	               have_value = true;
643  	               val = LPFreadValue(pos, spxout, lineno);
644  	               val *= pre_sign;
645  	            }
646  	
647  	            if(*pos == '\0')
648  	               continue;
649  	
650  	            if(!have_value || !LPFisColName(pos))
651  	               goto syntax_error;
652  	
653  	            have_value = false;
654  	            colidx = LPFreadColName(pos, cnames, cset, &emptycol, spxout);
655  	            vec.add(colidx, val);
656  	            break;
657  	
658  	         case CONSTRAINTS:
659  	            if(LPFisValue(pos))
660  	            {
661  	               Rational pre_sign = 1;
662  	
663  	               /* Already having here a value could only result from being the first number in a constraint, or a sign
664  	                * '+' or '-' as last token on the previous line.
665  	                */
666  	               if(have_value)
667  	               {
668  	                  if(spxAbs(val) != 1)
669  	                     goto syntax_error;
670  	
671  	                  if(val == -1)
672  	                     pre_sign = val;
673  	               }
674  	
675  	               have_value = true;
676  	               val = LPFreadValue(pos, spxout, lineno);
677  	               val *= pre_sign;
678  	
679  	               if(sense != 0)
680  	               {
681  	                  if(sense == '<')
682  	                  {
683  	                     row.setLhs(-infinity);
684  	                     row.setRhs(val);
685  	                  }
686  	                  else if(sense == '>')
687  	                  {
688  	                     row.setLhs(val);
689  	                     row.setRhs(infinity);
690  	                  }
691  	                  else
692  	                  {
693  	                     assert(sense == '=');
694  	
695  	                     row.setLhs(val);
696  	                     row.setRhs(val);
697  	                  }
698  	
699  	                  row.setRowVector(vec);
700  	                  rset.add(row);
701  	                  vec.clear();
702  	
703  	                  if(!unnamed)
704  	                     unnamed = true;
705  	                  else
706  	                  {
707  	                     char name[16];
708  	                     spxSnprintf(name, 16, "C%d", rset.num());
709  	                     rnames->add(name);
710  	                  }
711  	
712  	                  have_value = true;
713  	                  val = 1;
714  	                  sense = 0;
715  	                  pos = 0;
716  	                  // next line
717  	                  continue;
718  	               }
719  	            }
720  	
721  	            if(*pos == '\0')
722  	               continue;
723  	
724  	            if(have_value)
725  	            {
726  	               if(LPFisColName(pos))
727  	               {
728  	                  colidx = LPFreadColName(pos, cnames, cset, &emptycol, spxout);
729  	
730  	                  if(val != 0)
731  	                  {
732  	                     // Do we have this index already in the row?
733  	                     int n = vec.pos(colidx);
734  	
735  	                     // if not, add it
736  	                     if(n < 0)
737  	                        vec.add(colidx, val);
738  	                     // if yes, add them up and remove the element if it amounts to zero
739  	                     else
740  	                     {
741  	                        assert(vec.index(n) == colidx);
742  	
743  	                        val += vec.value(n);
744  	
745  	                        if(val == 0)
746  	                           vec.remove(n);
747  	                        else
748  	                           vec.value(n) = val;
749  	
750  	                        assert(cnames->has(colidx));
751  	
752  	                        SPX_MSG_WARNING((*this->spxout), (*this->spxout) << "WLPFRD10 Duplicate index "
753  	                                        << (*cnames)[colidx]
754  	                                        << " in line " << lineno
755  	                                        << std::endl;)
756  	                     }
757  	                  }
758  	
759  	                  have_value = false;
760  	               }
761  	               else
762  	               {
763  	                  // We have a row like c1: <= 5 with no variables. We can not handle 10 <= 5; issue a syntax error.
764  	                  if(val != 1)
765  	                     goto syntax_error;
766  	
767  	                  // If the next thing is not the sense we give up also.
768  	                  if(!LPFisSense(pos))
769  	                     goto syntax_error;
770  	
771  	                  have_value = false;
772  	               }
773  	            }
774  	
775  	            assert(!have_value);
776  	
777  	            if(LPFisSense(pos))
778  	               sense = LPFreadSense(pos);
779  	
780  	            break;
781  	
782  	         case BOUNDS:
783  	            other = false;
784  	            sense = 0;
785  	
786  	            if(LPFisValue(pos))
787  	            {
788  	               val = LPFisInfinity(pos) ? LPFreadInfinity(pos) : LPFreadValue(pos, spxout, lineno);
789  	
790  	               if(!LPFisSense(pos))
791  	                  goto syntax_error;
792  	
793  	               sense = LPFreadSense(pos);
794  	               other = true;
795  	            }
796  	
797  	            if(!LPFisColName(pos))
798  	               goto syntax_error;
799  	
800  	            if((colidx = LPFreadColName(pos, cnames, cset, 0, spxout)) < 0)
801  	            {
802  	               SPX_MSG_WARNING((*this->spxout), (*this->spxout) << "WLPFRD11 in Bounds section line "
803  	                               << lineno << " ignored" << std::endl;)
804  	               *pos = '\0';
805  	               continue;
806  	            }
807  	
808  	            if(sense)
809  	            {
810  	               if(sense == '<')
811  	                  cset.lower_w(colidx) = val;
812  	               else if(sense == '>')
813  	                  cset.upper_w(colidx) = val;
814  	               else
815  	               {
816  	                  assert(sense == '=');
817  	                  cset.lower_w(colidx) = val;
818  	                  cset.upper_w(colidx) = val;
819  	               }
820  	            }
821  	
822  	            if(LPFisFree(pos))
823  	            {
824  	               cset.lower_w(colidx) = -infinity;
825  	               cset.upper_w(colidx) =  infinity;
826  	               other = true;
827  	               pos += 4;  // set position after the word "free"
828  	            }
829  	            else if(LPFisSense(pos))
830  	            {
831  	               sense = LPFreadSense(pos);
832  	               other = true;
833  	
834  	               if(!LPFisValue(pos))
835  	                  goto syntax_error;
836  	
837  	               val = LPFisInfinity(pos) ? LPFreadInfinity(pos) : LPFreadValue(pos,  spxout, lineno);
838  	
839  	               if(sense == '<')
840  	                  cset.upper_w(colidx) = val;
841  	               else if(sense == '>')
842  	                  cset.lower_w(colidx) = val;
843  	               else
844  	               {
845  	                  assert(sense == '=');
846  	                  cset.lower_w(colidx) = val;
847  	                  cset.upper_w(colidx) = val;
848  	               }
849  	            }
850  	
851  	            /* Do we have only a single column name in the input line?  We could ignore this savely, but it is probably
852  	             * a sign of some other error.
853  	             */
854  	            if(!other)
855  	               goto syntax_error;
856  	
857  	            break;
858  	
859  	         case BINARIES:
860  	         case INTEGERS:
861  	            if((colidx = LPFreadColName(pos, cnames, cset, 0, spxout)) < 0)
862  	            {
863  	               SPX_MSG_WARNING((*this->spxout),
864  	                               (*this->spxout) << "WLPFRD12 in Binary/General section line " << lineno
865  	                               << " ignored" << std::endl;)
866  	            }
867  	            else
868  	            {
869  	               if(section == BINARIES)
870  	               {
871  	                  if(cset.lower(colidx) < 0)
872  	                  {
873  	                     cset.lower_w(colidx) = 0;
874  	                  }
875  	
876  	                  if(cset.upper(colidx) > 1)
877  	                  {
878  	                     cset.upper_w(colidx) = 1;
879  	                  }
880  	               }
881  	
882  	               if(p_intvars != 0)
883  	                  p_intvars->addIdx(colidx);
884  	            }
885  	
886  	            break;
887  	
888  	         case START:
889  	            SPX_MSG_ERROR(std::cerr << "ELPFRD13 This seems to be no LP format file" << std::endl;)
890  	            goto syntax_error;
891  	
892  	         default:
893  	            throw SPxInternalCodeException("XLPFRD01 This should never happen.");
894  	         }
895  	
896  	         if(pos == pos_old)
897  	            goto syntax_error;
898  	      }
(45) Event loop_end: Reached end of loop.
899  	   }
900  	
901  	   assert(isConsistent());
902  	
903  	   addCols(cset);
904  	   assert(isConsistent());
905  	
906  	   addRows(rset);
907  	   assert(isConsistent());
908  	
909  	syntax_error:
910  	
(46) Event cond_true: Condition "finished", taking true branch.
911  	   if(finished)
912  	   {
(47) Event cond_true: Condition "this->spxout != NULL", taking true branch.
(48) Event cond_true: Condition "soplex::SPxOut::INFO2 <= this->spxout->getVerbosity()", taking true branch.
913  	      SPX_MSG_INFO2((*this->spxout), (*this->spxout) << "Finished reading " << lineno << " lines" <<
914  	                    std::endl;)
(49) Event if_fallthrough: Falling through to end of if statement.
915  	   }
916  	   else
(50) Event if_end: End of if statement.
917  	      SPX_MSG_ERROR(std::cerr << "ELPFRD15 Syntax error in line " << lineno << std::endl;)
918  	
(51) Event cond_false: Condition "p_cnames == NULL", taking false branch.
919  	      if(p_cnames == 0)
(52) Event if_end: End of if statement.
920  	         spx_free(cnames);
921  	
(53) Event cond_false: Condition "p_rnames == NULL", taking false branch.
922  	   if(p_rnames == 0)
(54) Event if_end: End of if statement.
923  	      spx_free(rnames);
924  	
(55) Event leaked_storage: Variable "pos" going out of scope leaks the storage it points to.
(56) Event leaked_storage: Variable "s" going out of scope leaks the storage it points to.
(57) Event leaked_storage: Variable "buf" going out of scope leaks the storage it points to.
Also see events: [alloc_arg][noescape][noescape][var_assign][identity_transfer][noescape][var_assign]
925  	   return finished;
926  	}
927  	
928  	/// Process ROWS section.
929  	static void MPSreadRows(MPSInput& mps, LPRowSetBase<Rational>& rset, NameSet& rnames,
930  	                        SPxOut* spxout)
931  	{
932  	   LPRowBase<Rational> row;
933  	
934  	   while(mps.readLine())
935  	   {
936  	      if(mps.field0() != 0)
937  	      {
938  	         SPX_MSG_INFO2((*spxout), (*spxout) << "IMPSRD02 Objective name : " << mps.objName() << std::endl;)
939  	
940  	         if(strcmp(mps.field0(), "COLUMNS"))
941  	            break;
942  	
943  	         mps.setSection(MPSInput::COLUMNS);
944  	
945  	         return;
946  	      }
947  	
948  	      if(*mps.field1() == 'N')
949  	      {
950  	         if(*mps.objName() == '\0')
951  	            mps.setObjName(mps.field2());
952  	      }
953  	      else
954  	      {
955  	         if(rnames.has(mps.field2()))
956  	            break;
957  	
958  	         rnames.add(mps.field2());
959  	
960  	         switch(*mps.field1())
961  	         {
962  	         case 'G':
963  	            row.setLhs(0);
964  	            row.setRhs(infinity);
965  	            break;
966  	
967  	         case 'E':
968  	            row.setLhs(0);
969  	            row.setRhs(0);
970  	            break;
971  	
972  	         case 'L':
973  	            row.setLhs(-infinity);
974  	            row.setRhs(0);
975  	            break;
976  	
977  	         default:
978  	            mps.syntaxError();
979  	            return;
980  	         }
981  	
982  	         rset.add(row);
983  	      }
984  	
985  	      assert((*mps.field1() == 'N') || (rnames.number(mps.field2()) == rset.num() - 1));
986  	   }
987  	
988  	   mps.syntaxError();
989  	}
990  	
991  	
992  	
993  	/// Process COLUMNS section.
994  	static void MPSreadCols(MPSInput& mps, const LPRowSetBase<Rational>& rset, const NameSet&  rnames,
995  	                        LPColSetBase<Rational>& cset, NameSet& cnames, DIdxSet* intvars, SPxOut* spxout)
996  	{
997  	   Rational val;
998  	   int idx;
999  	   char colname[MPSInput::MAX_LINE_LEN] = { '\0' };
1000 	   LPColBase<Rational> col(rset.num());
1001 	   DSVectorBase<Rational> vec;
1002 	
1003 	   col.setObj(0);
1004 	   vec.clear();
1005 	
1006 	   while(mps.readLine())
1007 	   {
1008 	      if(mps.field0() != 0)
1009 	      {
1010 	         if(strcmp(mps.field0(), "RHS"))
1011 	            break;
1012 	
1013 	         if(colname[0] != '\0')
1014 	         {
1015 	            col.setColVector(vec);
1016 	            cset.add(col);
1017 	         }
1018 	
1019 	         mps.setSection(MPSInput::RHS);
1020 	
1021 	         return;
1022 	      }
1023 	
1024 	      if((mps.field1() == 0) || (mps.field2() == 0) || (mps.field3() == 0))
1025 	         break;
1026 	
1027 	      // new column?
1028 	      if(strcmp(colname, mps.field1()))
1029 	      {
1030 	         // first column?
1031 	         if(colname[0] != '\0')
1032 	         {
1033 	            col.setColVector(vec);
1034 	            cset.add(col);
1035 	         }
1036 	
1037 	         // save copy of string (make sure string ends with \0)
1038 	         spxSnprintf(colname, MPSInput::MAX_LINE_LEN - 1, "%s", mps.field1());
1039 	         colname[MPSInput::MAX_LINE_LEN - 1] = '\0';
1040 	
1041 	         int ncnames = cnames.size();
1042 	         cnames.add(colname);
1043 	
1044 	         // check whether the new name is unique wrt previous column names
1045 	         if(cnames.size() <= ncnames)
1046 	         {
1047 	            SPX_MSG_ERROR(std::cerr << "ERROR in COLUMNS: duplicate column name or not column-wise ordering" <<
1048 	                          std::endl;)
1049 	            break;
1050 	         }
1051 	
1052 	         vec.clear();
1053 	         col.setObj(0);
1054 	         col.setLower(0);
1055 	         col.setUpper(infinity);
1056 	
1057 	         if(mps.isInteger())
1058 	         {
1059 	            assert(cnames.number(colname) == cset.num());
1060 	
1061 	            if(intvars != 0)
1062 	               intvars->addIdx(cnames.number(colname));
1063 	
1064 	            // for Integer variable the default bounds are 0/1
1065 	            col.setUpper(1);
1066 	         }
1067 	      }
1068 	
1069 	      try
1070 	      {
1071 	         val = ratFromString(mps.field3());
1072 	      }
1073 	      catch(const std::exception& e)
1074 	      {
1075 	         SPX_MSG_WARNING((*spxout), (*spxout) << "WMPSRD01 Warning: malformed rational value in MPS file\n");
1076 	         std::cerr << e.what() << '\n';
1077 	      }
1078 	
1079 	      if(!strcmp(mps.field2(), mps.objName()))
1080 	         col.setObj(val);
1081 	      else
1082 	      {
1083 	         if((idx = rnames.number(mps.field2())) < 0)
1084 	            mps.entryIgnored("Column", mps.field1(), "row", mps.field2());
1085 	         else if(val != 0)
1086 	            vec.add(idx, val);
1087 	      }
1088 	
1089 	      if(mps.field5() != 0)
1090 	      {
1091 	         assert(mps.field4() != 0);
1092 	
1093 	         try
1094 	         {
1095 	            val = ratFromString(mps.field5());
1096 	         }
1097 	         catch(const std::exception& e)
1098 	         {
1099 	            SPX_MSG_WARNING((*spxout), (*spxout) << "WMPSRD02 Warning: malformed rational value in MPS file\n");
1100 	            std::cerr << e.what() << '\n';
1101 	         }
1102 	
1103 	         if(!strcmp(mps.field4(), mps.objName()))
1104 	            col.setObj(val);
1105 	         else
1106 	         {
1107 	            if((idx = rnames.number(mps.field4())) < 0)
1108 	               mps.entryIgnored("Column", mps.field1(), "row", mps.field4());
1109 	            else if(val != 0)
1110 	               vec.add(idx, val);
1111 	         }
1112 	      }
1113 	   }
1114 	
1115 	   mps.syntaxError();
1116 	}
1117 	
1118 	
1119 	
1120 	/// Process RHS section.
1121 	static void MPSreadRhs(MPSInput& mps, LPRowSetBase<Rational>& rset, const NameSet& rnames,
1122 	                       SPxOut* spxout)
1123 	{
1124 	   char rhsname[MPSInput::MAX_LINE_LEN] = { '\0' };
1125 	   char addname[MPSInput::MAX_LINE_LEN] = { '\0' };
1126 	   int idx;
1127 	   Rational val;
1128 	
1129 	   while(mps.readLine())
1130 	   {
1131 	      if(mps.field0() != 0)
1132 	      {
1133 	         SPX_MSG_INFO2((*spxout), (*spxout) << "IMPSRD03 RHS name       : " << rhsname  << std::endl;);
1134 	
1135 	         if(!strcmp(mps.field0(), "RANGES"))
1136 	            mps.setSection(MPSInput::RANGES);
1137 	         else if(!strcmp(mps.field0(), "BOUNDS"))
1138 	            mps.setSection(MPSInput::BOUNDS);
1139 	         else if(!strcmp(mps.field0(), "ENDATA"))
1140 	            mps.setSection(MPSInput::ENDATA);
1141 	         else
1142 	            break;
1143 	
1144 	         return;
1145 	      }
1146 	
1147 	      if(((mps.field2() != 0) && (mps.field3() == 0)) || ((mps.field4() != 0) && (mps.field5() == 0)))
1148 	         mps.insertName("_RHS_");
1149 	
1150 	      if((mps.field1() == 0) || (mps.field2() == 0) || (mps.field3() == 0))
1151 	         break;
1152 	
1153 	      if(*rhsname == '\0')
1154 	         spxSnprintf(rhsname, MPSInput::MAX_LINE_LEN, "%s", mps.field1());
1155 	
1156 	      if(strcmp(rhsname, mps.field1()))
1157 	      {
1158 	         if(strcmp(addname, mps.field1()))
1159 	         {
1160 	            assert(strlen(mps.field1()) < MPSInput::MAX_LINE_LEN);
1161 	            spxSnprintf(addname, MPSInput::MAX_LINE_LEN, "%s", mps.field1());
1162 	            SPX_MSG_INFO3((*spxout), (*spxout) << "IMPSRD07 RHS ignored    : " << addname << std::endl);
1163 	         }
1164 	      }
1165 	      else
1166 	      {
1167 	         if((idx = rnames.number(mps.field2())) < 0)
1168 	            mps.entryIgnored("RHS", mps.field1(), "row", mps.field2());
1169 	         else
1170 	         {
1171 	            try
1172 	            {
1173 	               val = ratFromString(mps.field3());
1174 	            }
1175 	            catch(const std::exception& e)
1176 	            {
1177 	               SPX_MSG_WARNING((*spxout), (*spxout) << "WMPSRD03 Warning: malformed rational value in MPS file\n");
1178 	               std::cerr << e.what() << '\n';
1179 	            }
1180 	
1181 	            // LE or EQ
1182 	            if(double(rset.rhs(idx)) < double(infinity))
1183 	               rset.rhs_w(idx) = val;
1184 	
1185 	            // GE or EQ
1186 	            if(double(rset.lhs(idx)) > double(-infinity))
1187 	               rset.lhs_w(idx) = val;
1188 	         }
1189 	
1190 	         if(mps.field5() != 0)
1191 	         {
1192 	            if((idx = rnames.number(mps.field4())) < 0)
1193 	               mps.entryIgnored("RHS", mps.field1(), "row", mps.field4());
1194 	            else
1195 	            {
1196 	               try
1197 	               {
1198 	                  val = ratFromString(mps.field5());
1199 	               }
1200 	               catch(const std::exception& e)
1201 	               {
1202 	                  SPX_MSG_WARNING((*spxout), (*spxout) << "WMPSRD04 Warning: malformed rational value in MPS file\n");
1203 	                  std::cerr << e.what() << '\n';
1204 	               }
1205 	
1206 	               // LE or EQ
1207 	               if(double(rset.rhs(idx)) < double(infinity))
1208 	                  rset.rhs_w(idx) = val;
1209 	
1210 	               // GE or EQ
1211 	               if(double(rset.lhs(idx)) > double(-infinity))
1212 	                  rset.lhs_w(idx) = val;
1213 	            }
1214 	         }
1215 	      }
1216 	   }
1217 	
1218 	   mps.syntaxError();
1219 	}
1220 	
1221 	
1222 	
1223 	/// Process RANGES section.
1224 	static void MPSreadRanges(MPSInput& mps,  LPRowSetBase<Rational>& rset, const NameSet& rnames,
1225 	                          SPxOut* spxout)
1226 	{
1227 	   char rngname[MPSInput::MAX_LINE_LEN] = { '\0' };
1228 	   int idx;
1229 	   Rational val;
1230 	
1231 	   while(mps.readLine())
1232 	   {
1233 	      if(mps.field0() != 0)
1234 	      {
1235 	         SPX_MSG_INFO2((*spxout), (*spxout) << "IMPSRD04 Range name     : " << rngname << std::endl;);
1236 	
1237 	         if(!strcmp(mps.field0(), "BOUNDS"))
1238 	            mps.setSection(MPSInput::BOUNDS);
1239 	         else if(!strcmp(mps.field0(), "ENDATA"))
1240 	            mps.setSection(MPSInput::ENDATA);
1241 	         else
1242 	            break;
1243 	
1244 	         return;
1245 	      }
1246 	
1247 	      if(((mps.field2() != 0) && (mps.field3() == 0)) || ((mps.field4() != 0) && (mps.field5() == 0)))
1248 	         mps.insertName("_RNG_");
1249 	
1250 	      if((mps.field1() == 0) || (mps.field2() == 0) || (mps.field3() == 0))
1251 	         break;
1252 	
1253 	      if(*rngname == '\0')
1254 	      {
1255 	         assert(strlen(mps.field1()) < MPSInput::MAX_LINE_LEN);
1256 	         spxSnprintf(rngname, MPSInput::MAX_LINE_LEN, "%s", mps.field1());
1257 	      }
1258 	
1259 	      /* The rules are:
1260 	       * Row Sign   LHS             RHS
1261 	       * ----------------------------------------
1262 	       *  G   +/-   rhs             rhs + |range|
1263 	       *  L   +/-   rhs - |range|   rhs
1264 	       *  E   +     rhs             rhs + range
1265 	       *  E   -     rhs + range     rhs
1266 	       * ----------------------------------------
1267 	       */
1268 	      if(!strcmp(rngname, mps.field1()))
1269 	      {
1270 	         if((idx = rnames.number(mps.field2())) < 0)
1271 	            mps.entryIgnored("Range", mps.field1(), "row", mps.field2());
1272 	         else
1273 	         {
1274 	            try
1275 	            {
1276 	               val = ratFromString(mps.field3());
1277 	            }
1278 	            catch(const std::exception& e)
1279 	            {
1280 	               SPX_MSG_WARNING((*spxout), (*spxout) << "WMPSRD05 Warning: malformed rational value in MPS file\n");
1281 	               std::cerr << e.what() << '\n';
1282 	            }
1283 	
1284 	            // EQ
1285 	            if((double(rset.lhs(idx)) > -double(infinity)) && (double(rset.rhs_w(idx)) < double(infinity)))
1286 	            {
1287 	               assert(rset.lhs(idx) == rset.rhs(idx));
1288 	
1289 	               if(double(val) >= 0)
1290 	                  rset.rhs_w(idx) += val;
1291 	               else
1292 	                  rset.lhs_w(idx) += val;
1293 	            }
1294 	            else
1295 	            {
1296 	               // GE
1297 	               if(double(rset.lhs(idx)) > -double(infinity))
1298 	               {
1299 	                  rset.rhs_w(idx) = rset.lhs(idx);
1300 	                  rset.rhs_w(idx) += spxAbs(val);
1301 	               }
1302 	               // LE
1303 	               else
1304 	               {
1305 	                  rset.lhs_w(idx) = rset.rhs(idx);
1306 	                  rset.lhs_w(idx) -= spxAbs(val);
1307 	               }
1308 	            }
1309 	         }
1310 	
1311 	         if(mps.field5() != 0)
1312 	         {
1313 	            if((idx = rnames.number(mps.field4())) < 0)
1314 	               mps.entryIgnored("Range", mps.field1(), "row", mps.field4());
1315 	            else
1316 	            {
1317 	               try
1318 	               {
1319 	                  val = ratFromString(mps.field5());
1320 	               }
1321 	               catch(const std::exception& e)
1322 	               {
1323 	                  SPX_MSG_WARNING((*spxout), (*spxout) << "WMPSRD06 Warning: malformed rational value in MPS file\n");
1324 	                  std::cerr << e.what() << '\n';
1325 	               }
1326 	
1327 	               // EQ
1328 	               if((double(rset.lhs(idx)) > -double(infinity)) && (double(rset.rhs(idx)) <  double(infinity)))
1329 	               {
1330 	                  assert(rset.lhs(idx) == rset.rhs(idx));
1331 	
1332 	                  if(double(val) >= 0)
1333 	                     rset.rhs_w(idx) += val;
1334 	                  else
1335 	                     rset.lhs_w(idx) += val;
1336 	               }
1337 	               else
1338 	               {
1339 	                  // GE
1340 	                  if(double(rset.lhs(idx)) > -double(infinity))
1341 	                  {
1342 	                     rset.rhs_w(idx) = rset.lhs(idx);
1343 	                     rset.rhs_w(idx) += spxAbs(val);
1344 	                  }
1345 	                  // LE
1346 	                  else
1347 	                  {
1348 	                     rset.lhs_w(idx) = rset.rhs(idx);
1349 	                     rset.lhs_w(idx) -= spxAbs(val);
1350 	                  }
1351 	               }
1352 	            }
1353 	         }
1354 	      }
1355 	   }
1356 	
1357 	   mps.syntaxError();
1358 	}
1359 	
1360 	
1361 	
1362 	/// Process BOUNDS section.
1363 	static void MPSreadBounds(MPSInput& mps, LPColSetBase<Rational>& cset, const NameSet& cnames,
1364 	                          DIdxSet* intvars, SPxOut* spxout)
1365 	{
1366 	   DIdxSet oldbinvars;
1367 	   char bndname[MPSInput::MAX_LINE_LEN] = { '\0' };
1368 	   int  idx;
1369 	   Rational val;
1370 	
1371 	   while(mps.readLine())
1372 	   {
1373 	      if(mps.field0() != 0)
1374 	      {
1375 	         SPX_MSG_INFO2((*spxout), (*spxout) << "IMPSRD05 Bound name     : " << bndname << std::endl;)
1376 	
1377 	         if(strcmp(mps.field0(), "ENDATA"))
1378 	            break;
1379 	
1380 	         mps.setSection(MPSInput::ENDATA);
1381 	
1382 	         return;
1383 	      }
1384 	
1385 	      // Is the value field used ?
1386 	      if((!strcmp(mps.field1(), "LO"))
1387 	            || (!strcmp(mps.field1(), "UP"))
1388 	            || (!strcmp(mps.field1(), "FX"))
1389 	            || (!strcmp(mps.field1(), "LI"))
1390 	            || (!strcmp(mps.field1(), "UI")))
1391 	      {
1392 	         if((mps.field3() != 0) && (mps.field4() == 0))
1393 	            mps.insertName("_BND_", true);
1394 	      }
1395 	      else
1396 	      {
1397 	         if((mps.field2() != 0) && (mps.field3() == 0))
1398 	            mps.insertName("_BND_", true);
1399 	      }
1400 	
1401 	      if((mps.field1() == 0) || (mps.field2() == 0) || (mps.field3() == 0))
1402 	         break;
1403 	
1404 	      if(*bndname == '\0')
1405 	      {
1406 	         assert(strlen(mps.field2()) < MPSInput::MAX_LINE_LEN);
1407 	         spxSnprintf(bndname, MPSInput::MAX_LINE_LEN, "%s", mps.field2());
1408 	      }
1409 	
1410 	      // Only read the first Bound in section
1411 	      if(!strcmp(bndname, mps.field2()))
1412 	      {
1413 	         if((idx = cnames.number(mps.field3())) < 0)
1414 	            mps.entryIgnored("column", mps.field3(), "bound", bndname);
1415 	         else
1416 	         {
1417 	            if(mps.field4() == 0)
1418 	               val = 0;
1419 	            else if(!strcmp(mps.field4(), "-Inf") || !strcmp(mps.field4(), "-inf"))
1420 	               val = -infinity;
1421 	            else if(!strcmp(mps.field4(), "Inf") || !strcmp(mps.field4(), "inf")
1422 	                    || !strcmp(mps.field4(), "+Inf") || !strcmp(mps.field4(), "+inf"))
1423 	               val = infinity;
1424 	            else
1425 	               try
1426 	               {
1427 	                  val = ratFromString(mps.field4());
1428 	               }
1429 	               catch(const std::exception& e)
1430 	               {
1431 	                  SPX_MSG_WARNING((*spxout), (*spxout) << "WMPSRD07 Warning: malformed rational value in MPS file\n");
1432 	                  std::cerr << e.what() << '\n';
1433 	               }
1434 	
1435 	            // ILOG extension (Integer Bound)
1436 	            if(mps.field1()[1] == 'I')
1437 	            {
1438 	               if(intvars != 0)
1439 	                  intvars->addIdx(idx);
1440 	
1441 	               // if the variable has appeared in the MARKER section of the COLUMNS section then its default bounds were
1442 	               // set to 0,1; the first time it is declared integer we need to change to default bounds 0,infinity
1443 	               if(oldbinvars.pos(idx) < 0)
1444 	               {
1445 	                  cset.upper_w(idx) = infinity;
1446 	                  oldbinvars.addIdx(idx);
1447 	               }
1448 	            }
1449 	
1450 	            switch(*mps.field1())
1451 	            {
1452 	            case 'L':
1453 	               cset.lower_w(idx) = val;
1454 	               break;
1455 	
1456 	            case 'U':
1457 	               cset.upper_w(idx) = val;
1458 	               break;
1459 	
1460 	            case 'F':
1461 	               if(mps.field1()[1] == 'X')
1462 	               {
1463 	                  cset.lower_w(idx) = val;
1464 	                  cset.upper_w(idx) = val;
1465 	               }
1466 	               else
1467 	               {
1468 	                  cset.lower_w(idx) = -infinity;
1469 	                  cset.upper_w(idx) = infinity;
1470 	               }
1471 	
1472 	               break;
1473 	
1474 	            case 'M':
1475 	               cset.lower_w(idx) = -infinity;
1476 	               break;
1477 	
1478 	            case 'P':
1479 	               cset.upper_w(idx) = infinity;
1480 	               break;
1481 	
1482 	            // Ilog extension (Binary)
1483 	            case 'B':
1484 	               cset.lower_w(idx) = 0;
1485 	               cset.upper_w(idx) = 1;
1486 	
1487 	               if(intvars != 0)
1488 	                  intvars->addIdx(idx);
1489 	
1490 	               break;
1491 	
1492 	            default:
1493 	               mps.syntaxError();
1494 	               return;
1495 	            }
1496 	         }
1497 	      }
1498 	   }
1499 	
1500 	   mps.syntaxError();
1501 	}
1502 	
1503 	/// Read LP in MPS File Format.
1504 	/**
1505 	 *  The specification is taken from the IBM Optimization Library Guide and Reference, online available at
1506 	 *  http://www.software.ibm.com/sos/features/libuser.htm and from the ILOG CPLEX 7.0 Reference Manual, Appendix E, Page
1507 	 *  531.
1508 	 *
1509 	 *  This routine should read all valid MPS format files.  What it will not do, is find all cases where a file is ill
1510 	 *  formed.  If this happens it may complain and read nothing or read "something".
1511 	 *
1512 	 *  @return true if the file was read correctly.
1513 	 */
1514 	#define SOPLEX_INIT_COLS 1000 ///< initialy allocated columns.
1515 	#define SOPLEX_INIT_NZOS 5000 ///< initialy allocated non zeros.
1516 	template <> inline
1517 	bool SPxLPBase<Rational>::readMPS(
1518 	   std::istream& p_input,           ///< input stream.
1519 	   NameSet*      p_rnames,          ///< row names.
1520 	   NameSet*      p_cnames,          ///< column names.
1521 	   DIdxSet*      p_intvars)         ///< integer variables.
1522 	{
1523 	   LPRowSetBase<Rational>& rset = *this;
1524 	   LPColSetBase<Rational>& cset = *this;
1525 	   NameSet* rnames;
1526 	   NameSet* cnames;
1527 	
1528 	   if(p_cnames)
1529 	      cnames = p_cnames;
1530 	   else
1531 	   {
1532 	      cnames = 0;
1533 	      spx_alloc(cnames);
1534 	      cnames = new(cnames) NameSet();
1535 	   }
1536 	
1537 	   cnames->clear();
1538 	
1539 	   if(p_rnames)
1540 	      rnames = p_rnames;
1541 	   else
1542 	   {
1543 	      try
1544 	      {
1545 	         rnames = 0;
1546 	         spx_alloc(rnames);
1547 	         rnames = new(rnames) NameSet();
1548 	      }
1549 	      catch(const SPxMemoryException& x)
1550 	      {
1551 	         if(!p_cnames)
1552 	         {
1553 	            cnames->~NameSet();
1554 	            spx_free(cnames);
1555 	         }
1556 	
1557 	         throw x;
1558 	      }
1559 	   }
1560 	
1561 	   rnames->clear();
1562 	
1563 	   SPxLPBase<Rational>::clear(); // clear the LP.
1564 	
1565 	   cset.memRemax(SOPLEX_INIT_NZOS);
1566 	   cset.reMax(SOPLEX_INIT_COLS);
1567 	
1568 	   MPSInput mps(p_input);
1569 	
1570 	   MPSreadName(mps, spxout);
1571 	
1572 	   if(mps.section() == MPSInput::OBJSEN)
1573 	      MPSreadObjsen(mps);
1574 	
1575 	   if(mps.section() == MPSInput::OBJNAME)
1576 	      MPSreadObjname(mps);
1577 	
1578 	   if(mps.section() == MPSInput::ROWS)
1579 	      MPSreadRows(mps, rset, *rnames, spxout);
1580 	
1581 	   addedRows(rset.num());
1582 	
1583 	   if(mps.section() == MPSInput::COLUMNS)
1584 	      MPSreadCols(mps, rset, *rnames, cset, *cnames, p_intvars, spxout);
1585 	
1586 	   if(mps.section() == MPSInput::RHS)
1587 	      MPSreadRhs(mps, rset, *rnames, spxout);
1588 	
1589 	   if(mps.section() == MPSInput::RANGES)
1590 	      MPSreadRanges(mps, rset, *rnames, spxout);
1591 	
1592 	   if(mps.section() == MPSInput::BOUNDS)
1593 	      MPSreadBounds(mps, cset, *cnames, p_intvars, spxout);
1594 	
1595 	   if(mps.section() != MPSInput::ENDATA)
1596 	      mps.syntaxError();
1597 	
1598 	   if(mps.hasError())
1599 	      clear();
1600 	   else
1601 	   {
1602 	      changeSense(mps.objSense() == MPSInput::MINIMIZE ? SPxLPBase<Rational>::MINIMIZE :
1603 	                  SPxLPBase<Rational>::MAXIMIZE);
1604 	
1605 	      SPX_MSG_INFO2((*spxout), (*spxout) << "IMPSRD06 Objective sense: " << ((mps.objSense() ==
1606 	                    MPSInput::MINIMIZE) ? "Minimize\n" : "Maximize\n"));
1607 	
1608 	      added2Set(
1609 	         *(reinterpret_cast<SVSetBase<Rational>*>(static_cast<LPRowSetBase<Rational>*>(this))),
1610 	         *(reinterpret_cast<SVSetBase<Rational>*>(static_cast<LPColSetBase<Rational>*>(this))),
1611 	         cset.num());
1612 	      addedCols(cset.num());
1613 	
1614 	      assert(isConsistent());
1615 	   }
1616 	
1617 	   if(p_cnames == 0)
1618 	   {
1619 	      cnames->~NameSet();
1620 	      spx_free(cnames);
1621 	   }
1622 	
1623 	   if(p_rnames == 0)
1624 	   {
1625 	      rnames->~NameSet();
1626 	      spx_free(rnames);
1627 	   }
1628 	
1629 	   return !mps.hasError();
1630 	}
1631 	
1632 	
1633 	
1634 	// ---------------------------------------------------------------------------------------------------------------------
1635 	// Specialization for writing LP format
1636 	// ---------------------------------------------------------------------------------------------------------------------
1637 	
1638 	// get the name of a row or construct one
1639 	static const char* LPFgetRowName(
1640 	   const SPxLPBase<Rational>& p_lp,
1641 	   int                    p_idx,
1642 	   const NameSet*         p_rnames,
1643 	   char*                  p_buf,
1644 	   int                    p_num_written_rows
1645 	)
1646 	{
1647 	   assert(p_buf != 0);
1648 	   assert(p_idx >= 0);
1649 	   assert(p_idx <  p_lp.nRows());
1650 	
1651 	   if(p_rnames != 0)
1652 	   {
1653 	      DataKey key = p_lp.rId(p_idx);
1654 	
1655 	      if(p_rnames->has(key))
1656 	         return (*p_rnames)[key];
1657 	   }
1658 	
1659 	   spxSnprintf(p_buf, 16, "C%d", p_num_written_rows);
1660 	
1661 	   return p_buf;
1662 	}
1663 	
1664 	
1665 	
1666 	// get the name of a column or construct one
1667 	static const char* getColName(
1668 	   const SPxLPBase<Rational>& p_lp,
1669 	   int                    p_idx,
1670 	   const NameSet*         p_cnames,
1671 	   char*                  p_buf
1672 	)
1673 	{
1674 	   assert(p_buf != 0);
1675 	   assert(p_idx >= 0);
1676 	   assert(p_idx <  p_lp.nCols());
1677 	
1678 	   if(p_cnames != 0)
1679 	   {
1680 	      DataKey key = p_lp.cId(p_idx);
1681 	
1682 	      if(p_cnames->has(key))
1683 	         return (*p_cnames)[key];
1684 	   }
1685 	
1686 	   spxSnprintf(p_buf, 16, "x%d", p_idx);
1687 	
1688 	   return p_buf;
1689 	}
1690 	
1691 	
1692 	
1693 	// write an SVector
1694 	#define SOPLEX_NUM_ENTRIES_PER_LINE 5
1695 	static void LPFwriteSVector(
1696 	   const SPxLPBase<Rational>&   p_lp,       ///< the LP
1697 	   std::ostream&            p_output,   ///< output stream
1698 	   const NameSet*           p_cnames,   ///< column names
1699 	   const SVectorBase<Rational>& p_svec,     ///< vector to write
1700 	   SPxOut*                  spxout      ///< out stream
1701 	)
1702 	{
1703 	
1704 	   char name[16];
1705 	   int num_coeffs = 0;
1706 	   long long pos;
1707 	
1708 	   pos = p_output.tellp();
1709 	
1710 	   for(int j = 0; j < p_lp.nCols(); ++j)
1711 	   {
1712 	      const Rational coeff = p_svec[j];
1713 	
1714 	      if(coeff == 0)
1715 	         continue;
1716 	
1717 	      if(num_coeffs == 0)
1718 	         p_output << coeff << " " << getColName(p_lp, j, p_cnames, name);
1719 	      else
1720 	      {
1721 	         // insert a line break every SOPLEX_NUM_ENTRIES_PER_LINE columns or whenever max line length is nearly exceeded
1722 	         if(num_coeffs == SOPLEX_NUM_ENTRIES_PER_LINE ||
1723 	               (long long)(p_output.tellp()) - pos + (long long)(coeff.str().length() + 100) >
1724 	               SOPLEX_MAX_LINE_WRITE_LEN)
1725 	         {
1726 	            num_coeffs = 0;
1727 	            p_output << "\n\t";
1728 	
1729 	            if((long long)(p_output.tellp()) - pos  >  SOPLEX_MAX_LINE_WRITE_LEN)
1730 	            {
1731 	               SPX_MSG_WARNING((*spxout), (*spxout) <<
1732 	                               "XLPSWR01 Warning: SOPLEX_MAX_LINE_WRITE_LEN possibly exceeded when writing LP file\n");
1733 	            }
1734 	
1735 	            pos = p_output.tellp();
1736 	         }
1737 	
1738 	         if(coeff < 0)
1739 	            p_output << " - " << -coeff;
1740 	         else
1741 	            p_output << " + " << coeff;
1742 	
1743 	         p_output << " " << getColName(p_lp, j, p_cnames, name);
1744 	      }
1745 	
1746 	      ++num_coeffs;
1747 	   }
1748 	}
1749 	
1750 	
1751 	
1752 	// write the objective
1753 	static void LPFwriteObjective(
1754 	   const SPxLPBase<Rational>& p_lp,       ///< the LP
1755 	   std::ostream&          p_output,   ///< output stream
1756 	   const NameSet*         p_cnames,   ///< column names
1757 	   SPxOut*                spxout      ///< out stream
1758 	)
1759 	{
1760 	
1761 	   const int sense = p_lp.spxSense();
1762 	
1763 	   p_output << ((sense == SPxLPBase<Rational>::MINIMIZE) ? "Minimize\n" : "Maximize\n");
1764 	   p_output << "  obj: ";
1765 	
1766 	   const VectorBase<Rational>& obj = p_lp.maxObj();
1767 	   DSVectorBase<Rational> svec(obj.dim());
1768 	   svec.operator = (obj);
1769 	   svec *= Rational(sense);
1770 	   LPFwriteSVector(p_lp, p_output, p_cnames, svec, spxout);
1771 	   p_output << "\n";
1772 	}
1773 	
1774 	
1775 	
1776 	// write non-ranged rows
1777 	static void LPFwriteRow(
1778 	   const SPxLPBase<Rational>&   p_lp,       ///< the LP
1779 	   std::ostream&            p_output,   ///< output stream
1780 	   const NameSet*           p_cnames,   ///< column names
1781 	   const SVectorBase<Rational>& p_svec,     ///< vector of the row
1782 	   const Rational&              p_lhs,      ///< lhs of the row
1783 	   const Rational&              p_rhs,      ///< rhs of the row
1784 	   SPxOut*                      spxout      ///< out stream
1785 	)
1786 	{
1787 	
1788 	   long long pos;
1789 	   pos = p_output.tellp();
1790 	
1791 	   LPFwriteSVector(p_lp, p_output, p_cnames, p_svec, spxout);
1792 	
1793 	   long long sidelen;
1794 	   sidelen = (p_lhs == p_rhs
1795 	              || double(p_lhs) <= double(-infinity)) ? (long long)p_rhs.str().length()
1796 	             : (long long)p_lhs.str().length();
1797 	
1798 	   // insert a line break if max line length is in danger of being exceeded
1799 	   if((long long)(p_output.tellp()) - pos + sidelen + (long long)100 > SOPLEX_MAX_LINE_WRITE_LEN)
1800 	   {
1801 	      p_output << "\n\t";
1802 	
1803 	      if((long long)(p_output.tellp()) - pos  >  SOPLEX_MAX_LINE_WRITE_LEN)
1804 	      {
1805 	         SPX_MSG_WARNING((*spxout), (*spxout) <<
1806 	                         "XLPSWR02 Warning: SOPLEX_MAX_LINE_WRITE_LEN possibly exceeded when writing LP file\n");
1807 	      }
1808 	
1809 	      pos = p_output.tellp();
1810 	   }
1811 	
1812 	   // write bound value
1813 	   if(p_lhs == p_rhs)
1814 	      p_output << " = " << p_rhs;
1815 	   else if(double(p_lhs) <= double(-infinity))
1816 	      p_output << " <= " << p_rhs;
1817 	   else
1818 	   {
1819 	      assert(double(p_rhs) >= double(infinity));
1820 	      p_output << " >= " << p_lhs;
1821 	   }
1822 	
1823 	   p_output << "\n";
1824 	
1825 	   if((long long)(p_output.tellp()) - pos  >  SOPLEX_MAX_LINE_WRITE_LEN)
1826 	   {
1827 	      SPX_MSG_WARNING((*spxout), (*spxout) <<
1828 	                      "XLPSWR03 Warning: SOPLEX_MAX_LINE_WRITE_LEN possibly exceeded when writing LP file\n");
1829 	   }
1830 	}
1831 	
1832 	
1833 	
1834 	// write all rows
1835 	static void LPFwriteRows(
1836 	   const SPxLPBase<Rational>& p_lp,       ///< the LP
1837 	   std::ostream&          p_output,   ///< output stream
1838 	   const NameSet*         p_rnames,   ///< row names
1839 	   const NameSet*         p_cnames,   ///< column names
1840 	   SPxOut*                spxout      ///< out stream
1841 	)
1842 	{
1843 	
1844 	   char name[16];
1845 	
1846 	   p_output << "Subject To\n";
1847 	
1848 	   for(int i = 0; i < p_lp.nRows(); ++i)
1849 	   {
1850 	      const Rational lhs = p_lp.lhs(i);
1851 	      const Rational rhs = p_lp.rhs(i);
1852 	
1853 	      if(double(lhs) > -double(infinity) && double(rhs) < double(infinity) && lhs != rhs)
1854 	      {
1855 	         // ranged row -> write two non-ranged rows
1856 	         p_output << " " << LPFgetRowName(p_lp, i, p_rnames, name, i) << "_1 : ";
1857 	         LPFwriteRow(p_lp, p_output, p_cnames, p_lp.rowVector(i), lhs, infinity, spxout);
1858 	
1859 	         p_output << " " << LPFgetRowName(p_lp, i, p_rnames, name, i) << "_2 : ";
1860 	         LPFwriteRow(p_lp, p_output, p_cnames, p_lp.rowVector(i), -infinity, rhs, spxout);
1861 	      }
1862 	      else
1863 	      {
1864 	         p_output << " " << LPFgetRowName(p_lp, i, p_rnames, name, i) << " : ";
1865 	         LPFwriteRow(p_lp, p_output, p_cnames, p_lp.rowVector(i), lhs, rhs, spxout);
1866 	      }
1867 	   }
1868 	}
1869 	
1870 	
1871 	
1872 	// write the variable bounds
1873 	// (the default bounds 0 <= x <= infinity are not written)
1874 	static void LPFwriteBounds(
1875 	   const SPxLPBase<Rational>&   p_lp,       ///< the LP to write
1876 	   std::ostream&            p_output,   ///< output stream
1877 	   const NameSet*           p_cnames,   ///< column names
1878 	   SPxOut*                  spxout      ///< out stream
1879 	)
1880 	{
1881 	
1882 	   char name[16];
1883 	   long long pos;
1884 	
1885 	   pos = p_output.tellp();
1886 	
1887 	   p_output << "Bounds\n";
1888 	
1889 	   for(int j = 0; j < p_lp.nCols(); ++j)
1890 	   {
1891 	      const Rational lower = p_lp.lower(j);
1892 	      const Rational upper = p_lp.upper(j);
1893 	
1894 	      if(lower == upper)
1895 	      {
1896 	         p_output << "  "   << getColName(p_lp, j, p_cnames, name) << " = "  << upper << '\n';
1897 	      }
1898 	      else if(double(lower) > -double(infinity))
1899 	      {
1900 	         if(double(upper) < double(infinity))
1901 	         {
1902 	            // range bound
1903 	            if(lower != 0)
1904 	               p_output << "  "   << lower << " <= "
1905 	                        << getColName(p_lp, j, p_cnames, name)
1906 	                        << " <= " << upper << '\n';
1907 	            else
1908 	               p_output << "  "   << getColName(p_lp, j, p_cnames, name)
1909 	                        << " <= " << upper << '\n';
1910 	         }
1911 	         else if(lower != 0)
1912 	            p_output << "  " << lower << " <= "
1913 	                     << getColName(p_lp, j, p_cnames, name)
1914 	                     << '\n';
1915 	      }
1916 	      else if(double(upper) < double(infinity))
1917 	         p_output << "   -Inf <= "
1918 	                  << getColName(p_lp, j, p_cnames, name)
1919 	                  << " <= " << upper << '\n';
1920 	      else
1921 	         p_output << "  "   << getColName(p_lp, j, p_cnames, name)
1922 	                  << " free\n";
1923 	
1924 	      // check if max line length exceeded
1925 	      if((long long)(p_output.tellp()) - pos  >  SOPLEX_MAX_LINE_WRITE_LEN)
1926 	      {
1927 	         SPX_MSG_WARNING((*spxout), (*spxout) <<
1928 	                         "XLPSWR04 Warning: SOPLEX_MAX_LINE_WRITE_LEN exceeded when writing LP file\n");
1929 	      }
1930 	
1931 	      pos = p_output.tellp();
1932 	   }
1933 	}
1934 	
1935 	
1936 	
1937 	// write the generals section
1938 	static void LPFwriteGenerals(
1939 	   const SPxLPBase<Rational>&   p_lp,         ///< the LP to write
1940 	   std::ostream&            p_output,     ///< output stream
1941 	   const NameSet*           p_cnames,     ///< column names
1942 	   const DIdxSet*           p_intvars     ///< integer variables
1943 	)
1944 	{
1945 	
1946 	   char name[16];
1947 	
1948 	   if(p_intvars == NULL || p_intvars->size() <= 0)
1949 	      return;  // no integer variables
1950 	
1951 	   p_output << "Generals\n";
1952 	
1953 	   for(int j = 0; j < p_lp.nCols(); ++j)
1954 	      if(p_intvars->pos(j) >= 0)
1955 	         p_output << "  " << getColName(p_lp, j, p_cnames, name) << "\n";
1956 	}
1957 	
1958 	
1959 	/// Write LP in LP Format.
1960 	template <> inline
1961 	void SPxLPBase<Rational>::writeLPF(
1962 	   std::ostream&  p_output,          ///< output stream
1963 	   const NameSet* p_rnames,          ///< row names
1964 	   const NameSet* p_cnames,          ///< column names
1965 	   const DIdxSet* p_intvars          ///< integer variables
1966 	) const
1967 	{
1968 	   LPFwriteObjective(*this, p_output, p_cnames, spxout);
1969 	   LPFwriteRows(*this, p_output, p_rnames, p_cnames, spxout);
1970 	   LPFwriteBounds(*this, p_output, p_cnames, spxout);
1971 	   LPFwriteGenerals(*this, p_output, p_cnames, p_intvars);
1972 	
1973 	   p_output << "End" << std::endl;
1974 	}
1975 	
1976 	
1977 	
1978 	// ---------------------------------------------------------------------------------------------------------------------
1979 	// Specialization for writing MPS format
1980 	// ---------------------------------------------------------------------------------------------------------------------
1981 	
1982 	// A problem here.
1983 	static void MPSwriteRecord(
1984 	   std::ostream&  os,
1985 	   const char*    indicator,
1986 	   const char*    name,
1987 	   SPxOut* spxout,
1988 	   const char*    name1  = nullptr,
1989 	   const Rational value1 = 0,
1990 	   const char*    name2  = nullptr,
1991 	   const Rational value2 = 0
1992 	)
1993 	{
1994 	   char buf[81];
1995 	   long long pos;
1996 	   pos = os.tellp();
1997 	
1998 	   spxSnprintf(buf, sizeof(buf), " %-2.2s %-8.8s", (indicator == 0) ? "" : indicator,
1999 	               (name == 0)      ? "" : name);
2000 	   os << buf;
2001 	
2002 	   if(name1 != nullptr)
2003 	   {
2004 	      spxSnprintf(buf, sizeof(buf), " %-8.8s ", name1);
2005 	      os << buf << value1;
2006 	
2007 	      if(name2 != 0)
2008 	      {
2009 	         spxSnprintf(buf, sizeof(buf), " %-8.8s ", name2);
2010 	         os << buf << value2;
2011 	      }
2012 	   }
2013 	
2014 	   os << std::endl;
2015 	
2016 	   // Warning if line is too long
2017 	   if((long long)(os.tellp()) - pos > SOPLEX_MAX_LINE_WRITE_LEN)
2018 	   {
2019 	      SPX_MSG_WARNING((*spxout), (*spxout) <<
2020 	                      "XMPSWR04 Warning: SOPLEX_MAX_LINE_WRITE_LEN exceeded when writing MPS file\n");
2021 	   }
2022 	}
2023 	
2024 	
2025 	
2026 	static Rational MPSgetRHS(Rational left, Rational right)
2027 	{
2028 	   Rational rhsval;
2029 	
2030 	   if(double(left) > -double(infinity))   /// This includes ranges
2031 	      rhsval = left;
2032 	   else if(double(right) <  double(infinity))
2033 	      rhsval = right;
2034 	   else
2035 	      throw SPxInternalCodeException("XMPSWR01 This should never happen.");
2036 	
2037 	   return rhsval;
2038 	}
2039 	
2040 	
2041 	
2042 	static const char* MPSgetRowName(
2043 	   const SPxLPBase<Rational>& lp,
2044 	   int                   idx,
2045 	   const NameSet*        rnames,
2046 	   char*                 buf
2047 	)
2048 	{
2049 	   assert(buf != 0);
2050 	   assert(idx >= 0);
2051 	   assert(idx <  lp.nRows());
2052 	
2053 	   if(rnames != 0)
2054 	   {
2055 	      DataKey key = lp.rId(idx);
2056 	
2057 	      if(rnames->has(key))
2058 	         return (*rnames)[key];
2059 	   }
2060 	
2061 	   spxSnprintf(buf, 16, "C%d", idx);
2062 	
2063 	   return buf;
2064 	}
2065 	
2066 	
2067 	
2068 	/// Write LP in MPS format.
2069 	/** @note There will always be a BOUNDS section, even if there are no bounds.
2070 	 */
2071 	template <> inline
2072 	void SPxLPBase<Rational>::writeMPS(
2073 	   std::ostream&  p_output,          ///< output stream.
2074 	   const NameSet* p_rnames,          ///< row names.
2075 	   const NameSet* p_cnames,          ///< column names.
2076 	   const DIdxSet* p_intvars          ///< integer variables.
2077 	) const
2078 	{
2079 	
2080 	   const char*    indicator;
2081 	   char           name [16];
2082 	   char           name1[16];
2083 	   char           name2[16];
2084 	   bool           has_ranges = false;
2085 	   int            i;
2086 	   int            k;
2087 	
2088 	   // --- NAME Section ---
2089 	   p_output << "NAME          MPSDATA" << std::endl;
2090 	
2091 	   // --- ROWS Section ---
2092 	   p_output << "ROWS" << std::endl;
2093 	
2094 	   for(i = 0; i < nRows(); i++)
2095 	   {
2096 	      if(lhs(i) == rhs(i))
2097 	         indicator = "E";
2098 	      else if((double(lhs(i)) > -double(infinity)) && (double(rhs(i)) < double(infinity)))
2099 	      {
2100 	         indicator = "E";
2101 	         has_ranges = true;
2102 	      }
2103 	      else if(double(lhs(i)) > -double(infinity))
2104 	         indicator = "G";
2105 	      else if(double(rhs(i)) <  double(infinity))
2106 	         indicator = "L";
2107 	      else
2108 	         throw SPxInternalCodeException("XMPSWR02 This should never happen.");
2109 	
2110 	      MPSwriteRecord(p_output, indicator, MPSgetRowName(*this, i, p_rnames, name), spxout);
2111 	   }
2112 	
2113 	   MPSwriteRecord(p_output, "N", "MINIMIZE", spxout);
2114 	
2115 	   // --- COLUMNS Section ---
2116 	   p_output << "COLUMNS" << std::endl;
2117 	
2118 	   bool has_intvars = (p_intvars != 0) && (p_intvars->size() > 0);
2119 	
2120 	   for(int j = 0; j < (has_intvars ? 2 : 1); j++)
2121 	   {
2122 	      bool is_intrun = has_intvars && (j == 1);
2123 	
2124 	      if(is_intrun)
2125 	         p_output << "    MARK0001  'MARKER'                 'INTORG'" << std::endl;
2126 	
2127 	      for(i = 0; i < nCols(); i++)
2128 	      {
2129 	         bool is_intvar = has_intvars && (p_intvars->pos(i) >= 0);
2130 	
2131 	         if((is_intrun && !is_intvar) || (!is_intrun &&  is_intvar))
2132 	            continue;
2133 	
2134 	         const SVectorBase<Rational>& col = colVector(i);
2135 	         int colsize2 = (col.size() / 2) * 2;
2136 	
2137 	         assert(colsize2 % 2 == 0);
2138 	
2139 	         for(k = 0; k < colsize2; k += 2)
2140 	            MPSwriteRecord(p_output, 0, getColName(*this, i, p_cnames, name), spxout,
2141 	                           MPSgetRowName(*this, col.index(k), p_rnames, name1), col.value(k),
2142 	                           MPSgetRowName(*this, col.index(k + 1), p_rnames, name2), col.value(k + 1));
2143 	
2144 	         if(colsize2 != col.size())
2145 	            MPSwriteRecord(p_output, 0, getColName(*this, i, p_cnames, name), spxout,
2146 	                           MPSgetRowName(*this, col.index(k), p_rnames, name1), col.value(k));
2147 	
2148 	         if(maxObj(i) != 0)
2149 	            MPSwriteRecord(p_output, 0, getColName(*this, i, p_cnames, name), spxout, "MINIMIZE", -maxObj(i));
2150 	      }
2151 	
2152 	      if(is_intrun)
2153 	         p_output << "    MARK0001  'MARKER'                 'INTEND'" << std::endl;
2154 	   }
2155 	
2156 	   // --- RHS Section ---
2157 	   p_output << "RHS" << std::endl;
2158 	
2159 	   i = 0;
2160 	
2161 	   while(i < nRows())
2162 	   {
2163 	      Rational rhsval1 = 0;
2164 	      Rational rhsval2 = 0;
2165 	
2166 	      for(; i < nRows(); i++)
2167 	         if((rhsval1 = MPSgetRHS(lhs(i), rhs(i))) != 0)
2168 	            break;
2169 	
2170 	      if(i < nRows())
2171 	      {
2172 	         for(k = i + 1; k < nRows(); k++)
2173 	         {
2174 	            if((rhsval2 = MPSgetRHS(lhs(k), rhs(k))) != 0)
2175 	               break;
2176 	         }
2177 	
2178 	         if(k < nRows())
2179 	         {
2180 	            MPSwriteRecord(p_output, 0, "RHS", spxout, MPSgetRowName(*this, i, p_rnames, name1), rhsval1,
2181 	                           MPSgetRowName(*this, k, p_rnames, name2), rhsval2);
2182 	         }
2183 	         else
2184 	            MPSwriteRecord(p_output, 0, "RHS", spxout, MPSgetRowName(*this, i, p_rnames, name1), rhsval1);
2185 	
2186 	         i = k + 1;
2187 	      }
2188 	   }
2189 	
2190 	   // --- RANGES Section ---
2191 	   if(has_ranges)
2192 	   {
2193 	      p_output << "RANGES" << std::endl;
2194 	
2195 	      for(i = 0; i < nRows(); i++)
2196 	      {
2197 	         if((double(lhs(i)) > -double(infinity)) && (double(rhs(i)) < double(infinity)))
2198 	         {
2199 	            Rational range = rhs(i);
2200 	            range -= lhs(i);
2201 	            MPSwriteRecord(p_output, "", "RANGE", spxout, MPSgetRowName(*this, i, p_rnames, name1), range);
2202 	         }
2203 	      }
2204 	   }
2205 	
2206 	   // --- BOUNDS Section ---
2207 	   p_output << "BOUNDS" << std::endl;
2208 	
2209 	   for(i = 0; i < nCols(); i++)
2210 	   {
2211 	      // skip variables that do not appear in the objective function or any constraint
2212 	      const SVectorBase<Rational>& col = colVector(i);
2213 	
2214 	      if(col.size() == 0 && maxObj(i) == 0)
2215 	         continue;
2216 	
2217 	      if(lower(i) == upper(i))
2218 	      {
2219 	         MPSwriteRecord(p_output, "FX", "BOUND", spxout, getColName(*this, i, p_cnames, name1), lower(i));
2220 	         continue;
2221 	      }
2222 	
2223 	      if((double(lower(i)) <= double(-infinity)) && (double(upper(i)) >= double(infinity)))
2224 	      {
2225 	         MPSwriteRecord(p_output, "FR", "BOUND", spxout, getColName(*this, i, p_cnames, name1));
2226 	         continue;
2227 	      }
2228 	
2229 	      if(lower(i) != 0)
2230 	      {
2231 	         if(double(lower(i)) > -double(infinity))
2232 	            MPSwriteRecord(p_output, "LO", "BOUND", spxout, getColName(*this, i, p_cnames, name1), lower(i));
2233 	         else
2234 	            MPSwriteRecord(p_output, "MI", "BOUND", spxout, getColName(*this, i, p_cnames, name1));
2235 	      }
2236 	
2237 	      if(has_intvars && (p_intvars->pos(i) >= 0))
2238 	      {
2239 	         // Integer variables have default upper bound 1, but we should write
2240 	         // it nevertheless since CPLEX seems to assume infinity otherwise.
2241 	         MPSwriteRecord(p_output, "UP", "BOUND", spxout, getColName(*this, i, p_cnames, name1), upper(i));
2242 	      }
2243 	      else
2244 	      {
2245 	         // Continous variables have default upper bound infinity
2246 	         if(double(upper(i)) < double(infinity))
2247 	            MPSwriteRecord(p_output, "UP", "BOUND", spxout, getColName(*this, i, p_cnames, name1), upper(i));
2248 	      }
2249 	   }
2250 	
2251 	   // --- ENDATA Section ---
2252 	   p_output << "ENDATA" << std::endl;
2253 	
2254 	   // Output warning when writing a maximisation problem
2255 	   if(spxSense() == SPxLPBase<Rational>::MAXIMIZE)
2256 	   {
2257 	      SPX_MSG_WARNING((*spxout), (*spxout) <<
2258 	                      "XMPSWR03 Warning: objective function inverted when writing maximization problem in MPS file format\n");
2259 	   }
2260 	}
2261 	
2262 	
2263 	
2264 	/// Building the dual problem from a given LP
2265 	/// @note primalRows must be as large as the number of unranged primal rows + 2 * the number of ranged primal rows.
2266 	///       dualCols must have the identical size to the primal rows.
2267 	template <> inline
2268 	void SPxLPBase<Rational>::buildDualProblem(SPxLPBase<Rational>& dualLP, SPxRowId primalRowIds[],
2269 	      SPxColId primalColIds[],
2270 	      SPxRowId dualRowIds[], SPxColId dualColIds[], int* nprimalrows, int* nprimalcols, int* ndualrows,
2271 	      int* ndualcols)
2272 	{
2273 	   assert(false);
2274 	   SPX_MSG_ERROR(std::cerr << "Method buildDualProblem() not implemented for Rational\n");
2275 	}
2276 	
2277 	
2278 	// ---------------------------------------------------------------------------------------------------------------------
2279 	//  Explicit instantiation
2280 	// ---------------------------------------------------------------------------------------------------------------------
2281 	template class SPxLPBase < Rational >;
2282 	} // namespace soplex
2283