1 /* $Id: CoinLpIO.cpp 2122 2019-04-08 03:26:16Z stefan $ */
2 // Last edit: 11/5/08
3 //
4 // Name:     CoinLpIO.cpp; Support for Lp files
5 // Author:   Francois Margot
6 //           Tepper School of Business
7 //           Carnegie Mellon University, Pittsburgh, PA 15213
8 // Date:     12/28/03
9 //-----------------------------------------------------------------------------
10 // Copyright (C) 2003, Francois Margot, International Business Machines
11 // Corporation and others.  All Rights Reserved.
12 // This code is licensed under the terms of the Eclipse Public License (EPL).
13 
14 #include "CoinUtilsConfig.h"
15 
16 #include <cmath>
17 #include <cfloat>
18 #include <cctype>
19 #include <cassert>
20 #include <string>
21 #include <cstdarg>
22 
23 #include "CoinError.hpp"
24 #include "CoinHelperFunctions.hpp"
25 #include "CoinPackedMatrix.hpp"
26 #include "CoinLpIO.hpp"
27 #include "CoinMpsIO.hpp"
28 #include "CoinFinite.hpp"
29 #include "CoinSort.hpp"
30 
31 using namespace std;
32 
33 //#define LPIO_DEBUG
34 
35 /************************************************************************/
36 
CoinLpIO()37 CoinLpIO::CoinLpIO()
38   : problemName_(CoinStrdup(""))
39   , defaultHandler_(true)
40   , numberRows_(0)
41   , numberColumns_(0)
42   , numberElements_(0)
43   , matrixByColumn_(NULL)
44   , matrixByRow_(NULL)
45   , rowlower_(NULL)
46   , rowupper_(NULL)
47   , collower_(NULL)
48   , colupper_(NULL)
49   , rhs_(NULL)
50   , rowrange_(NULL)
51   , rowsense_(NULL)
52   , num_objectives_(0)
53   , integerType_(NULL)
54   , set_(NULL)
55   , numberSets_(0)
56   , fileName_(NULL)
57   , infinity_(COIN_DBL_MAX)
58   , epsilon_(1e-5)
59   , numberAcross_(10)
60   , decimals_(9)
61   , wasMaximization_(false)
62   , input_(NULL)
63 {
64   for (int j = 0; j < MAX_OBJECTIVES; j++) {
65     objective_[j] = NULL;
66     objName_[j] = NULL;
67     objectiveOffset_[j] = 0;
68   }
69   card_previous_names_[0] = 0;
70   card_previous_names_[1] = 0;
71   previous_names_[0] = NULL;
72   previous_names_[1] = NULL;
73 
74   maxHash_[0] = 0;
75   numberHash_[0] = 0;
76   hash_[0] = NULL;
77   names_[0] = NULL;
78   maxHash_[1] = 0;
79   numberHash_[1] = 0;
80   hash_[1] = NULL;
81   names_[1] = NULL;
82   handler_ = new CoinMessageHandler();
83   messages_ = CoinMessage();
84 }
85 
86 //-------------------------------------------------------------------
87 // Copy constructor
88 //-------------------------------------------------------------------
CoinLpIO(const CoinLpIO & rhs)89 CoinLpIO::CoinLpIO(const CoinLpIO &rhs)
90   : problemName_(CoinStrdup(""))
91   , defaultHandler_(true)
92   , numberRows_(0)
93   , numberColumns_(0)
94   , numberElements_(0)
95   , matrixByColumn_(NULL)
96   , matrixByRow_(NULL)
97   , rowlower_(NULL)
98   , rowupper_(NULL)
99   , collower_(NULL)
100   , colupper_(NULL)
101   , rhs_(NULL)
102   , rowrange_(NULL)
103   , rowsense_(NULL)
104   , integerType_(NULL)
105   , set_(NULL)
106   , numberSets_(0)
107   , fileName_(CoinStrdup(""))
108   , infinity_(COIN_DBL_MAX)
109   , epsilon_(1e-5)
110   , numberAcross_(10)
111   , input_(NULL)
112 {
113   num_objectives_ = rhs.num_objectives_;
114   for (int j = 0; j < MAX_OBJECTIVES; j++) {
115     objective_[j] = NULL;
116     if (j < num_objectives_) {
117       objName_[j] = CoinStrdup(rhs.objName_[j]);
118     } else {
119       objName_[j] = NULL;
120     }
121     objectiveOffset_[j] = 0;
122   }
123   card_previous_names_[0] = 0;
124   card_previous_names_[1] = 0;
125   previous_names_[0] = NULL;
126   previous_names_[1] = NULL;
127   maxHash_[0] = 0;
128   numberHash_[0] = 0;
129   hash_[0] = NULL;
130   names_[0] = NULL;
131   maxHash_[1] = 0;
132   numberHash_[1] = 0;
133   hash_[1] = NULL;
134   names_[1] = NULL;
135 
136   if (rhs.rowlower_ != NULL || rhs.collower_ != NULL) {
137     gutsOfCopy(rhs);
138   }
139 
140   defaultHandler_ = rhs.defaultHandler_;
141 
142   if (defaultHandler_) {
143     handler_ = new CoinMessageHandler(*rhs.handler_);
144   } else {
145     handler_ = rhs.handler_;
146   }
147 
148   messages_ = CoinMessage();
149 }
150 
gutsOfCopy(const CoinLpIO & rhs)151 void CoinLpIO::gutsOfCopy(const CoinLpIO &rhs)
152 {
153   defaultHandler_ = rhs.defaultHandler_;
154 
155   if (rhs.matrixByRow_) {
156     matrixByRow_ = new CoinPackedMatrix(*(rhs.matrixByRow_));
157   }
158 
159   numberElements_ = rhs.numberElements_;
160   numberRows_ = rhs.numberRows_;
161   numberColumns_ = rhs.numberColumns_;
162   decimals_ = rhs.decimals_;
163   wasMaximization_ = rhs.wasMaximization_;
164 
165   if (rhs.rowlower_) {
166     rowlower_ = reinterpret_cast< double * >(malloc(numberRows_ * sizeof(double)));
167     rowupper_ = reinterpret_cast< double * >(malloc(numberRows_ * sizeof(double)));
168     memcpy(rowlower_, rhs.rowlower_, numberRows_ * sizeof(double));
169     memcpy(rowupper_, rhs.rowupper_, numberRows_ * sizeof(double));
170     rowrange_ = reinterpret_cast< double * >(malloc(numberRows_ * sizeof(double)));
171     rowsense_ = reinterpret_cast< char * >(malloc(numberRows_ * sizeof(char)));
172     rhs_ = reinterpret_cast< double * >(malloc(numberRows_ * sizeof(double)));
173     memcpy(rowrange_, rhs.getRowRange(), numberRows_ * sizeof(double));
174     memcpy(rowsense_, rhs.getRowSense(), numberRows_ * sizeof(char));
175     memcpy(rhs_, rhs.getRightHandSide(), numberRows_ * sizeof(double));
176   }
177 
178   if (rhs.collower_) {
179     collower_ = reinterpret_cast< double * >(malloc(numberColumns_ * sizeof(double)));
180     colupper_ = reinterpret_cast< double * >(malloc(numberColumns_ * sizeof(double)));
181     memcpy(collower_, rhs.collower_, numberColumns_ * sizeof(double));
182     memcpy(colupper_, rhs.colupper_, numberColumns_ * sizeof(double));
183     for (int j = 0; j < num_objectives_; j++) {
184       objective_[j] = reinterpret_cast< double * >(malloc(numberColumns_ * sizeof(double)));
185       memcpy(objective_[j], rhs.objective_[j], numberColumns_ * sizeof(double));
186     }
187   }
188 
189   if (rhs.integerType_) {
190     integerType_ = reinterpret_cast< char * >(malloc(numberColumns_ * sizeof(char)));
191     memcpy(integerType_, rhs.integerType_, numberColumns_ * sizeof(char));
192   }
193   numberSets_ = rhs.numberSets_;
194   if (numberSets_) {
195     set_ = new CoinSet *[numberSets_];
196     for (int j = 0; j < numberSets_; j++)
197       set_[j] = new CoinSet(*rhs.set_[j]);
198   }
199 
200   free(fileName_);
201   free(problemName_);
202   fileName_ = CoinStrdup(rhs.fileName_);
203   problemName_ = CoinStrdup(rhs.problemName_);
204   numberHash_[0] = rhs.numberHash_[0];
205   numberHash_[1] = rhs.numberHash_[1];
206   maxHash_[0] = rhs.maxHash_[0];
207   maxHash_[1] = rhs.maxHash_[1];
208   infinity_ = rhs.infinity_;
209   numberAcross_ = rhs.numberAcross_;
210   for (int j = 0; j < num_objectives_; j++) {
211     objectiveOffset_[j] = rhs.objectiveOffset_[j];
212   }
213   int section;
214 
215   for (section = 0; section < 2; section++) {
216     if (numberHash_[section]) {
217       char **names2 = rhs.names_[section];
218       names_[section] = reinterpret_cast< char ** >(malloc(maxHash_[section] * sizeof(char *)));
219       char **names = names_[section];
220       int i;
221 
222       for (i = 0; i < numberHash_[section]; i++) {
223         names[i] = CoinStrdup(names2[i]);
224       }
225 
226       hash_[section] = new CoinHashLink[maxHash_[section]];
227       std::memcpy(hash_[section], rhs.hash_[section], maxHash_[section] * sizeof(CoinHashLink));
228     }
229   }
230 }
231 
232 CoinLpIO &
operator =(const CoinLpIO & rhs)233 CoinLpIO::operator=(const CoinLpIO &rhs)
234 {
235   if (this != &rhs) {
236     gutsOfDestructor();
237 
238     if (rhs.rowlower_ != NULL || rhs.collower_ != NULL) {
239       gutsOfCopy(rhs);
240     }
241 
242     defaultHandler_ = rhs.defaultHandler_;
243 
244     if (defaultHandler_) {
245       handler_ = new CoinMessageHandler(*rhs.handler_);
246     } else {
247       handler_ = rhs.handler_;
248     }
249 
250     messages_ = CoinMessage();
251   }
252 
253   return *this;
254 }
255 
gutsOfDestructor()256 void CoinLpIO::gutsOfDestructor()
257 {
258   freeAll();
259 
260   if (defaultHandler_) {
261     delete handler_;
262     handler_ = NULL;
263   }
264 }
265 
266 /************************************************************************/
~CoinLpIO()267 CoinLpIO::~CoinLpIO()
268 {
269   stopHash(0);
270   stopHash(1);
271   freeAll();
272   if (defaultHandler_) {
273     delete handler_;
274     handler_ = NULL;
275   }
276 }
277 
278 /************************************************************************/
freePreviousNames(const int section)279 void CoinLpIO::freePreviousNames(const int section)
280 {
281 
282   int j;
283 
284   if (previous_names_[section] != NULL) {
285     for (j = 0; j < card_previous_names_[section]; j++) {
286       free(previous_names_[section][j]);
287     }
288     free(previous_names_[section]);
289   }
290   previous_names_[section] = NULL;
291   card_previous_names_[section] = 0;
292 } /* freePreviousNames */
293 
294 /************************************************************************/
freeAll()295 void CoinLpIO::freeAll()
296 {
297 
298   delete matrixByColumn_;
299   matrixByColumn_ = NULL;
300   delete matrixByRow_;
301   matrixByRow_ = NULL;
302   free(rowupper_);
303   rowupper_ = NULL;
304   free(rowlower_);
305   rowlower_ = NULL;
306   free(colupper_);
307   colupper_ = NULL;
308   free(collower_);
309   collower_ = NULL;
310   free(rhs_);
311   rhs_ = NULL;
312   free(rowrange_);
313   rowrange_ = NULL;
314   free(rowsense_);
315   rowsense_ = NULL;
316   for (int j = 0; j < num_objectives_; j++) {
317     free(objective_[j]);
318     objective_[j] = NULL;
319   }
320   free(integerType_);
321   integerType_ = NULL;
322   for (int j = 0; j < numberSets_; j++)
323     delete set_[j];
324   delete[] set_;
325   set_ = NULL;
326   numberSets_ = 0;
327   free(problemName_);
328   problemName_ = NULL;
329   free(fileName_);
330   fileName_ = NULL;
331 
332   freePreviousNames(0);
333   freePreviousNames(1);
334   delete input_;
335   input_ = NULL;
336 }
337 
338 /*************************************************************************/
getProblemName() const339 const char *CoinLpIO::getProblemName() const
340 {
341   return problemName_;
342 }
343 
setProblemName(const char * name)344 void CoinLpIO::setProblemName(const char *name)
345 {
346   free(problemName_);
347   problemName_ = CoinStrdup(name);
348 }
349 
350 /*************************************************************************/
getNumCols() const351 int CoinLpIO::getNumCols() const
352 {
353   return numberColumns_;
354 }
355 
356 /*************************************************************************/
getNumRows() const357 int CoinLpIO::getNumRows() const
358 {
359   return numberRows_;
360 }
361 
362 /*************************************************************************/
getNumElements() const363 CoinBigIndex CoinLpIO::getNumElements() const
364 {
365   return numberElements_;
366 }
367 
368 /*************************************************************************/
getColLower() const369 const double *CoinLpIO::getColLower() const
370 {
371   return collower_;
372 }
373 
374 /*************************************************************************/
getColUpper() const375 const double *CoinLpIO::getColUpper() const
376 {
377   return colupper_;
378 }
379 
380 /*************************************************************************/
getRowLower() const381 const double *CoinLpIO::getRowLower() const
382 {
383   return rowlower_;
384 }
385 
386 /*************************************************************************/
getRowUpper() const387 const double *CoinLpIO::getRowUpper() const
388 {
389   return rowupper_;
390 }
391 
392 /*************************************************************************/
393 /** A quick inlined function to convert from lb/ub style constraint
394     definition to sense/rhs/range style */
395 inline void
convertBoundToSense(const double lower,const double upper,char & sense,double & right,double & range) const396 CoinLpIO::convertBoundToSense(const double lower, const double upper,
397   char &sense, double &right,
398   double &range) const
399 {
400   range = 0.0;
401   if (lower > -infinity_) {
402     if (upper < infinity_) {
403       right = upper;
404       if (upper == lower) {
405         sense = 'E';
406       } else {
407         sense = 'R';
408         range = upper - lower;
409       }
410     } else {
411       sense = 'G';
412       right = lower;
413     }
414   } else {
415     if (upper < infinity_) {
416       sense = 'L';
417       right = upper;
418     } else {
419       sense = 'N';
420       right = 0.0;
421     }
422   }
423 }
424 
425 /*************************************************************************/
getRowSense() const426 const char *CoinLpIO::getRowSense() const
427 {
428   if (rowsense_ == NULL) {
429     int nr = numberRows_;
430     rowsense_ = reinterpret_cast< char * >(malloc(nr * sizeof(char)));
431 
432     double dum1, dum2;
433     int i;
434     for (i = 0; i < nr; i++) {
435       convertBoundToSense(rowlower_[i], rowupper_[i], rowsense_[i], dum1, dum2);
436     }
437   }
438   return rowsense_;
439 }
440 
441 /*************************************************************************/
getRightHandSide() const442 const double *CoinLpIO::getRightHandSide() const
443 {
444   if (rhs_ == NULL) {
445     int nr = numberRows_;
446     rhs_ = reinterpret_cast< double * >(malloc(nr * sizeof(double)));
447 
448     char dum1;
449     double dum2;
450     int i;
451     for (i = 0; i < nr; i++) {
452       convertBoundToSense(rowlower_[i], rowupper_[i], dum1, rhs_[i], dum2);
453     }
454   }
455   return rhs_;
456 }
457 
458 /*************************************************************************/
getRowRange() const459 const double *CoinLpIO::getRowRange() const
460 {
461   if (rowrange_ == NULL) {
462     int nr = numberRows_;
463     rowrange_ = reinterpret_cast< double * >(malloc(nr * sizeof(double)));
464     std::fill(rowrange_, rowrange_ + nr, 0.0);
465 
466     char dum1;
467     double dum2;
468     int i;
469     for (i = 0; i < nr; i++) {
470       convertBoundToSense(rowlower_[i], rowupper_[i], dum1, dum2, rowrange_[i]);
471     }
472   }
473   return rowrange_;
474 }
475 
476 /*************************************************************************/
getNumObjectives() const477 const int CoinLpIO::getNumObjectives() const
478 {
479   return num_objectives_;
480 }
481 
482 /*************************************************************************/
getObjCoefficients() const483 const double *CoinLpIO::getObjCoefficients() const
484 {
485   return objective_[0];
486 }
487 
488 /*************************************************************************/
getObjCoefficients(int j) const489 const double *CoinLpIO::getObjCoefficients(int j) const
490 {
491   return objective_[j];
492 }
493 
494 /*************************************************************************/
getMatrixByRow() const495 const CoinPackedMatrix *CoinLpIO::getMatrixByRow() const
496 {
497   return matrixByRow_;
498 }
499 
500 /*************************************************************************/
getMatrixByCol() const501 const CoinPackedMatrix *CoinLpIO::getMatrixByCol() const
502 {
503   if (matrixByColumn_ == NULL && matrixByRow_) {
504     matrixByColumn_ = new CoinPackedMatrix(*matrixByRow_);
505     matrixByColumn_->reverseOrdering();
506   }
507   return matrixByColumn_;
508 }
509 
510 /*************************************************************************/
getObjName() const511 const char *CoinLpIO::getObjName() const
512 {
513   return objName_[0];
514 }
515 
516 /*************************************************************************/
getObjName(int j) const517 const char *CoinLpIO::getObjName(int j) const
518 {
519   return objName_[j];
520 }
521 
522 /*************************************************************************/
checkRowNames()523 void CoinLpIO::checkRowNames()
524 {
525 
526   int i, nrow = getNumRows();
527 
528   if (numberHash_[0] != nrow + 1) {
529     setDefaultRowNames();
530     handler_->message(COIN_GENERAL_WARNING, messages_) << "### CoinLpIO::checkRowNames(): non distinct or missing row names or objective function name.\nNow using default row names."
531                                                        << CoinMessageEol;
532   }
533 
534   char const *const *rowNames = getRowNames();
535   const char *rSense = getRowSense();
536   char rName[256];
537 
538   // Check that row names and objective function name are all distinct,
539   /// even after adding "_low" to ranged constraint names
540 
541   for (i = 0; i < nrow; i++) {
542     if (rSense[i] == 'R') {
543       sprintf(rName, "%s_low", rowNames[i]);
544       if (findHash(rName, 0) != -1) {
545         setDefaultRowNames();
546         char printBuffer[512];
547         sprintf(printBuffer, "### CoinLpIO::checkRowNames(): ranged constraint %d has a name %s identical to another constraint name or objective function name.\nUse getPreviousNames() to get the old row names.\nNow using default row names.", i, rName);
548         handler_->message(COIN_GENERAL_WARNING, messages_) << printBuffer
549                                                            << CoinMessageEol;
550         break;
551       }
552     }
553   }
554 } /* checkRowNames */
555 
556 /*************************************************************************/
checkColNames()557 void CoinLpIO::checkColNames()
558 {
559 
560   int ncol = getNumCols();
561 
562   if (numberHash_[1] != ncol) {
563     setDefaultColNames();
564     handler_->message(COIN_GENERAL_WARNING, messages_) << "### CoinLpIO::checkColNames(): non distinct or missing column names.\nNow using default column names."
565                                                        << CoinMessageEol;
566   }
567 } /* checkColNames */
568 
569 /*************************************************************************/
getPreviousRowNames(char const * const * prev,int * card_prev) const570 void CoinLpIO::getPreviousRowNames(char const *const *prev,
571   int *card_prev) const
572 {
573   *card_prev = card_previous_names_[0];
574   prev = previous_names_[0];
575 }
576 
577 /*************************************************************************/
getPreviousColNames(char const * const * prev,int * card_prev) const578 void CoinLpIO::getPreviousColNames(char const *const *prev,
579   int *card_prev) const
580 {
581   *card_prev = card_previous_names_[1];
582   prev = previous_names_[1];
583 }
584 
585 /*************************************************************************/
getRowNames() const586 char const *const *CoinLpIO::getRowNames() const
587 {
588   return names_[0];
589 }
590 
591 /*************************************************************************/
getColNames() const592 char const *const *CoinLpIO::getColNames() const
593 {
594   return names_[1];
595 }
596 
597 /*************************************************************************/
rowName(int index) const598 const char *CoinLpIO::rowName(int index) const
599 {
600 
601   if ((names_[0] != NULL) && (index >= 0) && (index < numberRows_ + 1)) {
602     return names_[0][index];
603   } else {
604     return NULL;
605   }
606 }
607 
608 /*************************************************************************/
columnName(int index) const609 const char *CoinLpIO::columnName(int index) const
610 {
611 
612   if ((names_[1] != NULL) && (index >= 0) && (index < numberColumns_)) {
613     return names_[1][index];
614   } else {
615     return NULL;
616   }
617 }
618 
619 /*************************************************************************/
rowIndex(const char * name) const620 int CoinLpIO::rowIndex(const char *name) const
621 {
622 
623   if (!hash_[0]) {
624     return -1;
625   }
626   return findHash(name, 0);
627 }
628 
629 /*************************************************************************/
columnIndex(const char * name) const630 int CoinLpIO::columnIndex(const char *name) const
631 {
632 
633   if (!hash_[1]) {
634     return -1;
635   }
636   return findHash(name, 1);
637 }
638 
639 /************************************************************************/
getInfinity() const640 double CoinLpIO::getInfinity() const
641 {
642   return infinity_;
643 }
644 
645 /************************************************************************/
setInfinity(const double value)646 void CoinLpIO::setInfinity(const double value)
647 {
648   if (value >= 1.0e20) {
649     infinity_ = value;
650   } else {
651     char str[8192];
652     sprintf(str, "### ERROR: value: %f\n", value);
653     throw CoinError(str, "setInfinity", "CoinLpIO", __FILE__, __LINE__);
654   }
655 }
656 
657 /************************************************************************/
getEpsilon() const658 double CoinLpIO::getEpsilon() const
659 {
660   return epsilon_;
661 }
662 
663 /************************************************************************/
setEpsilon(const double value)664 void CoinLpIO::setEpsilon(const double value)
665 {
666   if (value < 0.1) {
667     epsilon_ = value;
668   } else {
669     char str[8192];
670     sprintf(str, "### ERROR: value: %f\n", value);
671     throw CoinError(str, "setEpsilon", "CoinLpIO", __FILE__, __LINE__);
672   }
673 }
674 
675 /************************************************************************/
getNumberAcross() const676 int CoinLpIO::getNumberAcross() const
677 {
678   return numberAcross_;
679 }
680 
681 /************************************************************************/
setNumberAcross(const int value)682 void CoinLpIO::setNumberAcross(const int value)
683 {
684   if (value > 0) {
685     numberAcross_ = value;
686   } else {
687     char str[8192];
688     sprintf(str, "### ERROR: value: %d\n", value);
689     throw CoinError(str, "setNumberAcross", "CoinLpIO", __FILE__, __LINE__);
690   }
691 }
692 
693 /************************************************************************/
getDecimals() const694 int CoinLpIO::getDecimals() const
695 {
696   return decimals_;
697 }
698 
699 /************************************************************************/
setDecimals(const int value)700 void CoinLpIO::setDecimals(const int value)
701 {
702   if (value > 0) {
703     decimals_ = value;
704   } else {
705     char str[8192];
706     sprintf(str, "### ERROR: value: %d\n", value);
707     throw CoinError(str, "setDecimals", "CoinLpIO", __FILE__, __LINE__);
708   }
709 }
710 
711 /************************************************************************/
objectiveOffset() const712 double CoinLpIO::objectiveOffset() const
713 {
714   return objectiveOffset_[0];
715 }
716 
717 /************************************************************************/
objectiveOffset(int j) const718 double CoinLpIO::objectiveOffset(int j) const
719 {
720   return objectiveOffset_[j];
721 }
722 
723 /************************************************************************/
isInteger(int columnNumber) const724 bool CoinLpIO::isInteger(int columnNumber) const
725 {
726   const char *intType = integerType_;
727   if (intType == NULL)
728     return false;
729   assert(columnNumber >= 0 && columnNumber < numberColumns_);
730   if (intType[columnNumber] != 0)
731     return true;
732   return false;
733 }
734 
735 /************************************************************************/
integerColumns() const736 const char *CoinLpIO::integerColumns() const
737 {
738   return integerType_;
739 }
740 
741 /************************************************************************/
setLpDataWithoutRowAndColNames(const CoinPackedMatrix & m,const double * collb,const double * colub,const double * obj_coeff,const char * is_integer,const double * rowlb,const double * rowub)742 void CoinLpIO::setLpDataWithoutRowAndColNames(
743   const CoinPackedMatrix &m,
744   const double *collb, const double *colub,
745   const double *obj_coeff,
746   const char *is_integer,
747   const double *rowlb, const double *rowub)
748 {
749 
750   setLpDataWithoutRowAndColNames(m, collb, colub, &obj_coeff, 1, is_integer,
751     rowlb, rowub);
752 }
753 
754 /************************************************************************/
setLpDataWithoutRowAndColNames(const CoinPackedMatrix & m,const double * collb,const double * colub,const double * obj_coeff[MAX_OBJECTIVES],int num_objectives,const char * is_integer,const double * rowlb,const double * rowub)755 void CoinLpIO::setLpDataWithoutRowAndColNames(
756   const CoinPackedMatrix &m,
757   const double *collb, const double *colub,
758   const double *obj_coeff[MAX_OBJECTIVES],
759   int num_objectives,
760   const char *is_integer,
761   const double *rowlb, const double *rowub)
762 {
763 
764   freeAll();
765   problemName_ = CoinStrdup("");
766 
767   if (m.isColOrdered()) {
768     matrixByRow_ = new CoinPackedMatrix();
769     matrixByRow_->reverseOrderedCopyOf(m);
770   } else {
771     matrixByRow_ = new CoinPackedMatrix(m);
772   }
773   numberColumns_ = matrixByRow_->getNumCols();
774   numberRows_ = matrixByRow_->getNumRows();
775 
776   rowlower_ = reinterpret_cast< double * >(malloc(numberRows_ * sizeof(double)));
777   rowupper_ = reinterpret_cast< double * >(malloc(numberRows_ * sizeof(double)));
778   collower_ = reinterpret_cast< double * >(malloc(numberColumns_ * sizeof(double)));
779   colupper_ = reinterpret_cast< double * >(malloc(numberColumns_ * sizeof(double)));
780   std::copy(rowlb, rowlb + numberRows_, rowlower_);
781   std::copy(rowub, rowub + numberRows_, rowupper_);
782   std::copy(collb, collb + numberColumns_, collower_);
783   std::copy(colub, colub + numberColumns_, colupper_);
784   num_objectives_ = num_objectives;
785   for (int j = 0; j < num_objectives; j++) {
786     objective_[j] = reinterpret_cast< double * >(malloc(numberColumns_ * sizeof(double)));
787     std::copy(obj_coeff[j], obj_coeff[j] + numberColumns_, objective_[j]);
788   }
789 
790   if (is_integer) {
791     integerType_ = reinterpret_cast< char * >(malloc(numberColumns_ * sizeof(char)));
792     std::copy(is_integer, is_integer + numberColumns_, integerType_);
793   } else {
794     integerType_ = 0;
795   }
796 
797   if ((numberHash_[0] > 0) && (numberHash_[0] != numberRows_ + 1)) {
798     stopHash(0);
799   }
800   if ((numberHash_[1] > 0) && (numberHash_[1] != numberColumns_)) {
801     stopHash(1);
802   }
803 } /* SetLpDataWithoutRowAndColNames */
804 
805 /*************************************************************************/
setDefaultRowNames()806 void CoinLpIO::setDefaultRowNames()
807 {
808 
809   int i, nrow = getNumRows();
810   char **defaultRowNames = reinterpret_cast< char ** >(malloc((nrow + 1) * sizeof(char *)));
811   char buff[1024];
812 
813   for (i = 0; i < nrow; i++) {
814     sprintf(buff, "cons%d", i);
815     defaultRowNames[i] = CoinStrdup(buff);
816   }
817   sprintf(buff, "obj");
818   defaultRowNames[nrow] = CoinStrdup(buff);
819 
820   stopHash(0);
821   startHash(defaultRowNames, nrow + 1, 0);
822   objName_[0] = CoinStrdup("obj");
823 
824   for (i = 0; i < nrow + 1; i++) {
825     free(defaultRowNames[i]);
826   }
827   free(defaultRowNames);
828 
829 } /* setDefaultRowNames */
830 
831 /*************************************************************************/
setDefaultColNames()832 void CoinLpIO::setDefaultColNames()
833 {
834 
835   int j, ncol = getNumCols();
836   char **defaultColNames = reinterpret_cast< char ** >(malloc(ncol * sizeof(char *)));
837   char buff[256];
838 
839   for (j = 0; j < ncol; j++) {
840     sprintf(buff, "x%d", j);
841     defaultColNames[j] = CoinStrdup(buff);
842   }
843   stopHash(1);
844   startHash(defaultColNames, ncol, 1);
845 
846   for (j = 0; j < ncol; j++) {
847     free(defaultColNames[j]);
848   }
849   free(defaultColNames);
850 
851 } /* setDefaultColNames */
852 
853 /*************************************************************************/
setLpDataRowAndColNames(char const * const * const rownames,char const * const * const colnames)854 void CoinLpIO::setLpDataRowAndColNames(char const *const *const rownames,
855   char const *const *const colnames)
856 {
857 
858   int nrow = getNumRows();
859   int ncol = getNumCols();
860 
861   if (rownames != NULL) {
862     if (are_invalid_names(rownames, nrow + 1, true)) {
863       setDefaultRowNames();
864       handler_->message(COIN_GENERAL_WARNING, messages_) << "### CoinLpIO::setLpDataRowAndColNames(): Invalid row names\nUse getPreviousNames() to get the old row names.\nNow using default row names."
865                                                          << CoinMessageEol;
866     } else {
867       stopHash(0);
868       startHash(rownames, nrow + 1, 0);
869       objName_[0] = CoinStrdup(rownames[nrow]);
870       checkRowNames();
871     }
872   } else {
873     if (objName_[0] == NULL) {
874       objName_[0] = CoinStrdup("obj");
875     }
876   }
877 
878   if (colnames != NULL) {
879     if (are_invalid_names(colnames, ncol, false)) {
880       setDefaultColNames();
881       handler_->message(COIN_GENERAL_WARNING, messages_) << "### CoinLpIO::setLpDataRowAndColNames(): Invalid column names\nNow using default row names."
882                                                          << CoinMessageEol;
883     } else {
884       stopHash(1);
885       startHash(colnames, ncol, 1);
886       checkColNames();
887     }
888   }
889 } /* setLpDataColAndRowNames */
890 // Load in SOS stuff
loadSOS(int numberSets,const CoinSet * sets)891 void CoinLpIO::loadSOS(int numberSets, const CoinSet *sets)
892 {
893   if (numberSets_) {
894     for (int i = 0; i < numberSets_; i++)
895       delete set_[i];
896     delete[] set_;
897     set_ = NULL;
898     numberSets_ = 0;
899   }
900   if (numberSets) {
901     numberSets_ = numberSets;
902     set_ = new CoinSet *[numberSets_];
903     for (int i = 0; i < numberSets_; i++)
904       set_[i] = new CoinSet(sets[i]);
905   }
906 }
907 
908 // Load in SOS stuff
loadSOS(int numberSets,const CoinSet ** sets)909 void CoinLpIO::loadSOS(int numberSets, const CoinSet **sets)
910 {
911   if (numberSets_) {
912     for (int i = 0; i < numberSets_; i++)
913       delete set_[i];
914     delete[] set_;
915     set_ = NULL;
916     numberSets_ = 0;
917   }
918   if (numberSets) {
919     numberSets_ = numberSets;
920     set_ = new CoinSet *[numberSets_];
921     for (int i = 0; i < numberSets_; i++)
922       set_[i] = new CoinSet(*sets[i]);
923   }
924 }
925 
926 /************************************************************************/
out_coeff(FILE * fp,const double v,const int print_1) const927 void CoinLpIO::out_coeff(FILE *fp, const double v, const int print_1) const
928 {
929 
930   double lp_eps = getEpsilon();
931 
932   if (!print_1) {
933     if (fabs(v - 1) < lp_eps) {
934       return;
935     }
936     if (fabs(v + 1) < lp_eps) {
937       fprintf(fp, " -");
938       return;
939     }
940   }
941 
942   double frac = v - floor(v);
943 
944   if (frac < lp_eps) {
945     fprintf(fp, " %.0f", floor(v));
946   } else {
947     if (frac > 1 - lp_eps) {
948       fprintf(fp, " %.0f", floor(v + 0.5));
949     } else {
950       int decimals = getDecimals();
951       char form[15];
952       sprintf(form, " %%.%df", decimals);
953       fprintf(fp, form, v);
954     }
955   }
956 } /* out_coeff */
957 
958 /************************************************************************/
writeLp(const char * filename,const double epsilon,const int numberAcross,const int decimals,const bool useRowNames)959 int CoinLpIO::writeLp(const char *filename, const double epsilon,
960   const int numberAcross, const int decimals,
961   const bool useRowNames)
962 {
963 
964   FILE *fp = NULL;
965   fp = fopen(filename, "w");
966   if (!fp) {
967     char str[8192];
968     sprintf(str, "### ERROR: unable to open file %s\n", filename);
969     throw CoinError(str, "writeLP", "CoinLpIO", __FILE__, __LINE__);
970   }
971   int nerr = writeLp(fp, epsilon, numberAcross, decimals, useRowNames);
972   fclose(fp);
973   return (nerr);
974 }
975 
976 /************************************************************************/
writeLp(FILE * fp,const double epsilon,const int numberAcross,const int decimals,const bool useRowNames)977 int CoinLpIO::writeLp(FILE *fp, const double epsilon,
978   const int numberAcross, const int decimals,
979   const bool useRowNames)
980 {
981 
982   setEpsilon(epsilon);
983   setNumberAcross(numberAcross);
984   setDecimals(decimals);
985   return writeLp(fp, useRowNames);
986 }
987 
988 /************************************************************************/
writeLp(const char * filename,const bool useRowNames)989 int CoinLpIO::writeLp(const char *filename, const bool useRowNames)
990 {
991   FILE *fp = NULL;
992   fp = fopen(filename, "w");
993   if (!fp) {
994     char str[8192];
995     sprintf(str, "### ERROR: unable to open file %s\n", filename);
996     throw CoinError(str, "writeLP", "CoinLpIO", __FILE__, __LINE__);
997   }
998   int nerr = writeLp(fp, useRowNames);
999   fclose(fp);
1000   return (nerr);
1001 }
1002 
1003 /************************************************************************/
writeLp(FILE * fp,const bool useRowNames)1004 int CoinLpIO::writeLp(FILE *fp, const bool useRowNames)
1005 {
1006   double lp_eps = getEpsilon();
1007   double lp_inf = getInfinity();
1008   int numberAcross = getNumberAcross();
1009 
1010   int i, cnt_print, loc_row_names = 0, loc_col_names = 0;
1011   CoinBigIndex j;
1012   char **prowNames = NULL, **pcolNames = NULL;
1013 
1014   const int *indices = matrixByRow_->getIndices();
1015   const double *elements = matrixByRow_->getElements();
1016   int ncol = getNumCols();
1017   int nrow = getNumRows();
1018   const double *collow = getColLower();
1019   const double *colup = getColUpper();
1020   const double *rowlow = getRowLower();
1021   const double *rowup = getRowUpper();
1022   const char *integerType = integerColumns();
1023   char const *const *rowNames = getRowNames();
1024   char const *const *colNames = getColNames();
1025 
1026   char buff[256];
1027 
1028   if (rowNames == NULL) {
1029     loc_row_names = 1;
1030     prowNames = reinterpret_cast< char ** >(malloc((nrow + 1) * sizeof(char *)));
1031 
1032     for (j = 0; j < nrow; j++) {
1033       sprintf(buff, "cons%d", j);
1034       prowNames[j] = CoinStrdup(buff);
1035     }
1036     prowNames[nrow] = CoinStrdup("obj");
1037     rowNames = prowNames;
1038   }
1039 
1040   if (colNames == NULL) {
1041     loc_col_names = 1;
1042     pcolNames = reinterpret_cast< char ** >(malloc(ncol * sizeof(char *)));
1043 
1044     for (j = 0; j < ncol; j++) {
1045       sprintf(buff, "x%d", j);
1046       pcolNames[j] = CoinStrdup(buff);
1047     }
1048     colNames = pcolNames;
1049   }
1050 
1051 #ifdef LPIO_DEBUG
1052   printf("CoinLpIO::writeLp(): numberRows: %d numberColumns: %d\n",
1053     nrow, ncol);
1054 #endif
1055 
1056   fprintf(fp, "\\Problem name: %s\n\n", getProblemName());
1057   fprintf(fp, "Minimize\n");
1058 
1059   for (int k = 0; k < num_objectives_; k++) {
1060     if (useRowNames) {
1061       fprintf(fp, "%s:", objName_[k]);
1062     }
1063 
1064     cnt_print = 0;
1065     for (j = 0; j < ncol; j++) {
1066       if ((cnt_print > 0) && (objective_[k][j] > lp_eps)) {
1067         fprintf(fp, " +");
1068       }
1069       if (fabs(objective_[k][j]) > lp_eps) {
1070         out_coeff(fp, objective_[k][j], 0);
1071         fprintf(fp, " %s", colNames[j]);
1072         cnt_print++;
1073         if (cnt_print % numberAcross == 0) {
1074           fprintf(fp, "\n");
1075         }
1076       }
1077     }
1078 
1079     if ((cnt_print > 0) && (objectiveOffset_[k] > lp_eps)) {
1080       fprintf(fp, " +");
1081     }
1082     if (fabs(objectiveOffset_[k]) > lp_eps) {
1083       out_coeff(fp, objectiveOffset_[k], 1);
1084       cnt_print++;
1085     }
1086     if ((cnt_print == 0) || (cnt_print % numberAcross != 0)) {
1087       fprintf(fp, "\n");
1088     }
1089   }
1090 
1091   fprintf(fp, "Subject To\n");
1092 
1093   int cnt_out_rows = 0;
1094 
1095   for (i = 0; i < nrow; i++) {
1096     cnt_print = 0;
1097 
1098     if (useRowNames) {
1099       fprintf(fp, "%s: ", rowNames[i]);
1100     }
1101     cnt_out_rows++;
1102 
1103     for (j = matrixByRow_->getVectorFirst(i);
1104          j < matrixByRow_->getVectorLast(i); j++) {
1105       if ((cnt_print > 0) && (elements[j] > lp_eps)) {
1106         fprintf(fp, " +");
1107       }
1108       if (fabs(elements[j]) > lp_eps) {
1109         out_coeff(fp, elements[j], 0);
1110         fprintf(fp, " %s", colNames[indices[j]]);
1111         cnt_print++;
1112         if (cnt_print % numberAcross == 0) {
1113           fprintf(fp, "\n");
1114         }
1115       }
1116     }
1117 
1118     if (rowup[i] - rowlow[i] < lp_eps) {
1119       fprintf(fp, " =");
1120       out_coeff(fp, rowlow[i], 1);
1121       fprintf(fp, "\n");
1122     } else {
1123       if (rowup[i] < lp_inf) {
1124         fprintf(fp, " <=");
1125         out_coeff(fp, rowup[i], 1);
1126         fprintf(fp, "\n");
1127 
1128         if (rowlower_[i] > -lp_inf) {
1129 
1130           cnt_print = 0;
1131 
1132           if (useRowNames) {
1133             fprintf(fp, "%s_low:", rowNames[i]);
1134           }
1135           cnt_out_rows++;
1136 
1137           for (j = matrixByRow_->getVectorFirst(i);
1138                j < matrixByRow_->getVectorLast(i); j++) {
1139             if ((cnt_print > 0) && (elements[j] > lp_eps)) {
1140               fprintf(fp, " +");
1141             }
1142             if (fabs(elements[j]) > lp_eps) {
1143               out_coeff(fp, elements[j], 0);
1144               fprintf(fp, " %s", colNames[indices[j]]);
1145               cnt_print++;
1146               if (cnt_print % numberAcross == 0) {
1147                 fprintf(fp, "\n");
1148               }
1149             }
1150           }
1151           fprintf(fp, " >=");
1152           out_coeff(fp, rowlow[i], 1);
1153           fprintf(fp, "\n");
1154         }
1155 
1156       } else {
1157         fprintf(fp, " >=");
1158         out_coeff(fp, rowlow[i], 1);
1159         fprintf(fp, "\n");
1160       }
1161     }
1162   }
1163 
1164 #ifdef LPIO_DEBUG
1165   printf("CoinLpIO::writeLp(): Done with constraints\n");
1166 #endif
1167 
1168   fprintf(fp, "Bounds\n");
1169 
1170   for (j = 0; j < ncol; j++) {
1171     if ((collow[j] > -lp_inf) && (colup[j] < lp_inf)) {
1172       out_coeff(fp, collow[j], 1);
1173       fprintf(fp, " <= %s <=", colNames[j]);
1174       out_coeff(fp, colup[j], 1);
1175       fprintf(fp, "\n");
1176     }
1177     if ((collow[j] == -lp_inf) && (colup[j] < lp_inf)) {
1178       fprintf(fp, "%s <=", colNames[j]);
1179       out_coeff(fp, colup[j], 1);
1180       fprintf(fp, "\n");
1181     }
1182     if ((collow[j] > -lp_inf) && (colup[j] == lp_inf)) {
1183       if (fabs(collow[j]) > lp_eps) {
1184         out_coeff(fp, collow[j], 1);
1185         fprintf(fp, " <= %s\n", colNames[j]);
1186       }
1187     }
1188     if (collow[j] == -lp_inf) {
1189       fprintf(fp, " %s Free\n", colNames[j]);
1190     }
1191   }
1192 
1193 #ifdef LPIO_DEBUG
1194   printf("CoinLpIO::writeLp(): Done with bounds\n");
1195 #endif
1196 
1197   bool semis = false;
1198   if (integerType != NULL) {
1199     int first_int = 1;
1200     cnt_print = 0;
1201     for (j = 0; j < ncol; j++) {
1202       if (integerType[j] == 1 || integerType[j] == 4) {
1203 
1204         if (first_int) {
1205           fprintf(fp, "Integers\n");
1206           first_int = 0;
1207         }
1208 
1209         fprintf(fp, "%s ", colNames[j]);
1210         cnt_print++;
1211         if (cnt_print % numberAcross == 0) {
1212           fprintf(fp, "\n");
1213         }
1214       }
1215       if (integerType[j] > 1)
1216         semis = true;
1217     }
1218 
1219     if (cnt_print % numberAcross != 0) {
1220       fprintf(fp, "\n");
1221     }
1222     if (semis) {
1223       int first_int = 1;
1224       cnt_print = 0;
1225       for (j = 0; j < ncol; j++) {
1226         if (integerType[j] > 2) {
1227 
1228           if (first_int) {
1229             fprintf(fp, "Semis\n");
1230             first_int = 0;
1231           }
1232 
1233           fprintf(fp, "%s ", colNames[j]);
1234           cnt_print++;
1235           if (cnt_print % numberAcross == 0) {
1236             fprintf(fp, "\n");
1237           }
1238         }
1239       }
1240 
1241       if (cnt_print % numberAcross != 0) {
1242         fprintf(fp, "\n");
1243       }
1244     }
1245   }
1246 
1247 #ifdef LPIO_DEBUG
1248   printf("CoinLpIO::writeLp(): Done with integers\n");
1249 #endif
1250 
1251   if (set_ != NULL) {
1252     fprintf(fp, "SOS\n");
1253     double lp_eps = getEpsilon();
1254     int decimals = getDecimals();
1255     char form[15];
1256     sprintf(form, "%%.%df", decimals);
1257     for (int iSet = 0; iSet < numberSets_; iSet++) {
1258       cnt_print = 0;
1259       const CoinSet *set = set_[iSet];
1260       // no space as readLp gets marginally confused
1261       fprintf(fp, "set%d:S%c::", iSet, '0' + set->setType());
1262       const int *which = set->which();
1263       const double *weights = set->weights();
1264       int numberEntries = set->numberEntries();
1265       for (j = 0; j < numberEntries; j++) {
1266         int iColumn = which[j];
1267         fprintf(fp, " %s:", colNames[iColumn]);
1268         // modified out_coeff (no leading space)
1269         double v = weights[j];
1270         double frac = v - floor(v);
1271 
1272         if (frac < lp_eps) {
1273           fprintf(fp, "%.0f", floor(v));
1274         } else {
1275           if (frac > 1 - lp_eps) {
1276             fprintf(fp, "%.0f", floor(v + 0.5));
1277           } else {
1278             fprintf(fp, form, v);
1279           }
1280         }
1281         cnt_print++;
1282         if (cnt_print % numberAcross == 0) {
1283           fprintf(fp, "\n");
1284         }
1285       }
1286 
1287       if (cnt_print % numberAcross != 0) {
1288         fprintf(fp, "\n");
1289       }
1290     }
1291   }
1292 
1293 #ifdef LPIO_DEBUG
1294   printf("CoinLpIO::writeLp(): Done with SOS\n");
1295 #endif
1296 
1297   fprintf(fp, "End\n");
1298 
1299   if (loc_row_names) {
1300     for (j = 0; j < nrow + 1; j++) {
1301       free(prowNames[j]);
1302     }
1303     free(prowNames);
1304   }
1305 
1306   if (loc_col_names) {
1307     for (j = 0; j < ncol; j++) {
1308       free(pcolNames[j]);
1309     }
1310     free(pcolNames);
1311   }
1312   return 0;
1313 } /* writeLp */
1314 
1315 /*************************************************************************/
find_obj() const1316 int CoinLpIO::find_obj() const
1317 {
1318 
1319   char buff[1024];
1320 
1321   sprintf(buff, "aa");
1322   size_t lbuff = strlen(buff);
1323 
1324   while (((lbuff != 8) || (CoinStrNCaseCmp(buff, "minimize", 8) != 0)) && ((lbuff != 3) || (CoinStrNCaseCmp(buff, "min", 3) != 0)) && ((lbuff != 8) || (CoinStrNCaseCmp(buff, "maximize", 8) != 0)) && ((lbuff != 3) || (CoinStrNCaseCmp(buff, "max", 3) != 0))) {
1325 
1326     int x = fscanfLpIO(buff);
1327     lbuff = strlen(buff);
1328 
1329     if (x <= 0) {
1330       char str[8192];
1331       sprintf(str, "### ERROR: Unable to locate objective function\n");
1332       throw CoinError(str, "find_obj", "CoinLpIO", __FILE__, __LINE__);
1333     }
1334   }
1335 
1336   if (((lbuff == 8) && (CoinStrNCaseCmp(buff, "minimize", 8) == 0)) || ((lbuff == 3) && (CoinStrNCaseCmp(buff, "min", 3) == 0))) {
1337     return (1);
1338   }
1339   return (-1);
1340 } /* find_obj */
1341 
1342 /*************************************************************************/
is_subject_to(const char * buff) const1343 int CoinLpIO::is_subject_to(const char *buff) const
1344 {
1345 
1346   size_t lbuff = strlen(buff);
1347 
1348   if (((lbuff == 4) && (CoinStrNCaseCmp(buff, "s.t.", 4) == 0)) || ((lbuff == 3) && (CoinStrNCaseCmp(buff, "st.", 3) == 0)) || ((lbuff == 2) && (CoinStrNCaseCmp(buff, "st", 2) == 0))) {
1349     return (1);
1350   }
1351   if ((lbuff == 7) && (CoinStrNCaseCmp(buff, "subject", 7) == 0)) {
1352     return (2);
1353   }
1354   return (0);
1355 } /* is_subject_to */
1356 
1357 /*************************************************************************/
first_is_number(const char * buff) const1358 int CoinLpIO::first_is_number(const char *buff) const
1359 {
1360 
1361   size_t pos;
1362   char str_num[] = "1234567890";
1363 
1364   pos = strcspn(buff, str_num);
1365   if (pos == 0) {
1366     return (1);
1367   }
1368   return (0);
1369 } /* first_is_number */
1370 
1371 /*************************************************************************/
is_sense(const char * buff) const1372 int CoinLpIO::is_sense(const char *buff) const
1373 {
1374 
1375   size_t pos;
1376   char str_sense[] = "<>=";
1377 
1378   pos = strcspn(buff, str_sense);
1379   if (pos == 0) {
1380     if (strcmp(buff, "<=") == 0) {
1381       return (0);
1382     }
1383     if (strcmp(buff, "=") == 0) {
1384       return (1);
1385     }
1386     if (strcmp(buff, ">=") == 0) {
1387       return (2);
1388     }
1389 
1390     printf("### ERROR: CoinLpIO: is_sense(): string: %s \n", buff);
1391   }
1392   return (-1);
1393 } /* is_sense */
1394 
1395 /*************************************************************************/
is_free(const char * buff) const1396 int CoinLpIO::is_free(const char *buff) const
1397 {
1398 
1399   size_t lbuff = strlen(buff);
1400 
1401   if ((lbuff == 4) && (CoinStrNCaseCmp(buff, "free", 4) == 0)) {
1402     return (1);
1403   }
1404   return (0);
1405 } /* is_free */
1406 
1407 /*************************************************************************/
is_inf(const char * buff) const1408 int CoinLpIO::is_inf(const char *buff) const
1409 {
1410 
1411   size_t lbuff = strlen(buff);
1412 
1413   if ((lbuff == 3) && (CoinStrNCaseCmp(buff, "inf", 3) == 0)) {
1414     return (1);
1415   }
1416   return (0);
1417 } /* is_inf */
1418 
1419 /*************************************************************************/
is_comment(const char * buff) const1420 int CoinLpIO::is_comment(const char *buff) const
1421 {
1422 
1423   if ((buff[0] == '/') || (buff[0] == '\\')) {
1424     return (1);
1425   }
1426   return (0);
1427 } /* is_comment */
1428 
1429 /*************************************************************************/
skip_comment(char * buff) const1430 void CoinLpIO::skip_comment(char *buff) const
1431 {
1432 
1433   while (strcspn(buff, "\n") == strlen(buff)) { // end of line not read yet
1434     // keep going until in correct buffer
1435     while (bufferLength_ < 0) {
1436       if (fscanfLpIO(buff) == 0)
1437         throw("bad fgets");
1438     }
1439     // and throw away
1440     bufferPosition_ = bufferLength_;
1441     break;
1442   }
1443 } /* skip_comment */
1444 
1445 /*************************************************************************/
is_invalid_name(const char * name,const bool ranged) const1446 int CoinLpIO::is_invalid_name(const char *name,
1447   const bool ranged) const
1448 {
1449 
1450   size_t pos, lname, valid_lname = 100;
1451   char str_valid[] = "1234567890abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ\"!#$%&(),.;?@_'`{}~";
1452 
1453   if (ranged) {
1454     valid_lname -= 4; // will add "_low" when writing the Lp file
1455   }
1456 
1457   if (name == NULL) {
1458     lname = 0;
1459   } else {
1460     lname = strlen(name);
1461   }
1462   if (lname < 1) {
1463     handler_->message(COIN_GENERAL_WARNING, messages_) << "### CoinLpIO::is_invalid_name(): Name is empty"
1464                                                        << CoinMessageEol;
1465     return (5);
1466   }
1467   if (lname > valid_lname) {
1468     char printBuffer[512];
1469     sprintf(printBuffer, "### CoinLpIO::is_invalid_name(): Name %s is too long",
1470       name);
1471     handler_->message(COIN_GENERAL_WARNING, messages_) << printBuffer
1472                                                        << CoinMessageEol;
1473     return (1);
1474   }
1475   if (first_is_number(name)) {
1476     char printBuffer[512];
1477     sprintf(printBuffer, "### CoinLpIO::is_invalid_name(): Name %s should not start with a number", name);
1478     handler_->message(COIN_GENERAL_WARNING, messages_) << printBuffer
1479                                                        << CoinMessageEol;
1480     return (2);
1481   }
1482   pos = strspn(name, str_valid);
1483   if (pos != lname) {
1484     char printBuffer[512];
1485     sprintf(printBuffer, "### CoinLpIO::is_invalid_name(): Name %s contains illegal character '%c'", name, name[pos]);
1486     handler_->message(COIN_GENERAL_WARNING, messages_) << printBuffer
1487                                                        << CoinMessageEol;
1488     return (3);
1489   }
1490 
1491   if ((is_keyword(name)) || (is_free(name) || (is_inf(name)))) {
1492     return (4);
1493   }
1494 
1495   return (0);
1496 } /* is_invalid_name */
1497 
1498 /*************************************************************************/
are_invalid_names(char const * const * const vnames,const int card_vnames,const bool check_ranged) const1499 int CoinLpIO::are_invalid_names(char const *const *const vnames,
1500   const int card_vnames,
1501   const bool check_ranged) const
1502 {
1503 
1504   int i, invalid = 0, flag, nrows = getNumRows();
1505   bool is_ranged = 0;
1506   const char *rSense = getRowSense();
1507 
1508   if ((check_ranged) && (card_vnames != nrows + 1)) {
1509     char str[8192];
1510     sprintf(str, "### ERROR: card_vnames: %d   number of rows: %d\n",
1511       card_vnames, getNumRows());
1512     throw CoinError(str, "are_invalid_names", "CoinLpIO", __FILE__, __LINE__);
1513   }
1514 
1515   for (i = 0; i < card_vnames; i++) {
1516 
1517     if ((check_ranged) && (i < nrows) && (rSense[i] == 'R')) {
1518       is_ranged = true;
1519     } else {
1520       is_ranged = false;
1521     }
1522     flag = is_invalid_name(vnames[i], is_ranged);
1523     if (flag) {
1524       char printBuffer[512];
1525       sprintf(printBuffer, "### CoinLpIO::are_invalid_names(): Invalid name: vnames[%d]: %s",
1526         i, vnames[i]);
1527       handler_->message(COIN_GENERAL_WARNING, messages_) << printBuffer
1528                                                          << CoinMessageEol;
1529       invalid = flag;
1530     }
1531   }
1532   return (invalid);
1533 } /* are_invalid_names */
1534 
1535 /*************************************************************************/
read_monom_obj(double * coeff,char ** name,int * cnt,char ** obj_name,int * num_objectives,int * obj_starts)1536 int CoinLpIO::read_monom_obj(double *coeff, char **name, int *cnt,
1537   char **obj_name, int *num_objectives, int *obj_starts)
1538 {
1539 
1540   double mult;
1541   char buff[1024] = "aa", loc_name[1024], *start;
1542   int read_st = 0;
1543 
1544   int x = fscanfLpIO(buff);
1545 
1546   if (x <= 0) {
1547     char str[8192];
1548     sprintf(str, "### ERROR: Unable to read objective function\n");
1549     throw CoinError(str, "read_monom_obj", "CoinLpIO", __FILE__, __LINE__);
1550   }
1551 
1552   if (buff[strlen(buff) - 1] == ':') {
1553     buff[strlen(buff) - 1] = '\0';
1554 
1555 #ifdef LPIO_DEBUG
1556     printf("CoinLpIO: read_monom_obj(): obj_name: %s\n", buff);
1557 #endif
1558 
1559     if (*num_objectives == MAX_OBJECTIVES) {
1560       char str[8192];
1561       sprintf(str, "### ERROR: Too many objective functions.\n");
1562       sprintf(str, "### ERROR: Change MAX_OBJECTIVES to larger number.\n");
1563       throw CoinError(str, "read_monom_obj", "CoinLpIO", __FILE__, __LINE__);
1564     }
1565     obj_name[*num_objectives] = CoinStrdup(buff);
1566     obj_starts[(*num_objectives)++] = *cnt;
1567     return (0);
1568   }
1569 
1570   if (*num_objectives == 0) {
1571     obj_starts[(*num_objectives)++] = *cnt;
1572   }
1573 
1574   read_st = is_subject_to(buff);
1575 
1576 #ifdef LPIO_DEBUG
1577   printf("read_monom_obj: first buff: (%s)\n", buff);
1578 #endif
1579 
1580   if (read_st > 0) {
1581     return (read_st);
1582   }
1583 
1584   start = buff;
1585   mult = 1;
1586   if (buff[0] == '+') {
1587     mult = 1;
1588     if (strlen(buff) == 1) {
1589       fscanfLpIO(buff);
1590       start = buff;
1591     } else {
1592       start = &(buff[1]);
1593     }
1594   }
1595 
1596   if (buff[0] == '-') {
1597     mult = -1;
1598     if (strlen(buff) == 1) {
1599       fscanfLpIO(buff);
1600       start = buff;
1601     } else {
1602       start = &(buff[1]);
1603     }
1604   }
1605 
1606   if (first_is_number(start)) {
1607     coeff[*cnt] = atof(start);
1608     sprintf(loc_name, "aa");
1609     fscanfLpIO(loc_name);
1610   } else {
1611     coeff[*cnt] = 1;
1612     strcpy(loc_name, start);
1613   }
1614 
1615   read_st = is_subject_to(loc_name);
1616 
1617 #ifdef LPIO_DEBUG
1618   printf("read_monom_obj: second buff: (%s)\n", buff);
1619 #endif
1620 
1621   if (read_st > 0) {
1622     setObjectiveOffset(mult * coeff[*cnt]);
1623 
1624 #ifdef LPIO_DEBUG
1625     printf("read_monom_obj: objectiveOffset: %f\n", objectiveOffset_);
1626 #endif
1627 
1628     return (read_st);
1629   }
1630 
1631   coeff[*cnt] *= mult;
1632   name[*cnt] = CoinStrdup(loc_name);
1633 
1634 #ifdef LPIO_DEBUG
1635   printf("read_monom_obj: (%f)  (%s)\n", coeff[*cnt], name[*cnt]);
1636 #endif
1637 
1638   (*cnt)++;
1639 
1640   return (read_st);
1641 } /* read_monom_obj */
1642 
1643 /*************************************************************************/
read_monom_row(char * start_str,double * coeff,char ** name,int cnt_coeff) const1644 int CoinLpIO::read_monom_row(char *start_str,
1645   double *coeff, char **name,
1646   int cnt_coeff) const
1647 {
1648 
1649   double mult;
1650   char buff[1024], loc_name[1024], *start;
1651   int read_sense = -1;
1652 
1653   sprintf(buff, "%s", start_str);
1654   read_sense = is_sense(buff);
1655   if (read_sense > -1) {
1656     return (read_sense);
1657   }
1658 
1659   start = buff;
1660   mult = 1;
1661   if (buff[0] == '+') {
1662     mult = 1;
1663     if (strlen(buff) == 1) {
1664       fscanfLpIO(buff);
1665       start = buff;
1666     } else {
1667       start = &(buff[1]);
1668     }
1669   }
1670 
1671   if (buff[0] == '-') {
1672     mult = -1;
1673     if (strlen(buff) == 1) {
1674       fscanfLpIO(buff);
1675       start = buff;
1676     } else {
1677       start = &(buff[1]);
1678     }
1679   }
1680 
1681   if (first_is_number(start)) {
1682     coeff[cnt_coeff] = atof(start);
1683     fscanfLpIO(loc_name);
1684   } else {
1685     coeff[cnt_coeff] = 1;
1686     strcpy(loc_name, start);
1687   }
1688 
1689   coeff[cnt_coeff] *= mult;
1690 #ifdef KILL_ZERO_READLP
1691   if (fabs(coeff[cnt_coeff]) > epsilon_)
1692     name[cnt_coeff] = CoinStrdup(loc_name);
1693   else
1694     read_sense = -2; // effectively zero
1695 #else
1696   name[cnt_coeff] = CoinStrdup(loc_name);
1697 #endif
1698 
1699 #ifdef LPIO_DEBUG
1700   printf("CoinLpIO: read_monom_row: (%f)  (%s)\n",
1701     coeff[cnt_coeff], name[cnt_coeff]);
1702 #endif
1703   return (read_sense);
1704 } /* read_monom_row */
1705 
1706 /*************************************************************************/
realloc_coeff(double ** coeff,char *** colNames,int * maxcoeff) const1707 void CoinLpIO::realloc_coeff(double **coeff, char ***colNames,
1708   int *maxcoeff) const
1709 {
1710 
1711   *maxcoeff *= 5;
1712 
1713   *colNames = reinterpret_cast< char ** >(realloc((*colNames), (*maxcoeff + 1) * sizeof(char *)));
1714   *coeff = reinterpret_cast< double * >(realloc((*coeff), (*maxcoeff + 1) * sizeof(double)));
1715 
1716 } /* realloc_coeff */
1717 
1718 /*************************************************************************/
realloc_row(char *** rowNames,CoinBigIndex ** start,double ** rhs,double ** rowlow,double ** rowup,int * maxrow) const1719 void CoinLpIO::realloc_row(char ***rowNames, CoinBigIndex **start, double **rhs,
1720   double **rowlow, double **rowup, int *maxrow) const
1721 {
1722 
1723   *maxrow *= 5;
1724   *rowNames = reinterpret_cast< char ** >(realloc((*rowNames), (*maxrow + 1) * sizeof(char *)));
1725   *start = reinterpret_cast< CoinBigIndex * >(realloc((*start), (*maxrow + 1) * sizeof(CoinBigIndex)));
1726   *rhs = reinterpret_cast< double * >(realloc((*rhs), (*maxrow + 1) * sizeof(double)));
1727   *rowlow = reinterpret_cast< double * >(realloc((*rowlow), (*maxrow + 1) * sizeof(double)));
1728   *rowup = reinterpret_cast< double * >(realloc((*rowup), (*maxrow + 1) * sizeof(double)));
1729 
1730 } /* realloc_row */
1731 
1732 /*************************************************************************/
realloc_col(double ** collow,double ** colup,char ** is_int,int * maxcol) const1733 void CoinLpIO::realloc_col(double **collow, double **colup, char **is_int,
1734   int *maxcol) const
1735 {
1736   *maxcol += 100;
1737   *collow = reinterpret_cast< double * >(realloc((*collow), (*maxcol + 1) * sizeof(double)));
1738   *colup = reinterpret_cast< double * >(realloc((*colup), (*maxcol + 1) * sizeof(double)));
1739   *is_int = reinterpret_cast< char * >(realloc((*is_int), (*maxcol + 1) * sizeof(char)));
1740   // clean values
1741   double lp_inf = getInfinity();
1742   for (int i = (*maxcol) - 100; i < *maxcol; i++) {
1743     (*collow)[i] = 0;
1744     (*colup)[i] = lp_inf;
1745     (*is_int)[i] = 0;
1746   }
1747 
1748 } /* realloc_col */
1749 
1750 /*************************************************************************/
read_row(char * buff,double ** pcoeff,char *** pcolNames,int * cnt_coeff,int * maxcoeff,double * rhs,double * rowlow,double * rowup,int * cnt_row,double inf) const1751 void CoinLpIO::read_row(char *buff,
1752   double **pcoeff, char ***pcolNames,
1753   int *cnt_coeff,
1754   int *maxcoeff,
1755   double *rhs, double *rowlow, double *rowup,
1756   int *cnt_row, double inf) const
1757 {
1758 
1759   int read_sense = -1;
1760   char start_str[1024];
1761 
1762   sprintf(start_str, "%s", buff);
1763 
1764   while (read_sense < 0) {
1765 
1766     if ((*cnt_coeff) == (*maxcoeff)) {
1767       realloc_coeff(pcoeff, pcolNames, maxcoeff);
1768     }
1769     read_sense = read_monom_row(start_str,
1770       *pcoeff, *pcolNames, *cnt_coeff);
1771 #ifdef KILL_ZERO_READLP
1772     if (read_sense != -2) // see if zero
1773 #endif
1774       (*cnt_coeff)++;
1775 
1776     int x = fscanfLpIO(start_str);
1777 
1778     if (x <= 0) {
1779       char str[8192];
1780       sprintf(str, "### ERROR: Unable to read row monomial\n");
1781       throw CoinError(str, "read_monom_row", "CoinLpIO", __FILE__, __LINE__);
1782     }
1783   }
1784   (*cnt_coeff)--;
1785 
1786   rhs[*cnt_row] = atof(start_str);
1787 
1788   switch (read_sense) {
1789   case 0:
1790     rowlow[*cnt_row] = -inf;
1791     rowup[*cnt_row] = rhs[*cnt_row];
1792     break;
1793   case 1:
1794     rowlow[*cnt_row] = rhs[*cnt_row];
1795     rowup[*cnt_row] = rhs[*cnt_row];
1796     break;
1797   case 2:
1798     rowlow[*cnt_row] = rhs[*cnt_row];
1799     rowup[*cnt_row] = inf;
1800     break;
1801   default:
1802     break;
1803   }
1804   (*cnt_row)++;
1805 
1806 } /* read_row */
1807 
1808 /*************************************************************************/
is_keyword(const char * buff) const1809 int CoinLpIO::is_keyword(const char *buff) const
1810 {
1811 
1812   size_t lbuff = strlen(buff);
1813 
1814   if (((lbuff == 5) && (CoinStrNCaseCmp(buff, "bound", 5) == 0)) || ((lbuff == 6) && (CoinStrNCaseCmp(buff, "bounds", 6) == 0))) {
1815     return (1);
1816   }
1817 
1818   if (((lbuff == 7) && (CoinStrNCaseCmp(buff, "integer", 7) == 0)) || ((lbuff == 8) && (CoinStrNCaseCmp(buff, "integers", 8) == 0))) {
1819     return (2);
1820   }
1821 
1822   if (((lbuff == 7) && (CoinStrNCaseCmp(buff, "general", 7) == 0)) || ((lbuff == 8) && (CoinStrNCaseCmp(buff, "generals", 8) == 0))) {
1823     return (2);
1824   }
1825 
1826   if (((lbuff == 6) && (CoinStrNCaseCmp(buff, "binary", 6) == 0)) || ((lbuff == 8) && (CoinStrNCaseCmp(buff, "binaries", 8) == 0))) {
1827     return (3);
1828   }
1829 
1830   if (((lbuff == 15) && (CoinStrNCaseCmp(buff, "semi-continuous", 15) == 0)) || ((lbuff == 4) && (CoinStrNCaseCmp(buff, "semi", 4) == 0)) || ((lbuff == 5) && (CoinStrNCaseCmp(buff, "semis", 5) == 0))) {
1831     return (4);
1832   }
1833 
1834   if ((lbuff == 3) && (CoinStrNCaseCmp(buff, "sos", 3) == 0)) {
1835     return (5);
1836   }
1837 
1838   if ((lbuff == 3) && (CoinStrNCaseCmp(buff, "end", 3) == 0)) {
1839     return (6);
1840   }
1841 
1842   return (0);
1843 
1844 } /* is_keyword */
1845 
1846 /*************************************************************************/
readLp(const char * filename,const double epsilon)1847 void CoinLpIO::readLp(const char *filename, const double epsilon)
1848 {
1849   setEpsilon(epsilon);
1850   readLp(filename);
1851 }
1852 
1853 /*************************************************************************/
readLp(const char * filename)1854 void CoinLpIO::readLp(const char *filename)
1855 {
1856   delete input_;
1857   input_ = NULL;
1858   bool readable = false;
1859   // see if just .lp
1860   int length = strlen(filename);
1861   if ((length > 3 && !strncmp(filename + length - 3, ".lp", 3))) {
1862     FILE *fp = fopen(filename, "r");
1863     if (fp) {
1864       readable = true;
1865       input_ = new CoinPlainFileInput(fp);
1866     }
1867   } else if (strstr(filename, ".lp")) {
1868     std::string fname(filename);
1869     readable = fileCoinReadable(fname);
1870     if (readable)
1871       input_ = CoinFileInput::create(fname);
1872   }
1873   if (!readable) {
1874     char str[8192];
1875     sprintf(str, "### ERROR: Unable to open file %s for reading\n", filename);
1876     throw CoinError(str, "readLp", "CoinLpIO", __FILE__, __LINE__);
1877   }
1878   readLp();
1879 }
1880 
1881 /*************************************************************************/
readLp(FILE * fp,const double epsilon)1882 void CoinLpIO::readLp(FILE *fp, const double epsilon)
1883 {
1884   setEpsilon(epsilon);
1885   readLp(fp);
1886 }
1887 
1888 /*************************************************************************/
readLp(FILE * fp)1889 void CoinLpIO::readLp(FILE *fp)
1890 {
1891   delete input_;
1892   input_ = new CoinPlainFileInput(fp);
1893   readLp();
1894 }
1895 /*************************************************************************/
readLp()1896 void CoinLpIO::readLp()
1897 {
1898 
1899   int maxrow = 1000;
1900   int maxcoeff = 40000;
1901   double lp_eps = getEpsilon();
1902   double lp_inf = getInfinity();
1903 
1904   char buff[1024];
1905   bufferPosition_ = 0;
1906   bufferLength_ = 0;
1907   eofFound_ = false;
1908 
1909   int objsense, cnt_coeff = 0, cnt_row = 0, cnt_obj = 0;
1910   int num_objectives = 0;
1911   char *objName[MAX_OBJECTIVES] = { NULL, NULL };
1912   int obj_starts[MAX_OBJECTIVES + 1];
1913   char **colNames = reinterpret_cast< char ** >(malloc((maxcoeff + 1) * sizeof(char *)));
1914   double *coeff = reinterpret_cast< double * >(malloc((maxcoeff + 1) * sizeof(double)));
1915   char **rowNames = reinterpret_cast< char ** >(malloc((maxrow + MAX_OBJECTIVES) * sizeof(char *)));
1916   CoinBigIndex *start = reinterpret_cast< CoinBigIndex * >(malloc((maxrow + MAX_OBJECTIVES) * sizeof(CoinBigIndex)));
1917   double *rhs = reinterpret_cast< double * >(malloc((maxrow + 1) * sizeof(double)));
1918   double *rowlow = reinterpret_cast< double * >(malloc((maxrow + 1) * sizeof(double)));
1919   double *rowup = reinterpret_cast< double * >(malloc((maxrow + 1) * sizeof(double)));
1920 
1921   int i;
1922 
1923   objsense = find_obj();
1924 
1925   int read_st = 0;
1926   while (!read_st) {
1927     read_st = read_monom_obj(coeff, colNames, &cnt_obj, objName, &num_objectives, obj_starts);
1928 
1929     if (cnt_obj == maxcoeff) {
1930       realloc_coeff(&coeff, &colNames, &maxcoeff);
1931     }
1932   }
1933 
1934   obj_starts[num_objectives] = cnt_obj;
1935   start[0] = cnt_obj;
1936   cnt_coeff = cnt_obj;
1937 
1938   if (read_st == 2) {
1939     int x = fscanfLpIO(buff);
1940     if (x <= 0)
1941       throw("bad fscanf");
1942     size_t lbuff = strlen(buff);
1943 
1944     if ((lbuff != 2) || (CoinStrNCaseCmp(buff, "to", 2) != 0)) {
1945       char str[8192];
1946       sprintf(str, "### ERROR: Can not locate keyword 'Subject To'\n");
1947       throw CoinError(str, "readLp", "CoinLpIO", __FILE__, __LINE__);
1948     }
1949   }
1950 
1951   fscanfLpIO(buff);
1952 
1953   while (!is_keyword(buff)) {
1954     if (buff[strlen(buff) - 1] == ':') {
1955       buff[strlen(buff) - 1] = '\0';
1956 
1957 #ifdef LPIO_DEBUG
1958       printf("CoinLpIO::readLp(): rowName[%d]: %s\n", cnt_row, buff);
1959 #endif
1960 
1961       rowNames[cnt_row] = CoinStrdup(buff);
1962       fscanfLpIO(buff);
1963     } else {
1964       char rname[15];
1965       sprintf(rname, "cons%d", cnt_row);
1966       rowNames[cnt_row] = CoinStrdup(rname);
1967     }
1968     read_row(buff,
1969       &coeff, &colNames, &cnt_coeff, &maxcoeff, rhs, rowlow, rowup,
1970       &cnt_row, lp_inf);
1971     fscanfLpIO(buff);
1972     start[cnt_row] = cnt_coeff;
1973 
1974     if (cnt_row == maxrow) {
1975       realloc_row(&rowNames, &start, &rhs, &rowlow, &rowup, &maxrow);
1976     }
1977   }
1978 
1979   numberRows_ = cnt_row;
1980 
1981   stopHash(1);
1982   startHash(colNames, cnt_coeff, 1);
1983 
1984   COINColumnIndex icol;
1985   int read_sense1, read_sense2;
1986   double bnd1 = 0, bnd2 = 0;
1987 
1988   int maxcol = numberHash_[1] + 100;
1989 
1990   double *collow = reinterpret_cast< double * >(malloc((maxcol + 1) * sizeof(double)));
1991   double *colup = reinterpret_cast< double * >(malloc((maxcol + 1) * sizeof(double)));
1992   char *is_int = reinterpret_cast< char * >(malloc((maxcol + 1) * sizeof(char)));
1993   int has_int = 0;
1994 
1995   for (i = 0; i < maxcol; i++) {
1996     collow[i] = 0;
1997     colup[i] = lp_inf;
1998     is_int[i] = 0;
1999   }
2000 
2001   int done = 0;
2002 
2003   while (!done) {
2004     switch (is_keyword(buff)) {
2005 
2006     case 1: /* Bounds section */
2007       fscanfLpIO(buff);
2008 
2009       while (is_keyword(buff) == 0) {
2010 
2011         read_sense1 = -1;
2012         read_sense2 = -1;
2013         int mult = 1;
2014         char *start_str = buff;
2015 
2016         if (buff[0] == '-' || buff[0] == '+') {
2017           mult = (buff[0] == '-') ? -1 : +1;
2018           if (strlen(buff) == 1) {
2019             fscanfLpIO(buff);
2020             start_str = buff;
2021           } else {
2022             start_str = &(buff[1]);
2023           }
2024         }
2025 
2026         int scan_sense = 0;
2027         if (first_is_number(start_str)) {
2028           bnd1 = mult * atof(start_str);
2029           scan_sense = 1;
2030         } else {
2031           if (is_inf(start_str)) {
2032             bnd1 = mult * lp_inf;
2033             scan_sense = 1;
2034           }
2035         }
2036         if (scan_sense) {
2037           fscanfLpIO(buff);
2038           read_sense1 = is_sense(buff);
2039           if (read_sense1 < 0) {
2040             char str[8192];
2041             sprintf(str, "### ERROR: Bounds; expect a sense, get: %s\n", buff);
2042             throw CoinError(str, "readLp", "CoinLpIO", __FILE__, __LINE__);
2043           }
2044           fscanfLpIO(buff);
2045         }
2046 
2047         icol = findHash(buff, 1);
2048         if (icol < 0) {
2049           char printBuffer[512];
2050           sprintf(printBuffer, "### CoinLpIO::readLp(): Variable %s does not appear in objective function or constraints", buff);
2051           handler_->message(COIN_GENERAL_WARNING, messages_) << printBuffer
2052                                                              << CoinMessageEol;
2053           insertHash(buff, 1);
2054           icol = findHash(buff, 1);
2055           if (icol == maxcol) {
2056             realloc_col(&collow, &colup, &is_int, &maxcol);
2057           }
2058         }
2059 
2060         fscanfLpIO(buff);
2061         if (is_free(buff)) {
2062           collow[icol] = -lp_inf;
2063           fscanfLpIO(buff);
2064         } else {
2065           read_sense2 = is_sense(buff);
2066           if (read_sense2 > -1) {
2067             fscanfLpIO(buff);
2068             mult = 1;
2069             start_str = buff;
2070 
2071             if (buff[0] == '-' || buff[0] == '+') {
2072               mult = (buff[0] == '-') ? -1 : +1;
2073               if (strlen(buff) == 1) {
2074                 fscanfLpIO(buff);
2075                 start_str = buff;
2076               } else {
2077                 start_str = &(buff[1]);
2078               }
2079             }
2080             if (first_is_number(start_str)) {
2081               bnd2 = mult * atof(start_str);
2082               fscanfLpIO(buff);
2083             } else {
2084               if (is_inf(start_str)) {
2085                 bnd2 = mult * lp_inf;
2086                 fscanfLpIO(buff);
2087               } else {
2088                 char str[8192];
2089                 sprintf(str, "### ERROR: Bounds; expect a number, get: %s\n",
2090                   buff);
2091                 throw CoinError(str, "readLp", "CoinLpIO", __FILE__, __LINE__);
2092               }
2093             }
2094           }
2095 
2096           if ((read_sense1 > -1) && (read_sense2 > -1)) {
2097             if (read_sense1 != read_sense2) {
2098               char str[8192];
2099               sprintf(str, "### ERROR: Bounds; variable: %s read_sense1: %d  read_sense2: %d\n",
2100                 buff, read_sense1, read_sense2);
2101               throw CoinError(str, "readLp", "CoinLpIO", __FILE__, __LINE__);
2102             } else {
2103               if (read_sense1 == 1) {
2104                 if (fabs(bnd1 - bnd2) > lp_eps) {
2105                   char str[8192];
2106                   sprintf(str, "### ERROR: Bounds; variable: %s read_sense1: %d  read_sense2: %d  bnd1: %f  bnd2: %f\n",
2107                     buff, read_sense1, read_sense2, bnd1, bnd2);
2108                   throw CoinError(str, "readLp", "CoinLpIO", __FILE__, __LINE__);
2109                 }
2110                 collow[icol] = bnd1;
2111                 colup[icol] = bnd1;
2112               }
2113               if (read_sense1 == 0) {
2114                 collow[icol] = bnd1;
2115                 colup[icol] = bnd2;
2116               }
2117               if (read_sense1 == 2) {
2118                 colup[icol] = bnd1;
2119                 collow[icol] = bnd2;
2120               }
2121             }
2122           } else {
2123             if (read_sense1 > -1) {
2124               switch (read_sense1) {
2125               case 0:
2126                 collow[icol] = bnd1;
2127                 break;
2128               case 1:
2129                 collow[icol] = bnd1;
2130                 colup[icol] = bnd1;
2131                 break;
2132               case 2:
2133                 colup[icol] = bnd1;
2134                 break;
2135               }
2136             }
2137             if (read_sense2 > -1) {
2138               switch (read_sense2) {
2139               case 0:
2140                 colup[icol] = bnd2;
2141                 break;
2142               case 1:
2143                 collow[icol] = bnd2;
2144                 colup[icol] = bnd2;
2145                 break;
2146               case 2:
2147                 collow[icol] = bnd2;
2148                 break;
2149               }
2150             }
2151           }
2152         }
2153       }
2154       break;
2155 
2156     case 2: /* Integers/Generals section */
2157 
2158       fscanfLpIO(buff);
2159 
2160       while (is_keyword(buff) == 0) {
2161 
2162         icol = findHash(buff, 1);
2163 
2164 #ifdef LPIO_DEBUG
2165         printf("CoinLpIO::readLp(): Integer: colname: (%s)  icol: %d\n",
2166           buff, icol);
2167 #endif
2168 
2169         if (icol < 0) {
2170           char printBuffer[512];
2171           sprintf(printBuffer, "### CoinLpIO::readLp(): Integer variable %s does not appear in objective function or constraints", buff);
2172           handler_->message(COIN_GENERAL_WARNING, messages_) << printBuffer
2173                                                              << CoinMessageEol;
2174           insertHash(buff, 1);
2175           icol = findHash(buff, 1);
2176           if (icol == maxcol) {
2177             realloc_col(&collow, &colup, &is_int, &maxcol);
2178           }
2179 
2180 #ifdef LPIO_DEBUG
2181           printf("CoinLpIO::readLp(): Integer: colname: (%s)  icol: %d\n",
2182             buff, icol);
2183 #endif
2184         }
2185         if (is_int[icol] == 3)
2186           is_int[icol] = 4;
2187         else
2188           is_int[icol] = 1;
2189         has_int = 1;
2190         fscanfLpIO(buff);
2191       };
2192       break;
2193 
2194     case 3: /* Binaries section */
2195 
2196       fscanfLpIO(buff);
2197 
2198       while (is_keyword(buff) == 0) {
2199 
2200         icol = findHash(buff, 1);
2201 
2202 #ifdef LPIO_DEBUG
2203         printf("CoinLpIO::readLp(): binary: colname: (%s)  icol: %d\n",
2204           buff, icol);
2205 #endif
2206 
2207         if (icol < 0) {
2208           char printBuffer[512];
2209           sprintf(printBuffer, "### CoinLpIO::readLp(): Binary variable %s does not appear in objective function or constraints", buff);
2210           handler_->message(COIN_GENERAL_WARNING, messages_) << printBuffer
2211                                                              << CoinMessageEol;
2212           insertHash(buff, 1);
2213           icol = findHash(buff, 1);
2214           if (icol == maxcol) {
2215             realloc_col(&collow, &colup, &is_int, &maxcol);
2216           }
2217 #ifdef LPIO_DEBUG
2218           printf("CoinLpIO::readLp(): binary: colname: (%s)  icol: %d\n",
2219             buff, icol);
2220 #endif
2221         }
2222 
2223         is_int[icol] = 1;
2224         has_int = 1;
2225         if (collow[icol] < 0) {
2226           collow[icol] = 0;
2227         }
2228         if (colup[icol] > 1) {
2229           colup[icol] = 1;
2230         }
2231         fscanfLpIO(buff);
2232       }
2233       break;
2234     case 4: /* Semis section */
2235 
2236       fscanfLpIO(buff);
2237 
2238       while (is_keyword(buff) == 0) {
2239 
2240         icol = findHash(buff, 1);
2241 
2242 #ifdef LPIO_DEBUG
2243         printf("CoinLpIO::readLp(): Semi: colname: (%s)  icol: %d\n",
2244           buff, icol);
2245 #endif
2246 
2247         if (icol < 0) {
2248           char printBuffer[512];
2249           sprintf(printBuffer, "### CoinLpIO::readLp(): Semi-continuous variable %s does not appear in objective function or constraints", buff);
2250           handler_->message(COIN_GENERAL_WARNING, messages_) << printBuffer
2251                                                              << CoinMessageEol;
2252           insertHash(buff, 1);
2253           icol = findHash(buff, 1);
2254           if (icol == maxcol) {
2255             realloc_col(&collow, &colup, &is_int, &maxcol);
2256           }
2257 
2258 #ifdef LPIO_DEBUG
2259           printf("CoinLpIO::readLp(): Semi-continuous: colname: (%s)  icol: %d\n",
2260             buff, icol);
2261 #endif
2262         }
2263         if (is_int[icol] == 1)
2264           is_int[icol] = 4;
2265         else
2266           is_int[icol] = 3;
2267         has_int = 1;
2268         fscanfLpIO(buff);
2269       };
2270       break;
2271 
2272     case 5: /* sos section */
2273     {
2274       numberSets_ = 0;
2275       int maxSets = 10;
2276       CoinSet **set = new CoinSet *[maxSets];
2277       int maxEntries = 100;
2278       double *weights = new double[maxEntries];
2279       int *which = new int[maxEntries];
2280       char printBuffer[512];
2281       int numberBad = 0;
2282       bool maybeSetName;
2283       fscanfLpIO(buff);
2284       while (true) {
2285         int numberEntries = 0;
2286         int setType = -1;
2287         int goodLine = 2;
2288         bool endLine = false;
2289         bool gotStart = false;
2290         maybeSetName = false;
2291         while (!endLine) {
2292           if (is_keyword(buff) == 0) {
2293             // see if ::
2294             char *next = strstr(buff, "::");
2295             if (!gotStart) {
2296               if (!next) {
2297                 // OK first time - may be name of set
2298                 if (goodLine == 2) {
2299                   int length = strlen(buff);
2300                   if (buff[length - 1] == ':') {
2301                     goodLine = 1;
2302                     // merge to get rid of space
2303                     char temp[200];
2304                     strcpy(temp, buff);
2305                     fscanfLpIO(buff); // try again
2306                     strcat(temp, buff);
2307                     strcpy(buff, temp);
2308                     if (maybeSetName) {
2309                       // get rid of error
2310                       numberBad--;
2311                       maybeSetName = false;
2312                     }
2313                     continue;
2314                   } else {
2315                     goodLine = 0;
2316                   }
2317                 } else {
2318                   goodLine = 0;
2319                 }
2320               } else {
2321                 // check nothing or set name
2322                 if (strchr(buff, ':') < next || next == buff + 2) {
2323                   // be lazy and assume set name
2324                   // get type
2325                   next -= 2;
2326                   if (next >= buff && (!strncmp(next, "S1::", 4) || !strncmp(next, "S2::", 4))) {
2327                     setType = next[1] - '0';
2328                     gotStart = true;
2329                   } else {
2330                     // error
2331                     goodLine = 0;
2332                   }
2333                 } else {
2334                   goodLine = 0;
2335                 }
2336               }
2337             } else if (next) {
2338               // end of set
2339               endLine = true;
2340             }
2341           } else {
2342             endLine = true;
2343           }
2344           if (!goodLine) {
2345             endLine = true;
2346           }
2347           while (!endLine) {
2348             fscanfLpIO(buff);
2349             if (is_keyword(buff) == 0 && !strstr(buff, "::")) {
2350               // expect pair
2351               char *start_str = buff;
2352               char *next = strchr(start_str, ':');
2353               if (!next) {
2354                 endLine = true;
2355                 goodLine = 0;
2356               } else {
2357                 *next = '\0';
2358                 int iColumn = columnIndex(start_str);
2359                 *next = ':';
2360                 if (iColumn >= 0) {
2361                   int length = strlen(next + 1);
2362                   if (!length) {
2363                     // assume user put in spaces
2364                     fscanfLpIO(buff);
2365                     if (is_keyword(buff) != 0 || strstr(buff, "::")) {
2366                       goodLine = 0;
2367                     } else {
2368                       next = buff - 1;
2369                     }
2370                   }
2371                   double value = atof(next + 1);
2372                   if (numberEntries == maxEntries) {
2373                     maxEntries = 2 * maxEntries;
2374                     double *tempD = new double[maxEntries];
2375                     int *tempI = new int[maxEntries];
2376                     memcpy(tempD, weights, numberEntries * sizeof(double));
2377                     memcpy(tempI, which, numberEntries * sizeof(int));
2378                     delete[] weights;
2379                     weights = tempD;
2380                     delete[] which;
2381                     which = tempI;
2382                   }
2383                   weights[numberEntries] = value;
2384                   which[numberEntries++] = iColumn;
2385                 } else {
2386                   // no match - assume start of next set
2387                   if (!numberBad) {
2388                     sprintf(printBuffer, "### CoinLpIO::readLp(): Variable %s not found or no weight",
2389                       buff);
2390                     handler_->message(COIN_GENERAL_WARNING, messages_) << printBuffer
2391                                                                        << CoinMessageEol;
2392                     sprintf(printBuffer,
2393                       "Assuming next set name - consider no set names or use setnn:S1:: (no spaces)");
2394                     handler_->message(COIN_GENERAL_WARNING, messages_) << printBuffer
2395                                                                        << CoinMessageEol;
2396                     maybeSetName = true;
2397                   }
2398                   numberBad++;
2399                   endLine = true;
2400                 }
2401               }
2402             } else {
2403               endLine = true;
2404             }
2405           }
2406           if (!goodLine) {
2407             // print bad line
2408             setType = 3;
2409             sprintf(printBuffer, "### CoinLpIO::readLp(): bad SOS item %s", buff);
2410             handler_->message(COIN_GENERAL_WARNING, messages_) << printBuffer
2411                                                                << CoinMessageEol;
2412             numberBad++;
2413             endLine = true;
2414             break;
2415           }
2416         }
2417         if (setType == 1 || setType == 2) {
2418           if (!numberEntries) {
2419             // empty set - error
2420             sprintf(printBuffer, "### CoinLpIO::readLp(): set %d is empty", numberSets_);
2421             handler_->message(COIN_GENERAL_WARNING, messages_) << printBuffer
2422                                                                << CoinMessageEol;
2423           } else {
2424             CoinSort_2(weights, weights + numberEntries, which);
2425             double last = weights[0];
2426             for (int i = 1; i < numberEntries; i++) {
2427               if (fabs(last - weights[i]) < 1.0e-12) {
2428                 setType = 3;
2429                 break;
2430               }
2431             }
2432             if (setType != 3) {
2433               if (numberSets_ == maxSets) {
2434                 maxSets *= 2;
2435                 CoinSet **temp = new CoinSet *[maxSets];
2436                 memcpy(temp, set, numberSets_ * sizeof(CoinSet *));
2437                 delete[] set;
2438                 set = temp;
2439               }
2440               CoinSosSet *newSet = new CoinSosSet(numberEntries, which, weights, setType);
2441               set[numberSets_++] = newSet;
2442             } else {
2443               sprintf(printBuffer, "### CoinLpIO::readLp(): set %d has duplicate weights",
2444                 numberSets_);
2445               handler_->message(COIN_GENERAL_WARNING, messages_) << printBuffer
2446                                                                  << CoinMessageEol;
2447             }
2448           }
2449         }
2450         if (is_keyword(buff) || (numberBad && !maybeSetName))
2451           break; // end
2452       }
2453       delete[] weights;
2454       delete[] which;
2455       if (numberSets_) {
2456         set_ = new CoinSet *[numberSets_];
2457         memcpy(set_, set, numberSets_ * sizeof(CoinSet *));
2458         delete[] set;
2459       }
2460     } break;
2461 
2462     case 6:
2463       done = 1;
2464       break;
2465 
2466     default:
2467       char str[8192];
2468       sprintf(str, "### ERROR: Lost while reading: (%s)\n", buff);
2469       throw CoinError(str, "readLp", "CoinLpIO", __FILE__, __LINE__);
2470       break;
2471     }
2472   }
2473 
2474 #ifdef LPIO_DEBUG
2475   printf("CoinLpIO::readLp(): Done with reading the Lp file\n");
2476 #endif
2477 
2478   int *ind = reinterpret_cast< int * >(malloc((maxcoeff + 1) * sizeof(int)));
2479 
2480   for (i = 0; i < cnt_coeff; i++) {
2481     ind[i] = findHash(colNames[i], 1);
2482 
2483 #ifdef LPIO_DEBUG
2484     printf("CoinLpIO::readLp(): name[%d]: (%s)   ind: %d\n",
2485       i, colNames[i], ind[i]);
2486 #endif
2487 
2488     if (ind[i] < 0) {
2489       char str[8192];
2490       sprintf(str, "### ERROR: Hash table: %s not found\n", colNames[i]);
2491       throw CoinError(str, "readLp", "CoinLpIO", __FILE__, __LINE__);
2492     }
2493   }
2494 
2495   numberColumns_ = numberHash_[1];
2496   numberElements_ = cnt_coeff - start[0];
2497 
2498   double *obj[MAX_OBJECTIVES];
2499   // Check for duplicates - first in objectives
2500   int * whichColumn = new int [numberColumns_];
2501   char * inRow = new char[numberColumns_];
2502   memset(inRow,0,numberColumns_);
2503   int numberDuplicates = 0;
2504 
2505   for (int j = 0; j < num_objectives; j++) {
2506     obj[j] = reinterpret_cast< double * >(malloc(numberColumns_ * sizeof(double)));
2507     memset(obj[j], 0, numberColumns_ * sizeof(double));
2508 
2509     for (i = obj_starts[j]; i < obj_starts[j + 1]; i++) {
2510       icol = findHash(colNames[i], 1);
2511       if (icol < 0) {
2512         char str[8192];
2513         sprintf(str, "### ERROR: Hash table: %s (obj) not found\n", colNames[i]);
2514         throw CoinError(str, "readLp", "CoinLpIO", __FILE__, __LINE__);
2515       }
2516       if (!inRow[icol])
2517 	inRow[icol]=1;
2518       else
2519 	numberDuplicates++;
2520       obj[j][icol] += objsense * coeff[i];
2521     }
2522     memset(inRow,0,numberColumns_);
2523   }
2524   if (numberDuplicates) {
2525     char str[8192];
2526     sprintf(str, "### ERROR: %d duplicates in objective\n",
2527 	    numberDuplicates);
2528     handler_->message(COIN_GENERAL_INFO, messages_) << str
2529                                                     << CoinMessageEol;
2530   }
2531 
2532   if (objsense == -1) {
2533     handler_->message(COIN_GENERAL_INFO, messages_) << " CoinLpIO::readLp(): Maximization problem reformulated as minimization"
2534                                                     << CoinMessageEol;
2535     for (int j = 0; j < num_objectives_; j++) {
2536       objectiveOffset_[j] = -objectiveOffset_[j];
2537     }
2538     wasMaximization_ = true;
2539   }
2540 
2541 
2542   for (i = 0; i < cnt_row + 1; i++) {
2543     start[i] -= cnt_obj;
2544   }
2545   // Check for duplicates
2546   for (int iRow = 0;iRow<numberRows_;iRow++) {
2547     CoinBigIndex startRow = start[iRow]+cnt_obj;
2548     CoinBigIndex endRow = start[iRow+1]+cnt_obj;
2549     for (CoinBigIndex j=startRow;j<endRow;j++) {
2550       int iColumn = ind[j];
2551       if (!inRow[iColumn])
2552 	inRow[iColumn]=1;
2553       else
2554 	numberDuplicates ++;
2555     }
2556     for (CoinBigIndex j=startRow;j<endRow;j++) {
2557       int iColumn = ind[j];
2558       inRow[iColumn] = 0;
2559     }
2560   }
2561   delete [] inRow;
2562   delete [] whichColumn;
2563   if (numberDuplicates) {
2564     char str[8192];
2565     sprintf(str, "### ERROR: %d duplicates in objective and matrix\n",
2566 	    numberDuplicates);
2567     handler_->message(COIN_GENERAL_INFO, messages_) << str
2568                                                     << CoinMessageEol;
2569     throw CoinError(str, "readLp", "CoinLpIO", __FILE__, __LINE__);
2570   }
2571   CoinPackedMatrix *matrix = new CoinPackedMatrix(false,
2572     numberColumns_, numberRows_, numberElements_,
2573     &(coeff[cnt_obj]), &(ind[cnt_obj]), start, NULL);
2574 
2575 #ifdef LPIO_DEBUG
2576   matrix->dumpMatrix();
2577 #endif
2578   // save sets
2579   CoinSet **saveSet = set_;
2580   int saveNumberSets = numberSets_;
2581   set_ = NULL;
2582   numberSets_ = 0;
2583 
2584   setLpDataWithoutRowAndColNames(*matrix, collow, colup,
2585     const_cast< const double ** >(obj),
2586     num_objectives, has_int ? is_int : 0, rowlow, rowup);
2587 
2588   set_ = saveSet;
2589   numberSets_ = saveNumberSets;
2590 
2591   for (int j = 0; j < num_objectives; j++) {
2592     if (objName[j] == NULL) {
2593       rowNames[cnt_row + j] = CoinStrdup("obj");
2594     } else {
2595       rowNames[cnt_row + j] = CoinStrdup(objName[j]);
2596     }
2597   }
2598   // Hash tables for column names are already set up
2599   setLpDataRowAndColNames(rowNames, NULL);
2600 
2601   if (are_invalid_names(names_[1], numberHash_[1], false)) {
2602     setDefaultColNames();
2603     handler_->message(COIN_GENERAL_WARNING, messages_) << "### CoinLpIO::readLp(): Invalid column names\nNow using default column names."
2604                                                        << CoinMessageEol;
2605   }
2606 
2607   for (i = 0; i < cnt_coeff; i++) {
2608     free(colNames[i]);
2609   }
2610   free(colNames);
2611 
2612   for (i = 0; i < cnt_row + 1; i++) {
2613     free(rowNames[i]);
2614   }
2615   free(rowNames);
2616 
2617   for (int j = 0; j < num_objectives; j++) {
2618     free(objName[j]);
2619   }
2620 
2621 #ifdef LPIO_DEBUG
2622   writeLp("readlp.xxx");
2623   printf("CoinLpIO::readLp(): read Lp file written in file readlp.xxx\n");
2624 #endif
2625 
2626   free(coeff);
2627   free(start);
2628   free(ind);
2629   free(colup);
2630   free(collow);
2631   free(rhs);
2632   free(rowlow);
2633   free(rowup);
2634   free(is_int);
2635   for (int j = 0; j < num_objectives; j++) {
2636     free(obj[j]);
2637   }
2638   delete matrix;
2639 
2640 } /* readLp */
2641 
2642 /*************************************************************************/
print() const2643 void CoinLpIO::print() const
2644 {
2645 
2646   printf("problemName_: %s\n", problemName_);
2647   printf("numberRows_: %d\n", numberRows_);
2648   printf("numberColumns_: %d\n", numberColumns_);
2649 
2650   printf("matrixByRows_:\n");
2651   matrixByRow_->dumpMatrix();
2652 
2653   int i;
2654   printf("rowlower_:\n");
2655   for (i = 0; i < numberRows_; i++) {
2656     printf("%.5f ", rowlower_[i]);
2657   }
2658   printf("\n");
2659 
2660   printf("rowupper_:\n");
2661   for (i = 0; i < numberRows_; i++) {
2662     printf("%.5f ", rowupper_[i]);
2663   }
2664   printf("\n");
2665 
2666   printf("collower_:\n");
2667   for (i = 0; i < numberColumns_; i++) {
2668     printf("%.5f ", collower_[i]);
2669   }
2670   printf("\n");
2671 
2672   printf("colupper_:\n");
2673   for (i = 0; i < numberColumns_; i++) {
2674     printf("%.5f ", colupper_[i]);
2675   }
2676   printf("\n");
2677 
2678   for (int j = 0; j < num_objectives_; j++) {
2679     printf("objective_[%i]:\n", j);
2680     for (i = 0; i < numberColumns_; i++) {
2681       printf("%.5f ", objective_[j][i]);
2682     }
2683   }
2684   printf("\n");
2685 
2686   if (integerType_ != NULL) {
2687     printf("integerType_:\n");
2688     for (i = 0; i < numberColumns_; i++) {
2689       printf("%c ", integerType_[i]);
2690     }
2691   } else {
2692     printf("integerType_: NULL\n");
2693   }
2694 
2695   printf("\n");
2696   if (fileName_ != NULL) {
2697     printf("fileName_: %s\n", fileName_);
2698   }
2699   printf("infinity_: %.5f\n", infinity_);
2700 } /* print */
2701 
2702 /*************************************************************************/
2703 // Hash functions slightly modified from CoinMpsIO.cpp
2704 
2705 namespace {
2706 const int mmult[] = {
2707   262139, 259459, 256889, 254291, 251701, 249133, 246709, 244247,
2708   241667, 239179, 236609, 233983, 231289, 228859, 226357, 223829,
2709   221281, 218849, 216319, 213721, 211093, 208673, 206263, 203773,
2710   201233, 198637, 196159, 193603, 191161, 188701, 186149, 183761,
2711   181303, 178873, 176389, 173897, 171469, 169049, 166471, 163871,
2712   161387, 158941, 156437, 153949, 151531, 149159, 146749, 144299,
2713   141709, 139369, 136889, 134591, 132169, 129641, 127343, 124853,
2714   122477, 120163, 117757, 115361, 112979, 110567, 108179, 105727,
2715   103387, 101021, 98639, 96179, 93911, 91583, 89317, 86939, 84521,
2716   82183, 79939, 77587, 75307, 72959, 70793, 68447, 66103
2717 };
compute_hash(const char * name,int maxsiz,int length)2718 int compute_hash(const char *name, int maxsiz, int length)
2719 {
2720 
2721   int n = 0;
2722   int j;
2723 
2724   const int nEntriesMMult = sizeof(mmult) / sizeof(int);
2725 
2726   for (j = 0; j < length; ++j) {
2727     int iname = name[j];
2728 
2729     n += mmult[j % nEntriesMMult] * iname;
2730   }
2731   return (abs(n) % maxsiz); /* integer abs */
2732 }
2733 } // end file-local namespace
2734 
2735 /************************************************************************/
2736 //  startHash.  Creates hash list for names
2737 //  setup names_[section] with names in the same order as in the parameter,
2738 //  but removes duplicates
2739 
startHash(char const * const * const names,const COINColumnIndex number,int section)2740 void CoinLpIO::startHash(char const *const *const names,
2741   const COINColumnIndex number, int section)
2742 {
2743   maxHash_[section] = 4 * number;
2744   int maxhash = maxHash_[section];
2745   COINColumnIndex i, ipos, iput;
2746 
2747   names_[section] = reinterpret_cast< char ** >(malloc(maxhash * sizeof(char *)));
2748   hash_[section] = new CoinHashLink[maxhash];
2749 
2750   CoinHashLink *hashThis = hash_[section];
2751   char **hashNames = names_[section];
2752 
2753   for (i = 0; i < maxhash; i++) {
2754     hashThis[i].index = -1;
2755     hashThis[i].next = -1;
2756   }
2757 
2758   /*
2759    * Initialize the hash table.  Only the index of the first name that
2760    * hashes to a value is entered in the table; subsequent names that
2761    * collide with it are not entered.
2762    */
2763 
2764   for (i = 0; i < number; i++) {
2765     const char *thisName = names[i];
2766     int length = CoinStrlenAsInt(thisName);
2767 
2768     ipos = compute_hash(thisName, maxhash, length);
2769     if (hashThis[ipos].index == -1) {
2770       hashThis[ipos].index = i; // will be changed below
2771     }
2772   }
2773 
2774   /*
2775    * Now take care of the names that collided in the preceding loop,
2776    * by finding some other entry in the table for them.
2777    * Since there are as many entries in the table as there are names,
2778    * there must be room for them.
2779    * Also setting up hashNames.
2780    */
2781 
2782   int cnt_distinct = 0;
2783 
2784   iput = -1;
2785   for (i = 0; i < number; i++) {
2786     const char *thisName = names[i];
2787     int length = CoinStrlenAsInt(thisName);
2788 
2789     ipos = compute_hash(thisName, maxhash, length);
2790 
2791     while (1) {
2792       COINColumnIndex j1 = hashThis[ipos].index;
2793 
2794       if (j1 == i) {
2795 
2796         // first occurence of thisName in the parameter "names"
2797 
2798         hashThis[ipos].index = cnt_distinct;
2799         hashNames[cnt_distinct] = CoinStrdup(thisName);
2800         cnt_distinct++;
2801         break;
2802       } else {
2803 
2804 #ifdef LPIO_DEBUG
2805         if (j1 > i) {
2806           char str[8192];
2807           sprintf(str, "### ERROR: Hash table: j1: %d  i: %d\n", j1, i);
2808           throw CoinError(str, "startHash", "CoinLpIO", __FILE__, __LINE__);
2809         }
2810 #endif
2811 
2812         if (strcmp(thisName, hashNames[j1]) == 0) {
2813 
2814           // thisName already entered
2815 
2816           break;
2817         } else {
2818           // Collision; check if thisName already entered
2819 
2820           COINColumnIndex k = hashThis[ipos].next;
2821 
2822           if (k == -1) {
2823 
2824             // thisName not found; enter it
2825 
2826             while (1) {
2827               ++iput;
2828               if (iput > maxhash) {
2829                 char str[8192];
2830                 sprintf(str, "### ERROR: Hash table: too many names\n");
2831                 throw CoinError(str, "startHash", "CoinLpIO", __FILE__, __LINE__);
2832                 break;
2833               }
2834               if (hashThis[iput].index == -1) {
2835                 break;
2836               }
2837             }
2838             hashThis[ipos].next = iput;
2839             hashThis[iput].index = cnt_distinct;
2840             hashNames[cnt_distinct] = CoinStrdup(thisName);
2841             cnt_distinct++;
2842             break;
2843           } else {
2844             ipos = k;
2845 
2846             // continue the check with names in collision
2847           }
2848         }
2849       }
2850     }
2851   }
2852 
2853   numberHash_[section] = cnt_distinct;
2854 
2855 } /* startHash */
2856 
2857 /**************************************************************************/
2858 //  stopHash.  Deletes hash storage
stopHash(int section)2859 void CoinLpIO::stopHash(int section)
2860 {
2861   freePreviousNames(section);
2862   previous_names_[section] = names_[section];
2863   card_previous_names_[section] = numberHash_[section];
2864 
2865   delete[] hash_[section];
2866   hash_[section] = NULL;
2867 
2868   maxHash_[section] = 0;
2869   numberHash_[section] = 0;
2870 
2871   if (section == 0) {
2872     for (int j = 0; j < num_objectives_; j++) {
2873       if (objName_[j] != NULL) {
2874         free(objName_[j]);
2875         objName_[j] = NULL;
2876       }
2877     }
2878   }
2879 } /* stopHash */
2880 
2881 /**********************************************************************/
2882 //  findHash.  -1 not found
2883 COINColumnIndex
findHash(const char * name,int section) const2884 CoinLpIO::findHash(const char *name, int section) const
2885 {
2886   COINColumnIndex found = -1;
2887 
2888   char **names = names_[section];
2889   CoinHashLink *hashThis = hash_[section];
2890   COINColumnIndex maxhash = maxHash_[section];
2891   COINColumnIndex ipos;
2892 
2893   /* default if we don't find anything */
2894   if (!maxhash)
2895     return -1;
2896 
2897   int length = CoinStrlenAsInt(name);
2898 
2899   ipos = compute_hash(name, maxhash, length);
2900   while (1) {
2901     COINColumnIndex j1 = hashThis[ipos].index;
2902 
2903     if (j1 >= 0) {
2904       char *thisName2 = names[j1];
2905 
2906       if (strcmp(name, thisName2) != 0) {
2907         COINColumnIndex k = hashThis[ipos].next;
2908 
2909         if (k != -1)
2910           ipos = k;
2911         else
2912           break;
2913       } else {
2914         found = j1;
2915         break;
2916       }
2917     } else {
2918       found = -1;
2919       break;
2920     }
2921   }
2922   return found;
2923 } /* findHash */
2924 
2925 /*********************************************************************/
insertHash(const char * thisName,int section)2926 void CoinLpIO::insertHash(const char *thisName, int section)
2927 {
2928 
2929   int number = numberHash_[section];
2930   int maxhash = maxHash_[section];
2931 
2932   CoinHashLink *hashThis = hash_[section];
2933   char **hashNames = names_[section];
2934 
2935   int iput = -1;
2936   int length = CoinStrlenAsInt(thisName);
2937 
2938   int ipos = compute_hash(thisName, maxhash, length);
2939 
2940   while (1) {
2941     COINColumnIndex j1 = hashThis[ipos].index;
2942 
2943     if (j1 == -1) {
2944       hashThis[ipos].index = number;
2945       break;
2946     } else {
2947       char *thisName2 = hashNames[j1];
2948 
2949       if (strcmp(thisName, thisName2) != 0) {
2950         COINColumnIndex k = hashThis[ipos].next;
2951 
2952         if (k == -1) {
2953           while (1) {
2954             ++iput;
2955             if (iput == maxhash) {
2956               char str[8192];
2957               sprintf(str, "### ERROR: Hash table: too many names\n");
2958               throw CoinError(str, "insertHash", "CoinLpIO", __FILE__, __LINE__);
2959               break;
2960             }
2961             if (hashThis[iput].index == -1) {
2962               break;
2963             }
2964           }
2965           hashThis[ipos].next = iput;
2966           hashThis[iput].index = number;
2967           break;
2968         } else {
2969           ipos = k;
2970           /* nothing worked - try it again */
2971         }
2972       }
2973     }
2974   }
2975 
2976   hashNames[number] = CoinStrdup(thisName);
2977   (numberHash_[section])++;
2978 }
2979 // Pass in Message handler (not deleted at end)
passInMessageHandler(CoinMessageHandler * handler)2980 void CoinLpIO::passInMessageHandler(CoinMessageHandler *handler)
2981 {
2982   if (defaultHandler_)
2983     delete handler_;
2984   defaultHandler_ = false;
2985   handler_ = handler;
2986 }
2987 // Set language
newLanguage(CoinMessages::Language language)2988 void CoinLpIO::newLanguage(CoinMessages::Language language)
2989 {
2990   messages_ = CoinMessage(language);
2991 }
2992 
2993 // Get next line into inputBuffer_ (returns number in)
newCardLpIO() const2994 int CoinLpIO::newCardLpIO() const
2995 {
2996   while (bufferPosition_ == bufferLength_) {
2997     // new line
2998     bufferPosition_ = 0;
2999     bufferLength_ = 0;
3000     char *ok = input_->gets(inputBuffer_, 1024);
3001     if (!ok)
3002       return 0;
3003     int length = strlen(inputBuffer_);
3004     // take off blanks or below
3005     if (length  && length < 1023) {
3006       length--;
3007       while(length>=0) {
3008 	if (inputBuffer_[length]<=' ')
3009 	  length--;
3010 	else
3011 	  break;
3012       }
3013       // but put back something
3014       inputBuffer_[length+1]='\n';
3015       inputBuffer_[length+2]='\0';
3016     }
3017     // go to single blanks and remove all blanks before :: or :
3018     char *colons = strstr(inputBuffer_, "::");
3019     int nn = 0;
3020     if (colons) {
3021       nn = colons - inputBuffer_;
3022       for (int i = 0; i < nn; i++) {
3023         if (inputBuffer_[i] != ' ')
3024           inputBuffer_[bufferLength_++] = inputBuffer_[i];
3025       }
3026     }
3027     bool gotEol = false;
3028     while (nn < 1024) {
3029       if (inputBuffer_[nn] == ':') {
3030         // take out blank before
3031         if (inputBuffer_[bufferLength_ - 1] == ' ')
3032           bufferLength_--;
3033       }
3034       if (inputBuffer_[nn] == '\t')
3035         inputBuffer_[nn] = ' ';
3036       if (inputBuffer_[nn] == '\0' || inputBuffer_[nn] == '\n' || inputBuffer_[nn] == '\r') {
3037         if (inputBuffer_[nn] == '\n' || inputBuffer_[nn] == '\r')
3038           gotEol = true;
3039         break;
3040       }
3041       if (inputBuffer_[nn] != ' ' || inputBuffer_[nn + 1] != ' ')
3042         inputBuffer_[bufferLength_++] = inputBuffer_[nn];
3043       nn++;
3044     }
3045     if (gotEol) {
3046       //inputBuffer_[bufferLength_]='\n';
3047       inputBuffer_[bufferLength_] = '\0';
3048     }
3049     if (inputBuffer_[0] == ' ')
3050       bufferPosition_++;
3051     if (!gotEol)
3052       bufferLength_ = -bufferLength_;
3053   }
3054   return abs(bufferLength_);
3055 }
3056 
3057 // Get next string (returns number in)
fscanfLpIO(char * buff) const3058 int CoinLpIO::fscanfLpIO(char *buff) const
3059 {
3060   assert(input_);
3061   if (bufferPosition_ == bufferLength_) {
3062     int returnCode = newCardLpIO();
3063     if (!returnCode) {
3064       if (eofFound_)
3065         return 0;
3066       eofFound_ = true;
3067       handler_->message(COIN_GENERAL_WARNING, messages_) << "### CoinLpIO::scan_next(): End inserted" << CoinMessageEol;
3068       strcpy(buff, "End");
3069     }
3070   }
3071   char *space = strchr(inputBuffer_ + bufferPosition_, ' ');
3072   int n = 0;
3073   int start = 0;
3074   if (space)
3075     n = space - (inputBuffer_ + bufferPosition_);
3076   if (n == 0) {
3077     if (bufferLength_ >= 0) {
3078       n = bufferLength_ - bufferPosition_;
3079     } else {
3080       // partial line - get more
3081       start = CoinMax(abs(bufferLength_) - bufferPosition_, 0);
3082       memcpy(buff, inputBuffer_ + bufferPosition_, start);
3083       bufferPosition_ = bufferLength_;
3084       int returnCode = newCardLpIO();
3085       if (!returnCode)
3086         return 0;
3087       if (inputBuffer_[0] != ' ') {
3088         space = strchr(inputBuffer_, ' ');
3089         assert(space || bufferLength_ > 0);
3090         if (space)
3091           n = space - (inputBuffer_ + bufferPosition_);
3092         else
3093           n = bufferLength_ - bufferPosition_;
3094       } else {
3095         n = 0;
3096       }
3097     }
3098   }
3099   memcpy(buff + start, inputBuffer_ + bufferPosition_, n);
3100   bufferPosition_ += n;
3101   if (inputBuffer_[bufferPosition_] == ' ')
3102     bufferPosition_++;
3103   buff[start + n] = '\0';
3104   while (is_comment(buff)) {
3105     skip_comment(buff);
3106     int x = fscanfLpIO(buff);
3107     if (x <= 0) {
3108       handler_->message(COIN_GENERAL_WARNING, messages_) << "### CoinLpIO::scan_next(): field expected" << CoinMessageEol;
3109       throw("bad fscanf");
3110     }
3111   }
3112   return n + start;
3113 }
3114 
3115 /* vi: softtabstop=2 shiftwidth=2 expandtab tabstop=2
3116 */
3117