1 /* $Id: CoinMpsIO.cpp 2125 2019-04-10 03:55:09Z stefan $ */
2 // Copyright (C) 2000, International Business Machines
3 // Corporation and others. All Rights Reserved.
4 // This code is licensed under the terms of the Eclipse Public License (EPL).
5
6 #if defined(_MSC_VER)
7 // Turn off compiler warning about long names
8 #pragma warning(disable : 4786)
9 #endif
10
11 #include "CoinUtilsConfig.h"
12
13 #include <cassert>
14 #include <cstdlib>
15 #include <cmath>
16 #include <cfloat>
17 #include <string>
18 #include <cstdio>
19 #include <iostream>
20
21 #include "CoinMpsIO.hpp"
22 #include "CoinMessage.hpp"
23 #include "CoinHelperFunctions.hpp"
24 #include "CoinModel.hpp"
25 #include "CoinSort.hpp"
26
27 //#############################################################################
28 // type - 0 normal, 1 INTEL IEEE, 2 other IEEE
29
30 namespace {
31
32 const double fraction[] = { 1.0, 1.0e-1, 1.0e-2, 1.0e-3, 1.0e-4, 1.0e-5, 1.0e-6, 1.0e-7, 1.0e-8,
33 1.0e-9, 1.0e-10, 1.0e-11, 1.0e-12, 1.0e-13, 1.0e-14, 1.0e-15, 1.0e-16,
34 1.0e-17, 1.0e-18, 1.0e-19, 1.0e-20, 1.0e-21, 1.0e-22, 1.0e-23 };
35
36 const double exponent[] = { 1.0e-9, 1.0e-8, 1.0e-7, 1.0e-6, 1.0e-5, 1.0e-4, 1.0e-3, 1.0e-2, 1.0e-1,
37 1.0, 1.0e1, 1.0e2, 1.0e3, 1.0e4, 1.0e5, 1.0e6, 1.0e7, 1.0e8, 1.0e9 };
38
39 } // end file-local namespace
osi_strtod(char * ptr,char ** output,int type)40 double CoinMpsCardReader::osi_strtod(char *ptr, char **output, int type)
41 {
42
43 double value = 0.0;
44 char *save = ptr;
45
46 // take off leading white space
47 while (*ptr == ' ' || *ptr == '\t')
48 ptr++;
49 if (!type) {
50 double sign1 = 1.0;
51 // do + or -
52 if (*ptr == '-') {
53 sign1 = -1.0;
54 ptr++;
55 } else if (*ptr == '+') {
56 ptr++;
57 }
58 // more white space
59 while (*ptr == ' ' || *ptr == '\t')
60 ptr++;
61 char thisChar = 0;
62 while (value < 1.0e30) {
63 thisChar = *ptr;
64 ptr++;
65 if (thisChar >= '0' && thisChar <= '9')
66 value = value * 10.0 + thisChar - '0';
67 else
68 break;
69 }
70 if (value < 1.0e30) {
71 if (thisChar == '.') {
72 // do fraction
73 double value2 = 0.0;
74 int nfrac = 0;
75 while (nfrac < 24) {
76 thisChar = *ptr;
77 ptr++;
78 if (thisChar >= '0' && thisChar <= '9') {
79 value2 = value2 * 10.0 + thisChar - '0';
80 nfrac++;
81 } else {
82 break;
83 }
84 }
85 if (nfrac < 24) {
86 value += value2 * fraction[nfrac];
87 } else {
88 thisChar = 'x'; // force error
89 }
90 }
91 if (thisChar == 'e' || thisChar == 'E') {
92 // exponent
93 int sign2 = 1;
94 // do + or -
95 if (*ptr == '-') {
96 sign2 = -1;
97 ptr++;
98 } else if (*ptr == '+') {
99 ptr++;
100 }
101 int value3 = 0;
102 while (value3 < 1000) {
103 thisChar = *ptr;
104 ptr++;
105 if (thisChar >= '0' && thisChar <= '9') {
106 value3 = value3 * 10 + thisChar - '0';
107 } else {
108 break;
109 }
110 }
111 if (value3 < 300) {
112 value3 *= sign2; // power of 10
113 if (abs(value3) < 10) {
114 // do most common by lookup (for accuracy?)
115 value *= exponent[value3 + 9];
116 } else {
117 value *= pow(10.0, value3);
118 }
119 } else if (sign2 < 0.0) {
120 value = 0.0; // force zero
121 } else {
122 value = COIN_DBL_MAX;
123 }
124 }
125 if (thisChar == 0 || thisChar == '\t' || thisChar == ' ') {
126 // okay
127 *output = ptr;
128 } else {
129 value = osi_strtod(save, output);
130 sign1 = 1.0;
131 }
132 } else {
133 // bad value
134 value = osi_strtod(save, output);
135 sign1 = 1.0;
136 }
137 value *= sign1;
138 } else {
139 // ieee - 3 bytes go to 2
140 assert(sizeof(double) == 8 * sizeof(char));
141 assert(sizeof(unsigned short) == 2 * sizeof(char));
142 unsigned short shortValue[4];
143 *output = ptr + 12; // say okay
144 if (type == 1) {
145 // INTEL
146 for (int i = 3; i >= 0; i--) {
147 int integerValue = 0;
148 char *three = reinterpret_cast< char * >(&integerValue);
149 three[1] = ptr[0];
150 three[2] = ptr[1];
151 three[3] = ptr[2];
152 unsigned short thisValue = 0;
153 // decode 6 bits at a time
154 for (int j = 2; j >= 0; j--) {
155 thisValue = static_cast< unsigned short >(thisValue << 6);
156 char thisChar = ptr[j];
157 if (thisChar >= '0' && thisChar <= '0' + 9) {
158 thisValue = static_cast< unsigned short >(thisValue | (thisChar - '0'));
159 } else if (thisChar >= 'a' && thisChar <= 'a' + 25) {
160 thisValue = static_cast< unsigned short >(thisValue | (thisChar - 'a' + 10));
161 } else if (thisChar >= 'A' && thisChar <= 'A' + 25) {
162 thisValue = static_cast< unsigned short >(thisValue | (thisChar - 'A' + 36));
163 } else if (thisChar >= '*' && thisChar <= '*' + 1) {
164 thisValue = static_cast< unsigned short >(thisValue | (thisChar - '*' + 62));
165 } else {
166 // error
167 *output = save;
168 }
169 }
170 ptr += 3;
171 shortValue[i] = thisValue;
172 }
173 } else {
174 // not INTEL
175 for (int i = 0; i < 4; i++) {
176 int integerValue = 0;
177 char *three = reinterpret_cast< char * >(&integerValue);
178 three[1] = ptr[0];
179 three[2] = ptr[1];
180 three[3] = ptr[2];
181 unsigned short thisValue = 0;
182 // decode 6 bits at a time
183 for (int j = 2; j >= 0; j--) {
184 thisValue = static_cast< unsigned short >(thisValue << 6);
185 char thisChar = ptr[j];
186 if (thisChar >= '0' && thisChar <= '0' + 9) {
187 thisValue = static_cast< unsigned short >(thisValue | (thisChar - '0'));
188 } else if (thisChar >= 'a' && thisChar <= 'a' + 25) {
189 thisValue = static_cast< unsigned short >(thisValue | (thisChar - 'a' + 10));
190 } else if (thisChar >= 'A' && thisChar <= 'A' + 25) {
191 thisValue = static_cast< unsigned short >(thisValue | (thisChar - 'A' + 36));
192 } else if (thisChar >= '*' && thisChar <= '*' + 1) {
193 thisValue = static_cast< unsigned short >(thisValue | (thisChar - '*' + 62));
194 } else {
195 // error
196 *output = save;
197 }
198 }
199 ptr += 3;
200 shortValue[i] = thisValue;
201 }
202 }
203 memcpy(&value, shortValue, sizeof(double));
204 }
205 return value;
206 }
207 // for strings
osi_strtod(char * ptr,char ** output)208 double CoinMpsCardReader::osi_strtod(char *ptr, char **output)
209 {
210 char *save = ptr;
211 double value = -1.0e100;
212 if (!stringsAllowed_) {
213 *output = save;
214 } else {
215 // take off leading white space
216 while (*ptr == ' ' || *ptr == '\t')
217 ptr++;
218 if (*ptr == '=') {
219 strcpy(valueString_, ptr);
220 #define STRING_VALUE -1.234567e-101
221 value = STRING_VALUE;
222 *output = ptr + strlen(ptr);
223 } else {
224 *output = save;
225 }
226 }
227 return value;
228 }
229 //#############################################################################
230 // sections
231 namespace {
232 const static char *section[] = {
233 "", "NAME", "ROW", "COLUMN", "RHS", "RANGES", "BOUNDS", "ENDATA", " ", "QSECTION", "CSECTION",
234 "QUADOBJ", "SOS", "BASIS",
235 " "
236 };
237
238 // what is allowed in each section - must line up with COINSectionType
239 const static COINMpsType startType[] = {
240 COIN_UNKNOWN_MPS_TYPE, COIN_UNKNOWN_MPS_TYPE,
241 COIN_N_ROW, COIN_BLANK_COLUMN,
242 COIN_BLANK_COLUMN, COIN_BLANK_COLUMN,
243 COIN_UP_BOUND, COIN_UNKNOWN_MPS_TYPE,
244 COIN_UNKNOWN_MPS_TYPE,
245 COIN_BLANK_COLUMN, COIN_BLANK_COLUMN, COIN_BLANK_COLUMN, COIN_S1_BOUND,
246 COIN_BS_BASIS, COIN_UNKNOWN_MPS_TYPE
247 };
248 const static COINMpsType endType[] = {
249 COIN_UNKNOWN_MPS_TYPE, COIN_UNKNOWN_MPS_TYPE,
250 COIN_BLANK_COLUMN, COIN_UNSET_BOUND,
251 COIN_S1_COLUMN, COIN_S1_COLUMN,
252 COIN_UNKNOWN_MPS_TYPE, COIN_UNKNOWN_MPS_TYPE,
253 COIN_UNKNOWN_MPS_TYPE,
254 COIN_BLANK_COLUMN, COIN_BLANK_COLUMN, COIN_BLANK_COLUMN, COIN_BS_BASIS,
255 COIN_UNKNOWN_MPS_TYPE, COIN_UNKNOWN_MPS_TYPE
256 };
257 const static int allowedLength[] = {
258 0, 0,
259 1, 2,
260 0, 0,
261 2, 0,
262 0, 0,
263 0, 0,
264 0, 2,
265 0
266 };
267
268 // names of types
269 const static char *mpsTypes[] = {
270 "N", "E", "L", "G",
271 " ", "S1", "S2", "S3", " ", " ", " ",
272 " ", "UP", "FX", "LO", "FR", "MI", "PL", "BV", "UI", "LI", "XX", "SC",
273 "X1", "X2", "BS", "XL", "XU", "LL", "UL", " "
274 };
275 } // namespace {
276
cleanCard()277 int CoinMpsCardReader::cleanCard()
278 {
279 char *getit;
280 getit = input_->gets(card_, MAX_CARD_LENGTH);
281
282 if (getit) {
283 cardNumber_++;
284 unsigned char *lastNonBlank = reinterpret_cast< unsigned char * >(card_ - 1);
285 unsigned char *image = reinterpret_cast< unsigned char * >(card_);
286 bool tabs = false;
287 while (*image != '\0') {
288 if (*image != '\t' && *image < ' ') {
289 break;
290 } else if (*image != '\t' && *image != ' ') {
291 lastNonBlank = image;
292 } else if (*image == '\t') {
293 tabs = true;
294 }
295 image++;
296 }
297 *(lastNonBlank + 1) = '\0';
298 if (tabs && section_ == COIN_BOUNDS_SECTION && !freeFormat_ && eightChar_) {
299 int length = static_cast< int >(lastNonBlank + 1 - reinterpret_cast< unsigned char * >(card_));
300 assert(length < 81);
301 memcpy(card_ + 82, card_, length);
302 int pos[] = { 1, 4, 14, 24, 1000 };
303 int put = 0;
304 int tab = 0;
305 for (int i = 0; i < length; i++) {
306 char look = card_[i + 82];
307 if (look != '\t') {
308 card_[put++] = look;
309 } else {
310 // count on to next
311 for (; tab < 5; tab++) {
312 if (put < pos[tab]) {
313 while (put < pos[tab])
314 card_[put++] = ' ';
315 break;
316 }
317 }
318 }
319 }
320 card_[put++] = '\0';
321 }
322 return 0;
323 } else {
324 return 1;
325 }
326 }
327
328 char *
nextBlankOr(char * image)329 CoinMpsCardReader::nextBlankOr(char *image)
330 {
331 char *saveImage = image;
332 while (1) {
333 if (*image == ' ' || *image == '\t') {
334 break;
335 }
336 if (*image == '\0')
337 return NULL;
338 image++;
339 }
340 // Allow for floating - or +. Will fail if user has that as row name!!
341 if (image - saveImage == 1 && (*saveImage == '+' || *saveImage == '-')) {
342 while (*image == ' ' || *image == '\t') {
343 image++;
344 }
345 image = nextBlankOr(image);
346 }
347 return image;
348 }
349
350 // Read to NAME card - return nonzero if bad
351 COINSectionType
readToNextSection()352 CoinMpsCardReader::readToNextSection()
353 {
354 bool found = false;
355
356 while (!found) {
357 // need new image
358
359 if (cleanCard()) {
360 section_ = COIN_EOF_SECTION;
361 break;
362 }
363 if (!strncmp(card_, "NAME", 4) || !strncmp(card_, "TIME", 4) || !strncmp(card_, "BASIS", 5) || !strncmp(card_, "STOCH", 5)) {
364 section_ = COIN_NAME_SECTION;
365 char *next = card_ + 5;
366 position_ = eol_ = card_ + strlen(card_);
367
368 handler_->message(COIN_MPS_LINE, messages_) << cardNumber_
369 << card_ << CoinMessageEol;
370 while (next < eol_) {
371 if (*next == ' ' || *next == '\t') {
372 next++;
373 } else {
374 break;
375 }
376 }
377 if (next < eol_) {
378 char *nextBlank = nextBlankOr(next);
379 char save;
380
381 if (nextBlank) {
382 save = *nextBlank;
383 *nextBlank = '\0';
384 strcpy(columnName_, next);
385 *nextBlank = save;
386 if (strstr(nextBlank, "FREEIEEE")) {
387 freeFormat_ = true;
388 // see if intel
389 ieeeFormat_ = 1;
390 double value = 1.0;
391 char x[8];
392 memcpy(x, &value, 8);
393 if (x[0] == 63) {
394 ieeeFormat_ = 2; // not intel
395 } else {
396 assert(x[0] == 0);
397 }
398 } else if (strstr(nextBlank, "FREE")) {
399 freeFormat_ = true;
400 } else if (strstr(nextBlank, "VALUES")) {
401 // basis is always free - just use this to communicate back
402 freeFormat_ = true;
403 } else if (strstr(nextBlank, "IEEE")) {
404 // see if intel
405 ieeeFormat_ = 1;
406 double value = 1.0;
407 char x[8];
408 memcpy(x, &value, 8);
409 if (x[0] == 63) {
410 ieeeFormat_ = 2; // not intel
411 } else {
412 assert(x[0] == 0);
413 }
414 }
415 } else {
416 strcpy(columnName_, next);
417 }
418 } else {
419 strcpy(columnName_, "no_name");
420 }
421 break;
422 } else if (card_[0] != '*' && card_[0] != '#') {
423 // not a comment
424 int i;
425
426 handler_->message(COIN_MPS_LINE, messages_) << cardNumber_
427 << card_ << CoinMessageEol;
428 for (i = COIN_ROW_SECTION; i < COIN_UNKNOWN_SECTION; i++) {
429 if (!strncmp(card_, section[i], strlen(section[i]))) {
430 break;
431 }
432 }
433 position_ = card_;
434 eol_ = card_;
435 section_ = static_cast< COINSectionType >(i);
436 break;
437 }
438 }
439 return section_;
440 }
441
CoinMpsCardReader(CoinFileInput * input,CoinMpsIO * reader)442 CoinMpsCardReader::CoinMpsCardReader(CoinFileInput *input,
443 CoinMpsIO *reader)
444 {
445 memset(card_, 0, MAX_CARD_LENGTH);
446 position_ = card_;
447 eol_ = card_;
448 mpsType_ = COIN_UNKNOWN_MPS_TYPE;
449 memset(rowName_, 0, COIN_MAX_FIELD_LENGTH);
450 memset(columnName_, 0, COIN_MAX_FIELD_LENGTH);
451 value_ = 0.0;
452 input_ = input;
453 section_ = COIN_EOF_SECTION;
454 cardNumber_ = 0;
455 freeFormat_ = false;
456 ieeeFormat_ = 0;
457 eightChar_ = true;
458 reader_ = reader;
459 handler_ = reader_->messageHandler();
460 messages_ = reader_->messages();
461 memset(valueString_, 0, COIN_MAX_FIELD_LENGTH);
462 stringsAllowed_ = false;
463 }
464 // ~CoinMpsCardReader. Destructor
~CoinMpsCardReader()465 CoinMpsCardReader::~CoinMpsCardReader()
466 {
467 delete input_;
468 }
469
strcpyAndCompress(char * to,const char * from)470 void CoinMpsCardReader::strcpyAndCompress(char *to, const char *from)
471 {
472 int n = static_cast< int >(strlen(from));
473 int i;
474 int nto = 0;
475
476 for (i = 0; i < n; i++) {
477 if (from[i] != ' ') {
478 to[nto++] = from[i];
479 }
480 }
481 if (!nto)
482 to[nto++] = ' ';
483 to[nto] = '\0';
484 }
485
486 // nextField
487 COINSectionType
nextField()488 CoinMpsCardReader::nextField()
489 {
490 mpsType_ = COIN_BLANK_COLUMN;
491 // find next non blank character
492 char *next = position_;
493
494 while (next != eol_) {
495 if (*next == ' ' || *next == '\t') {
496 next++;
497 } else {
498 break;
499 }
500 }
501 bool gotCard;
502
503 if (next == eol_) {
504 gotCard = false;
505 } else {
506 gotCard = true;
507 }
508 while (!gotCard) {
509 // need new image
510
511 if (cleanCard()) {
512 return COIN_EOF_SECTION;
513 }
514 if (card_[0] == ' ' || card_[0] == '\0') {
515 // not a section or comment
516 position_ = card_;
517 eol_ = card_ + strlen(card_);
518 // get mps type and column name
519 // scan to first non blank
520 next = card_;
521 while (next != eol_) {
522 if (*next == ' ' || *next == '\t') {
523 next++;
524 } else {
525 break;
526 }
527 }
528 if (next != eol_) {
529 char *nextBlank = nextBlankOr(next);
530 int nchar;
531
532 if (nextBlank) {
533 nchar = static_cast< int >(nextBlank - next);
534 } else {
535 nchar = -1;
536 }
537 mpsType_ = COIN_BLANK_COLUMN;
538 // special coding if RHS or RANGES, not free format and blanks
539 if ((section_ != COIN_RHS_SECTION
540 && section_ != COIN_RANGES_SECTION)
541 || freeFormat_ || strncmp(card_ + 4, " ", 8)) {
542 // if columns section only look for first field if MARKER
543 if (section_ == COIN_COLUMN_SECTION
544 && !strstr(next, "'MARKER'"))
545 nchar = -1;
546 if (section_ == COIN_SOS_SECTION) {
547 if (!strncmp(card_, " S1", 3)) {
548 mpsType_ = COIN_S1_BOUND;
549 break;
550 } else if (!strncmp(card_, " S2", 3)) {
551 mpsType_ = COIN_S2_BOUND;
552 break;
553 }
554 }
555 if (nchar == allowedLength[section_]) {
556 //could be a type
557 int i;
558
559 for (i = startType[section_]; i < endType[section_]; i++) {
560 if (!strncmp(next, mpsTypes[i], nchar)) {
561 mpsType_ = static_cast< COINMpsType >(i);
562 break;
563 }
564 }
565 if (mpsType_ != COIN_BLANK_COLUMN) {
566 //we know all we need so we can skip over
567 next = nextBlank;
568 while (next != eol_) {
569 if (*next == ' ' || *next == '\t') {
570 next++;
571 } else {
572 break;
573 }
574 }
575 if (next == eol_) {
576 // error
577 position_ = eol_;
578 mpsType_ = COIN_UNKNOWN_MPS_TYPE;
579 } else {
580 nextBlank = nextBlankOr(next);
581 }
582 } else if (section_ == COIN_BOUNDS_SECTION) {
583 // should have been something - but just fix LI problem
584 // set to something illegal
585 if (card_[0] == ' ' && card_[3] == ' ' && (card_[1] != ' ' || card_[2] != ' ')) {
586 mpsType_ = COIN_S3_COLUMN;
587 //we know all we need so we can skip over
588 next = nextBlank;
589 while (next != eol_) {
590 if (*next == ' ' || *next == '\t') {
591 next++;
592 } else {
593 break;
594 }
595 }
596 if (next == eol_) {
597 // error
598 position_ = eol_;
599 mpsType_ = COIN_UNKNOWN_MPS_TYPE;
600 } else {
601 nextBlank = nextBlankOr(next);
602 }
603 }
604 }
605 }
606 if (mpsType_ != COIN_UNKNOWN_MPS_TYPE) {
607 // special coding if BOUND, not free format and blanks
608 if (section_ != COIN_BOUNDS_SECTION || freeFormat_ || strncmp(card_ + 4, " ", 8)) {
609 char save = '?';
610
611 if (!freeFormat_ && eightChar_ && next == card_ + 4) {
612 if (eol_ - next >= 8) {
613 if (*(next + 8) != ' ' && *(next + 8) != '\0') {
614 eightChar_ = false;
615 } else {
616 nextBlank = next + 8;
617 }
618 if (nextBlank) {
619 save = *nextBlank;
620 *nextBlank = '\0';
621 }
622 } else {
623 nextBlank = NULL;
624 }
625 } else {
626 if (nextBlank) {
627 save = *nextBlank;
628 *nextBlank = '\0';
629 }
630 }
631 strcpyAndCompress(columnName_, next);
632 if (nextBlank) {
633 *nextBlank = save;
634 // on to next
635 next = nextBlank;
636 } else {
637 next = eol_;
638 }
639 } else {
640 // blank bounds name
641 strcpy(columnName_, " ");
642 }
643 while (next != eol_) {
644 if (*next == ' ' || *next == '\t') {
645 next++;
646 } else {
647 break;
648 }
649 }
650 if (next == eol_) {
651 // error unless row section or conic section
652 position_ = eol_;
653 value_ = -1.0e100;
654 if (section_ != COIN_ROW_SECTION && section_ != COIN_CONIC_SECTION)
655 mpsType_ = COIN_UNKNOWN_MPS_TYPE;
656 else
657 return section_;
658 } else {
659 nextBlank = nextBlankOr(next);
660 //if (section_==COIN_CONIC_SECTION)
661 }
662 if (section_ != COIN_ROW_SECTION) {
663 char save = '?';
664
665 if (!freeFormat_ && eightChar_ && next == card_ + 14) {
666 if (eol_ - next >= 8) {
667 if (*(next + 8) != ' ' && *(next + 8) != '\0') {
668 eightChar_ = false;
669 } else {
670 nextBlank = next + 8;
671 }
672 save = *nextBlank;
673 *nextBlank = '\0';
674 } else {
675 nextBlank = NULL;
676 }
677 } else {
678 if (nextBlank) {
679 save = *nextBlank;
680 *nextBlank = '\0';
681 }
682 }
683 strcpyAndCompress(rowName_, next);
684 if (nextBlank) {
685 *nextBlank = save;
686 // on to next
687 next = nextBlank;
688 } else {
689 next = eol_;
690 }
691 while (next != eol_) {
692 if (*next == ' ' || *next == '\t') {
693 next++;
694 } else {
695 break;
696 }
697 }
698 // special coding for markers
699 if (section_ == COIN_COLUMN_SECTION && !strncmp(rowName_, "'MARKER'", 8) && next != eol_) {
700 if (!strncmp(next, "'INTORG'", 8)) {
701 mpsType_ = COIN_INTORG;
702 } else if (!strncmp(next, "'INTEND'", 8)) {
703 mpsType_ = COIN_INTEND;
704 } else if (!strncmp(next, "'SOSORG'", 8)) {
705 if (mpsType_ == COIN_BLANK_COLUMN)
706 mpsType_ = COIN_S1_COLUMN;
707 } else if (!strncmp(next, "'SOSEND'", 8)) {
708 mpsType_ = COIN_SOSEND;
709 } else {
710 mpsType_ = COIN_UNKNOWN_MPS_TYPE;
711 }
712 position_ = eol_;
713 return section_;
714 }
715 if (next == eol_) {
716 // error unless bounds or basis
717 position_ = eol_;
718 if (section_ != COIN_BOUNDS_SECTION) {
719 if (section_ != COIN_BASIS_SECTION)
720 mpsType_ = COIN_UNKNOWN_MPS_TYPE;
721 value_ = -1.0e100;
722 } else {
723 value_ = 0.0;
724 }
725 } else {
726 nextBlank = nextBlankOr(next);
727 if (nextBlank) {
728 save = *nextBlank;
729 *nextBlank = '\0';
730 }
731 char *after;
732 value_ = osi_strtod(next, &after, ieeeFormat_);
733 // see if error
734 if (after > next) {
735 if (nextBlank) {
736 *nextBlank = save;
737 position_ = nextBlank;
738 } else {
739 position_ = eol_;
740 }
741 } else {
742 // error
743 position_ = eol_;
744 mpsType_ = COIN_UNKNOWN_MPS_TYPE;
745 value_ = -1.0e100;
746 }
747 }
748 }
749 }
750 } else {
751 //blank name in RHS or RANGES
752 strcpy(columnName_, " ");
753 char save = '?';
754
755 if (!freeFormat_ && eightChar_ && next == card_ + 14) {
756 if (eol_ - next >= 8) {
757 if (*(next + 8) != ' ' && *(next + 8) != '\0') {
758 eightChar_ = false;
759 } else {
760 nextBlank = next + 8;
761 }
762 save = *nextBlank;
763 *nextBlank = '\0';
764 } else {
765 nextBlank = NULL;
766 }
767 } else {
768 if (nextBlank) {
769 save = *nextBlank;
770 *nextBlank = '\0';
771 }
772 }
773 strcpyAndCompress(rowName_, next);
774 if (nextBlank) {
775 *nextBlank = save;
776 // on to next
777 next = nextBlank;
778 } else {
779 next = eol_;
780 }
781 while (next != eol_) {
782 if (*next == ' ' || *next == '\t') {
783 next++;
784 } else {
785 break;
786 }
787 }
788 if (next == eol_) {
789 // error
790 position_ = eol_;
791 value_ = -1.0e100;
792 mpsType_ = COIN_UNKNOWN_MPS_TYPE;
793 } else {
794 nextBlank = nextBlankOr(next);
795 value_ = -1.0e100;
796 if (nextBlank) {
797 save = *nextBlank;
798 *nextBlank = '\0';
799 }
800 char *after;
801 value_ = osi_strtod(next, &after, ieeeFormat_);
802 // see if error
803 if (after > next) {
804 if (nextBlank) {
805 *nextBlank = save;
806 position_ = nextBlank;
807 } else {
808 position_ = eol_;
809 }
810 } else {
811 // error
812 position_ = eol_;
813 mpsType_ = COIN_UNKNOWN_MPS_TYPE;
814 value_ = -1.0e100;
815 }
816 }
817 }
818 } else {
819 // blank
820 continue;
821 }
822 return section_;
823 } else if (card_[0] != '*') {
824 // not a comment
825 int i;
826
827 handler_->message(COIN_MPS_LINE, messages_) << cardNumber_
828 << card_ << CoinMessageEol;
829 for (i = COIN_ROW_SECTION; i < COIN_UNKNOWN_SECTION; i++) {
830 if (!strncmp(card_, section[i], strlen(section[i]))) {
831 break;
832 }
833 }
834 position_ = card_;
835 eol_ = card_;
836 section_ = static_cast< COINSectionType >(i);
837 return section_;
838 } else {
839 // comment
840 }
841 }
842 // we only get here for second field (we could even allow more???)
843 {
844 char save = '?';
845 char *nextBlank = nextBlankOr(next);
846
847 if (!freeFormat_ && eightChar_ && next == card_ + 39) {
848 if (eol_ - next >= 8) {
849 if (*(next + 8) != ' ' && *(next + 8) != '\0') {
850 eightChar_ = false;
851 } else {
852 nextBlank = next + 8;
853 }
854 save = *nextBlank;
855 *nextBlank = '\0';
856 } else {
857 nextBlank = NULL;
858 }
859 } else {
860 if (nextBlank) {
861 save = *nextBlank;
862 *nextBlank = '\0';
863 }
864 }
865 strcpyAndCompress(rowName_, next);
866 // on to next
867 if (nextBlank) {
868 *nextBlank = save;
869 next = nextBlank;
870 } else {
871 next = eol_;
872 }
873 while (next != eol_) {
874 if (*next == ' ' || *next == '\t') {
875 next++;
876 } else {
877 break;
878 }
879 }
880 if (next == eol_ && section_ != COIN_SOS_SECTION) {
881 // error
882 position_ = eol_;
883 mpsType_ = COIN_UNKNOWN_MPS_TYPE;
884 } else {
885 nextBlank = nextBlankOr(next);
886 }
887 if (nextBlank) {
888 save = *nextBlank;
889 *nextBlank = '\0';
890 }
891 //value_ = -1.0e100;
892 char *after;
893 value_ = osi_strtod(next, &after, ieeeFormat_);
894 // see if error
895 if (after > next) {
896 if (nextBlank) {
897 *nextBlank = save;
898 position_ = nextBlank;
899 } else {
900 position_ = eol_;
901 }
902 } else {
903 // error
904 position_ = eol_;
905 if (mpsType_ != COIN_S1_BOUND && mpsType_ != COIN_S2_BOUND)
906 mpsType_ = COIN_UNKNOWN_MPS_TYPE;
907 value_ = -1.0e100;
908 }
909 }
910 return section_;
911 }
912 static char *
nextNonBlank(char * image)913 nextNonBlank(char *image)
914 {
915 while (1) {
916 if (*image != ' ' && *image != '\t')
917 break;
918 else
919 image++;
920 }
921 if (*image == '\0')
922 image = NULL;
923 return image;
924 }
925 /** Gets next field for .gms file and returns type.
926 -1 - EOF
927 0 - what we expected (and processed so pointer moves past)
928 1 - not what we expected
929 2 - equation type when expecting value name pair
930 leading blanks always ignored
931 input types
932 0 - anything - stops on non blank card
933 1 - name (in columnname)
934 2 - value
935 3 - value name pair
936 4 - equation type
937 5 - ;
938 */
nextGmsField(int expectedType)939 int CoinMpsCardReader::nextGmsField(int expectedType)
940 {
941 int returnCode = -1;
942 bool good = false;
943 switch (expectedType) {
944 case 0:
945 // 0 - May get * in first column or anything
946 if (cleanCard())
947 return -1;
948 while (!strlen(card_)) {
949 if (cleanCard())
950 return -1;
951 }
952 eol_ = card_ + strlen(card_);
953 position_ = card_;
954 returnCode = 0;
955 break;
956 case 1:
957 // 1 - expect name
958 while (!good) {
959 position_ = nextNonBlank(position_);
960 if (position_ == NULL) {
961 if (cleanCard())
962 return -1;
963 eol_ = card_ + strlen(card_);
964 position_ = card_;
965 } else {
966 good = true;
967 char nextChar = *position_;
968 if ((nextChar >= 'a' && nextChar <= 'z') || (nextChar >= 'A' && nextChar <= 'Z')) {
969 returnCode = 0;
970 char *next = position_;
971 while (*next != ',' && *next != ';' && *next != '=' && *next != ' '
972 && *next != '\t' && *next != '-' && *next != '+' && *next >= 32)
973 next++;
974 if (next) {
975 int length = static_cast< int >(next - position_);
976 strncpy(columnName_, position_, length);
977 columnName_[length] = '\0';
978 } else {
979 strcpy(columnName_, position_);
980 next = eol_;
981 }
982 position_ = next;
983 } else {
984 returnCode = 1;
985 }
986 }
987 }
988 break;
989 case 2:
990 // 2 - expect value
991 while (!good) {
992 position_ = nextNonBlank(position_);
993 if (position_ == NULL) {
994 if (cleanCard())
995 return -1;
996 eol_ = card_ + strlen(card_);
997 position_ = card_;
998 } else {
999 good = true;
1000 char nextChar = *position_;
1001 if ((nextChar >= '0' && nextChar <= '9') || nextChar == '+' || nextChar == '-') {
1002 returnCode = 0;
1003 char *next = position_;
1004 while (*next != ',' && *next != ';' && *next != '=' && *next != ' '
1005 && *next != '\t' && *next >= 32)
1006 next++;
1007 if (next) {
1008 int length = static_cast< int >(next - position_);
1009 strncpy(rowName_, position_, length);
1010 rowName_[length] = '\0';
1011 } else {
1012 strcpy(rowName_, position_);
1013 next = eol_;
1014 }
1015 value_ = -1.0e100;
1016 sscanf(rowName_, "%lg", &value_);
1017 position_ = next;
1018 } else {
1019 returnCode = 1;
1020 }
1021 }
1022 }
1023 break;
1024 case 3:
1025 // 3 - expect value name pair
1026 while (!good) {
1027 position_ = nextNonBlank(position_);
1028 char *savePosition = position_;
1029 if (position_ == NULL) {
1030 if (cleanCard())
1031 return -1;
1032 eol_ = card_ + strlen(card_);
1033 position_ = card_;
1034 savePosition = position_;
1035 } else {
1036 good = true;
1037 value_ = 1.0;
1038 char nextChar = *position_;
1039 returnCode = 0;
1040 if ((nextChar >= '0' && nextChar <= '9') || nextChar == '+' || nextChar == '-') {
1041 char *next;
1042 int put = 0;
1043 if (nextChar == '+' || nextChar == '-') {
1044 rowName_[0] = nextChar;
1045 put = 1;
1046 next = position_ + 1;
1047 while (*next == ' ' || *next == '\t')
1048 next++;
1049 if ((*next >= 'a' && *next <= 'z') || (*next >= 'A' && *next <= 'Z')) {
1050 // name - set value
1051 if (nextChar == '+')
1052 value_ = 1.0;
1053 else
1054 value_ = -1.0;
1055 position_ = next;
1056 } else if ((*next >= '0' && *next <= '9') || *next == '+' || *next == '-') {
1057 rowName_[put++] = *next;
1058 next++;
1059 while (*next != ' ' && *next != '\t' && *next != '*') {
1060 rowName_[put++] = *next;
1061 next++;
1062 }
1063 assert(*next == '*');
1064 next++;
1065 rowName_[put] = '\0';
1066 value_ = -1.0e100;
1067 sscanf(rowName_, "%lg", &value_);
1068 position_ = next;
1069 } else {
1070 returnCode = 1;
1071 }
1072 } else {
1073 // number
1074 char *next = nextBlankOr(position_);
1075 // but could be *
1076 char *next2 = strchr(position_, '*');
1077 if (next2 && next2 - position_ < next - position_) {
1078 next = next2;
1079 }
1080 int length = static_cast< int >(next - position_);
1081 strncpy(rowName_, position_, length);
1082 rowName_[length] = '\0';
1083 value_ = -1.0e100;
1084 sscanf(rowName_, "%lg", &value_);
1085 position_ = next;
1086 }
1087 } else if ((nextChar >= 'a' && nextChar <= 'z') || (nextChar >= 'A' && nextChar <= 'Z')) {
1088 // name so take value as 1.0
1089 } else if (nextChar == '=') {
1090 returnCode = 2;
1091 position_ = savePosition;
1092 } else {
1093 returnCode = 1;
1094 position_ = savePosition;
1095 }
1096 if ((*position_) == '*')
1097 position_++;
1098 position_ = nextNonBlank(position_);
1099 if (!returnCode) {
1100 char nextChar = *position_;
1101 if ((nextChar >= 'a' && nextChar <= 'z') || (nextChar >= 'A' && nextChar <= 'Z')) {
1102 char *next = nextBlankOr(position_);
1103 if (next) {
1104 int length = static_cast< int >(next - position_);
1105 strncpy(columnName_, position_, length);
1106 columnName_[length] = '\0';
1107 } else {
1108 strcpy(columnName_, position_);
1109 next = eol_;
1110 }
1111 position_ = next;
1112 } else {
1113 returnCode = 1;
1114 position_ = savePosition;
1115 }
1116 }
1117 }
1118 }
1119 break;
1120 case 4:
1121 // 4 - expect equation type
1122 while (!good) {
1123 position_ = nextNonBlank(position_);
1124 if (position_ == NULL) {
1125 if (cleanCard())
1126 return -1;
1127 eol_ = card_ + strlen(card_);
1128 position_ = card_;
1129 } else {
1130 good = true;
1131 char nextChar = *position_;
1132 if (nextChar == '=') {
1133 returnCode = 0;
1134 char *next = nextBlankOr(position_);
1135 int length = static_cast< int >(next - position_);
1136 strncpy(rowName_, position_, length);
1137 rowName_[length] = '\0';
1138 position_ = next;
1139 } else {
1140 returnCode = 1;
1141 }
1142 }
1143 }
1144 break;
1145 case 5:
1146 // 5 - ; expected
1147 while (!good) {
1148 position_ = nextNonBlank(position_);
1149 if (position_ == NULL) {
1150 if (cleanCard())
1151 return -1;
1152 eol_ = card_ + strlen(card_);
1153 position_ = card_;
1154 } else {
1155 good = true;
1156 char nextChar = *position_;
1157 if (nextChar == ';') {
1158 returnCode = 0;
1159 char *next = nextBlankOr(position_);
1160 if (!next)
1161 next = eol_;
1162 position_ = next;
1163 } else {
1164 returnCode = 1;
1165 }
1166 }
1167 }
1168 break;
1169 }
1170 return returnCode;
1171 }
1172
1173 //#############################################################################
1174
1175 namespace {
1176 const int mmult[] = {
1177 262139, 259459, 256889, 254291, 251701, 249133, 246709, 244247,
1178 241667, 239179, 236609, 233983, 231289, 228859, 226357, 223829,
1179 221281, 218849, 216319, 213721, 211093, 208673, 206263, 203773,
1180 201233, 198637, 196159, 193603, 191161, 188701, 186149, 183761,
1181 181303, 178873, 176389, 173897, 171469, 169049, 166471, 163871,
1182 161387, 158941, 156437, 153949, 151531, 149159, 146749, 144299,
1183 141709, 139369, 136889, 134591, 132169, 129641, 127343, 124853,
1184 122477, 120163, 117757, 115361, 112979, 110567, 108179, 105727,
1185 103387, 101021, 98639, 96179, 93911, 91583, 89317, 86939, 84521,
1186 82183, 79939, 77587, 75307, 72959, 70793, 68447, 66103
1187 };
1188
hash(const char * name,int maxsiz,int length)1189 int hash(const char *name, int maxsiz, int length)
1190 {
1191
1192 int n = 0;
1193 int j;
1194
1195 for (j = 0; j < length; ++j) {
1196 int iname = name[j];
1197
1198 n += mmult[j] * iname;
1199 }
1200 return (abs(n) % maxsiz); /* integer abs */
1201 }
1202 } // end file-local namespace
1203
1204 // Define below if you are reading a Cnnnnnn file
1205 // Will not do row names (for electricfence)
1206 //#define NONAMES
1207 #ifndef NONAMES
1208 // startHash. Creates hash list for names
startHash(char ** names,const COINColumnIndex number,int section)1209 void CoinMpsIO::startHash(char **names, const COINColumnIndex number, int section)
1210 {
1211 names_[section] = names;
1212 numberHash_[section] = number;
1213 startHash(section);
1214 }
startHash(int section) const1215 void CoinMpsIO::startHash(int section) const
1216 {
1217 char **names = names_[section];
1218 COINColumnIndex number = numberHash_[section];
1219 COINColumnIndex i;
1220 COINColumnIndex maxhash = 4 * number;
1221 COINColumnIndex ipos, iput;
1222
1223 //hash_=(CoinHashLink *) malloc(maxhash*sizeof(CoinHashLink));
1224 hash_[section] = new CoinHashLink[maxhash];
1225
1226 CoinHashLink *hashThis = hash_[section];
1227
1228 for (i = 0; i < maxhash; i++) {
1229 hashThis[i].index = -1;
1230 hashThis[i].next = -1;
1231 }
1232
1233 /*
1234 * Initialize the hash table. Only the index of the first name that
1235 * hashes to a value is entered in the table; subsequent names that
1236 * collide with it are not entered.
1237 */
1238 for (i = 0; i < number; ++i) {
1239 char *thisName = names[i];
1240 int length = static_cast< int >(strlen(thisName));
1241
1242 ipos = hash(thisName, maxhash, length);
1243 if (hashThis[ipos].index == -1) {
1244 hashThis[ipos].index = i;
1245 }
1246 }
1247
1248 /*
1249 * Now take care of the names that collided in the preceding loop,
1250 * by finding some other entry in the table for them.
1251 * Since there are as many entries in the table as there are names,
1252 * there must be room for them.
1253 */
1254 iput = -1;
1255 for (i = 0; i < number; ++i) {
1256 char *thisName = names[i];
1257 int length = static_cast< int >(strlen(thisName));
1258
1259 ipos = hash(thisName, maxhash, length);
1260
1261 while (1) {
1262 COINColumnIndex j1 = hashThis[ipos].index;
1263
1264 if (j1 == i)
1265 break;
1266 else {
1267 char *thisName2 = names[j1];
1268
1269 if (strcmp(thisName, thisName2) == 0) {
1270 printf("** duplicate name %s\n", names[i]);
1271 break;
1272 } else {
1273 COINColumnIndex k = hashThis[ipos].next;
1274
1275 if (k == -1) {
1276 while (1) {
1277 ++iput;
1278 if (iput > number) {
1279 printf("** too many names\n");
1280 break;
1281 }
1282 if (hashThis[iput].index == -1) {
1283 break;
1284 }
1285 }
1286 hashThis[ipos].next = iput;
1287 hashThis[iput].index = i;
1288 break;
1289 } else {
1290 ipos = k;
1291 /* nothing worked - try it again */
1292 }
1293 }
1294 }
1295 }
1296 }
1297 }
1298
1299 // stopHash. Deletes hash storage
stopHash(int section)1300 void CoinMpsIO::stopHash(int section)
1301 {
1302 delete[] hash_[section];
1303 hash_[section] = NULL;
1304 }
1305
1306 // findHash. -1 not found
1307 COINColumnIndex
findHash(const char * name,int section) const1308 CoinMpsIO::findHash(const char *name, int section) const
1309 {
1310 COINColumnIndex found = -1;
1311
1312 char **names = names_[section];
1313 CoinHashLink *hashThis = hash_[section];
1314 COINColumnIndex maxhash = 4 * numberHash_[section];
1315 COINColumnIndex ipos;
1316
1317 /* default if we don't find anything */
1318 if (!maxhash)
1319 return -1;
1320 int length = static_cast< int >(strlen(name));
1321
1322 ipos = hash(name, maxhash, length);
1323 while (1) {
1324 COINColumnIndex j1 = hashThis[ipos].index;
1325
1326 if (j1 >= 0) {
1327 char *thisName2 = names[j1];
1328
1329 if (strcmp(name, thisName2) != 0) {
1330 COINColumnIndex k = hashThis[ipos].next;
1331
1332 if (k != -1)
1333 ipos = k;
1334 else
1335 break;
1336 } else {
1337 found = j1;
1338 break;
1339 }
1340 } else {
1341 found = -1;
1342 break;
1343 }
1344 }
1345 return found;
1346 }
1347 #else
1348 // Version when we know images are C/Rnnnnnn
1349 // startHash. Creates hash list for names
startHash(char ** names,const COINColumnIndex number,int section)1350 void CoinMpsIO::startHash(char **names, const COINColumnIndex number, int section)
1351 {
1352 numberHash_[section] = number;
1353 names_[section] = names;
1354 }
startHash(int section) const1355 void CoinMpsIO::startHash(int section) const
1356 {
1357 }
1358
1359 // stopHash. Deletes hash storage
stopHash(int section)1360 void CoinMpsIO::stopHash(int section)
1361 {
1362 }
1363
1364 // findHash. -1 not found
1365 COINColumnIndex
findHash(const char * name,int section) const1366 CoinMpsIO::findHash(const char *name, int section) const
1367 {
1368 COINColumnIndex found = atoi(name + 1);
1369 if (!strcmp(name, "OBJROW"))
1370 found = numberHash_[section] - 1;
1371 return found;
1372 }
1373 #endif
1374 //------------------------------------------------------------------
1375 // Get value for infinity
1376 //------------------------------------------------------------------
getInfinity() const1377 double CoinMpsIO::getInfinity() const
1378 {
1379 return infinity_;
1380 }
1381 //------------------------------------------------------------------
1382 // Set value for infinity
1383 //------------------------------------------------------------------
setInfinity(double value)1384 void CoinMpsIO::setInfinity(double value)
1385 {
1386 if (value >= 1.020) {
1387 infinity_ = value;
1388 } else {
1389 handler_->message(COIN_MPS_ILLEGAL, messages_) << "infinity"
1390 << value
1391 << CoinMessageEol;
1392 }
1393 }
1394 // Set file name
setFileName(const char * name)1395 void CoinMpsIO::setFileName(const char *name)
1396 {
1397 free(fileName_);
1398 fileName_ = CoinStrdup(name);
1399 }
1400 // Get file name
getFileName() const1401 const char *CoinMpsIO::getFileName() const
1402 {
1403 return fileName_;
1404 }
1405 // Deal with filename - +1 if new, 0 if same as before, -1 if error
dealWithFileName(const char * filename,const char * extension,CoinFileInput * & input)1406 int CoinMpsIO::dealWithFileName(const char *filename, const char *extension,
1407 CoinFileInput *&input)
1408 {
1409 if (input != 0) {
1410 delete input;
1411 input = 0;
1412 }
1413
1414 int goodFile = 0;
1415
1416 if (!fileName_ || (filename != NULL && strcmp(filename, fileName_))) {
1417 if (filename == NULL) {
1418 handler_->message(COIN_MPS_FILE, messages_) << "NULL"
1419 << CoinMessageEol;
1420 return -1;
1421 }
1422 goodFile = -1;
1423 // looks new name
1424 char newName[400];
1425 if (strcmp(filename, "stdin") && strcmp(filename, "-")) {
1426 if (extension && strlen(extension)) {
1427 // There was an extension - but see if user gave .xxx
1428 int i = static_cast< int >(strlen(filename)) - 1;
1429 strcpy(newName, filename);
1430 bool foundDot = false;
1431 for (; i >= 0; i--) {
1432 char character = filename[i];
1433 if (character == '/' || character == '\\') {
1434 break;
1435 } else if (character == '.') {
1436 foundDot = true;
1437 break;
1438 }
1439 }
1440 if (!foundDot) {
1441 strcat(newName, ".");
1442 strcat(newName, extension);
1443 }
1444 } else {
1445 // no extension
1446 strcpy(newName, filename);
1447 }
1448 } else {
1449 strcpy(newName, "stdin");
1450 }
1451 // See if new name
1452 if (fileName_ && !strcmp(newName, fileName_)) {
1453 // old name
1454 return 0;
1455 } else {
1456 // new file
1457 free(fileName_);
1458 fileName_ = CoinStrdup(newName);
1459 if (strcmp(fileName_, "stdin")) {
1460
1461 // be clever with extensions here
1462 std::string fname = fileName_;
1463 bool readable = fileCoinReadable(fname);
1464 if (!readable)
1465 goodFile = -1;
1466 else {
1467 input = CoinFileInput::create(fname);
1468 goodFile = 1;
1469 }
1470 } else {
1471 // only plain file at present
1472 input = CoinFileInput::create("stdin");
1473 goodFile = 1;
1474 }
1475 }
1476 } else {
1477 // same as before
1478 // reset section ?
1479 goodFile = 0;
1480 }
1481 if (goodFile < 0)
1482 handler_->message(COIN_MPS_FILE, messages_) << fileName_
1483 << CoinMessageEol;
1484 return goodFile;
1485 }
1486 /* objective offset - this is RHS entry for objective row */
objectiveOffset() const1487 double CoinMpsIO::objectiveOffset() const
1488 {
1489 return objectiveOffset_;
1490 }
1491 /*
1492 Prior to June 2007, this was set to 1e30. But that causes problems in
1493 some of the cut generators --- they need to see finite infinity in order
1494 to work properly.
1495 */
1496 #define MAX_INTEGER COIN_DBL_MAX
1497 // Sets default upper bound for integer variables
setDefaultBound(int value)1498 void CoinMpsIO::setDefaultBound(int value)
1499 {
1500 if (value >= 1 && value <= MAX_INTEGER) {
1501 defaultBound_ = value;
1502 } else {
1503 handler_->message(COIN_MPS_ILLEGAL, messages_) << "default integer bound"
1504 << value
1505 << CoinMessageEol;
1506 }
1507 }
1508 // gets default upper bound for integer variables
getDefaultBound() const1509 int CoinMpsIO::getDefaultBound() const
1510 {
1511 return defaultBound_;
1512 }
1513 //------------------------------------------------------------------
1514 // Read mps files
1515 //------------------------------------------------------------------
readMps(const char * filename,const char * extension)1516 int CoinMpsIO::readMps(const char *filename, const char *extension)
1517 {
1518 // Deal with filename - +1 if new, 0 if same as before, -1 if error
1519
1520 CoinFileInput *input = 0;
1521 int returnCode = dealWithFileName(filename, extension, input);
1522 if (returnCode < 0) {
1523 return -1;
1524 } else if (returnCode > 0) {
1525 delete cardReader_;
1526 cardReader_ = new CoinMpsCardReader(input, this);
1527 }
1528 if (!extension || (strcmp(extension, "gms") && !strstr(filename, ".gms"))) {
1529 return readMps();
1530 } else {
1531 int numberSets = 0;
1532 CoinSet **sets = NULL;
1533 int returnCode = readGms(numberSets, sets);
1534 for (int i = 0; i < numberSets; i++)
1535 delete sets[i];
1536 delete[] sets;
1537 return returnCode;
1538 }
1539 }
readMps(const char * filename,const char * extension,int & numberSets,CoinSet ** & sets)1540 int CoinMpsIO::readMps(const char *filename, const char *extension,
1541 int &numberSets, CoinSet **&sets)
1542 {
1543 // Deal with filename - +1 if new, 0 if same as before, -1 if error
1544 CoinFileInput *input = 0;
1545 int returnCode = dealWithFileName(filename, extension, input);
1546 if (returnCode < 0) {
1547 return -1;
1548 } else if (returnCode > 0) {
1549 delete cardReader_;
1550 cardReader_ = new CoinMpsCardReader(input, this);
1551 }
1552 return readMps(numberSets, sets);
1553 }
readMps()1554 int CoinMpsIO::readMps()
1555 {
1556 int numberSets = 0;
1557 CoinSet **sets = NULL;
1558 int returnCode = readMps(numberSets, sets);
1559 for (int i = 0; i < numberSets; i++)
1560 delete sets[i];
1561 delete[] sets;
1562 return returnCode;
1563 }
readMps(int & numberSets,CoinSet ** & sets)1564 int CoinMpsIO::readMps(int &numberSets, CoinSet **&sets)
1565 {
1566 bool ifmps;
1567
1568 cardReader_->readToNextSection();
1569
1570 if (cardReader_->whichSection() == COIN_NAME_SECTION) {
1571 ifmps = true;
1572 // save name of section
1573 free(problemName_);
1574 problemName_ = CoinStrdup(cardReader_->columnName());
1575 } else if (cardReader_->whichSection() == COIN_UNKNOWN_SECTION) {
1576 handler_->message(COIN_MPS_BADFILE1, messages_) << cardReader_->card()
1577 << 1
1578 << fileName_
1579 << CoinMessageEol;
1580
1581 if (cardReader_->fileInput()->getReadType() != "plain")
1582 handler_->message(COIN_MPS_BADFILE2, messages_)
1583 << cardReader_->fileInput()->getReadType()
1584 << CoinMessageEol;
1585
1586 return -2;
1587 } else if (cardReader_->whichSection() != COIN_EOF_SECTION) {
1588 // save name of section
1589 free(problemName_);
1590 problemName_ = CoinStrdup(cardReader_->card());
1591 ifmps = false;
1592 } else {
1593 handler_->message(COIN_MPS_EOF, messages_) << fileName_
1594 << CoinMessageEol;
1595 return -3;
1596 }
1597 CoinBigIndex *start;
1598 COINRowIndex *row;
1599 double *element;
1600 objectiveOffset_ = 0.0;
1601
1602 int numberErrors = 0;
1603 int i;
1604 if (ifmps) {
1605 // mps file - always read in free format
1606 bool gotNrow = false;
1607 // allow strings ?
1608 if (allowStringElements_)
1609 cardReader_->setStringsAllowed();
1610
1611 //get ROWS
1612 cardReader_->nextField();
1613 // Fudge for what ever code has OBJSENSE
1614 if (!strncmp(cardReader_->card(), "OBJSENSE", 8)) {
1615 cardReader_->nextField();
1616 int i;
1617 const char *thisCard = cardReader_->card();
1618 int direction = 0;
1619 for (i = 0; i < 20; i++) {
1620 if (thisCard[i] != ' ') {
1621 if (!strncmp(thisCard + i, "MAX", 3))
1622 direction = -1;
1623 else if (!strncmp(thisCard + i, "MIN", 3))
1624 direction = 1;
1625 break;
1626 }
1627 }
1628 if (!direction)
1629 printf("No MAX/MIN found after OBJSENSE\n");
1630 else
1631 printf("%s found after OBJSENSE - Coin ignores\n",
1632 (direction > 0 ? "MIN" : "MAX"));
1633 cardReader_->nextField();
1634 }
1635 if (cardReader_->whichSection() != COIN_ROW_SECTION) {
1636 handler_->message(COIN_MPS_BADIMAGE, messages_) << cardReader_->cardNumber()
1637 << cardReader_->card()
1638 << CoinMessageEol;
1639 handler_->message(COIN_MPS_RETURNING, messages_) << CoinMessageEol;
1640 return numberErrors + 100000;
1641 }
1642 //use malloc etc as I don't know how to do realloc in C++
1643 numberRows_ = 0;
1644 numberColumns_ = 0;
1645 numberElements_ = 0;
1646 COINRowIndex maxRows = 1000;
1647 COINMpsType *rowType =
1648
1649 reinterpret_cast< COINMpsType * >(malloc(maxRows * sizeof(COINMpsType)));
1650 char **rowName = reinterpret_cast< char ** >(malloc(maxRows * sizeof(char *)));
1651
1652 // for discarded free rows
1653 COINRowIndex maxFreeRows = 100;
1654 COINRowIndex numberOtherFreeRows = 0;
1655 char **freeRowName =
1656
1657 reinterpret_cast< char ** >(malloc(maxFreeRows * sizeof(char *)));
1658 while (cardReader_->nextField() == COIN_ROW_SECTION) {
1659 switch (cardReader_->mpsType()) {
1660 case COIN_N_ROW:
1661 if (!gotNrow) {
1662 gotNrow = true;
1663 // save name of section
1664 free(objectiveName_);
1665 objectiveName_ = CoinStrdup(cardReader_->columnName());
1666 } else {
1667 // add to discard list
1668 if (numberOtherFreeRows == maxFreeRows) {
1669 maxFreeRows = (3 * maxFreeRows) / 2 + 100;
1670 freeRowName = reinterpret_cast< char ** >(realloc(freeRowName,
1671 maxFreeRows * sizeof(char *)));
1672 }
1673 freeRowName[numberOtherFreeRows] = CoinStrdup(cardReader_->columnName());
1674 numberOtherFreeRows++;
1675 }
1676 break;
1677 case COIN_E_ROW:
1678 case COIN_L_ROW:
1679 case COIN_G_ROW:
1680 if (numberRows_ == maxRows) {
1681 maxRows = (3 * maxRows) / 2 + 1000;
1682 rowType = reinterpret_cast< COINMpsType * >(realloc(rowType,
1683 maxRows * sizeof(COINMpsType)));
1684 rowName =
1685
1686 reinterpret_cast< char ** >(realloc(rowName, maxRows * sizeof(char *)));
1687 }
1688 rowType[numberRows_] = cardReader_->mpsType();
1689 #ifndef NONAMES
1690 rowName[numberRows_] = CoinStrdup(cardReader_->columnName());
1691 #endif
1692 numberRows_++;
1693 break;
1694 default:
1695 numberErrors++;
1696 if (numberErrors < 100) {
1697 handler_->message(COIN_MPS_BADIMAGE, messages_) << cardReader_->cardNumber()
1698 << cardReader_->card()
1699 << CoinMessageEol;
1700 } else if (numberErrors > 100000) {
1701 handler_->message(COIN_MPS_RETURNING, messages_) << CoinMessageEol;
1702 return numberErrors;
1703 }
1704 }
1705 }
1706 if (cardReader_->whichSection() != COIN_COLUMN_SECTION) {
1707 handler_->message(COIN_MPS_BADIMAGE, messages_) << cardReader_->cardNumber()
1708 << cardReader_->card()
1709 << CoinMessageEol;
1710 handler_->message(COIN_MPS_RETURNING, messages_) << CoinMessageEol;
1711 return numberErrors + 100000;
1712 }
1713 //assert ( gotNrow );
1714 if (numberRows_)
1715 rowType = reinterpret_cast< COINMpsType * >(realloc(rowType,
1716 numberRows_ * sizeof(COINMpsType)));
1717 else
1718 rowType = reinterpret_cast< COINMpsType * >(realloc(rowType, sizeof(COINMpsType)));
1719 // put objective and other free rows at end
1720 rowName = reinterpret_cast< char ** >(realloc(rowName,
1721 (numberRows_ + 1 +
1722
1723 numberOtherFreeRows)
1724 * sizeof(char *)));
1725 #ifndef NONAMES
1726 rowName[numberRows_] = CoinStrdup(objectiveName_);
1727 memcpy(rowName + numberRows_ + 1, freeRowName,
1728 numberOtherFreeRows * sizeof(char *));
1729 // now we can get rid of this array
1730 free(freeRowName);
1731 #else
1732 memset(rowName, 0, (numberRows_ + 1) * sizeof(char **));
1733 #endif
1734
1735 startHash(rowName, numberRows_ + 1 + numberOtherFreeRows, 0);
1736 COINColumnIndex maxColumns = 1000 + numberRows_ / 5;
1737 CoinBigIndex maxElements = 5000 + numberRows_ / 2;
1738 COINMpsType *columnType = reinterpret_cast< COINMpsType * >(malloc(maxColumns * sizeof(COINMpsType)));
1739 char **columnName = reinterpret_cast< char ** >(malloc(maxColumns * sizeof(char *)));
1740
1741 objective_ = reinterpret_cast< double * >(malloc(maxColumns * sizeof(double)));
1742 start = reinterpret_cast< CoinBigIndex * >(malloc((maxColumns + 1) * sizeof(CoinBigIndex)));
1743 row = reinterpret_cast< COINRowIndex * >(malloc(maxElements * sizeof(COINRowIndex)));
1744 element = reinterpret_cast< double * >(malloc(maxElements * sizeof(double)));
1745 // for duplicates
1746 CoinBigIndex *rowUsed = new CoinBigIndex[numberRows_];
1747
1748 for (i = 0; i < numberRows_; i++) {
1749 rowUsed[i] = -1;
1750 }
1751 bool objUsed = false;
1752
1753 numberElements_ = 0;
1754 char lastColumn[200];
1755
1756 memset(lastColumn, '\0', 200);
1757 COINColumnIndex column = -1;
1758 bool inIntegerSet = false;
1759 COINColumnIndex numberIntegers = 0;
1760
1761 while (cardReader_->nextField() == COIN_COLUMN_SECTION) {
1762 switch (cardReader_->mpsType()) {
1763 case COIN_BLANK_COLUMN:
1764 if (strcmp(lastColumn, cardReader_->columnName())) {
1765 // new column
1766
1767 // reset old column and take out tiny
1768 if (numberColumns_) {
1769 objUsed = false;
1770 CoinBigIndex i;
1771 CoinBigIndex k = start[column];
1772
1773 for (i = k; i < numberElements_; i++) {
1774 COINRowIndex irow = row[i];
1775 #if 0
1776 if ( fabs ( element[i] ) > smallElement_ ) {
1777 element[k++] = element[i];
1778 }
1779 #endif
1780 rowUsed[irow] = -1;
1781 }
1782 //numberElements_ = k;
1783 }
1784 column = numberColumns_;
1785 if (numberColumns_ == maxColumns) {
1786 maxColumns = (3 * maxColumns) / 2 + 1000;
1787 columnType = reinterpret_cast< COINMpsType * >(realloc(columnType, maxColumns * sizeof(COINMpsType)));
1788 columnName = reinterpret_cast< char ** >(realloc(columnName, maxColumns * sizeof(char *)));
1789
1790 objective_ = reinterpret_cast< double * >(realloc(objective_, maxColumns * sizeof(double)));
1791 start = reinterpret_cast< CoinBigIndex * >(realloc(start,
1792 (maxColumns + 1) * sizeof(CoinBigIndex)));
1793 }
1794 if (!inIntegerSet) {
1795 columnType[column] = COIN_UNSET_BOUND;
1796 } else {
1797 columnType[column] = COIN_INTORG;
1798 numberIntegers++;
1799 }
1800 #ifndef NONAMES
1801 columnName[column] = CoinStrdup(cardReader_->columnName());
1802 #else
1803 columnName[column] = NULL;
1804 #endif
1805 strcpy(lastColumn, cardReader_->columnName());
1806 objective_[column] = 0.0;
1807 start[column] = numberElements_;
1808 numberColumns_++;
1809 }
1810 if (fabs(cardReader_->value()) > smallElement_) {
1811 if (numberElements_ == maxElements) {
1812 maxElements = (3 * maxElements) / 2 + 1000;
1813 row = reinterpret_cast< COINRowIndex * >(realloc(row, maxElements * sizeof(COINRowIndex)));
1814 element = reinterpret_cast< double * >(realloc(element, maxElements * sizeof(double)));
1815 }
1816 // get row number
1817 COINRowIndex irow = findHash(cardReader_->rowName(), 0);
1818
1819 if (irow >= 0) {
1820 double value = cardReader_->value();
1821
1822 // check for duplicates
1823 if (irow == numberRows_) {
1824 // objective
1825 if (objUsed) {
1826 numberErrors++;
1827 if (numberErrors < 100) {
1828 handler_->message(COIN_MPS_DUPOBJ, messages_)
1829 << cardReader_->cardNumber() << cardReader_->card()
1830 << CoinMessageEol;
1831 } else if (numberErrors > 100000) {
1832 handler_->message(COIN_MPS_RETURNING, messages_)
1833 << CoinMessageEol;
1834 return numberErrors;
1835 }
1836 } else {
1837 objUsed = true;
1838 }
1839 value += objective_[column];
1840 if (fabs(value) <= smallElement_)
1841 value = 0.0;
1842 objective_[column] = value;
1843 } else if (irow < numberRows_) {
1844 // other free rows will just be discarded so won't get here
1845 if (rowUsed[irow] >= 0) {
1846 element[rowUsed[irow]] += value;
1847 numberErrors++;
1848 if (numberErrors < 100) {
1849 handler_->message(COIN_MPS_DUPROW, messages_)
1850 << cardReader_->rowName() << cardReader_->cardNumber()
1851 << cardReader_->card()
1852 << CoinMessageEol;
1853 } else if (numberErrors > 100000) {
1854 handler_->message(COIN_MPS_RETURNING, messages_)
1855 << CoinMessageEol;
1856 return numberErrors;
1857 }
1858 } else {
1859 row[numberElements_] = irow;
1860 element[numberElements_] = value;
1861 rowUsed[irow] = numberElements_;
1862 numberElements_++;
1863 }
1864 }
1865 } else {
1866 numberErrors++;
1867 if (numberErrors < 100) {
1868 handler_->message(COIN_MPS_NOMATCHROW, messages_)
1869 << cardReader_->rowName() << cardReader_->cardNumber() << cardReader_->card()
1870 << CoinMessageEol;
1871 } else if (numberErrors > 100000) {
1872 handler_->message(COIN_MPS_RETURNING, messages_) << CoinMessageEol;
1873 return numberErrors;
1874 }
1875 }
1876 } else if (cardReader_->value() == STRING_VALUE) {
1877 // tiny element - string
1878 const char *s = cardReader_->valueString();
1879 assert(*s == '=');
1880 // get row number
1881 COINRowIndex irow = findHash(cardReader_->rowName(), 0);
1882
1883 if (irow >= 0) {
1884 addString(irow, column, s + 1);
1885 } else {
1886 numberErrors++;
1887 if (numberErrors < 100) {
1888 handler_->message(COIN_MPS_NOMATCHROW, messages_)
1889 << cardReader_->rowName() << cardReader_->cardNumber() << cardReader_->card()
1890 << CoinMessageEol;
1891 } else if (numberErrors > 100000) {
1892 handler_->message(COIN_MPS_RETURNING, messages_) << CoinMessageEol;
1893 return numberErrors;
1894 }
1895 }
1896 }
1897 break;
1898 case COIN_INTORG:
1899 inIntegerSet = true;
1900 break;
1901 case COIN_INTEND:
1902 inIntegerSet = false;
1903 break;
1904 case COIN_S1_COLUMN:
1905 case COIN_S2_COLUMN:
1906 case COIN_S3_COLUMN:
1907 case COIN_SOSEND:
1908 std::cout << "** code sos etc later" << std::endl;
1909 abort();
1910 break;
1911 default:
1912 numberErrors++;
1913 if (numberErrors < 100) {
1914 handler_->message(COIN_MPS_BADIMAGE, messages_) << cardReader_->cardNumber()
1915 << cardReader_->card()
1916 << CoinMessageEol;
1917 } else if (numberErrors > 100000) {
1918 handler_->message(COIN_MPS_RETURNING, messages_) << CoinMessageEol;
1919 return numberErrors;
1920 }
1921 }
1922 }
1923 start[numberColumns_] = numberElements_;
1924 delete[] rowUsed;
1925 if (cardReader_->whichSection() != COIN_RHS_SECTION) {
1926 handler_->message(COIN_MPS_BADIMAGE, messages_) << cardReader_->cardNumber()
1927 << cardReader_->card()
1928 << CoinMessageEol;
1929 handler_->message(COIN_MPS_RETURNING, messages_) << CoinMessageEol;
1930 return numberErrors + 100000;
1931 }
1932 if (numberColumns_) {
1933 columnType = reinterpret_cast< COINMpsType * >(realloc(columnType,
1934 numberColumns_ * sizeof(COINMpsType)));
1935 columnName =
1936
1937 reinterpret_cast< char ** >(realloc(columnName, numberColumns_ * sizeof(char *)));
1938 objective_ = reinterpret_cast< double * >(realloc(objective_, numberColumns_ * sizeof(double)));
1939 } else {
1940 columnType = reinterpret_cast< COINMpsType * >(realloc(columnType,
1941 sizeof(COINMpsType)));
1942 columnName =
1943
1944 reinterpret_cast< char ** >(realloc(columnName, sizeof(char *)));
1945 objective_ = reinterpret_cast< double * >(realloc(objective_, sizeof(double)));
1946 }
1947 start = reinterpret_cast< CoinBigIndex * >(realloc(start, (numberColumns_ + 1) * sizeof(CoinBigIndex)));
1948 if (numberElements_) {
1949 row = reinterpret_cast< COINRowIndex * >(realloc(row, numberElements_ * sizeof(COINRowIndex)));
1950 element = reinterpret_cast< double * >(realloc(element, numberElements_ * sizeof(double)));
1951 } else {
1952 row = reinterpret_cast< COINRowIndex * >(realloc(row, sizeof(COINRowIndex)));
1953 element = reinterpret_cast< double * >(realloc(element, sizeof(double)));
1954 }
1955 if (numberRows_) {
1956 rowlower_ = reinterpret_cast< double * >(malloc(numberRows_ * sizeof(double)));
1957 rowupper_ = reinterpret_cast< double * >(malloc(numberRows_ * sizeof(double)));
1958 } else {
1959 rowlower_ = reinterpret_cast< double * >(malloc(sizeof(double)));
1960 rowupper_ = reinterpret_cast< double * >(malloc(sizeof(double)));
1961 }
1962 for (i = 0; i < numberRows_; i++) {
1963 rowlower_[i] = -infinity_;
1964 rowupper_[i] = infinity_;
1965 }
1966 objUsed = false;
1967 memset(lastColumn, '\0', 200);
1968 bool gotRhs = false;
1969
1970 // need coding for blank rhs
1971 while (cardReader_->nextField() == COIN_RHS_SECTION) {
1972 COINRowIndex irow;
1973
1974 switch (cardReader_->mpsType()) {
1975 case COIN_BLANK_COLUMN:
1976 if (strcmp(lastColumn, cardReader_->columnName())) {
1977
1978 // skip rest if got a rhs
1979 if (gotRhs) {
1980 while (cardReader_->nextField() == COIN_RHS_SECTION) {
1981 }
1982 break;
1983 } else {
1984 gotRhs = true;
1985 strcpy(lastColumn, cardReader_->columnName());
1986 // save name of section
1987 free(rhsName_);
1988 rhsName_ = CoinStrdup(cardReader_->columnName());
1989 }
1990 }
1991 // get row number
1992 irow = findHash(cardReader_->rowName(), 0);
1993 if (irow >= 0) {
1994 double value = cardReader_->value();
1995
1996 // check for duplicates
1997 if (irow == numberRows_) {
1998 // objective
1999 if (objUsed) {
2000 numberErrors++;
2001 if (numberErrors < 100) {
2002 handler_->message(COIN_MPS_DUPOBJ, messages_)
2003 << cardReader_->cardNumber() << cardReader_->card()
2004 << CoinMessageEol;
2005 } else if (numberErrors > 100000) {
2006 handler_->message(COIN_MPS_RETURNING, messages_) << CoinMessageEol;
2007 return numberErrors;
2008 }
2009 } else {
2010 objUsed = true;
2011 }
2012 if (value == STRING_VALUE) {
2013 value = 0.0;
2014 // tiny element - string
2015 const char *s = cardReader_->valueString();
2016 assert(*s == '=');
2017 addString(irow, numberColumns_, s + 1);
2018 }
2019 objectiveOffset_ += value;
2020 } else if (irow < numberRows_) {
2021 if (rowlower_[irow] != -infinity_) {
2022 numberErrors++;
2023 if (numberErrors < 100) {
2024 handler_->message(COIN_MPS_DUPROW, messages_)
2025 << cardReader_->rowName() << cardReader_->cardNumber() << cardReader_->card()
2026 << CoinMessageEol;
2027 } else if (numberErrors > 100000) {
2028 handler_->message(COIN_MPS_RETURNING, messages_) << CoinMessageEol;
2029 return numberErrors;
2030 }
2031 } else {
2032 if (value == STRING_VALUE) {
2033 value = 0.0;
2034 // tiny element - string
2035 const char *s = cardReader_->valueString();
2036 assert(*s == '=');
2037 addString(irow, numberColumns_, s + 1);
2038 }
2039 rowlower_[irow] = value;
2040 }
2041 }
2042 } else {
2043 numberErrors++;
2044 if (numberErrors < 100) {
2045 handler_->message(COIN_MPS_NOMATCHROW, messages_)
2046 << cardReader_->rowName() << cardReader_->cardNumber() << cardReader_->card()
2047 << CoinMessageEol;
2048 } else if (numberErrors > 100000) {
2049 handler_->message(COIN_MPS_RETURNING, messages_) << CoinMessageEol;
2050 return numberErrors;
2051 }
2052 }
2053 break;
2054 default:
2055 numberErrors++;
2056 if (numberErrors < 100) {
2057 handler_->message(COIN_MPS_BADIMAGE, messages_) << cardReader_->cardNumber()
2058 << cardReader_->card()
2059 << CoinMessageEol;
2060 } else if (numberErrors > 100000) {
2061 handler_->message(COIN_MPS_RETURNING, messages_) << CoinMessageEol;
2062 return numberErrors;
2063 }
2064 }
2065 }
2066 if (cardReader_->whichSection() == COIN_RANGES_SECTION) {
2067 memset(lastColumn, '\0', 200);
2068 bool gotRange = false;
2069 COINRowIndex irow;
2070
2071 // need coding for blank range
2072 while (cardReader_->nextField() == COIN_RANGES_SECTION) {
2073 switch (cardReader_->mpsType()) {
2074 case COIN_BLANK_COLUMN:
2075 if (strcmp(lastColumn, cardReader_->columnName())) {
2076
2077 // skip rest if got a range
2078 if (gotRange) {
2079 while (cardReader_->nextField() == COIN_RANGES_SECTION) {
2080 }
2081 break;
2082 } else {
2083 gotRange = true;
2084 strcpy(lastColumn, cardReader_->columnName());
2085 // save name of section
2086 free(rangeName_);
2087 rangeName_ = CoinStrdup(cardReader_->columnName());
2088 }
2089 }
2090 // get row number
2091 irow = findHash(cardReader_->rowName(), 0);
2092 if (irow >= 0) {
2093 double value = cardReader_->value();
2094
2095 // check for duplicates
2096 if (irow == numberRows_) {
2097 // objective
2098 numberErrors++;
2099 if (numberErrors < 100) {
2100 handler_->message(COIN_MPS_DUPOBJ, messages_)
2101 << cardReader_->cardNumber() << cardReader_->card()
2102 << CoinMessageEol;
2103 } else if (numberErrors > 100000) {
2104 handler_->message(COIN_MPS_RETURNING, messages_) << CoinMessageEol;
2105 return numberErrors;
2106 }
2107 } else {
2108 if (rowupper_[irow] != infinity_) {
2109 numberErrors++;
2110 if (numberErrors < 100) {
2111 handler_->message(COIN_MPS_DUPROW, messages_)
2112 << cardReader_->rowName() << cardReader_->cardNumber() << cardReader_->card()
2113 << CoinMessageEol;
2114 } else if (numberErrors > 100000) {
2115 handler_->message(COIN_MPS_RETURNING, messages_)
2116 << CoinMessageEol;
2117 return numberErrors;
2118 }
2119 } else {
2120 rowupper_[irow] = value;
2121 }
2122 }
2123 } else {
2124 numberErrors++;
2125 if (numberErrors < 100) {
2126 handler_->message(COIN_MPS_NOMATCHROW, messages_)
2127 << cardReader_->rowName() << cardReader_->cardNumber() << cardReader_->card()
2128 << CoinMessageEol;
2129 } else if (numberErrors > 100000) {
2130 handler_->message(COIN_MPS_RETURNING, messages_) << CoinMessageEol;
2131 return numberErrors;
2132 }
2133 }
2134 break;
2135 default:
2136 numberErrors++;
2137 if (numberErrors < 100) {
2138 handler_->message(COIN_MPS_BADIMAGE, messages_) << cardReader_->cardNumber()
2139 << cardReader_->card()
2140 << CoinMessageEol;
2141 } else if (numberErrors > 100000) {
2142 handler_->message(COIN_MPS_RETURNING, messages_) << CoinMessageEol;
2143 return numberErrors;
2144 }
2145 }
2146 }
2147 }
2148 stopHash(0);
2149 // massage ranges
2150 {
2151 COINRowIndex irow;
2152
2153 for (irow = 0; irow < numberRows_; irow++) {
2154 double lo = rowlower_[irow];
2155 double up = rowupper_[irow];
2156 double up2 = rowupper_[irow]; //range
2157
2158 switch (rowType[irow]) {
2159 case COIN_E_ROW:
2160 if (lo == -infinity_)
2161 lo = 0.0;
2162 if (up == infinity_) {
2163 up = lo;
2164 } else if (up > 0.0) {
2165 up += lo;
2166 } else {
2167 up = lo;
2168 lo += up2;
2169 }
2170 break;
2171 case COIN_L_ROW:
2172 if (lo == -infinity_) {
2173 up = 0.0;
2174 } else {
2175 up = lo;
2176 lo = -infinity_;
2177 }
2178 if (up2 != infinity_) {
2179 lo = up - fabs(up2);
2180 }
2181 break;
2182 case COIN_G_ROW:
2183 if (lo == -infinity_) {
2184 lo = 0.0;
2185 up = infinity_;
2186 } else {
2187 up = infinity_;
2188 }
2189 if (up2 != infinity_) {
2190 up = lo + fabs(up2);
2191 }
2192 break;
2193 default:
2194 abort();
2195 }
2196 rowlower_[irow] = lo;
2197 rowupper_[irow] = up;
2198 }
2199 }
2200 free(rowType);
2201 // default bounds
2202 if (numberColumns_) {
2203 collower_ = reinterpret_cast< double * >(malloc(numberColumns_ * sizeof(double)));
2204 colupper_ = reinterpret_cast< double * >(malloc(numberColumns_ * sizeof(double)));
2205 } else {
2206 collower_ = reinterpret_cast< double * >(malloc(sizeof(double)));
2207 colupper_ = reinterpret_cast< double * >(malloc(sizeof(double)));
2208 }
2209 for (i = 0; i < numberColumns_; i++) {
2210 collower_[i] = 0.0;
2211 colupper_[i] = infinity_;
2212 }
2213 // set up integer region just in case
2214 if (numberColumns_)
2215 integerType_ = reinterpret_cast< char * >(malloc(numberColumns_ * sizeof(char)));
2216 else
2217 integerType_ = reinterpret_cast< char * >(malloc(sizeof(char)));
2218 for (column = 0; column < numberColumns_; column++) {
2219 if (columnType[column] == COIN_INTORG) {
2220 columnType[column] = COIN_UNSET_BOUND;
2221 integerType_[column] = 1;
2222 } else {
2223 integerType_[column] = 0;
2224 }
2225 }
2226 // start hash even if no bound section - to make sure names survive
2227 startHash(columnName, numberColumns_, 1);
2228 if (cardReader_->whichSection() == COIN_BOUNDS_SECTION) {
2229 memset(lastColumn, '\0', 200);
2230 bool gotBound = false;
2231
2232 while (cardReader_->nextField() == COIN_BOUNDS_SECTION) {
2233 if (strcmp(lastColumn, cardReader_->columnName())) {
2234
2235 // skip rest if got a bound
2236 if (gotBound) {
2237 while (cardReader_->nextField() == COIN_BOUNDS_SECTION) {
2238 }
2239 break;
2240 } else {
2241 gotBound = true;
2242 ;
2243 strcpy(lastColumn, cardReader_->columnName());
2244 // save name of section
2245 free(boundName_);
2246 boundName_ = CoinStrdup(cardReader_->columnName());
2247 }
2248 }
2249 // get column number
2250 COINColumnIndex icolumn = findHash(cardReader_->rowName(), 1);
2251
2252 if (icolumn >= 0) {
2253 double value = cardReader_->value();
2254 bool ifError = false;
2255
2256 switch (cardReader_->mpsType()) {
2257 case COIN_UP_BOUND:
2258 if (value == -1.0e100)
2259 ifError = true;
2260 if (value == STRING_VALUE) {
2261 value = 1.0e10;
2262 // tiny element - string
2263 const char *s = cardReader_->valueString();
2264 assert(*s == '=');
2265 addString(numberRows_ + 2, icolumn, s + 1);
2266 }
2267 if (columnType[icolumn] == COIN_UNSET_BOUND) {
2268 if (value < 0.0) {
2269 collower_[icolumn] = -infinity_;
2270 }
2271 } else if (columnType[icolumn] == COIN_LO_BOUND || columnType[icolumn] == COIN_LI_BOUND) {
2272 if (value < collower_[icolumn]) {
2273 ifError = true;
2274 } else if (value < collower_[icolumn] + smallElement_) {
2275 value = collower_[icolumn];
2276 }
2277 } else if (columnType[icolumn] == COIN_MI_BOUND) {
2278 } else {
2279 ifError = true;
2280 }
2281 if (value > 1.0e25)
2282 value = infinity_;
2283 colupper_[icolumn] = value;
2284 if (columnType[icolumn] == COIN_UNSET_BOUND) {
2285 columnType[icolumn] = COIN_UP_BOUND;
2286 } else {
2287 columnType[icolumn] = COIN_BOTH_BOUNDS_SET;
2288 }
2289 break;
2290 case COIN_LO_BOUND:
2291 if (value == -1.0e100)
2292 ifError = true;
2293 if (value == STRING_VALUE) {
2294 value = -1.0e10;
2295 // tiny element - string
2296 const char *s = cardReader_->valueString();
2297 assert(*s == '=');
2298 addString(numberRows_ + 1, icolumn, s + 1);
2299 }
2300 if (columnType[icolumn] == COIN_UNSET_BOUND) {
2301 } else if (columnType[icolumn] == COIN_UP_BOUND || columnType[icolumn] == COIN_SC_BOUND || columnType[icolumn] == COIN_UI_BOUND) {
2302 if (value > colupper_[icolumn]) {
2303 ifError = true;
2304 } else if (value > colupper_[icolumn] - smallElement_) {
2305 value = colupper_[icolumn];
2306 }
2307 } else if (columnType[icolumn] == COIN_PL_BOUND) {
2308 } else {
2309 ifError = true;
2310 }
2311 if (value < -1.0e25)
2312 value = -infinity_;
2313 collower_[icolumn] = value;
2314 if (columnType[icolumn] == COIN_UNSET_BOUND) {
2315 columnType[icolumn] = COIN_LO_BOUND;
2316 } else {
2317 columnType[icolumn] = COIN_BOTH_BOUNDS_SET;
2318 }
2319 break;
2320 case COIN_FX_BOUND:
2321 if (value == -1.0e100)
2322 ifError = true;
2323 if (value == STRING_VALUE) {
2324 value = 0.0;
2325 // tiny element - string
2326 const char *s = cardReader_->valueString();
2327 assert(*s == '=');
2328 addString(numberRows_ + 1, icolumn, s + 1);
2329 addString(numberRows_ + 2, icolumn, s + 1);
2330 }
2331 if (columnType[icolumn] == COIN_UNSET_BOUND) {
2332 } else if (columnType[icolumn] == COIN_FX_BOUND) {
2333 ifError = true;
2334 } else if (integerType_[icolumn]) {
2335 // Allow so people can easily put FX's at end
2336 double value2 = floor(value);
2337 if (fabs(value2 - value) > 1.0e-12 || value2 < collower_[icolumn] || value2 > colupper_[icolumn]) {
2338 ifError = true;
2339 } else {
2340 // take off integer list
2341 numberIntegers--;
2342 integerType_[icolumn] = 0;
2343 }
2344 } else {
2345 ifError = true;
2346 }
2347 collower_[icolumn] = value;
2348 colupper_[icolumn] = value;
2349 columnType[icolumn] = COIN_FX_BOUND;
2350 break;
2351 case COIN_FR_BOUND:
2352 if (columnType[icolumn] == COIN_UNSET_BOUND) {
2353 } else {
2354 ifError = true;
2355 }
2356 collower_[icolumn] = -infinity_;
2357 colupper_[icolumn] = infinity_;
2358 columnType[icolumn] = COIN_FR_BOUND;
2359 break;
2360 case COIN_MI_BOUND:
2361 if (columnType[icolumn] == COIN_UNSET_BOUND) {
2362 colupper_[icolumn] = COIN_DBL_MAX;
2363 } else if (columnType[icolumn] == COIN_UP_BOUND || columnType[icolumn] == COIN_UI_BOUND) {
2364 } else {
2365 ifError = true;
2366 }
2367 collower_[icolumn] = -infinity_;
2368 if (columnType[icolumn] == COIN_UNSET_BOUND) {
2369 columnType[icolumn] = COIN_MI_BOUND;
2370 } else {
2371 columnType[icolumn] = COIN_BOTH_BOUNDS_SET;
2372 }
2373 break;
2374 case COIN_PL_BOUND:
2375 // change to allow if no upper bound set
2376 //if ( columnType[icolumn] == COIN_UNSET_BOUND ) {
2377 if (colupper_[icolumn] == infinity_) {
2378 } else {
2379 ifError = true;
2380 }
2381 if (columnType[icolumn] == COIN_UNSET_BOUND) {
2382 columnType[icolumn] = COIN_PL_BOUND;
2383 } else {
2384 columnType[icolumn] = COIN_BOTH_BOUNDS_SET;
2385 }
2386 break;
2387 case COIN_UI_BOUND:
2388 if (value == STRING_VALUE) {
2389 value = 1.0e20;
2390 // tiny element - string
2391 const char *s = cardReader_->valueString();
2392 assert(*s == '=');
2393 addString(numberRows_ + 2, icolumn, s + 1);
2394 }
2395 #if 0
2396 if ( value == -1.0e100 )
2397 ifError = true;
2398 if ( columnType[icolumn] == COIN_UNSET_BOUND ) {
2399 } else if ( columnType[icolumn] == COIN_LO_BOUND ||
2400 columnType[icolumn] == COIN_LI_BOUND) {
2401 if ( value < collower_[icolumn] ) {
2402 ifError = true;
2403 } else if ( value < collower_[icolumn] + smallElement_ ) {
2404 value = collower_[icolumn];
2405 }
2406 } else if ( columnType[icolumn] == COIN_MI_BOUND ) {
2407 } else {
2408 ifError = true;
2409 }
2410 #else
2411 if (value == -1.0e100) {
2412 value = infinity_;
2413 if (columnType[icolumn] != COIN_UNSET_BOUND && columnType[icolumn] != COIN_LO_BOUND && columnType[icolumn] != COIN_LI_BOUND && columnType[icolumn] != COIN_MI_BOUND) {
2414 ifError = true;
2415 }
2416 } else {
2417 if (columnType[icolumn] == COIN_UNSET_BOUND) {
2418 } else if (columnType[icolumn] == COIN_LO_BOUND || columnType[icolumn] == COIN_LI_BOUND || columnType[icolumn] == COIN_MI_BOUND) {
2419 if (value < collower_[icolumn]) {
2420 ifError = true;
2421 } else if (value < collower_[icolumn] + smallElement_) {
2422 value = collower_[icolumn];
2423 }
2424 } else {
2425 ifError = true;
2426 }
2427 }
2428 #endif
2429 if (value > 1.0e25)
2430 value = infinity_;
2431 colupper_[icolumn] = value;
2432 if (columnType[icolumn] == COIN_UNSET_BOUND) {
2433 columnType[icolumn] = COIN_UI_BOUND;
2434 } else {
2435 columnType[icolumn] = COIN_BOTH_BOUNDS_SET;
2436 }
2437 if (!integerType_[icolumn]) {
2438 numberIntegers++;
2439 integerType_[icolumn] = 1;
2440 }
2441 break;
2442 case COIN_LI_BOUND:
2443 if (value == -1.0e100)
2444 ifError = true;
2445 if (value == STRING_VALUE) {
2446 value = -1.0e20;
2447 // tiny element - string
2448 const char *s = cardReader_->valueString();
2449 assert(*s == '=');
2450 addString(numberRows_ + 1, icolumn, s + 1);
2451 }
2452 if (columnType[icolumn] == COIN_UNSET_BOUND) {
2453 } else if (columnType[icolumn] == COIN_UP_BOUND || columnType[icolumn] == COIN_SC_BOUND || columnType[icolumn] == COIN_UI_BOUND) {
2454 if (value > colupper_[icolumn]) {
2455 ifError = true;
2456 } else if (value > colupper_[icolumn] - smallElement_) {
2457 value = colupper_[icolumn];
2458 }
2459 } else if (columnType[icolumn] == COIN_PL_BOUND) {
2460 } else {
2461 ifError = true;
2462 }
2463 if (value < -1.0e25)
2464 value = -infinity_;
2465 collower_[icolumn] = value;
2466 if (columnType[icolumn] == COIN_UNSET_BOUND) {
2467 columnType[icolumn] = COIN_LI_BOUND;
2468 } else {
2469 columnType[icolumn] = COIN_BOTH_BOUNDS_SET;
2470 }
2471 if (!integerType_[icolumn]) {
2472 numberIntegers++;
2473 integerType_[icolumn] = 1;
2474 } else if (integerType_[icolumn] == 3) {
2475 integerType_[icolumn] = 4; // SC and integer
2476 }
2477 break;
2478 case COIN_BV_BOUND:
2479 if (columnType[icolumn] == COIN_UNSET_BOUND) {
2480 } else {
2481 ifError = true;
2482 }
2483 collower_[icolumn] = 0.0;
2484 colupper_[icolumn] = 1.0;
2485 columnType[icolumn] = COIN_BV_BOUND;
2486 if (!integerType_[icolumn]) {
2487 numberIntegers++;
2488 integerType_[icolumn] = 1;
2489 }
2490 break;
2491 case COIN_SC_BOUND:
2492 if (value == STRING_VALUE) {
2493 value = 1.0e20;
2494 // tiny element - string
2495 const char *s = cardReader_->valueString();
2496 assert(*s == '=');
2497 addString(numberRows_ + 2, icolumn, s + 1);
2498 }
2499 if (value == -1.0e100 || value == 0.0) {
2500 value = infinity_;
2501 if (columnType[icolumn] != COIN_UNSET_BOUND && columnType[icolumn] != COIN_LO_BOUND && columnType[icolumn] != COIN_LI_BOUND) {
2502 ifError = true;
2503 }
2504 } else {
2505 if (columnType[icolumn] == COIN_UNSET_BOUND) {
2506 } else if (columnType[icolumn] == COIN_LO_BOUND || columnType[icolumn] == COIN_LI_BOUND) {
2507 if (value < collower_[icolumn]) {
2508 ifError = true;
2509 } else if (value < collower_[icolumn] + smallElement_) {
2510 value = collower_[icolumn];
2511 }
2512 } else {
2513 ifError = true;
2514 }
2515 }
2516 if (value > 1.0e25)
2517 value = infinity_;
2518 colupper_[icolumn] = value;
2519 if (columnType[icolumn] == COIN_UNSET_BOUND) {
2520 columnType[icolumn] = COIN_SC_BOUND;
2521 } else {
2522 columnType[icolumn] = COIN_BOTH_BOUNDS_SET;
2523 }
2524 if (!integerType_[icolumn]) {
2525 numberIntegers++;
2526 integerType_[icolumn] = 3;
2527 } else if (integerType_[icolumn] == 1) {
2528 integerType_[icolumn] = 4; // SC and integer
2529 }
2530 break;
2531 default:
2532 ifError = true;
2533 break;
2534 }
2535 if (ifError) {
2536 numberErrors++;
2537 if (numberErrors < 100) {
2538 handler_->message(COIN_MPS_BADIMAGE, messages_)
2539 << cardReader_->cardNumber()
2540 << cardReader_->card()
2541 << CoinMessageEol;
2542 } else if (numberErrors > 100000) {
2543 handler_->message(COIN_MPS_RETURNING, messages_) << CoinMessageEol;
2544 return numberErrors;
2545 }
2546 }
2547 } else {
2548 numberErrors++;
2549 if (numberErrors < 100) {
2550 handler_->message(COIN_MPS_NOMATCHCOL, messages_)
2551 << cardReader_->rowName() << cardReader_->cardNumber() << cardReader_->card()
2552 << CoinMessageEol;
2553 } else if (numberErrors > 100000) {
2554 handler_->message(COIN_MPS_RETURNING, messages_) << CoinMessageEol;
2555 return numberErrors;
2556 }
2557 }
2558 }
2559 }
2560 //for (i=0;i<numberSets;i++)
2561 //delete sets[i];
2562 numberSets = 0;
2563 //delete [] sets;
2564 sets = NULL;
2565
2566 // Do SOS if found
2567 if (cardReader_->whichSection() == COIN_SOS_SECTION) {
2568 // Go to free format
2569 cardReader_->setFreeFormat(true);
2570 int numberInSet = 0;
2571 int iType = -1;
2572 int *which = new int[numberColumns_];
2573 double *weights = new double[numberColumns_];
2574 CoinSet **setsA = new CoinSet *[numberColumns_];
2575 while (cardReader_->nextField() == COIN_SOS_SECTION) {
2576 if (cardReader_->mpsType() == COIN_S1_BOUND || cardReader_->mpsType() == COIN_S2_BOUND) {
2577 if (numberInSet) {
2578 CoinSosSet *newSet = new CoinSosSet(numberInSet, which, weights, iType);
2579 setsA[numberSets++] = newSet;
2580 }
2581 numberInSet = 0;
2582 iType = cardReader_->mpsType() == COIN_S1_BOUND ? 1 : 2;
2583 // skip
2584 continue;
2585 }
2586 // get column number
2587 COINColumnIndex icolumn = findHash(cardReader_->columnName(), 1);
2588 if (icolumn >= 0) {
2589 //integerType_[icolumn]=2;
2590 double value = cardReader_->value();
2591 if (value == -1.0e100)
2592 value = atof(cardReader_->rowName()); // try from row name
2593 which[numberInSet] = icolumn;
2594 weights[numberInSet++] = value;
2595 } else {
2596 numberErrors++;
2597 if (numberErrors < 100) {
2598 handler_->message(COIN_MPS_NOMATCHCOL, messages_)
2599 << cardReader_->columnName() << cardReader_->cardNumber() << cardReader_->card()
2600 << CoinMessageEol;
2601 } else if (numberErrors > 100000) {
2602 handler_->message(COIN_MPS_RETURNING, messages_) << CoinMessageEol;
2603 return numberErrors;
2604 }
2605 }
2606 }
2607 if (numberInSet) {
2608 CoinSosSet *newSet = new CoinSosSet(numberInSet, which, weights, iType);
2609 setsA[numberSets++] = newSet;
2610 }
2611 if (numberSets) {
2612 sets = new CoinSet *[numberSets];
2613 memcpy(sets, setsA, numberSets * sizeof(CoinSet **));
2614 }
2615 delete[] setsA;
2616 delete[] which;
2617 delete[] weights;
2618 }
2619 stopHash(1);
2620 // clean up integers
2621 if (!numberIntegers) {
2622 free(integerType_);
2623 integerType_ = NULL;
2624 } else {
2625 COINColumnIndex icolumn;
2626
2627 for (icolumn = 0; icolumn < numberColumns_; icolumn++) {
2628 if (integerType_[icolumn]) {
2629 collower_[icolumn] = CoinMax(collower_[icolumn], -MAX_INTEGER);
2630 // if 0 infinity make 0-1 ???
2631 if (columnType[icolumn] == COIN_UNSET_BOUND)
2632 colupper_[icolumn] = defaultBound_;
2633 if (colupper_[icolumn] > MAX_INTEGER)
2634 colupper_[icolumn] = MAX_INTEGER;
2635 // clean up to allow for bad reads on 1.0e2 etc
2636 if (colupper_[icolumn] < 1.0e10) {
2637 double value = colupper_[icolumn];
2638 double value2 = floor(value + 0.5);
2639 if (value != value2) {
2640 if (fabs(value - value2) < 1.0e-5)
2641 colupper_[icolumn] = value2;
2642 }
2643 }
2644 if (collower_[icolumn] > -1.0e10) {
2645 double value = collower_[icolumn];
2646 double value2 = floor(value + 0.5);
2647 if (value != value2) {
2648 if (fabs(value - value2) < 1.0e-5)
2649 collower_[icolumn] = value2;
2650 }
2651 }
2652 }
2653 }
2654 }
2655 free(columnType);
2656 if (cardReader_->whichSection() != COIN_ENDATA_SECTION && cardReader_->whichSection() != COIN_QUAD_SECTION && cardReader_->whichSection() != COIN_CONIC_SECTION) {
2657 handler_->message(COIN_MPS_BADIMAGE, messages_) << cardReader_->cardNumber()
2658 << cardReader_->card()
2659 << CoinMessageEol;
2660 handler_->message(COIN_MPS_RETURNING, messages_) << CoinMessageEol;
2661 return numberErrors + 100000;
2662 }
2663 } else {
2664 // This is very simple format - what should we use?
2665 COINColumnIndex i;
2666
2667 /* old:
2668 FILE * fp = cardReader_->filePointer();
2669 fscanf ( fp, "%d %d %d\n", &numberRows_, &numberColumns_, &i);
2670 */
2671 // new:
2672 char buffer[1000];
2673 cardReader_->fileInput()->gets(buffer, 1000);
2674 sscanf(buffer, "%d %d %d\n", &numberRows_, &numberColumns_, &i);
2675
2676 numberElements_ = i; // done this way in case numberElements_ long
2677
2678 rowlower_ = reinterpret_cast< double * >(malloc(numberRows_ * sizeof(double)));
2679 rowupper_ = reinterpret_cast< double * >(malloc(numberRows_ * sizeof(double)));
2680 for (i = 0; i < numberRows_; i++) {
2681 int j;
2682
2683 // old: fscanf ( fp, "%d %lg %lg\n", &j, &rowlower_[i], &rowupper_[i] );
2684 // new:
2685 cardReader_->fileInput()->gets(buffer, 1000);
2686 sscanf(buffer, "%d %lg %lg\n", &j, &rowlower_[i], &rowupper_[i]);
2687
2688 assert(i == j);
2689 }
2690 collower_ = reinterpret_cast< double * >(malloc(numberColumns_ * sizeof(double)));
2691 colupper_ = reinterpret_cast< double * >(malloc(numberColumns_ * sizeof(double)));
2692 objective_ = reinterpret_cast< double * >(malloc(numberColumns_ * sizeof(double)));
2693 start = reinterpret_cast< CoinBigIndex * >(malloc((numberColumns_ + 1) * sizeof(CoinBigIndex)));
2694 row = reinterpret_cast< COINRowIndex * >(malloc(numberElements_ * sizeof(COINRowIndex)));
2695 element = reinterpret_cast< double * >(malloc(numberElements_ * sizeof(double)));
2696
2697 start[0] = 0;
2698 numberElements_ = 0;
2699 for (i = 0; i < numberColumns_; i++) {
2700 int j;
2701 int n;
2702
2703 /* old:
2704 fscanf ( fp, "%d %d %lg %lg %lg\n", &j, &n,
2705 &collower_[i], &colupper_[i],
2706 &objective_[i] );
2707 */
2708 // new:
2709 cardReader_->fileInput()->gets(buffer, 1000);
2710 sscanf(buffer, "%d %d %lg %lg %lg\n", &j, &n,
2711 &collower_[i], &colupper_[i], &objective_[i]);
2712
2713 assert(i == j);
2714 for (j = 0; j < n; j++) {
2715 /* old:
2716 fscanf ( fp, " %d %lg\n", &row[numberElements_],
2717 &element[numberElements_] );
2718 */
2719 // new:
2720 cardReader_->fileInput()->gets(buffer, 1000);
2721 sscanf(buffer, " %d %lg\n", &row[numberElements_],
2722 &element[numberElements_]);
2723
2724 numberElements_++;
2725 }
2726 start[i + 1] = numberElements_;
2727 }
2728 }
2729 // construct packed matrix
2730 matrixByColumn_ = new CoinPackedMatrix(true,
2731 numberRows_, numberColumns_, numberElements_,
2732 element, row, start, NULL);
2733 free(row);
2734 free(start);
2735 free(element);
2736
2737 handler_->message(COIN_MPS_STATS, messages_) << problemName_
2738 << numberRows_
2739 << numberColumns_
2740 << numberElements_
2741 << CoinMessageEol;
2742
2743 if (integerType_) {
2744 int numberSC = 0;
2745 int numberSC_int = 0;
2746 for (int i = 0; i < numberColumns_; i++) {
2747 if (integerType_[i] > 2 && integerType_[i] < 5)
2748 numberSC++;
2749 if (integerType_[i] == 4)
2750 numberSC_int++;
2751 }
2752 if (numberSC) {
2753 char generalPrint[100];
2754 if (!numberSC_int)
2755 sprintf(generalPrint, "%d semi-continuous variables - report odd behavior",
2756 numberSC);
2757 else
2758 sprintf(generalPrint, "%d semi-continuous variables (%d integer!) - be wary",
2759 numberSC, numberSC_int);
2760 handler_->message(COIN_GENERAL_INFO, messages_) << generalPrint << CoinMessageEol;
2761 }
2762 }
2763 return numberErrors;
2764 }
2765 #ifdef COIN_HAS_GLPK
2766 #include "glpk.h"
2767 glp_tran *cbc_glp_tran = NULL;
2768 glp_prob *cbc_glp_prob = NULL;
2769 #endif
2770 /* Read a problem in GMPL (subset of AMPL) format from the given filenames.
2771 Thanks to Ted Ralphs - I just looked at his coding rather than look at the GMPL documentation.
2772 */
readGMPL(const char * modelName,const char * dataName,bool keepNames)2773 int CoinMpsIO::readGMPL(const char *modelName, const char *dataName,
2774 bool keepNames)
2775 {
2776 #ifdef COIN_HAS_GLPK
2777 int returnCode;
2778 gutsOfDestructor();
2779 // initialize
2780 cbc_glp_tran = glp_mpl_alloc_wksp();
2781 // read model
2782 char name[2000]; // should be long enough
2783 assert(strlen(modelName) < 2000 && (!dataName || strlen(dataName) < 2000));
2784 strcpy(name, modelName);
2785 returnCode = glp_mpl_read_model(cbc_glp_tran, name, false);
2786 if (returnCode != 0) {
2787 // errors
2788 glp_mpl_free_wksp(cbc_glp_tran);
2789 cbc_glp_tran = NULL;
2790 return 1;
2791 }
2792 if (dataName) {
2793 // read data
2794 strcpy(name, dataName);
2795 returnCode = glp_mpl_read_data(cbc_glp_tran, name);
2796 if (returnCode != 0) {
2797 // errors
2798 glp_mpl_free_wksp(cbc_glp_tran);
2799 cbc_glp_tran = NULL;
2800 return 1;
2801 }
2802 }
2803 // generate model
2804 returnCode = glp_mpl_generate(cbc_glp_tran, NULL);
2805 if (returnCode != 0) {
2806 // errors
2807 glp_mpl_free_wksp(cbc_glp_tran);
2808 cbc_glp_tran = NULL;
2809 return 2;
2810 }
2811 cbc_glp_prob = glp_create_prob();
2812 glp_mpl_build_prob(cbc_glp_tran, cbc_glp_prob);
2813 // Get number of rows, columns, and elements
2814 numberRows_ = glp_get_num_rows(cbc_glp_prob);
2815 numberColumns_ = glp_get_num_cols(cbc_glp_prob);
2816 numberElements_ = glp_get_num_nz(cbc_glp_prob);
2817 int iRow, iColumn;
2818 CoinBigIndex *start = new CoinBigIndex[numberRows_ + 1];
2819 int *index = new int[numberElements_];
2820 double *element = new double[numberElements_];
2821 // Row stuff
2822 rowlower_ = reinterpret_cast< double * >(malloc(numberRows_ * sizeof(double)));
2823 rowupper_ = reinterpret_cast< double * >(malloc(numberRows_ * sizeof(double)));
2824 // and objective
2825 objective_ = reinterpret_cast< double * >(malloc(numberColumns_ * sizeof(double)));
2826 problemName_ = CoinStrdup(glp_get_prob_name(cbc_glp_prob));
2827 int kRow = 0;
2828 start[0] = 0;
2829 numberElements_ = 0;
2830 // spare space for checking
2831 double *el = new double[numberColumns_];
2832 int *ind = new int[numberColumns_];
2833 char **names = NULL;
2834 if (keepNames) {
2835 names = reinterpret_cast< char ** >(malloc(numberRows_ * sizeof(char *)));
2836 names_[0] = names;
2837 numberHash_[0] = numberRows_;
2838 }
2839 for (iRow = 0; iRow < numberRows_; iRow++) {
2840 int number = glp_get_mat_row(cbc_glp_prob, iRow + 1, ind - 1, el - 1);
2841 double rowLower, rowUpper;
2842 int rowType;
2843 rowLower = glp_get_row_lb(cbc_glp_prob, iRow + 1);
2844 rowUpper = glp_get_row_ub(cbc_glp_prob, iRow + 1);
2845 rowType = glp_get_row_type(cbc_glp_prob, iRow + 1);
2846 switch (rowType) {
2847 case GLP_LO:
2848 rowUpper = COIN_DBL_MAX;
2849 break;
2850 case GLP_UP:
2851 rowLower = -COIN_DBL_MAX;
2852 break;
2853 case GLP_FR:
2854 rowLower = -COIN_DBL_MAX;
2855 rowUpper = COIN_DBL_MAX;
2856 break;
2857 default:
2858 break;
2859 }
2860 rowlower_[kRow] = rowLower;
2861 rowupper_[kRow] = rowUpper;
2862 for (int i = 0; i < number; i++) {
2863 iColumn = ind[i] - 1;
2864 index[numberElements_] = iColumn;
2865 element[numberElements_++] = el[i];
2866 }
2867 if (keepNames) {
2868 strcpy(name, glp_get_row_name(cbc_glp_prob, iRow + 1));
2869 // could look at name?
2870 names[kRow] = CoinStrdup(name);
2871 }
2872 kRow++;
2873 start[kRow] = numberElements_;
2874 }
2875 delete[] el;
2876 delete[] ind;
2877
2878 // FIXME why this variable is not used?
2879 bool minimize = (glp_get_obj_dir(cbc_glp_prob) == GLP_MAX ? false : true);
2880 // sign correct?
2881 objectiveOffset_ = glp_get_obj_coef(cbc_glp_prob, 0);
2882 for (int i = 0; i < numberColumns_; i++)
2883 objective_[i] = glp_get_obj_coef(cbc_glp_prob, i + 1);
2884 if (!minimize) {
2885 for (int i = 0; i < numberColumns_; i++)
2886 objective_[i] = -objective_[i];
2887 handler_->message(COIN_GENERAL_INFO, messages_) << " CoinMpsIO::readGMPL(): Maximization problem reformulated as minimization"
2888 << CoinMessageEol;
2889 objectiveOffset_ = -objectiveOffset_;
2890 }
2891
2892 // Matrix
2893 matrixByColumn_ = new CoinPackedMatrix(false, numberColumns_, numberRows_, numberElements_,
2894 element, index, start, NULL);
2895 matrixByColumn_->reverseOrdering();
2896 delete[] element;
2897 delete[] start;
2898 delete[] index;
2899 // Now do columns
2900 collower_ = reinterpret_cast< double * >(malloc(numberColumns_ * sizeof(double)));
2901 colupper_ = reinterpret_cast< double * >(malloc(numberColumns_ * sizeof(double)));
2902 integerType_ = reinterpret_cast< char * >(malloc(numberColumns_ * sizeof(char)));
2903 if (keepNames) {
2904 names = reinterpret_cast< char ** >(malloc(numberColumns_ * sizeof(char *)));
2905 names_[1] = names;
2906 numberHash_[1] = numberColumns_;
2907 }
2908 int numberIntegers = 0;
2909 for (iColumn = 0; iColumn < numberColumns_; iColumn++) {
2910 double columnLower = glp_get_col_lb(cbc_glp_prob, iColumn + 1);
2911 double columnUpper = glp_get_col_ub(cbc_glp_prob, iColumn + 1);
2912 int columnType = glp_get_col_type(cbc_glp_prob, iColumn + 1);
2913 switch (columnType) {
2914 case GLP_LO:
2915 columnUpper = COIN_DBL_MAX;
2916 break;
2917 case GLP_UP:
2918 columnLower = -COIN_DBL_MAX;
2919 break;
2920 case GLP_FR:
2921 columnLower = -COIN_DBL_MAX;
2922 columnUpper = COIN_DBL_MAX;
2923 break;
2924 default:
2925 break;
2926 }
2927 collower_[iColumn] = columnLower;
2928 colupper_[iColumn] = columnUpper;
2929 columnType = glp_get_col_kind(cbc_glp_prob, iColumn + 1);
2930 if (columnType == GLP_IV) {
2931 integerType_[iColumn] = 1;
2932 numberIntegers++;
2933 //assert ( collower_[iColumn] >= -MAX_INTEGER );
2934 if (collower_[iColumn] < -MAX_INTEGER)
2935 collower_[iColumn] = -MAX_INTEGER;
2936 if (colupper_[iColumn] > MAX_INTEGER)
2937 colupper_[iColumn] = MAX_INTEGER;
2938 } else if (columnType == GLP_BV) {
2939 numberIntegers++;
2940 integerType_[iColumn] = 1;
2941 collower_[iColumn] = 0.0;
2942 colupper_[iColumn] = 1.0;
2943 } else {
2944 integerType_[iColumn] = 0;
2945 }
2946 if (keepNames) {
2947 strcpy(name, glp_get_col_name(cbc_glp_prob, iColumn + 1));
2948 // could look at name?
2949 names[iColumn] = CoinStrdup(name);
2950 }
2951 }
2952 // leave in case report needed
2953 //glp_free(cbc_glp_prob);
2954 //glp_mpl_free_wksp(cbc_glp_tran);
2955 //glp_free_env();
2956 if (!numberIntegers) {
2957 free(integerType_);
2958 integerType_ = NULL;
2959 }
2960 if (handler_)
2961 handler_->message(COIN_MPS_STATS, messages_) << problemName_
2962 << numberRows_
2963 << numberColumns_
2964 << numberElements_
2965 << CoinMessageEol;
2966 return 0;
2967 #else
2968 printf("GLPK is not available\n");
2969 abort();
2970 return 1;
2971 #endif
2972 }
2973 //------------------------------------------------------------------
2974 // Read gams files
2975 //------------------------------------------------------------------
readGms(const char * filename,const char * extension,bool convertObjective)2976 int CoinMpsIO::readGms(const char *filename, const char *extension, bool convertObjective)
2977 {
2978 convertObjective_ = convertObjective;
2979 // Deal with filename - +1 if new, 0 if same as before, -1 if error
2980 CoinFileInput *input = 0;
2981 int returnCode = dealWithFileName(filename, extension, input);
2982 if (returnCode < 0) {
2983 return -1;
2984 } else if (returnCode > 0) {
2985 delete cardReader_;
2986 cardReader_ = new CoinMpsCardReader(input, this);
2987 }
2988 int numberSets = 0;
2989 CoinSet **sets = NULL;
2990 returnCode = readGms(numberSets, sets);
2991 for (int i = 0; i < numberSets; i++)
2992 delete sets[i];
2993 delete[] sets;
2994 return returnCode;
2995 }
readGms(const char * filename,const char * extension,int & numberSets,CoinSet ** & sets)2996 int CoinMpsIO::readGms(const char *filename, const char *extension,
2997 int &numberSets, CoinSet **&sets)
2998 {
2999 // Deal with filename - +1 if new, 0 if same as before, -1 if error
3000 CoinFileInput *input = 0;
3001 int returnCode = dealWithFileName(filename, extension, input);
3002 if (returnCode < 0) {
3003 return -1;
3004 } else if (returnCode > 0) {
3005 delete cardReader_;
3006 cardReader_ = new CoinMpsCardReader(input, this);
3007 }
3008 return readGms(numberSets, sets);
3009 }
readGms(int &,CoinSet ** &)3010 int CoinMpsIO::readGms(int & /*numberSets*/, CoinSet **& /*sets*/)
3011 {
3012 // First version expects comments giving size
3013 numberRows_ = 0;
3014 numberColumns_ = 0;
3015 numberElements_ = 0;
3016 bool gotName = false;
3017 bool minimize = false;
3018 char objName[COIN_MAX_FIELD_LENGTH];
3019 int decodeType = -1;
3020 while (!gotName) {
3021 if (cardReader_->nextGmsField(0) < 0) {
3022 handler_->message(COIN_MPS_EOF, messages_) << fileName_
3023 << CoinMessageEol;
3024 return -3;
3025 } else {
3026 char *card = cardReader_->mutableCard();
3027 if (card[0] != '*') {
3028 // finished preamble without finding name
3029 printf("bad gms file\n");
3030 return -1;
3031 } else {
3032 // skip * and find next
3033 char *next = nextNonBlank(card + 1);
3034 if (!next)
3035 continue;
3036 if (decodeType >= 0) {
3037 // in middle of getting a total
3038 if (!strncmp(next, "Total", 5)) {
3039 // next line wanted
3040 decodeType += 100;
3041 } else if (decodeType >= 100) {
3042 decodeType -= 100;
3043 int number = atoi(next);
3044 assert(number > 0);
3045 if (decodeType == 0)
3046 numberRows_ = number;
3047 else if (decodeType == 1)
3048 numberColumns_ = number;
3049 else
3050 numberElements_ = number;
3051 decodeType = -1;
3052 }
3053 } else if (!strncmp(next, "Equation", 8)) {
3054 decodeType = 0;
3055 } else if (!strncmp(next, "Variable", 8)) {
3056 decodeType = 1;
3057 } else if (!strncmp(next, "Nonzero", 7)) {
3058 decodeType = 2;
3059 } else if (!strncmp(next, "Solve", 5)) {
3060 decodeType = -1;
3061 gotName = true;
3062 assert(numberRows_ > 0 && numberColumns_ > 0 && numberElements_ > 0);
3063 next = cardReader_->nextBlankOr(next + 5);
3064 char name[100];
3065 char *put = name;
3066 next = nextNonBlank(next);
3067 while (*next != ' ' && *next != '\t') {
3068 *put = *next;
3069 put++;
3070 next++;
3071 }
3072 *put = '\0';
3073 assert(put - name < 100);
3074 free(problemName_);
3075 problemName_ = CoinStrdup(name);
3076 next = strchr(next, ';');
3077 assert(next);
3078 // backup
3079 while (*next != ' ' && *next != '\t') {
3080 next--;
3081 }
3082 cardReader_->setPosition(next);
3083 #ifdef NDEBUG
3084 cardReader_->nextGmsField(1);
3085 #else
3086 int returnCode = cardReader_->nextGmsField(1);
3087 assert(!returnCode);
3088 #endif
3089 next = strchr(next, ';');
3090 cardReader_->setPosition(next + 1);
3091 strcpy(objName, cardReader_->columnName());
3092 char *semi = strchr(objName, ';');
3093 if (semi)
3094 *semi = '\0';
3095 if (strstr(card, "minim")) {
3096 minimize = true;
3097 } else {
3098 assert(strstr(card, "maxim"));
3099 minimize = false;
3100 }
3101 } else {
3102 decodeType = -1;
3103 }
3104 }
3105 }
3106 }
3107
3108 objectiveOffset_ = 0.0;
3109 rowlower_ = reinterpret_cast< double * >(malloc(numberRows_ * sizeof(double)));
3110 rowupper_ = reinterpret_cast< double * >(malloc(numberRows_ * sizeof(double)));
3111 collower_ = reinterpret_cast< double * >(malloc(numberColumns_ * sizeof(double)));
3112 colupper_ = reinterpret_cast< double * >(malloc(numberColumns_ * sizeof(double)));
3113 objective_ = reinterpret_cast< double * >(malloc(numberColumns_ * sizeof(double)));
3114 CoinBigIndex *start = reinterpret_cast< CoinBigIndex * >(malloc((numberRows_ + 1) * sizeof(CoinBigIndex)));
3115 COINColumnIndex *column = reinterpret_cast< COINRowIndex * >(malloc(numberElements_ * sizeof(COINRowIndex)));
3116 double *element = reinterpret_cast< double * >(malloc(numberElements_ * sizeof(double)));
3117 COINMpsType *rowType = reinterpret_cast< COINMpsType * >(malloc(numberRows_ * sizeof(COINMpsType)));
3118 char **rowName = reinterpret_cast< char ** >(malloc(numberRows_ * sizeof(char *)));
3119 COINMpsType *columnType = reinterpret_cast< COINMpsType * >(malloc(numberColumns_ * sizeof(COINMpsType)));
3120 char **columnName = reinterpret_cast< char ** >(malloc(numberColumns_ * sizeof(char *)));
3121
3122 start[0] = 0;
3123 numberElements_ = 0;
3124
3125 int numberErrors = 0;
3126 int i;
3127 COINColumnIndex numberIntegers = 0;
3128
3129 // expect Variables
3130 int returnCode;
3131 returnCode = cardReader_->nextGmsField(1);
3132 assert(!returnCode && !strcmp(cardReader_->columnName(), "Variables"));
3133 for (i = 0; i < numberColumns_; i++) {
3134 returnCode = cardReader_->nextGmsField(1);
3135 assert(!returnCode);
3136 char *next = cardReader_->getPosition();
3137 if (*next == '\0') {
3138 // eol - expect , at beginning of next line
3139 returnCode = cardReader_->nextGmsField(0);
3140 assert(!returnCode);
3141 next = strchr(cardReader_->mutableCard(), ',');
3142 assert(next);
3143 }
3144 assert(*next == ',' || *next == ';');
3145 cardReader_->setPosition(next + 1);
3146 columnName[i] = CoinStrdup(cardReader_->columnName());
3147 // Default is free?
3148 collower_[i] = -COIN_DBL_MAX;
3149 // Surely not - check
3150 collower_[i] = 0.0;
3151 colupper_[i] = COIN_DBL_MAX;
3152 objective_[i] = 0.0;
3153 columnType[i] = COIN_UNSET_BOUND;
3154 }
3155 startHash(columnName, numberColumns_, 1);
3156 integerType_ = reinterpret_cast< char * >(malloc(numberColumns_ * sizeof(char)));
3157 memset(integerType_, 0, numberColumns_);
3158 // Lists come in various flavors - I don't know many now
3159 // 0 - Positive
3160 // 1 - Binary
3161 // -1 end
3162 int listType = 10;
3163 while (listType >= 0) {
3164 returnCode = cardReader_->nextGmsField(1);
3165 assert(!returnCode);
3166 listType = -1;
3167 if (!strcmp(cardReader_->columnName(), "Positive")) {
3168 listType = 0;
3169 } else if (!strcmp(cardReader_->columnName(), "Binary")) {
3170 listType = 1;
3171 } else if (!strcmp(cardReader_->columnName(), "Integer")) {
3172 listType = 2;
3173 } else {
3174 break;
3175 }
3176 // skip Variables
3177 returnCode = cardReader_->nextGmsField(1);
3178 assert(!returnCode);
3179 assert(!strcmp(cardReader_->columnName(), "Variables"));
3180
3181 // Go through lists
3182 bool inList = true;
3183 while (inList) {
3184 returnCode = cardReader_->nextGmsField(1);
3185 assert(!returnCode);
3186 char *next = cardReader_->getPosition();
3187 if (*next == '\0') {
3188 // eol - expect , at beginning of next line
3189 returnCode = cardReader_->nextGmsField(0);
3190 assert(!returnCode);
3191 next = strchr(cardReader_->mutableCard(), ',');
3192 assert(next);
3193 }
3194 assert(*next == ',' || *next == ';');
3195 cardReader_->setPosition(next + 1);
3196 inList = (*next == ',');
3197 int iColumn = findHash(cardReader_->columnName(), 1);
3198 assert(iColumn >= 0);
3199 if (listType == 0) {
3200 collower_[iColumn] = 0.0;
3201 } else if (listType == 1) {
3202 collower_[iColumn] = 0.0;
3203 colupper_[iColumn] = 1.0;
3204 columnType[iColumn] = COIN_BV_BOUND;
3205 integerType_[iColumn] = 1;
3206 numberIntegers++;
3207 } else if (listType == 2) {
3208 collower_[iColumn] = 0.0;
3209 columnType[iColumn] = COIN_UI_BOUND;
3210 integerType_[iColumn] = 1;
3211 numberIntegers++;
3212 }
3213 }
3214 }
3215 // should be equations
3216 assert(!strcmp(cardReader_->columnName(), "Equations"));
3217 for (i = 0; i < numberRows_; i++) {
3218 returnCode = cardReader_->nextGmsField(1);
3219 assert(!returnCode);
3220 char *next = cardReader_->getPosition();
3221 if (*next == '\0') {
3222 // eol - expect , at beginning of next line
3223 returnCode = cardReader_->nextGmsField(0);
3224 assert(!returnCode);
3225 next = strchr(cardReader_->mutableCard(), ',');
3226 assert(next);
3227 }
3228 assert(*next == ',' || *next == ';');
3229 cardReader_->setPosition(next + 1);
3230 rowName[i] = CoinStrdup(cardReader_->columnName());
3231 // Default is free?
3232 rowlower_[i] = -COIN_DBL_MAX;
3233 rowupper_[i] = COIN_DBL_MAX;
3234 rowType[i] = COIN_N_ROW;
3235 }
3236 startHash(rowName, numberRows_, 0);
3237 const double largeElement = 1.0e14;
3238 int numberTiny = 0;
3239 int numberLarge = 0;
3240 // For now expect just equations so do loop
3241 for (i = 0; i < numberRows_; i++) {
3242 returnCode = cardReader_->nextGmsField(1);
3243 assert(!returnCode);
3244 char *next = cardReader_->getPosition();
3245 assert(*next == ' ');
3246 char rowName[COIN_MAX_FIELD_LENGTH];
3247 strcpy(rowName, cardReader_->columnName());
3248 char *dot = strchr(rowName, '.');
3249 assert(dot);
3250 *dot = '\0';
3251 assert(*(dot + 1) == '.');
3252 #ifndef NDEBUG
3253 int iRow = findHash(rowName, 0);
3254 assert(i == iRow);
3255 #endif
3256 returnCode = 0;
3257 while (!returnCode) {
3258 returnCode = cardReader_->nextGmsField(3);
3259 assert(returnCode == 0 || returnCode == 2);
3260 if (returnCode == 2)
3261 break;
3262 int iColumn = findHash(cardReader_->columnName(), 1);
3263 if (iColumn >= 0) {
3264 column[numberElements_] = iColumn;
3265 double value = cardReader_->value();
3266 if (fabs(value) < smallElement_)
3267 numberTiny++;
3268 else if (fabs(value) > largeElement)
3269 numberLarge++;
3270 element[numberElements_++] = value;
3271 } else {
3272 // may be string
3273 char temp[100];
3274 strcpy(temp, cardReader_->columnName());
3275 char *ast = strchr(temp, '*');
3276 if (!ast) {
3277 assert(iColumn >= 0);
3278 } else {
3279 assert(allowStringElements_);
3280 *ast = '\0';
3281 if (allowStringElements_ == 1)
3282 iColumn = findHash(temp, 1);
3283 else
3284 iColumn = findHash(ast + 1, 1);
3285 assert(iColumn >= 0);
3286 char temp2[100];
3287 temp2[0] = '\0';
3288 double value = cardReader_->value();
3289 if (value && value != 1.0)
3290 sprintf(temp2, "%g*", value);
3291 if (allowStringElements_ == 1)
3292 strcat(temp2, ast + 1);
3293 else
3294 strcat(temp2, temp);
3295 addString(i, iColumn, temp2);
3296 }
3297 }
3298 }
3299 start[i + 1] = numberElements_;
3300 next = cardReader_->getPosition();
3301 // what about ranges?
3302 COINMpsType type = COIN_N_ROW;
3303 if (!strncmp(next, "=E=", 3))
3304 type = COIN_E_ROW;
3305 else if (!strncmp(next, "=G=", 3))
3306 type = COIN_G_ROW;
3307 else if (!strncmp(next, "=L=", 3))
3308 type = COIN_L_ROW;
3309 assert(type != COIN_N_ROW);
3310 cardReader_->setPosition(next + 3);
3311 returnCode = cardReader_->nextGmsField(2);
3312 assert(!returnCode);
3313 if (type == COIN_E_ROW) {
3314 rowlower_[i] = cardReader_->value();
3315 rowupper_[i] = cardReader_->value();
3316 } else if (type == COIN_G_ROW) {
3317 rowlower_[i] = cardReader_->value();
3318 } else if (type == COIN_L_ROW) {
3319 rowupper_[i] = cardReader_->value();
3320 }
3321 rowType[i] = type;
3322 // and skip ;
3323 #ifdef NDEBUG
3324 cardReader_->nextGmsField(5);
3325 #else
3326 returnCode = cardReader_->nextGmsField(5);
3327 assert(!returnCode);
3328 #endif
3329 }
3330 // Now non default bounds
3331 while (true) {
3332 returnCode = cardReader_->nextGmsField(0);
3333 if (returnCode < 0)
3334 break;
3335 // if there is a . see if valid name
3336 char *card = cardReader_->mutableCard();
3337 char *dot = strchr(card, '.');
3338 if (dot) {
3339 *dot = '\0';
3340 int iColumn = findHash(card, 1);
3341 if (iColumn >= 0) {
3342 // bound
3343 char *next = strchr(dot + 1, '=');
3344 assert(next);
3345 double value = atof(next + 1);
3346 if (!strncmp(dot + 1, "fx", 2)) {
3347 collower_[iColumn] = value;
3348 colupper_[iColumn] = value;
3349 } else if (!strncmp(dot + 1, "up", 2)) {
3350 colupper_[iColumn] = value;
3351 } else if (!strncmp(dot + 1, "lo", 2)) {
3352 collower_[iColumn] = value;
3353 }
3354 }
3355 // may be two per card
3356 char *semi = strchr(dot + 1, ';');
3357 dot = NULL;
3358 if (semi)
3359 dot = strchr(semi + 1, '.');
3360 if (dot) {
3361 char *next = nextNonBlank(semi + 1);
3362 dot = strchr(next, '.');
3363 assert(dot);
3364 *dot = '\0';
3365 assert(iColumn == findHash(next, 1));
3366 // bound
3367 next = strchr(dot + 1, '=');
3368 assert(next);
3369 double value = atof(next + 1);
3370 if (!strncmp(dot + 1, "fx", 2)) {
3371 collower_[iColumn] = value;
3372 abort();
3373 colupper_[iColumn] = value;
3374 } else if (!strncmp(dot + 1, "up", 2)) {
3375 colupper_[iColumn] = value;
3376 } else if (!strncmp(dot + 1, "lo", 2)) {
3377 collower_[iColumn] = value;
3378 }
3379 // may be two per card
3380 semi = strchr(dot + 1, ';');
3381 assert(semi);
3382 }
3383 }
3384 }
3385 // Objective
3386 int iObjCol = findHash(objName, 1);
3387 int iObjRow = -1;
3388 assert(iObjCol >= 0);
3389 if (!convertObjective_) {
3390 objective_[iObjCol] = minimize ? 1.0 : -1.0;
3391 } else {
3392 // move column stuff
3393 COINColumnIndex iColumn;
3394 free(names_[1][iObjCol]);
3395 for (iColumn = iObjCol + 1; iColumn < numberColumns_; iColumn++) {
3396 integerType_[iColumn - 1] = integerType_[iColumn];
3397 collower_[iColumn - 1] = collower_[iColumn];
3398 colupper_[iColumn - 1] = colupper_[iColumn];
3399 names_[1][iColumn - 1] = names_[1][iColumn];
3400 }
3401 numberHash_[1]--;
3402 numberColumns_--;
3403 double multiplier = minimize ? 1.0 : -1.0;
3404 // but swap
3405 multiplier *= -1.0;
3406 int iRow;
3407 CoinBigIndex nel = 0;
3408 CoinBigIndex last = 0;
3409 int kRow = 0;
3410 for (iRow = 0; iRow < numberRows_; iRow++) {
3411 CoinBigIndex j;
3412 bool found = false;
3413 for (j = last; j < start[iRow + 1]; j++) {
3414 int iColumn = column[j];
3415 if (iColumn != iObjCol) {
3416 column[nel] = (iColumn < iObjCol) ? iColumn : iColumn - 1;
3417 element[nel++] = element[j];
3418 } else {
3419 found = true;
3420 assert(element[j] == 1.0);
3421 break;
3422 }
3423 }
3424 if (!found) {
3425 last = start[iRow + 1];
3426 rowlower_[kRow] = rowlower_[iRow];
3427 rowupper_[kRow] = rowupper_[iRow];
3428 names_[0][kRow] = names_[0][iRow];
3429 start[kRow + 1] = nel;
3430 kRow++;
3431 } else {
3432 free(names_[0][iRow]);
3433 iObjRow = iRow;
3434 for (j = last; j < start[iRow + 1]; j++) {
3435 int iColumn = column[j];
3436 if (iColumn != iObjCol) {
3437 if (iColumn > iObjCol)
3438 iColumn--;
3439 objective_[iColumn] = multiplier * element[j];
3440 }
3441 }
3442 nel = start[kRow];
3443 last = start[iRow + 1];
3444 }
3445 }
3446 numberRows_ = kRow;
3447 assert(iObjRow >= 0);
3448 numberHash_[0]--;
3449 }
3450 stopHash(0);
3451 stopHash(1);
3452 // clean up integers
3453 if (!numberIntegers) {
3454 free(integerType_);
3455 integerType_ = NULL;
3456 } else {
3457 COINColumnIndex iColumn;
3458 for (iColumn = 0; iColumn < numberColumns_; iColumn++) {
3459 if (integerType_[iColumn]) {
3460 //assert ( collower_[iColumn] >= -MAX_INTEGER );
3461 if (collower_[iColumn] < -MAX_INTEGER)
3462 collower_[iColumn] = -MAX_INTEGER;
3463 if (colupper_[iColumn] > MAX_INTEGER)
3464 colupper_[iColumn] = MAX_INTEGER;
3465 }
3466 }
3467 }
3468 free(columnType);
3469 free(rowType);
3470 if (numberStringElements() && convertObjective_) {
3471 int numberElements = numberStringElements();
3472 for (int i = 0; i < numberElements; i++) {
3473 char *line = stringElements_[i];
3474 int iRow;
3475 int iColumn;
3476 sscanf(line, "%d,%d,", &iRow, &iColumn);
3477 bool modify = false;
3478 if (iRow > iObjRow) {
3479 modify = true;
3480 iRow--;
3481 }
3482 if (iColumn > iObjCol) {
3483 modify = true;
3484 iColumn--;
3485 }
3486 if (modify) {
3487 char temp[500];
3488 const char *pos = strchr(line, ',');
3489 assert(pos);
3490 pos = strchr(pos + 1, ',');
3491 assert(pos);
3492 pos++;
3493 sprintf(temp, "%d,%d,%s", iRow, iColumn, pos);
3494 free(line);
3495 stringElements_[i] = CoinStrdup(temp);
3496 }
3497 }
3498 }
3499 // construct packed matrix and convert to column format
3500 CoinPackedMatrix matrixByRow(false,
3501 numberColumns_, numberRows_, numberElements_,
3502 element, column, start, NULL);
3503 free(column);
3504 free(start);
3505 free(element);
3506 matrixByColumn_ = new CoinPackedMatrix();
3507 matrixByColumn_->setExtraGap(0.0);
3508 matrixByColumn_->setExtraMajor(0.0);
3509 matrixByColumn_->reverseOrderedCopyOf(matrixByRow);
3510 if (!convertObjective_)
3511 assert(matrixByColumn_->getVectorLengths()[iObjCol] == 1);
3512
3513 handler_->message(COIN_MPS_STATS, messages_) << problemName_
3514 << numberRows_
3515 << numberColumns_
3516 << numberElements_
3517 << CoinMessageEol;
3518 if ((numberTiny || numberLarge) && handler_->logLevel() > 3)
3519 printf("There were %d coefficients < %g and %d > %g\n",
3520 numberTiny, smallElement_, numberLarge, largeElement);
3521 return numberErrors;
3522 }
3523 /* Read a basis in MPS format from the given filename.
3524 If VALUES on NAME card and solution not NULL fills in solution
3525 status values as for CoinWarmStartBasis (but one per char)
3526
3527 Use "stdin" or "-" to read from stdin.
3528 */
readBasis(const char * filename,const char * extension,double * solution,unsigned char * rowStatus,unsigned char * columnStatus,const std::vector<std::string> & colnames,int numberColumns,const std::vector<std::string> & rownames,int numberRows)3529 int CoinMpsIO::readBasis(const char *filename, const char *extension,
3530 double *solution, unsigned char *rowStatus, unsigned char *columnStatus,
3531 const std::vector< std::string > &colnames, int numberColumns,
3532 const std::vector< std::string > &rownames, int numberRows)
3533 {
3534 // Deal with filename - +1 if new, 0 if same as before, -1 if error
3535 CoinFileInput *input = 0;
3536 int returnCode = dealWithFileName(filename, extension, input);
3537 if (returnCode < 0) {
3538 return -1;
3539 } else if (returnCode > 0) {
3540 delete cardReader_;
3541 cardReader_ = new CoinMpsCardReader(input, this);
3542 }
3543
3544 cardReader_->readToNextSection();
3545
3546 if (cardReader_->whichSection() == COIN_NAME_SECTION) {
3547 // Get whether to use values (passed back by freeFormat)
3548 if (!cardReader_->freeFormat())
3549 solution = NULL;
3550
3551 } else if (cardReader_->whichSection() == COIN_UNKNOWN_SECTION) {
3552 handler_->message(COIN_MPS_BADFILE1, messages_) << cardReader_->card()
3553 << 1
3554 << fileName_
3555 << CoinMessageEol;
3556 if (cardReader_->fileInput()->getReadType() != "plain")
3557 handler_->message(COIN_MPS_BADFILE2, messages_)
3558 << cardReader_->fileInput()->getReadType()
3559 << CoinMessageEol;
3560
3561 return -2;
3562 } else if (cardReader_->whichSection() != COIN_EOF_SECTION) {
3563 return -4;
3564 } else {
3565 handler_->message(COIN_MPS_EOF, messages_) << fileName_
3566 << CoinMessageEol;
3567 return -3;
3568 }
3569 numberRows_ = numberRows;
3570 numberColumns_ = numberColumns;
3571 // bas file - always read in free format
3572 bool gotNames;
3573 if (rownames.size() != static_cast< unsigned int >(numberRows_) || colnames.size() != static_cast< unsigned int >(numberColumns_)) {
3574 gotNames = false;
3575 } else {
3576 gotNames = true;
3577 numberHash_[0] = numberRows_;
3578 numberHash_[1] = numberColumns_;
3579 names_[0] = reinterpret_cast< char ** >(malloc(numberRows_ * sizeof(char *)));
3580 names_[1] = reinterpret_cast< char ** >(malloc(numberColumns_ * sizeof(char *)));
3581 const char **rowNames = const_cast< const char ** >(names_[0]);
3582 const char **columnNames = const_cast< const char ** >(names_[1]);
3583 int i;
3584 for (i = 0; i < numberRows_; ++i) {
3585 rowNames[i] = rownames[i].c_str();
3586 }
3587 for (i = 0; i < numberColumns_; ++i) {
3588 columnNames[i] = colnames[i].c_str();
3589 }
3590 startHash(const_cast< char ** >(rowNames), numberRows, 0);
3591 startHash(const_cast< char ** >(columnNames), numberColumns, 1);
3592 }
3593 cardReader_->setWhichSection(COIN_BASIS_SECTION);
3594 cardReader_->setFreeFormat(true);
3595 // below matches CoinWarmStartBasis,
3596 const unsigned char basic = 0x01;
3597 const unsigned char atLowerBound = 0x03;
3598 const unsigned char atUpperBound = 0x02;
3599 while (cardReader_->nextField() == COIN_BASIS_SECTION) {
3600 // Get type and column number
3601 int iColumn;
3602 if (gotNames) {
3603 iColumn = findHash(cardReader_->columnName(), 1);
3604 } else {
3605 // few checks
3606 char check;
3607 sscanf(cardReader_->columnName(), "%c%d", &check, &iColumn);
3608 assert(check == 'C' && iColumn >= 0);
3609 if (iColumn >= numberColumns_)
3610 iColumn = -1;
3611 }
3612 if (iColumn >= 0) {
3613 double value = cardReader_->value();
3614 if (solution && value > -1.0e50)
3615 solution[iColumn] = value;
3616 int iRow = -1;
3617 switch (cardReader_->mpsType()) {
3618 case COIN_BS_BASIS:
3619 columnStatus[iColumn] = basic;
3620 break;
3621 case COIN_XL_BASIS:
3622 columnStatus[iColumn] = basic;
3623 // get row number
3624 if (gotNames) {
3625 iRow = findHash(cardReader_->rowName(), 0);
3626 } else {
3627 // few checks
3628 char check;
3629 sscanf(cardReader_->rowName(), "%c%d", &check, &iRow);
3630 assert(check == 'R' && iRow >= 0);
3631 if (iRow >= numberRows_)
3632 iRow = -1;
3633 }
3634 if (iRow >= 0) {
3635 rowStatus[iRow] = atLowerBound;
3636 }
3637 break;
3638 case COIN_XU_BASIS:
3639 columnStatus[iColumn] = basic;
3640 // get row number
3641 if (gotNames) {
3642 iRow = findHash(cardReader_->rowName(), 0);
3643 } else {
3644 // few checks
3645 char check;
3646 sscanf(cardReader_->rowName(), "%c%d", &check, &iRow);
3647 assert(check == 'R' && iRow >= 0);
3648 if (iRow >= numberRows_)
3649 iRow = -1;
3650 }
3651 if (iRow >= 0) {
3652 rowStatus[iRow] = atUpperBound;
3653 }
3654 break;
3655 case COIN_LL_BASIS:
3656 columnStatus[iColumn] = atLowerBound;
3657 break;
3658 case COIN_UL_BASIS:
3659 columnStatus[iColumn] = atUpperBound;
3660 break;
3661 default:
3662 break;
3663 }
3664 }
3665 }
3666 if (gotNames) {
3667 stopHash(0);
3668 stopHash(1);
3669 free(names_[0]);
3670 names_[0] = NULL;
3671 numberHash_[0] = 0;
3672 free(names_[1]);
3673 names_[1] = NULL;
3674 numberHash_[1] = 0;
3675 delete[] hash_[0];
3676 delete[] hash_[1];
3677 hash_[0] = 0;
3678 hash_[1] = 0;
3679 }
3680 if (cardReader_->whichSection() != COIN_ENDATA_SECTION) {
3681 handler_->message(COIN_MPS_BADIMAGE, messages_) << cardReader_->cardNumber()
3682 << cardReader_->card()
3683 << CoinMessageEol;
3684 handler_->message(COIN_MPS_RETURNING, messages_) << CoinMessageEol;
3685 return -1;
3686 } else {
3687 return solution ? 1 : 0;
3688 }
3689 }
3690
3691 //------------------------------------------------------------------
3692
3693 // Function to create row name field
3694 static void
convertRowName(int formatType,const char * name,char outputRow[100])3695 convertRowName(int formatType, const char *name, char outputRow[100])
3696 {
3697 strcpy(outputRow, name);
3698 if (!formatType) {
3699 int i;
3700 // pad out to 8
3701 for (i = 0; i < 8; i++) {
3702 if (outputRow[i] == '\0')
3703 break;
3704 }
3705 for (; i < 8; i++)
3706 outputRow[i] = ' ';
3707 outputRow[8] = '\0';
3708 } else if (formatType > 1 && formatType < 8) {
3709 int i;
3710 // pad out to 8
3711 for (i = 0; i < 8; i++) {
3712 if (outputRow[i] == '\0')
3713 break;
3714 }
3715 for (; i < 8; i++)
3716 outputRow[i] = ' ';
3717 outputRow[8] = '\0';
3718 }
3719 }
3720 // Function to return number in most efficient way
3721 // Also creates row name field
3722 /* formatType is
3723 0 - normal and 8 character names
3724 1 - extra accuracy
3725 2 - IEEE hex - INTEL
3726 3 - IEEE hex - not INTEL
3727 */
3728 static void
convertDouble(int section,int formatType,double value,char outputValue[24],const char * name,char outputRow[100])3729 convertDouble(int section, int formatType, double value, char outputValue[24],
3730 const char *name, char outputRow[100])
3731 {
3732 convertRowName(formatType, name, outputRow);
3733 CoinConvertDouble(section, formatType & 3, value, outputValue);
3734 }
3735 // Function to return number in most efficient way
3736 /* formatType is
3737 0 - normal and 8 character names
3738 1 - extra accuracy
3739 2 - IEEE hex - INTEL
3740 3 - IEEE hex - not INTEL
3741 */
CoinConvertDouble(int section,int formatType,double value,char outputValue[24])3742 void CoinConvertDouble(int section, int formatType, double value, char outputValue[24])
3743 {
3744 if (formatType == 0) {
3745 bool stripZeros = true;
3746 if (fabs(value) < 1.0e40) {
3747 int power10, decimal;
3748 if (value >= 0.0) {
3749 power10 = static_cast< int >(log10(value));
3750 if (power10 < 9 && power10 > -4) {
3751 decimal = CoinMin(10, 10 - power10);
3752 char format[8];
3753 sprintf(format, "%%12.%df", decimal);
3754 sprintf(outputValue, format, value);
3755 } else {
3756 sprintf(outputValue, "%13.7g", value);
3757 stripZeros = false;
3758 }
3759 } else {
3760 power10 = static_cast< int >(log10(-value)) + 1;
3761 if (power10 < 8 && power10 > -3) {
3762 decimal = CoinMin(9, 9 - power10);
3763 char format[8];
3764 sprintf(format, "%%12.%df", decimal);
3765 sprintf(outputValue, format, value);
3766 } else {
3767 sprintf(outputValue, "%13.6g", value);
3768 stripZeros = false;
3769 }
3770 }
3771 if (stripZeros) {
3772 // take off trailing 0
3773 int j;
3774 for (j = 11; j >= 0; j--) {
3775 if (outputValue[j] == '0')
3776 outputValue[j] = ' ';
3777 else
3778 break;
3779 }
3780 } else {
3781 // still need to make sure fits in 12 characters
3782 char *e = strchr(outputValue, 'e');
3783 if (!e) {
3784 // no e but better make sure fits in 12
3785 if (outputValue[12] != ' ' && outputValue[12] != '\0') {
3786 assert(outputValue[0] == ' ');
3787 int j;
3788 for (j = 0; j < 12; j++)
3789 outputValue[j] = outputValue[j + 1];
3790 }
3791 outputValue[12] = '\0';
3792 } else {
3793 // e take out 0s
3794 int j = static_cast< int >((e - outputValue)) + 1;
3795 int put = j + 1;
3796 assert(outputValue[j] == '-' || outputValue[j] == '+');
3797 for (j = put; j < 14; j++) {
3798 if (outputValue[j] != '0')
3799 break;
3800 }
3801 if (j == put) {
3802 // we need to lose something
3803 // try taking out blanks
3804 if (outputValue[0] == ' ') {
3805 // skip blank
3806 j = 1;
3807 put = 0;
3808 } else {
3809 // rounding will be wrong but ....
3810 put -= 3; // points to one before e
3811 j -= 2; // points to e
3812 }
3813 }
3814 // copy rest
3815 for (; j < 14; j++) {
3816 outputValue[put++] = outputValue[j];
3817 }
3818 }
3819 }
3820 // overwrite if very very small
3821 if (fabs(value) < 1.0e-20)
3822 strcpy(outputValue, "0.0");
3823 } else {
3824 if (section == 2) {
3825 outputValue[0] = '\0'; // needs no value
3826 } else {
3827 // probably error ... but ....
3828 sprintf(outputValue, "%12.6g", value);
3829 }
3830 }
3831 int i;
3832 // pad out to 12
3833 for (i = 0; i < 12; i++) {
3834 if (outputValue[i] == '\0')
3835 break;
3836 }
3837 for (; i < 12; i++)
3838 outputValue[i] = ' ';
3839 outputValue[12] = '\0';
3840 } else if (formatType == 1) {
3841 if (fabs(value) < 1.0e40) {
3842 memset(outputValue, ' ', 24);
3843 sprintf(outputValue, "%.16g", value);
3844 // take out blanks
3845 int i = 0;
3846 int j;
3847 for (j = 0; j < 23; j++) {
3848 if (outputValue[j] != ' ')
3849 outputValue[i++] = outputValue[j];
3850 }
3851 outputValue[i] = '\0';
3852 } else {
3853 if (section == 2) {
3854 outputValue[0] = '\0'; // needs no value
3855 } else {
3856 // probably error ... but ....
3857 sprintf(outputValue, "%12.6g", value);
3858 }
3859 }
3860 } else {
3861 // IEEE
3862 // ieee - 3 bytes go to 2
3863 assert(sizeof(double) == 8 * sizeof(char));
3864 assert(sizeof(unsigned short) == 2 * sizeof(char));
3865 unsigned short shortValue[4];
3866 memcpy(shortValue, &value, sizeof(double));
3867 outputValue[12] = '\0';
3868 if (formatType == 2) {
3869 // INTEL
3870 char *thisChar = outputValue;
3871 for (int i = 3; i >= 0; i--) {
3872 unsigned short thisValue = shortValue[i];
3873 // encode 6 bits at a time
3874 for (int j = 0; j < 3; j++) {
3875 unsigned short thisPart = static_cast< unsigned short >(thisValue & 63);
3876 thisValue = static_cast< unsigned short >(thisValue >> 6);
3877 if (thisPart < 10) {
3878 *thisChar = static_cast< char >(thisPart + '0');
3879 } else if (thisPart < 36) {
3880 *thisChar = static_cast< char >(thisPart - 10 + 'a');
3881 } else if (thisPart < 62) {
3882 *thisChar = static_cast< char >(thisPart - 36 + 'A');
3883 } else {
3884 *thisChar = static_cast< char >(thisPart - 62 + '*');
3885 }
3886 thisChar++;
3887 }
3888 }
3889 } else {
3890 // not INTEL
3891 char *thisChar = outputValue;
3892 for (int i = 0; i < 4; i++) {
3893 unsigned short thisValue = shortValue[i];
3894 // encode 6 bits at a time
3895 for (int j = 0; j < 3; j++) {
3896 unsigned short thisPart = static_cast< unsigned short >(thisValue & 63);
3897 thisValue = static_cast< unsigned short >(thisValue >> 6);
3898 if (thisPart < 10) {
3899 *thisChar = static_cast< char >(thisPart + '0');
3900 } else if (thisPart < 36) {
3901 *thisChar = static_cast< char >(thisPart - 10 + 'a');
3902 } else if (thisPart < 62) {
3903 *thisChar = static_cast< char >(thisPart - 36 + 'A');
3904 } else {
3905 *thisChar = static_cast< char >(thisPart - 62 + '*');
3906 }
3907 thisChar++;
3908 }
3909 }
3910 }
3911 }
3912 }
3913 static void
writeString(CoinFileOutput * output,const char * str)3914 writeString(CoinFileOutput *output, const char *str)
3915 {
3916 if (output != 0) {
3917 output->puts(str);
3918 }
3919 }
3920
3921 // Put out card image
outputCard(int formatType,int numberFields,CoinFileOutput * output,std::string head,const char * name,const char outputValue[2][24],const char outputRow[2][100])3922 static void outputCard(int formatType, int numberFields,
3923 CoinFileOutput *output,
3924 std::string head, const char *name,
3925 const char outputValue[2][24],
3926 const char outputRow[2][100])
3927 {
3928 // fprintf(fp,"%s",head.c_str());
3929 std::string line = head;
3930 int i;
3931 if (formatType == 0 || (formatType >= 2 && formatType < 8)) {
3932 char outputColumn[9];
3933 strcpy(outputColumn, name);
3934 for (i = 0; i < 8; i++) {
3935 if (outputColumn[i] == '\0')
3936 break;
3937 }
3938 for (; i < 8; i++)
3939 outputColumn[i] = ' ';
3940 outputColumn[8] = '\0';
3941 // fprintf(fp,"%s ",outputColumn);
3942 line += outputColumn;
3943 line += " ";
3944 for (i = 0; i < numberFields; i++) {
3945 // fprintf(fp,"%s %s",outputRow[i],outputValue[i]);
3946 line += outputRow[i];
3947 line += " ";
3948 line += outputValue[i];
3949 if (i < numberFields - 1) {
3950 // fprintf(fp," ");
3951 line += " ";
3952 }
3953 }
3954 } else {
3955 // fprintf(fp,"%s",name);
3956 line += name;
3957 for (i = 0; i < numberFields; i++) {
3958 // fprintf(fp," %s %s",outputRow[i],outputValue[i]);
3959 line += " ";
3960 line += outputRow[i];
3961 line += " ";
3962 line += outputValue[i];
3963 }
3964 }
3965
3966 // fprintf(fp,"\n");
3967 line += "\n";
3968 writeString(output, line.c_str());
3969 }
3970 static int
makeUniqueNames(char ** names,int number,char first)3971 makeUniqueNames(char **names, int number, char first)
3972 {
3973 int largest = -1;
3974 int i;
3975 for (i = 0; i < number; i++) {
3976 char *name = names[i];
3977 if (name[0] == first && strlen(name) == 8) {
3978 // check number
3979 int n = 0;
3980 for (int j = 1; j < 8; j++) {
3981 char num = name[j];
3982 if (num >= '0' && num <= '9') {
3983 n *= 10;
3984 n += num - '0';
3985 } else {
3986 n = -1;
3987 break;
3988 }
3989 }
3990 if (n >= 0)
3991 largest = CoinMax(largest, n);
3992 }
3993 }
3994 largest++;
3995 if (largest > 0) {
3996 // check
3997 char *used = new char[largest];
3998 memset(used, 0, largest);
3999 int nDup = 0;
4000 for (i = 0; i < number; i++) {
4001 char *name = names[i];
4002 if (name[0] == first && strlen(name) == 8) {
4003 // check number
4004 int n = 0;
4005 for (int j = 1; j < 8; j++) {
4006 char num = name[j];
4007 if (num >= '0' && num <= '9') {
4008 n *= 10;
4009 n += num - '0';
4010 } else {
4011 n = -1;
4012 break;
4013 }
4014 }
4015 if (n >= 0) {
4016 if (!used[n]) {
4017 used[n] = 1;
4018 } else {
4019 // duplicate
4020 nDup++;
4021 free(names[i]);
4022 char newName[12];
4023 sprintf(newName, "%c%7.7d", first, largest);
4024 names[i] = CoinStrdup(newName);
4025 largest++;
4026 }
4027 }
4028 }
4029 }
4030 delete[] used;
4031 return nDup;
4032 } else {
4033 return 0;
4034 }
4035 }
4036 static void
strcpyeq(char * output,const char * input)4037 strcpyeq(char *output, const char *input)
4038 {
4039 output[0] = '=';
4040 strcpy(output + 1, input);
4041 }
4042
writeMps(const char * filename,int compression,int formatType,int numberAcross,CoinPackedMatrix * quadratic,int numberSOS,const CoinSet * setInfo) const4043 int CoinMpsIO::writeMps(const char *filename, int compression,
4044 int formatType, int numberAcross,
4045 CoinPackedMatrix *quadratic,
4046 int numberSOS, const CoinSet *setInfo) const
4047 {
4048 // Clean up format and numberacross
4049 numberAcross = CoinMax(1, numberAcross);
4050 numberAcross = CoinMin(2, numberAcross);
4051 formatType = CoinMax(0, formatType);
4052 formatType = CoinMin(2, formatType);
4053 int possibleCompression = 0;
4054 #ifdef COIN_HAS_ZLIB
4055 possibleCompression = 1;
4056 #endif
4057 #ifdef COIN_HAS_BZLIB
4058 possibleCompression += 2;
4059 #endif
4060 if ((compression & possibleCompression) == 0) {
4061 // switch to other if possible
4062 if (compression && possibleCompression)
4063 compression = 3 - compression;
4064 else
4065 compression = 0;
4066 }
4067 std::string line = filename;
4068 CoinFileOutput *output = 0;
4069 switch (compression) {
4070 case 1:
4071 if (strcmp(line.c_str() + (line.size() - 3), ".gz") != 0) {
4072 line += ".gz";
4073 }
4074 output = CoinFileOutput::create(line, CoinFileOutput::COMPRESS_GZIP);
4075 break;
4076
4077 case 2:
4078 if (strcmp(line.c_str() + (line.size() - 4), ".bz2") != 0) {
4079 line += ".bz2";
4080 }
4081 output = CoinFileOutput::create(line, CoinFileOutput::COMPRESS_BZIP2);
4082 break;
4083
4084 case 0:
4085 default:
4086 output = CoinFileOutput::create(line, CoinFileOutput::COMPRESS_NONE);
4087 break;
4088 }
4089
4090 // Set locale so won't get , instead of .
4091 char *saveLocale = strdup(setlocale(LC_ALL, NULL));
4092 setlocale(LC_ALL, "C");
4093 const char *const *const rowNames = names_[0];
4094 const char *const *const columnNames = names_[1];
4095 int i;
4096 unsigned int length = 8;
4097 bool freeFormat = (formatType == 1);
4098 // Check names for uniqueness if default
4099 int nChanged;
4100 nChanged = makeUniqueNames(names_[0], numberRows_, 'R');
4101 if (nChanged)
4102 handler_->message(COIN_MPS_CHANGED, messages_) << "row" << nChanged
4103 << CoinMessageEol;
4104 nChanged = makeUniqueNames(names_[1], numberColumns_, 'C');
4105 if (nChanged)
4106 handler_->message(COIN_MPS_CHANGED, messages_) << "column" << nChanged
4107 << CoinMessageEol;
4108 for (i = 0; i < numberRows_; ++i) {
4109 if (strlen(rowNames[i]) > length) {
4110 length = static_cast< int >(strlen(rowNames[i]));
4111 break;
4112 }
4113 }
4114 if (length <= 8) {
4115 for (i = 0; i < numberColumns_; ++i) {
4116 if (strlen(columnNames[i]) > length) {
4117 length = static_cast< int >(strlen(columnNames[i]));
4118 break;
4119 }
4120 }
4121 }
4122 if (length > 8 && freeFormat != 1) {
4123 freeFormat = true;
4124 formatType += 8;
4125 }
4126 if (numberStringElements_) {
4127 freeFormat = true;
4128 numberAcross = 1;
4129 }
4130
4131 // NAME card
4132
4133 line = "NAME ";
4134 if (strcmp(problemName_, "") == 0) {
4135 line.append("BLANK ");
4136 } else {
4137 if (strlen(problemName_) >= 8) {
4138 line.append(problemName_, 8);
4139 } else {
4140 line.append(problemName_);
4141 line.append(8 - strlen(problemName_), ' ');
4142 }
4143 }
4144 if (freeFormat && (formatType & 7) != 2)
4145 line.append(" FREE");
4146 else if (freeFormat)
4147 line.append(" FREEIEEE");
4148 else if ((formatType & 7) == 2)
4149 line.append(" IEEE");
4150 // See if INTEL if IEEE
4151 if ((formatType & 7) == 2) {
4152 // test intel here and add 1 if not intel
4153 double value = 1.0;
4154 char x[8];
4155 memcpy(x, &value, 8);
4156 if (x[0] == 63) {
4157 formatType++; // not intel
4158 } else {
4159 assert(x[0] == 0);
4160 }
4161 }
4162 // finish off name and do ROWS card and objective
4163 char *objrow = CoinStrdup(strcmp(objectiveName_, "") == 0 ? "OBJROW" : objectiveName_);
4164 line.append("\nROWS\n N ");
4165 line.append(objrow);
4166 line.append("\n");
4167 writeString(output, line.c_str());
4168
4169 // Rows section
4170 // Sense array
4171 // But massage if looks odd
4172 char *sense = new char[numberRows_];
4173 memcpy(sense, getRowSense(), numberRows_);
4174 const double *rowLower = getRowLower();
4175 const double *rowUpper = getRowUpper();
4176
4177 for (i = 0; i < numberRows_; i++) {
4178 line = " ";
4179 if (sense[i] != 'R') {
4180 line.append(1, sense[i]);
4181 } else {
4182 if (rowLower[i] > -1.0e30) {
4183 if (rowUpper[i] < 1.0e30) {
4184 line.append("L");
4185 } else {
4186 sense[i] = 'G';
4187 line.append(1, sense[i]);
4188 }
4189 } else {
4190 sense[i] = 'L';
4191 line.append(1, sense[i]);
4192 }
4193 }
4194 line.append(" ");
4195 line.append(rowNames[i]);
4196 line.append("\n");
4197 writeString(output, line.c_str());
4198 }
4199
4200 // COLUMNS card
4201 writeString(output, "COLUMNS\n");
4202
4203 bool ifBounds = false;
4204 double largeValue = infinity_;
4205 largeValue = 1.0e30; // safer
4206
4207 const double *columnLower = getColLower();
4208 const double *columnUpper = getColUpper();
4209 const double *objective = getObjCoefficients();
4210 const CoinPackedMatrix *matrix = getMatrixByCol();
4211 const double *elements = matrix->getElements();
4212 const int *rows = matrix->getIndices();
4213 const CoinBigIndex *starts = matrix->getVectorStarts();
4214 const int *lengths = matrix->getVectorLengths();
4215
4216 char outputValue[2][24];
4217 char outputRow[2][100];
4218 // strings
4219 int nextRowString = numberRows_ + 10;
4220 int nextColumnString = numberColumns_ + 10;
4221 int whichString = 0;
4222 const char *nextString = NULL;
4223 // mark string rows
4224 char *stringRow = new char[numberRows_ + 1];
4225 memset(stringRow, 0, numberRows_ + 1);
4226 if (numberStringElements_) {
4227 decodeString(whichString, nextRowString, nextColumnString, nextString);
4228 }
4229 // Arrays so we can put out rows in order
4230 int *tempRow = new int[numberRows_];
4231 double *tempValue = new double[numberRows_];
4232
4233 // Through columns (only put out if elements or objective value)
4234 for (i = 0; i < numberColumns_; i++) {
4235 if (i == nextColumnString) {
4236 // set up
4237 int k = whichString;
4238 int iColumn = nextColumnString;
4239 int iRow = nextRowString;
4240 const char *dummy;
4241 while (iColumn == nextColumnString) {
4242 stringRow[iRow] = 1;
4243 k++;
4244 decodeString(k, iRow, iColumn, dummy);
4245 }
4246 }
4247 if (objective[i] || lengths[i] || i == nextColumnString) {
4248 // see if bound will be needed
4249 if (columnLower[i] || columnUpper[i] < largeValue || isInteger(i))
4250 ifBounds = true;
4251 int numberFields = 0;
4252 if (objective[i]) {
4253 convertDouble(0, formatType, objective[i], outputValue[0],
4254 objrow, outputRow[0]);
4255 numberFields = 1;
4256 if (stringRow[numberRows_]) {
4257 assert(objective[i] == STRING_VALUE);
4258 assert(nextColumnString == i && nextRowString == numberRows_);
4259 strcpyeq(outputValue[0], nextString);
4260 stringRow[numberRows_] = 0;
4261 decodeString(++whichString, nextRowString, nextColumnString, nextString);
4262 }
4263 }
4264 if (numberFields == numberAcross) {
4265 // put out card
4266 outputCard(formatType, numberFields,
4267 output, " ",
4268 columnNames[i],
4269 outputValue,
4270 outputRow);
4271 numberFields = 0;
4272 }
4273 int j;
4274 int numberEntries = lengths[i];
4275 CoinBigIndex start = starts[i];
4276 for (j = 0; j < numberEntries; j++) {
4277 tempRow[j] = rows[start + j];
4278 tempValue[j] = elements[start + j];
4279 }
4280 CoinSort_2(tempRow, tempRow + numberEntries, tempValue);
4281 for (j = 0; j < numberEntries; j++) {
4282 int jRow = tempRow[j];
4283 double value = tempValue[j];
4284 if (value && !stringRow[jRow]) {
4285 convertDouble(0, formatType, value,
4286 outputValue[numberFields],
4287 rowNames[jRow],
4288 outputRow[numberFields]);
4289 numberFields++;
4290 if (numberFields == numberAcross) {
4291 // put out card
4292 outputCard(formatType, numberFields,
4293 output, " ",
4294 columnNames[i],
4295 outputValue,
4296 outputRow);
4297 numberFields = 0;
4298 }
4299 }
4300 }
4301 if (numberFields) {
4302 // put out card
4303 outputCard(formatType, numberFields,
4304 output, " ",
4305 columnNames[i],
4306 outputValue,
4307 outputRow);
4308 }
4309 }
4310 // end see if any strings
4311 if (i == nextColumnString) {
4312 int iColumn = nextColumnString;
4313 int iRow = nextRowString;
4314 while (iColumn == nextColumnString) {
4315 double value = 1.0;
4316 convertDouble(0, formatType, value,
4317 outputValue[0],
4318 rowNames[nextRowString],
4319 outputRow[0]);
4320 strcpyeq(outputValue[0], nextString);
4321 // put out card
4322 outputCard(formatType, 1,
4323 output, " ",
4324 columnNames[i],
4325 outputValue,
4326 outputRow);
4327 stringRow[iRow] = 0;
4328 decodeString(++whichString, nextRowString, nextColumnString, nextString);
4329 }
4330 }
4331 }
4332 delete[] tempRow;
4333 delete[] tempValue;
4334 delete[] stringRow;
4335
4336 bool ifRange = false;
4337 // RHS
4338 writeString(output, "RHS\n");
4339
4340 int numberFields = 0;
4341 // If there is any offset - then do that
4342 if (objectiveOffset_) {
4343 convertDouble(1, formatType, objectiveOffset_,
4344 outputValue[0],
4345 objrow,
4346 outputRow[0]);
4347 numberFields++;
4348 if (numberFields == numberAcross) {
4349 // put out card
4350 outputCard(formatType, numberFields,
4351 output, " ",
4352 "RHS",
4353 outputValue,
4354 outputRow);
4355 numberFields = 0;
4356 }
4357 }
4358 for (i = 0; i < numberRows_; i++) {
4359 double value;
4360 switch (sense[i]) {
4361 case 'E':
4362 value = rowLower[i];
4363 break;
4364 case 'R':
4365 value = rowUpper[i];
4366 ifRange = true;
4367 break;
4368 case 'L':
4369 value = rowUpper[i];
4370 break;
4371 case 'G':
4372 value = rowLower[i];
4373 break;
4374 default:
4375 value = 0.0;
4376 break;
4377 }
4378 if (value != 0.0) {
4379 convertDouble(1, formatType, value,
4380 outputValue[numberFields],
4381 rowNames[i],
4382 outputRow[numberFields]);
4383 if (i == nextRowString && nextColumnString >= numberColumns_) {
4384 strcpyeq(outputValue[0], nextString);
4385 decodeString(++whichString, nextRowString, nextColumnString, nextString);
4386 }
4387 numberFields++;
4388 if (numberFields == numberAcross) {
4389 // put out card
4390 outputCard(formatType, numberFields,
4391 output, " ",
4392 "RHS",
4393 outputValue,
4394 outputRow);
4395 numberFields = 0;
4396 }
4397 }
4398 }
4399 if (numberFields) {
4400 // put out card
4401 outputCard(formatType, numberFields,
4402 output, " ",
4403 "RHS",
4404 outputValue,
4405 outputRow);
4406 }
4407
4408 if (ifRange) {
4409 // RANGES
4410 writeString(output, "RANGES\n");
4411
4412 numberFields = 0;
4413 for (i = 0; i < numberRows_; i++) {
4414 if (sense[i] == 'R') {
4415 double value = rowUpper[i] - rowLower[i];
4416 if (value < 1.0e30) {
4417 convertDouble(1, formatType, value,
4418 outputValue[numberFields],
4419 rowNames[i],
4420 outputRow[numberFields]);
4421 numberFields++;
4422 if (numberFields == numberAcross) {
4423 // put out card
4424 outputCard(formatType, numberFields,
4425 output, " ",
4426 "RANGE",
4427 outputValue,
4428 outputRow);
4429 numberFields = 0;
4430 }
4431 }
4432 }
4433 }
4434 if (numberFields) {
4435 // put out card
4436 outputCard(formatType, numberFields,
4437 output, " ",
4438 "RANGE",
4439 outputValue,
4440 outputRow);
4441 }
4442 }
4443 delete[] sense;
4444 if (ifBounds) {
4445 // BOUNDS
4446 writeString(output, "BOUNDS\n");
4447
4448 for (i = 0; i < numberColumns_; i++) {
4449 if (i == nextColumnString) {
4450 // just lo and up
4451 if (columnLower[i] == STRING_VALUE) {
4452 assert(nextRowString == numberRows_ + 1);
4453 convertDouble(2, formatType, 1.0,
4454 outputValue[0],
4455 columnNames[i],
4456 outputRow[0]);
4457 strcpyeq(outputValue[0], nextString);
4458 decodeString(++whichString, nextRowString, nextColumnString, nextString);
4459 if (i == nextColumnString) {
4460 assert(columnUpper[i] == STRING_VALUE);
4461 assert(nextRowString == numberRows_ + 2);
4462 if (!strcmp(nextString, outputValue[0])) {
4463 // put out card FX
4464 outputCard(formatType, 1,
4465 output, " FX ",
4466 "BOUND",
4467 outputValue,
4468 outputRow);
4469 } else {
4470 // put out card LO
4471 outputCard(formatType, 1,
4472 output, " LO ",
4473 "BOUND",
4474 outputValue,
4475 outputRow);
4476 // put out card UP
4477 strcpyeq(outputValue[0], nextString);
4478 outputCard(formatType, 1,
4479 output, " UP ",
4480 "BOUND",
4481 outputValue,
4482 outputRow);
4483 }
4484 decodeString(++whichString, nextRowString, nextColumnString, nextString);
4485 } else {
4486 // just LO
4487 // put out card LO
4488 outputCard(formatType, 1,
4489 output, " LO ",
4490 "BOUND",
4491 outputValue,
4492 outputRow);
4493 }
4494 } else if (columnUpper[i] == STRING_VALUE) {
4495 assert(nextRowString == numberRows_ + 2);
4496 convertDouble(2, formatType, 1.0,
4497 outputValue[0],
4498 columnNames[i],
4499 outputRow[0]);
4500 strcpyeq(outputValue[0], nextString);
4501 outputCard(formatType, 1,
4502 output, " UP ",
4503 "BOUND",
4504 outputValue,
4505 outputRow);
4506 decodeString(++whichString, nextRowString, nextColumnString, nextString);
4507 }
4508 continue;
4509 }
4510 if (objective[i] || lengths[i]) {
4511 // see if bound will be needed
4512 if (columnLower[i] || columnUpper[i] < largeValue || isInteger(i)) {
4513 double lowerValue = columnLower[i];
4514 double upperValue = columnUpper[i];
4515 if (isInteger(i)) {
4516 // Old argument - what are correct ranges for integer variables
4517 lowerValue = CoinMax(lowerValue, -MAX_INTEGER);
4518 upperValue = CoinMin(upperValue, MAX_INTEGER);
4519 }
4520 int numberFields = 1;
4521 std::string header[2];
4522 double value[2];
4523 if (lowerValue <= -largeValue) {
4524 // FR or MI
4525 if (upperValue >= largeValue && !isInteger(i)) {
4526 header[0] = " FR ";
4527 value[0] = largeValue;
4528 } else {
4529 header[0] = " MI ";
4530 value[0] = -largeValue;
4531 if (!isInteger(i))
4532 header[1] = " UP ";
4533 else
4534 header[1] = " UI ";
4535 if (upperValue < largeValue)
4536 value[1] = upperValue;
4537 else
4538 value[1] = largeValue;
4539 numberFields = 2;
4540 }
4541 } else if (fabs(upperValue - lowerValue) < 1.0e-8) {
4542 header[0] = " FX ";
4543 value[0] = lowerValue;
4544 } else {
4545 // do LO if needed
4546 if (lowerValue || isIntegerOrSemiContinuous(i) > 2) {
4547 // LO
4548 header[0] = " LO ";
4549 value[0] = lowerValue;
4550 if (isIntegerOrSemiContinuous(i) > 2) {
4551 if (lowerValue) {
4552 if (isIntegerOrSemiContinuous(i) == 4)
4553 header[0] = " LI ";
4554 numberFields = 2;
4555 }
4556 header[numberFields - 1] = " SC ";
4557 if (upperValue < largeValue)
4558 value[numberFields - 1] = upperValue;
4559 else
4560 value[numberFields - 1] = largeValue;
4561 } else if (isInteger(i)) {
4562 // Integer variable so UI
4563 header[1] = " UI ";
4564 if (upperValue < largeValue)
4565 value[1] = upperValue;
4566 else
4567 value[1] = largeValue;
4568 numberFields = 2;
4569 } else if (upperValue < largeValue) {
4570 // UP
4571 header[1] = " UP ";
4572 value[1] = upperValue;
4573 numberFields = 2;
4574 }
4575 } else {
4576 if (isInteger(i)) {
4577 // Integer variable so BV or UI
4578 if (fabs(upperValue - 1.0) < 1.0e-8) {
4579 // BV
4580 header[0] = " BV ";
4581 value[0] = 1.0;
4582 } else {
4583 // UI
4584 header[0] = " UI ";
4585 if (upperValue < largeValue)
4586 value[0] = upperValue;
4587 else
4588 value[0] = largeValue;
4589 }
4590 } else {
4591 // UP
4592 header[0] = " UP ";
4593 value[0] = upperValue;
4594 }
4595 }
4596 }
4597 // put out fields
4598 int j;
4599 for (j = 0; j < numberFields; j++) {
4600 convertDouble(2, formatType, value[j],
4601 outputValue[0],
4602 columnNames[i],
4603 outputRow[0]);
4604 // put out card
4605 outputCard(formatType, 1,
4606 output, header[j],
4607 "BOUND",
4608 outputValue,
4609 outputRow);
4610 }
4611 }
4612 }
4613 }
4614 }
4615
4616 // do any quadratic part
4617 if (quadratic) {
4618
4619 writeString(output, "QUADOBJ\n");
4620
4621 const int *columnQuadratic = quadratic->getIndices();
4622 const CoinBigIndex *columnQuadraticStart = quadratic->getVectorStarts();
4623 const int *columnQuadraticLength = quadratic->getVectorLengths();
4624 const double *quadraticElement = quadratic->getElements();
4625 for (int iColumn = 0; iColumn < numberColumns_; iColumn++) {
4626 int numberFields = 0;
4627 for (CoinBigIndex j = columnQuadraticStart[iColumn];
4628 j < columnQuadraticStart[iColumn] + columnQuadraticLength[iColumn]; j++) {
4629 int jColumn = columnQuadratic[j];
4630 double elementValue = quadraticElement[j];
4631 convertDouble(0, formatType, elementValue,
4632 outputValue[numberFields],
4633 columnNames[jColumn],
4634 outputRow[numberFields]);
4635 numberFields++;
4636 if (numberFields == numberAcross) {
4637 // put out card
4638 outputCard(formatType, numberFields,
4639 output, " ",
4640 columnNames[iColumn],
4641 outputValue,
4642 outputRow);
4643 numberFields = 0;
4644 }
4645 }
4646 if (numberFields) {
4647 // put out card
4648 outputCard(formatType, numberFields,
4649 output, " ",
4650 columnNames[iColumn],
4651 outputValue,
4652 outputRow);
4653 }
4654 }
4655 }
4656 // SOS
4657 if (numberSOS) {
4658 writeString(output, "SOS\n");
4659 for (int i = 0; i < numberSOS; i++) {
4660 int type = setInfo[i].setType();
4661 writeString(output, (type == 1) ? " S1\n" : " S2\n");
4662 int n = setInfo[i].numberEntries();
4663 const int *which = setInfo[i].which();
4664 const double *weights = setInfo[i].weights();
4665
4666 for (int j = 0; j < n; j++) {
4667 int k = which[j];
4668 convertDouble(2, formatType,
4669 weights ? weights[j] : COIN_DBL_MAX, outputValue[0],
4670 "", outputRow[0]);
4671 // put out card
4672 outputCard(formatType, 1,
4673 output, " ",
4674 columnNames[k],
4675 outputValue, outputRow);
4676 }
4677 }
4678 }
4679
4680 // and finish
4681
4682 writeString(output, "ENDATA\n");
4683
4684 free(objrow);
4685
4686 delete output;
4687 setlocale(LC_ALL, saveLocale);
4688 free(saveLocale);
4689 return 0;
4690 }
4691
4692 //------------------------------------------------------------------
4693 // Problem name
getProblemName() const4694 const char *CoinMpsIO::getProblemName() const
4695 {
4696 return problemName_;
4697 }
4698 // Objective name
getObjectiveName() const4699 const char *CoinMpsIO::getObjectiveName() const
4700 {
4701 return objectiveName_;
4702 }
4703 // Rhs name
getRhsName() const4704 const char *CoinMpsIO::getRhsName() const
4705 {
4706 return rhsName_;
4707 }
4708 // Range name
getRangeName() const4709 const char *CoinMpsIO::getRangeName() const
4710 {
4711 return rangeName_;
4712 }
4713 // Bound name
getBoundName() const4714 const char *CoinMpsIO::getBoundName() const
4715 {
4716 return boundName_;
4717 }
4718
4719 //------------------------------------------------------------------
4720 // Get number of rows, columns and elements
4721 //------------------------------------------------------------------
getNumCols() const4722 int CoinMpsIO::getNumCols() const
4723 {
4724 return numberColumns_;
4725 }
getNumRows() const4726 int CoinMpsIO::getNumRows() const
4727 {
4728 return numberRows_;
4729 }
getNumElements() const4730 CoinBigIndex CoinMpsIO::getNumElements() const
4731 {
4732 return numberElements_;
4733 }
4734
4735 //------------------------------------------------------------------
4736 // Get pointer to column lower and upper bounds.
4737 //------------------------------------------------------------------
getColLower() const4738 const double *CoinMpsIO::getColLower() const
4739 {
4740 return collower_;
4741 }
getColUpper() const4742 const double *CoinMpsIO::getColUpper() const
4743 {
4744 return colupper_;
4745 }
4746
4747 //------------------------------------------------------------------
4748 // Get pointer to row lower and upper bounds.
4749 //------------------------------------------------------------------
getRowLower() const4750 const double *CoinMpsIO::getRowLower() const
4751 {
4752 return rowlower_;
4753 }
getRowUpper() const4754 const double *CoinMpsIO::getRowUpper() const
4755 {
4756 return rowupper_;
4757 }
4758
4759 /** A quick inlined function to convert from lb/ub style constraint
4760 definition to sense/rhs/range style */
4761 inline void
convertBoundToSense(const double lower,const double upper,char & sense,double & right,double & range) const4762 CoinMpsIO::convertBoundToSense(const double lower, const double upper,
4763 char &sense, double &right,
4764 double &range) const
4765 {
4766 range = 0.0;
4767 if (lower > -infinity_) {
4768 if (upper < infinity_) {
4769 right = upper;
4770 if (upper == lower) {
4771 sense = 'E';
4772 } else {
4773 sense = 'R';
4774 range = upper - lower;
4775 }
4776 } else {
4777 sense = 'G';
4778 right = lower;
4779 }
4780 } else {
4781 if (upper < infinity_) {
4782 sense = 'L';
4783 right = upper;
4784 } else {
4785 sense = 'N';
4786 right = 0.0;
4787 }
4788 }
4789 }
4790
4791 //-----------------------------------------------------------------------------
4792 /** A quick inlined function to convert from sense/rhs/range stryle constraint
4793 definition to lb/ub style */
4794 inline void
convertSenseToBound(const char sense,const double right,const double range,double & lower,double & upper) const4795 CoinMpsIO::convertSenseToBound(const char sense, const double right,
4796 const double range,
4797 double &lower, double &upper) const
4798 {
4799 switch (sense) {
4800 case 'E':
4801 lower = upper = right;
4802 break;
4803 case 'L':
4804 lower = -infinity_;
4805 upper = right;
4806 break;
4807 case 'G':
4808 lower = right;
4809 upper = infinity_;
4810 break;
4811 case 'R':
4812 lower = right - range;
4813 upper = right;
4814 break;
4815 case 'N':
4816 lower = -infinity_;
4817 upper = infinity_;
4818 break;
4819 }
4820 }
4821 //------------------------------------------------------------------
4822 // Get sense of row constraints.
4823 //------------------------------------------------------------------
getRowSense() const4824 const char *CoinMpsIO::getRowSense() const
4825 {
4826 if (rowsense_ == NULL) {
4827
4828 int nr = numberRows_;
4829 rowsense_ = reinterpret_cast< char * >(malloc(nr * sizeof(char)));
4830
4831 double dum1, dum2;
4832 int i;
4833 for (i = 0; i < nr; i++) {
4834 convertBoundToSense(rowlower_[i], rowupper_[i], rowsense_[i], dum1, dum2);
4835 }
4836 }
4837 return rowsense_;
4838 }
4839
4840 //------------------------------------------------------------------
4841 // Get the rhs of rows.
4842 //------------------------------------------------------------------
getRightHandSide() const4843 const double *CoinMpsIO::getRightHandSide() const
4844 {
4845 if (rhs_ == NULL) {
4846
4847 int nr = numberRows_;
4848 rhs_ = reinterpret_cast< double * >(malloc(nr * sizeof(double)));
4849
4850 char dum1;
4851 double dum2;
4852 int i;
4853 for (i = 0; i < nr; i++) {
4854 convertBoundToSense(rowlower_[i], rowupper_[i], dum1, rhs_[i], dum2);
4855 }
4856 }
4857 return rhs_;
4858 }
4859
4860 //------------------------------------------------------------------
4861 // Get the range of rows.
4862 // Length of returned vector is getNumRows();
4863 //------------------------------------------------------------------
getRowRange() const4864 const double *CoinMpsIO::getRowRange() const
4865 {
4866 if (rowrange_ == NULL) {
4867
4868 int nr = numberRows_;
4869 rowrange_ = reinterpret_cast< double * >(malloc(nr * sizeof(double)));
4870 std::fill(rowrange_, rowrange_ + nr, 0.0);
4871
4872 char dum1;
4873 double dum2;
4874 int i;
4875 for (i = 0; i < nr; i++) {
4876 convertBoundToSense(rowlower_[i], rowupper_[i], dum1, dum2, rowrange_[i]);
4877 }
4878 }
4879 return rowrange_;
4880 }
4881
getObjCoefficients() const4882 const double *CoinMpsIO::getObjCoefficients() const
4883 {
4884 return objective_;
4885 }
4886
4887 //------------------------------------------------------------------
4888 // Create a row copy of the matrix ...
4889 //------------------------------------------------------------------
getMatrixByRow() const4890 const CoinPackedMatrix *CoinMpsIO::getMatrixByRow() const
4891 {
4892 if (matrixByRow_ == NULL && matrixByColumn_) {
4893 matrixByRow_ = new CoinPackedMatrix(*matrixByColumn_);
4894 matrixByRow_->reverseOrdering();
4895 }
4896 return matrixByRow_;
4897 }
4898
4899 //------------------------------------------------------------------
4900 // Create a column copy of the matrix ...
4901 //------------------------------------------------------------------
getMatrixByCol() const4902 const CoinPackedMatrix *CoinMpsIO::getMatrixByCol() const
4903 {
4904 return matrixByColumn_;
4905 }
4906
4907 //------------------------------------------------------------------
4908 // Save the data ...
4909 //------------------------------------------------------------------
setMpsDataWithoutRowAndColNames(const CoinPackedMatrix & m,const double infinity,const double * collb,const double * colub,const double * obj,const char * integrality,const double * rowlb,const double * rowub)4910 void CoinMpsIO::setMpsDataWithoutRowAndColNames(
4911 const CoinPackedMatrix &m, const double infinity,
4912 const double *collb, const double *colub,
4913 const double *obj, const char *integrality,
4914 const double *rowlb, const double *rowub)
4915 {
4916 freeAll();
4917 if (m.isColOrdered()) {
4918 matrixByColumn_ = new CoinPackedMatrix(m);
4919 } else {
4920 matrixByColumn_ = new CoinPackedMatrix;
4921 matrixByColumn_->reverseOrderedCopyOf(m);
4922 }
4923 numberColumns_ = matrixByColumn_->getNumCols();
4924 numberRows_ = matrixByColumn_->getNumRows();
4925 numberElements_ = matrixByColumn_->getNumElements();
4926 defaultBound_ = 1;
4927 infinity_ = infinity;
4928 objectiveOffset_ = 0;
4929
4930 rowlower_ = reinterpret_cast< double * >(malloc(numberRows_ * sizeof(double)));
4931 rowupper_ = reinterpret_cast< double * >(malloc(numberRows_ * sizeof(double)));
4932 collower_ = reinterpret_cast< double * >(malloc(numberColumns_ * sizeof(double)));
4933 colupper_ = reinterpret_cast< double * >(malloc(numberColumns_ * sizeof(double)));
4934 objective_ = reinterpret_cast< double * >(malloc(numberColumns_ * sizeof(double)));
4935 std::copy(rowlb, rowlb + numberRows_, rowlower_);
4936 std::copy(rowub, rowub + numberRows_, rowupper_);
4937 std::copy(collb, collb + numberColumns_, collower_);
4938 std::copy(colub, colub + numberColumns_, colupper_);
4939 std::copy(obj, obj + numberColumns_, objective_);
4940 if (integrality) {
4941 integerType_ = reinterpret_cast< char * >(malloc(numberColumns_ * sizeof(char)));
4942 std::copy(integrality, integrality + numberColumns_, integerType_);
4943 } else {
4944 integerType_ = NULL;
4945 }
4946
4947 problemName_ = CoinStrdup("");
4948 objectiveName_ = CoinStrdup("");
4949 rhsName_ = CoinStrdup("");
4950 rangeName_ = CoinStrdup("");
4951 boundName_ = CoinStrdup("");
4952 }
4953
setMpsDataColAndRowNames(char const * const * const colnames,char const * const * const rownames)4954 void CoinMpsIO::setMpsDataColAndRowNames(
4955 char const *const *const colnames,
4956 char const *const *const rownames)
4957 {
4958 releaseRowNames();
4959 releaseColumnNames();
4960 // If long names free format
4961 names_[0] = reinterpret_cast< char ** >(malloc(numberRows_ * sizeof(char *)));
4962 names_[1] = reinterpret_cast< char ** >(malloc(numberColumns_ * sizeof(char *)));
4963 numberHash_[0] = numberRows_;
4964 numberHash_[1] = numberColumns_;
4965 char **rowNames = names_[0];
4966 char **columnNames = names_[1];
4967 int i;
4968 // so we can adjust for long names
4969 int lengthMalloc = 9;
4970 int maxIndex = 10000000;
4971 if (rownames) {
4972 for (i = 0; i < numberRows_; ++i) {
4973 if (i == maxIndex) {
4974 lengthMalloc++;
4975 maxIndex *= 10;
4976 }
4977 if (rownames[i]) {
4978 rowNames[i] = CoinStrdup(rownames[i]);
4979 } else {
4980 rowNames[i] = reinterpret_cast< char * >(malloc(lengthMalloc * sizeof(char)));
4981 sprintf(rowNames[i], "R%7.7d", i);
4982 }
4983 }
4984 } else {
4985 for (i = 0; i < numberRows_; ++i) {
4986 if (i == maxIndex) {
4987 lengthMalloc++;
4988 maxIndex *= 10;
4989 }
4990 rowNames[i] = reinterpret_cast< char * >(malloc(lengthMalloc * sizeof(char)));
4991 sprintf(rowNames[i], "R%7.7d", i);
4992 }
4993 }
4994 #ifndef NONAMES
4995 lengthMalloc = 9;
4996 maxIndex = 10000000;
4997 if (colnames) {
4998 for (i = 0; i < numberColumns_; ++i) {
4999 if (i == maxIndex) {
5000 lengthMalloc++;
5001 maxIndex *= 10;
5002 }
5003 if (colnames[i]) {
5004 columnNames[i] = CoinStrdup(colnames[i]);
5005 } else {
5006 columnNames[i] = reinterpret_cast< char * >(malloc(lengthMalloc * sizeof(char)));
5007 sprintf(columnNames[i], "C%7.7d", i);
5008 }
5009 }
5010 } else {
5011 for (i = 0; i < numberColumns_; ++i) {
5012 if (i == maxIndex) {
5013 lengthMalloc++;
5014 maxIndex *= 10;
5015 }
5016 columnNames[i] = reinterpret_cast< char * >(malloc(lengthMalloc * sizeof(char)));
5017 sprintf(columnNames[i], "C%7.7d", i);
5018 }
5019 }
5020 #else
5021 const double *objective = getObjCoefficients();
5022 const CoinPackedMatrix *matrix = getMatrixByCol();
5023 const int *lengths = matrix->getVectorLengths();
5024 int k = 0;
5025 for (i = 0; i < numberColumns_; ++i) {
5026 columnNames[i] = reinterpret_cast< char * >(malloc(9 * sizeof(char)));
5027 sprintf(columnNames[i], "C%7.7d", k);
5028 if (objective[i] || lengths[i])
5029 k++;
5030 }
5031 #endif
5032 }
5033
setMpsDataColAndRowNames(const std::vector<std::string> & colnames,const std::vector<std::string> & rownames)5034 void CoinMpsIO::setMpsDataColAndRowNames(
5035 const std::vector< std::string > &colnames,
5036 const std::vector< std::string > &rownames)
5037 {
5038 // If long names free format
5039 names_[0] = reinterpret_cast< char ** >(malloc(numberRows_ * sizeof(char *)));
5040 names_[1] = reinterpret_cast< char ** >(malloc(numberColumns_ * sizeof(char *)));
5041 char **rowNames = names_[0];
5042 char **columnNames = names_[1];
5043 int i;
5044 if (rownames.size() != 0) {
5045 for (i = 0; i < numberRows_; ++i) {
5046 rowNames[i] = CoinStrdup(rownames[i].c_str());
5047 }
5048 } else {
5049 // so we can adjust for long names
5050 int lengthMalloc = 9;
5051 int maxIndex = 10000000;
5052 for (i = 0; i < numberRows_; ++i) {
5053 if (i == maxIndex) {
5054 lengthMalloc++;
5055 maxIndex *= 10;
5056 }
5057 rowNames[i] = reinterpret_cast< char * >(malloc(lengthMalloc * sizeof(char)));
5058 sprintf(rowNames[i], "R%7.7d", i);
5059 }
5060 }
5061 if (colnames.size() != 0) {
5062 for (i = 0; i < numberColumns_; ++i) {
5063 columnNames[i] = CoinStrdup(colnames[i].c_str());
5064 }
5065 } else {
5066 // so we can adjust for long names
5067 int lengthMalloc = 9;
5068 int maxIndex = 10000000;
5069 for (i = 0; i < numberColumns_; ++i) {
5070 if (i == maxIndex) {
5071 lengthMalloc++;
5072 maxIndex *= 10;
5073 }
5074 columnNames[i] = reinterpret_cast< char * >(malloc(lengthMalloc * sizeof(char)));
5075 sprintf(columnNames[i], "C%7.7d", i);
5076 }
5077 }
5078 }
5079
setMpsData(const CoinPackedMatrix & m,const double infinity,const double * collb,const double * colub,const double * obj,const char * integrality,const double * rowlb,const double * rowub,char const * const * const colnames,char const * const * const rownames)5080 void CoinMpsIO::setMpsData(const CoinPackedMatrix &m, const double infinity,
5081 const double *collb, const double *colub,
5082 const double *obj, const char *integrality,
5083 const double *rowlb, const double *rowub,
5084 char const *const *const colnames,
5085 char const *const *const rownames)
5086 {
5087 setMpsDataWithoutRowAndColNames(m, infinity, collb, colub, obj, integrality, rowlb, rowub);
5088 setMpsDataColAndRowNames(colnames, rownames);
5089 }
5090
setMpsData(const CoinPackedMatrix & m,const double infinity,const double * collb,const double * colub,const double * obj,const char * integrality,const double * rowlb,const double * rowub,const std::vector<std::string> & colnames,const std::vector<std::string> & rownames)5091 void CoinMpsIO::setMpsData(const CoinPackedMatrix &m, const double infinity,
5092 const double *collb, const double *colub,
5093 const double *obj, const char *integrality,
5094 const double *rowlb, const double *rowub,
5095 const std::vector< std::string > &colnames,
5096 const std::vector< std::string > &rownames)
5097 {
5098 setMpsDataWithoutRowAndColNames(m, infinity, collb, colub, obj, integrality, rowlb, rowub);
5099 setMpsDataColAndRowNames(colnames, rownames);
5100 }
5101
setMpsData(const CoinPackedMatrix & m,const double infinity,const double * collb,const double * colub,const double * obj,const char * integrality,const char * rowsen,const double * rowrhs,const double * rowrng,char const * const * const colnames,char const * const * const rownames)5102 void CoinMpsIO::setMpsData(const CoinPackedMatrix &m, const double infinity,
5103 const double *collb, const double *colub,
5104 const double *obj, const char *integrality,
5105 const char *rowsen, const double *rowrhs,
5106 const double *rowrng,
5107 char const *const *const colnames,
5108 char const *const *const rownames)
5109 {
5110 const int numrows = m.getNumRows();
5111
5112 double *rlb = numrows ? new double[numrows] : 0;
5113 double *rub = numrows ? new double[numrows] : 0;
5114
5115 for (int i = 0; i < numrows; ++i) {
5116 convertSenseToBound(rowsen[i], rowrhs[i], rowrng[i], rlb[i], rub[i]);
5117 }
5118 setMpsData(m, infinity, collb, colub, obj, integrality, rlb, rub,
5119 colnames, rownames);
5120 delete[] rlb;
5121 delete[] rub;
5122 }
5123
setMpsData(const CoinPackedMatrix & m,const double infinity,const double * collb,const double * colub,const double * obj,const char * integrality,const char * rowsen,const double * rowrhs,const double * rowrng,const std::vector<std::string> & colnames,const std::vector<std::string> & rownames)5124 void CoinMpsIO::setMpsData(const CoinPackedMatrix &m, const double infinity,
5125 const double *collb, const double *colub,
5126 const double *obj, const char *integrality,
5127 const char *rowsen, const double *rowrhs,
5128 const double *rowrng,
5129 const std::vector< std::string > &colnames,
5130 const std::vector< std::string > &rownames)
5131 {
5132 const int numrows = m.getNumRows();
5133
5134 double *rlb = numrows ? new double[numrows] : 0;
5135 double *rub = numrows ? new double[numrows] : 0;
5136
5137 for (int i = 0; i < numrows; ++i) {
5138 convertSenseToBound(rowsen[i], rowrhs[i], rowrng[i], rlb[i], rub[i]);
5139 }
5140 setMpsData(m, infinity, collb, colub, obj, integrality, rlb, rub,
5141 colnames, rownames);
5142 delete[] rlb;
5143 delete[] rub;
5144 }
5145
setProblemName(const char * name)5146 void CoinMpsIO::setProblemName(const char *name)
5147 {
5148 free(problemName_);
5149 problemName_ = CoinStrdup(name);
5150 }
5151
setObjectiveName(const char * name)5152 void CoinMpsIO::setObjectiveName(const char *name)
5153 {
5154 free(objectiveName_);
5155 objectiveName_ = CoinStrdup(name);
5156 }
5157
5158 //------------------------------------------------------------------
5159 // Return true if column is a continuous, binary, ...
5160 //------------------------------------------------------------------
isContinuous(int columnNumber) const5161 bool CoinMpsIO::isContinuous(int columnNumber) const
5162 {
5163 const char *intType = integerType_;
5164 if (intType == NULL)
5165 return true;
5166 assert(columnNumber >= 0 && columnNumber < numberColumns_);
5167 if (intType[columnNumber] == 0)
5168 return true;
5169 return false;
5170 }
5171
5172 /* Return true if column is integer.
5173 Note: This function returns true if the the column
5174 is binary or a general integer.
5175 */
isInteger(int columnNumber) const5176 bool CoinMpsIO::isInteger(int columnNumber) const
5177 {
5178 const char *intType = integerType_;
5179 if (intType == NULL)
5180 return false;
5181 assert(columnNumber >= 0 && columnNumber < numberColumns_);
5182 if (intType[columnNumber] != 0)
5183 return true;
5184 return false;
5185 }
5186 /* Return 1 if column is integer, 2 if optional,
5187 3 if semi-continuous, 4 if semi-continous integer.
5188 Note: This function returns 1 if the column
5189 is binary or a general integer.
5190 */
isIntegerOrSemiContinuous(int columnNumber) const5191 int CoinMpsIO::isIntegerOrSemiContinuous(int columnNumber) const
5192 {
5193 const char *intType = integerType_;
5194 if (intType == NULL)
5195 return false;
5196 assert(columnNumber >= 0 && columnNumber < numberColumns_);
5197 return intType[columnNumber];
5198 }
5199 // if integer
integerColumns() const5200 const char *CoinMpsIO::integerColumns() const
5201 {
5202 return integerType_;
5203 }
5204 // Pass in array saying if each variable integer
copyInIntegerInformation(const char * integerType)5205 void CoinMpsIO::copyInIntegerInformation(const char *integerType)
5206 {
5207 if (integerType) {
5208 if (!integerType_)
5209 integerType_ = reinterpret_cast< char * >(malloc(numberColumns_ * sizeof(char)));
5210 memcpy(integerType_, integerType, numberColumns_);
5211 } else {
5212 free(integerType_);
5213 integerType_ = NULL;
5214 }
5215 }
5216 // names - returns NULL if out of range
rowName(int index) const5217 const char *CoinMpsIO::rowName(int index) const
5218 {
5219 if (index >= 0 && index < numberRows_) {
5220 return names_[0][index];
5221 } else {
5222 return NULL;
5223 }
5224 }
columnName(int index) const5225 const char *CoinMpsIO::columnName(int index) const
5226 {
5227 if (index >= 0 && index < numberColumns_) {
5228 return names_[1][index];
5229 } else {
5230 return NULL;
5231 }
5232 }
5233 // names - returns -1 if name not found
rowIndex(const char * name) const5234 int CoinMpsIO::rowIndex(const char *name) const
5235 {
5236 if (!hash_[0]) {
5237 if (numberRows_) {
5238 startHash(0);
5239 } else {
5240 return -1;
5241 }
5242 }
5243 return findHash(name, 0);
5244 }
columnIndex(const char * name) const5245 int CoinMpsIO::columnIndex(const char *name) const
5246 {
5247 if (!hash_[1]) {
5248 if (numberColumns_) {
5249 startHash(1);
5250 } else {
5251 return -1;
5252 }
5253 }
5254 return findHash(name, 1);
5255 }
5256
5257 // Release all row information (lower, upper)
releaseRowInformation()5258 void CoinMpsIO::releaseRowInformation()
5259 {
5260 free(rowlower_);
5261 free(rowupper_);
5262 rowlower_ = NULL;
5263 rowupper_ = NULL;
5264 }
5265 // Release all column information (lower, upper, objective)
releaseColumnInformation()5266 void CoinMpsIO::releaseColumnInformation()
5267 {
5268 free(collower_);
5269 free(colupper_);
5270 free(objective_);
5271 collower_ = NULL;
5272 colupper_ = NULL;
5273 objective_ = NULL;
5274 }
5275 // Release integer information
releaseIntegerInformation()5276 void CoinMpsIO::releaseIntegerInformation()
5277 {
5278 free(integerType_);
5279 integerType_ = NULL;
5280 }
5281 // Release row names
releaseRowNames()5282 void CoinMpsIO::releaseRowNames()
5283 {
5284 releaseRedundantInformation();
5285 int i;
5286 for (i = 0; i < numberHash_[0]; i++) {
5287 free(names_[0][i]);
5288 }
5289 free(names_[0]);
5290 names_[0] = NULL;
5291 numberHash_[0] = 0;
5292 }
5293 // Release column names
releaseColumnNames()5294 void CoinMpsIO::releaseColumnNames()
5295 {
5296 releaseRedundantInformation();
5297 int i;
5298 for (i = 0; i < numberHash_[1]; i++) {
5299 free(names_[1][i]);
5300 }
5301 free(names_[1]);
5302 names_[1] = NULL;
5303 numberHash_[1] = 0;
5304 }
5305 // Release matrix information
releaseMatrixInformation()5306 void CoinMpsIO::releaseMatrixInformation()
5307 {
5308 releaseRedundantInformation();
5309 delete matrixByColumn_;
5310 matrixByColumn_ = NULL;
5311 }
5312
5313 //-------------------------------------------------------------------
5314 // Default Constructor
5315 //-------------------------------------------------------------------
CoinMpsIO()5316 CoinMpsIO::CoinMpsIO()
5317 : problemName_(CoinStrdup(""))
5318 , objectiveName_(CoinStrdup(""))
5319 , rhsName_(CoinStrdup(""))
5320 , rangeName_(CoinStrdup(""))
5321 , boundName_(CoinStrdup(""))
5322 , numberRows_(0)
5323 , numberColumns_(0)
5324 , numberElements_(0)
5325 , rowsense_(NULL)
5326 , rhs_(NULL)
5327 , rowrange_(NULL)
5328 , matrixByRow_(NULL)
5329 , matrixByColumn_(NULL)
5330 , rowlower_(NULL)
5331 , rowupper_(NULL)
5332 , collower_(NULL)
5333 , colupper_(NULL)
5334 , objective_(NULL)
5335 , objectiveOffset_(0.0)
5336 , integerType_(NULL)
5337 , fileName_(CoinStrdup("????"))
5338 , defaultBound_(1)
5339 , infinity_(COIN_DBL_MAX)
5340 , smallElement_(1.0e-14)
5341 , defaultHandler_(true)
5342 , cardReader_(NULL)
5343 , convertObjective_(false)
5344 , allowStringElements_(0)
5345 , maximumStringElements_(0)
5346 , numberStringElements_(0)
5347 , stringElements_(NULL)
5348 {
5349 numberHash_[0] = 0;
5350 hash_[0] = NULL;
5351 names_[0] = NULL;
5352 numberHash_[1] = 0;
5353 hash_[1] = NULL;
5354 names_[1] = NULL;
5355 handler_ = new CoinMessageHandler();
5356 messages_ = CoinMessage();
5357 }
5358
5359 //-------------------------------------------------------------------
5360 // Copy constructor
5361 //-------------------------------------------------------------------
CoinMpsIO(const CoinMpsIO & rhs)5362 CoinMpsIO::CoinMpsIO(const CoinMpsIO &rhs)
5363 : problemName_(CoinStrdup(""))
5364 , objectiveName_(CoinStrdup(""))
5365 , rhsName_(CoinStrdup(""))
5366 , rangeName_(CoinStrdup(""))
5367 , boundName_(CoinStrdup(""))
5368 , numberRows_(0)
5369 , numberColumns_(0)
5370 , numberElements_(0)
5371 , rowsense_(NULL)
5372 , rhs_(NULL)
5373 , rowrange_(NULL)
5374 , matrixByRow_(NULL)
5375 , matrixByColumn_(NULL)
5376 , rowlower_(NULL)
5377 , rowupper_(NULL)
5378 , collower_(NULL)
5379 , colupper_(NULL)
5380 , objective_(NULL)
5381 , objectiveOffset_(0.0)
5382 , integerType_(NULL)
5383 , fileName_(CoinStrdup("????"))
5384 , defaultBound_(1)
5385 , infinity_(COIN_DBL_MAX)
5386 , smallElement_(1.0e-14)
5387 , defaultHandler_(true)
5388 , cardReader_(NULL)
5389 , allowStringElements_(rhs.allowStringElements_)
5390 , maximumStringElements_(rhs.maximumStringElements_)
5391 , numberStringElements_(rhs.numberStringElements_)
5392 , stringElements_(NULL)
5393 {
5394 numberHash_[0] = 0;
5395 hash_[0] = NULL;
5396 names_[0] = NULL;
5397 numberHash_[1] = 0;
5398 hash_[1] = NULL;
5399 names_[1] = NULL;
5400 if (rhs.rowlower_ != NULL || rhs.collower_ != NULL) {
5401 gutsOfCopy(rhs);
5402 // OK and proper to leave rowsense_, rhs_, and
5403 // rowrange_ (also row copy and hash) to NULL. They will be constructed
5404 // if they are required.
5405 }
5406 defaultHandler_ = rhs.defaultHandler_;
5407 if (defaultHandler_)
5408 handler_ = new CoinMessageHandler(*rhs.handler_);
5409 else
5410 handler_ = rhs.handler_;
5411 messages_ = CoinMessage();
5412 }
5413
gutsOfCopy(const CoinMpsIO & rhs)5414 void CoinMpsIO::gutsOfCopy(const CoinMpsIO &rhs)
5415 {
5416 defaultHandler_ = rhs.defaultHandler_;
5417 if (rhs.matrixByColumn_)
5418 matrixByColumn_ = new CoinPackedMatrix(*(rhs.matrixByColumn_));
5419 numberElements_ = rhs.numberElements_;
5420 numberRows_ = rhs.numberRows_;
5421 numberColumns_ = rhs.numberColumns_;
5422 convertObjective_ = rhs.convertObjective_;
5423 if (rhs.rowlower_) {
5424 rowlower_ = reinterpret_cast< double * >(malloc(numberRows_ * sizeof(double)));
5425 rowupper_ = reinterpret_cast< double * >(malloc(numberRows_ * sizeof(double)));
5426 memcpy(rowlower_, rhs.rowlower_, numberRows_ * sizeof(double));
5427 memcpy(rowupper_, rhs.rowupper_, numberRows_ * sizeof(double));
5428 }
5429 if (rhs.collower_) {
5430 collower_ = reinterpret_cast< double * >(malloc(numberColumns_ * sizeof(double)));
5431 colupper_ = reinterpret_cast< double * >(malloc(numberColumns_ * sizeof(double)));
5432 objective_ = reinterpret_cast< double * >(malloc(numberColumns_ * sizeof(double)));
5433 memcpy(collower_, rhs.collower_, numberColumns_ * sizeof(double));
5434 memcpy(colupper_, rhs.colupper_, numberColumns_ * sizeof(double));
5435 memcpy(objective_, rhs.objective_, numberColumns_ * sizeof(double));
5436 }
5437 if (rhs.integerType_) {
5438 integerType_ = reinterpret_cast< char * >(malloc(numberColumns_ * sizeof(char)));
5439 memcpy(integerType_, rhs.integerType_, numberColumns_ * sizeof(char));
5440 }
5441 free(fileName_);
5442 free(problemName_);
5443 free(objectiveName_);
5444 free(rhsName_);
5445 free(rangeName_);
5446 free(boundName_);
5447 fileName_ = CoinStrdup(rhs.fileName_);
5448 problemName_ = CoinStrdup(rhs.problemName_);
5449 objectiveName_ = CoinStrdup(rhs.objectiveName_);
5450 rhsName_ = CoinStrdup(rhs.rhsName_);
5451 rangeName_ = CoinStrdup(rhs.rangeName_);
5452 boundName_ = CoinStrdup(rhs.boundName_);
5453 numberHash_[0] = rhs.numberHash_[0];
5454 numberHash_[1] = rhs.numberHash_[1];
5455 defaultBound_ = rhs.defaultBound_;
5456 infinity_ = rhs.infinity_;
5457 smallElement_ = rhs.smallElement_;
5458 objectiveOffset_ = rhs.objectiveOffset_;
5459 int section;
5460 for (section = 0; section < 2; section++) {
5461 if (numberHash_[section]) {
5462 char **names2 = rhs.names_[section];
5463 names_[section] = reinterpret_cast< char ** >(malloc(numberHash_[section] * sizeof(char *)));
5464 char **names = names_[section];
5465 int i;
5466 for (i = 0; i < numberHash_[section]; i++) {
5467 names[i] = CoinStrdup(names2[i]);
5468 }
5469 }
5470 }
5471 allowStringElements_ = rhs.allowStringElements_;
5472 maximumStringElements_ = rhs.maximumStringElements_;
5473 numberStringElements_ = rhs.numberStringElements_;
5474 if (numberStringElements_) {
5475 stringElements_ = new char *[maximumStringElements_];
5476 for (int i = 0; i < numberStringElements_; i++)
5477 stringElements_[i] = CoinStrdup(rhs.stringElements_[i]);
5478 } else {
5479 stringElements_ = NULL;
5480 }
5481 }
5482
5483 //-------------------------------------------------------------------
5484 // Destructor
5485 //-------------------------------------------------------------------
~CoinMpsIO()5486 CoinMpsIO::~CoinMpsIO()
5487 {
5488 gutsOfDestructor();
5489 }
5490
5491 //----------------------------------------------------------------
5492 // Assignment operator
5493 //-------------------------------------------------------------------
5494 CoinMpsIO &
operator =(const CoinMpsIO & rhs)5495 CoinMpsIO::operator=(const CoinMpsIO &rhs)
5496 {
5497 if (this != &rhs) {
5498 gutsOfDestructor();
5499 if (rhs.rowlower_ != NULL || rhs.collower_ != NULL) {
5500 gutsOfCopy(rhs);
5501 }
5502 defaultHandler_ = rhs.defaultHandler_;
5503 if (defaultHandler_)
5504 handler_ = new CoinMessageHandler(*rhs.handler_);
5505 else
5506 handler_ = rhs.handler_;
5507 messages_ = CoinMessage();
5508 }
5509 return *this;
5510 }
5511
5512 //-------------------------------------------------------------------
gutsOfDestructor()5513 void CoinMpsIO::gutsOfDestructor()
5514 {
5515 freeAll();
5516 if (defaultHandler_) {
5517 delete handler_;
5518 handler_ = NULL;
5519 }
5520 delete cardReader_;
5521 cardReader_ = NULL;
5522 }
5523
freeAll()5524 void CoinMpsIO::freeAll()
5525 {
5526 releaseRedundantInformation();
5527 releaseRowNames();
5528 releaseColumnNames();
5529 delete matrixByRow_;
5530 delete matrixByColumn_;
5531 matrixByRow_ = NULL;
5532 matrixByColumn_ = NULL;
5533 free(rowlower_);
5534 free(rowupper_);
5535 free(collower_);
5536 free(colupper_);
5537 free(objective_);
5538 free(integerType_);
5539 free(fileName_);
5540 rowlower_ = NULL;
5541 rowupper_ = NULL;
5542 collower_ = NULL;
5543 colupper_ = NULL;
5544 objective_ = NULL;
5545 integerType_ = NULL;
5546 fileName_ = NULL;
5547 free(problemName_);
5548 free(objectiveName_);
5549 free(rhsName_);
5550 free(rangeName_);
5551 free(boundName_);
5552 problemName_ = NULL;
5553 objectiveName_ = NULL;
5554 rhsName_ = NULL;
5555 rangeName_ = NULL;
5556 boundName_ = NULL;
5557 for (int i = 0; i < numberStringElements_; i++)
5558 free(stringElements_[i]);
5559 delete[] stringElements_;
5560 }
5561
5562 /* Release all information which can be re-calculated e.g. rowsense
5563 also any row copies OR hash tables for names */
releaseRedundantInformation()5564 void CoinMpsIO::releaseRedundantInformation()
5565 {
5566 free(rowsense_);
5567 free(rhs_);
5568 free(rowrange_);
5569 rowsense_ = NULL;
5570 rhs_ = NULL;
5571 rowrange_ = NULL;
5572 delete[] hash_[0];
5573 delete[] hash_[1];
5574 hash_[0] = 0;
5575 hash_[1] = 0;
5576 delete matrixByRow_;
5577 matrixByRow_ = NULL;
5578 }
5579 // Pass in Message handler (not deleted at end)
passInMessageHandler(CoinMessageHandler * handler)5580 void CoinMpsIO::passInMessageHandler(CoinMessageHandler *handler)
5581 {
5582 if (defaultHandler_)
5583 delete handler_;
5584 defaultHandler_ = false;
5585 handler_ = handler;
5586 }
5587 // Set language
newLanguage(CoinMessages::Language language)5588 void CoinMpsIO::newLanguage(CoinMessages::Language language)
5589 {
5590 messages_ = CoinMessage(language);
5591 }
5592
5593 /* Read in a quadratic objective from the given filename.
5594 If filename is NULL then continues reading from previous file. If
5595 not then the previous file is closed.
5596
5597 No assumption is made on symmetry, positive definite etc.
5598 No check is made for duplicates or non-triangular
5599
5600 Returns number of errors
5601 */
readQuadraticMps(const char * filename,CoinBigIndex * & columnStart,int * & column2,double * & elements,int checkSymmetry)5602 int CoinMpsIO::readQuadraticMps(const char *filename,
5603 CoinBigIndex *&columnStart, int *&column2, double *&elements,
5604 int checkSymmetry)
5605 {
5606 // Deal with filename - +1 if new, 0 if same as before, -1 if error
5607 CoinFileInput *input = 0;
5608 int returnCode = dealWithFileName(filename, "", input);
5609 if (returnCode < 0) {
5610 return -1;
5611 } else if (returnCode > 0) {
5612 delete cardReader_;
5613 cardReader_ = new CoinMpsCardReader(input, this);
5614 }
5615 // See if QUADOBJ just found
5616 if (!filename && cardReader_->whichSection() == COIN_QUAD_SECTION) {
5617 cardReader_->setWhichSection(COIN_QUAD_SECTION);
5618 } else if (cardReader_->whichSection() == COIN_CONIC_SECTION) {
5619 return -3;
5620 } else {
5621 cardReader_->readToNextSection();
5622
5623 // Skip NAME
5624 if (cardReader_->whichSection() == COIN_NAME_SECTION)
5625 cardReader_->readToNextSection();
5626 if (cardReader_->whichSection() == COIN_QUAD_SECTION) {
5627 // save name of section
5628 free(problemName_);
5629 problemName_ = CoinStrdup(cardReader_->columnName());
5630 } else if (cardReader_->whichSection() == COIN_EOF_SECTION) {
5631 handler_->message(COIN_MPS_EOF, messages_) << fileName_
5632 << CoinMessageEol;
5633 return -3;
5634 } else {
5635 handler_->message(COIN_MPS_BADFILE1, messages_) << cardReader_->card()
5636 << cardReader_->cardNumber()
5637 << fileName_
5638 << CoinMessageEol;
5639 return -2;
5640 }
5641 }
5642
5643 int numberErrors = 0;
5644
5645 // Guess at size of data
5646 int maximumNonZeros = 5 * numberColumns_;
5647 // Use malloc so can use realloc
5648 int *column = reinterpret_cast< int * >(malloc(maximumNonZeros * sizeof(int)));
5649 int *column2Temp = reinterpret_cast< int * >(malloc(maximumNonZeros * sizeof(int)));
5650 double *elementTemp = reinterpret_cast< double * >(malloc(maximumNonZeros * sizeof(double)));
5651
5652 startHash(1);
5653 int numberElements = 0;
5654
5655 while (cardReader_->nextField() == COIN_QUAD_SECTION) {
5656 switch (cardReader_->mpsType()) {
5657 case COIN_BLANK_COLUMN:
5658 if (fabs(cardReader_->value()) > smallElement_) {
5659 if (numberElements == maximumNonZeros) {
5660 maximumNonZeros = (3 * maximumNonZeros) / 2 + 1000;
5661 column = reinterpret_cast< COINColumnIndex * >(realloc(column, maximumNonZeros * sizeof(COINColumnIndex)));
5662 column2Temp = reinterpret_cast< COINColumnIndex * >(realloc(column2Temp, maximumNonZeros * sizeof(COINColumnIndex)));
5663 elementTemp = reinterpret_cast< double * >(realloc(elementTemp, maximumNonZeros * sizeof(double)));
5664 }
5665 // get indices
5666 COINColumnIndex iColumn1 = findHash(cardReader_->columnName(), 1);
5667 COINColumnIndex iColumn2 = findHash(cardReader_->rowName(), 1);
5668
5669 if (iColumn1 >= 0) {
5670 if (iColumn2 >= 0) {
5671 double value = cardReader_->value();
5672 column[numberElements] = iColumn1;
5673 column2Temp[numberElements] = iColumn2;
5674 elementTemp[numberElements++] = value;
5675 } else {
5676 numberErrors++;
5677 if (numberErrors < 100) {
5678 handler_->message(COIN_MPS_NOMATCHROW, messages_)
5679 << cardReader_->rowName() << cardReader_->cardNumber() << cardReader_->card()
5680 << CoinMessageEol;
5681 } else if (numberErrors > 100000) {
5682 handler_->message(COIN_MPS_RETURNING, messages_) << CoinMessageEol;
5683 return numberErrors;
5684 }
5685 }
5686 } else {
5687 numberErrors++;
5688 if (numberErrors < 100) {
5689 handler_->message(COIN_MPS_NOMATCHCOL, messages_)
5690 << cardReader_->columnName() << cardReader_->cardNumber() << cardReader_->card()
5691 << CoinMessageEol;
5692 } else if (numberErrors > 100000) {
5693 handler_->message(COIN_MPS_RETURNING, messages_) << CoinMessageEol;
5694 return numberErrors;
5695 }
5696 }
5697 }
5698 break;
5699 default:
5700 numberErrors++;
5701 if (numberErrors < 100) {
5702 handler_->message(COIN_MPS_BADIMAGE, messages_) << cardReader_->cardNumber()
5703 << cardReader_->card()
5704 << CoinMessageEol;
5705 } else if (numberErrors > 100000) {
5706 handler_->message(COIN_MPS_RETURNING, messages_) << CoinMessageEol;
5707 return numberErrors;
5708 }
5709 }
5710 }
5711 if (cardReader_->whichSection() != COIN_ENDATA_SECTION && cardReader_->whichSection() != COIN_CONIC_SECTION) {
5712 handler_->message(COIN_MPS_BADIMAGE, messages_) << cardReader_->cardNumber()
5713 << cardReader_->card()
5714 << CoinMessageEol;
5715 handler_->message(COIN_MPS_RETURNING, messages_) << CoinMessageEol;
5716 return numberErrors + 100000;
5717 }
5718
5719 stopHash(1);
5720 // Do arrays as new [] and make column ordered
5721 columnStart = new CoinBigIndex[numberColumns_ + 1];
5722 // for counts
5723 CoinBigIndex *count = new CoinBigIndex[numberColumns_];
5724 memset(count, 0, numberColumns_ * sizeof(CoinBigIndex));
5725 CoinBigIndex i;
5726 // See about lower triangular
5727 if (checkSymmetry && numberErrors)
5728 checkSymmetry = 2; // force corrections
5729 if (checkSymmetry) {
5730 if (checkSymmetry == 1) {
5731 // just check lower triangular
5732 for (i = 0; i < numberElements; i++) {
5733 int iColumn = column[i];
5734 int iColumn2 = column2Temp[i];
5735 if (iColumn2 < iColumn) {
5736 numberErrors = -4;
5737 column[i] = iColumn2;
5738 column2Temp[i] = iColumn;
5739 }
5740 }
5741 } else {
5742 // make lower triangular
5743 for (i = 0; i < numberElements; i++) {
5744 int iColumn = column[i];
5745 int iColumn2 = column2Temp[i];
5746 if (iColumn2 < iColumn) {
5747 column[i] = iColumn2;
5748 column2Temp[i] = iColumn;
5749 }
5750 }
5751 }
5752 }
5753 for (i = 0; i < numberElements; i++) {
5754 int iColumn = column[i];
5755 count[iColumn]++;
5756 }
5757 // Do starts
5758 CoinBigIndex number = 0;
5759 columnStart[0] = 0;
5760 for (i = 0; i < numberColumns_; i++) {
5761 number += count[i];
5762 count[i] = columnStart[i];
5763 columnStart[i + 1] = number;
5764 }
5765 column2 = new int[numberElements];
5766 elements = new double[numberElements];
5767
5768 // Get column ordering
5769 for (i = 0; i < numberElements; i++) {
5770 int iColumn = column[i];
5771 int iColumn2 = column2Temp[i];
5772 CoinBigIndex put = count[iColumn];
5773 elements[put] = elementTemp[i];
5774 column2[put++] = iColumn2;
5775 count[iColumn] = put;
5776 }
5777 free(column);
5778 free(column2Temp);
5779 free(elementTemp);
5780
5781 // Now in column order - deal with duplicates
5782 for (i = 0; i < numberColumns_; i++)
5783 count[i] = -1;
5784
5785 CoinBigIndex start = 0;
5786 number = 0;
5787 for (i = 0; i < numberColumns_; i++) {
5788 CoinBigIndex j;
5789 for (j = start; j < columnStart[i + 1]; j++) {
5790 int iColumn2 = column2[j];
5791 if (count[iColumn2] < 0) {
5792 count[iColumn2] = j;
5793 } else {
5794 // duplicate
5795 CoinBigIndex iOther = count[iColumn2];
5796 double value = elements[iOther] + elements[j];
5797 elements[iOther] = value;
5798 elements[j] = 0.0;
5799 }
5800 }
5801 for (j = start; j < columnStart[i + 1]; j++) {
5802 int iColumn2 = column2[j];
5803 count[iColumn2] = -1;
5804 double value = elements[j];
5805 if (value) {
5806 column2[number] = iColumn2;
5807 elements[number++] = value;
5808 }
5809 }
5810 start = columnStart[i + 1];
5811 columnStart[i + 1] = number;
5812 }
5813
5814 delete[] count;
5815 return numberErrors;
5816 }
5817 /* Read in a list of cones from the given filename.
5818 If filename is NULL (or same) then continues reading from previous file.
5819 If not then the previous file is closed. Code should be added to
5820 general MPS reader to read this if CSECTION
5821
5822 No checking is done that in unique cone
5823
5824 Arrays should be deleted by delete []
5825
5826 Returns number of errors, -1 bad file, -2 no conic section, -3 empty section
5827
5828 columnStart is numberCones+1 long, other number of columns in matrix
5829
5830 coneType is 1 for QUAD, 2 for RQUAD (numberCones long)
5831 */
readConicMps(const char * filename,int * & columnStart,int * & column,int * & coneType,int & numberCones)5832 int CoinMpsIO::readConicMps(const char *filename,
5833 int *&columnStart, int *&column, int *&coneType, int &numberCones)
5834 {
5835 // Deal with filename - +1 if new, 0 if same as before, -1 if error
5836 CoinFileInput *input = 0;
5837 int returnCode = dealWithFileName(filename, "", input);
5838 if (returnCode < 0) {
5839 return -1;
5840 } else if (returnCode > 0) {
5841 delete cardReader_;
5842 cardReader_ = new CoinMpsCardReader(input, this);
5843 }
5844
5845 // See if CSECTION just found
5846 if (!filename && cardReader_->whichSection() == COIN_CONIC_SECTION) {
5847 cardReader_->setWhichSection(COIN_CONIC_SECTION);
5848 } else {
5849 cardReader_->readToNextSection();
5850
5851 // Skip NAME
5852 if (cardReader_->whichSection() == COIN_NAME_SECTION)
5853 cardReader_->readToNextSection();
5854 if (cardReader_->whichSection() == COIN_CONIC_SECTION) {
5855 // looks good
5856 } else if (cardReader_->whichSection() == COIN_EOF_SECTION) {
5857 handler_->message(COIN_MPS_EOF, messages_) << fileName_
5858 << CoinMessageEol;
5859 return -3;
5860 } else {
5861 handler_->message(COIN_MPS_BADFILE1, messages_) << cardReader_->card()
5862 << cardReader_->cardNumber()
5863 << fileName_
5864 << CoinMessageEol;
5865 return -2;
5866 }
5867 }
5868
5869 numberCones = 0;
5870
5871 // Get arrays (some too big, but ...)
5872 columnStart = new int[numberColumns_ + 1];
5873 column = new int[numberColumns_];
5874 coneType = new int[numberColumns_];
5875 // check QUAD or RQUAD (by hand) - card has had end stripped
5876 const char *quad = cardReader_->card() + strlen(cardReader_->card()) - 4;
5877 // Should be QUAD but if not don't complain
5878 int type = 1;
5879 if (!strcmp(quad, "QUAD")) {
5880 if (*(quad - 1) == 'R')
5881 type = 2;
5882 }
5883 coneType[0] = type;
5884 int numberErrors = 0;
5885 columnStart[0] = 0;
5886 int numberElements = 0;
5887 startHash(1);
5888
5889 while (cardReader_->nextField() == COIN_CONIC_SECTION) {
5890 const char *card = cardReader_->card();
5891 if (!strncmp(card, "CSECTION", 8)) {
5892 // check QUAD or RQUAD (by hand) - card has had end stripped
5893 const char *quad = card + strlen(card) - 4;
5894 // Should be QUAD but if not don't complain
5895 int type = 1;
5896 if (!strcmp(quad, "QUAD")) {
5897 if (*(quad - 1) == 'R')
5898 type = 2;
5899 }
5900 if (numberElements == columnStart[numberCones]) {
5901 printf("Cone must have at least one column\n");
5902 abort();
5903 }
5904 columnStart[++numberCones] = numberElements;
5905 coneType[numberCones] = type;
5906 continue;
5907 }
5908 COINColumnIndex iColumn1;
5909 switch (cardReader_->mpsType()) {
5910 case COIN_BLANK_COLUMN:
5911 // get index
5912 iColumn1 = findHash(cardReader_->columnName(), 1);
5913
5914 if (iColumn1 >= 0) {
5915 column[numberElements++] = iColumn1;
5916 } else {
5917 numberErrors++;
5918 if (numberErrors < 100) {
5919 handler_->message(COIN_MPS_NOMATCHCOL, messages_)
5920 << cardReader_->columnName() << cardReader_->cardNumber() << cardReader_->card()
5921 << CoinMessageEol;
5922 } else if (numberErrors > 100000) {
5923 handler_->message(COIN_MPS_RETURNING, messages_) << CoinMessageEol;
5924 return numberErrors;
5925 }
5926 }
5927 break;
5928 default:
5929 numberErrors++;
5930 if (numberErrors < 100) {
5931 handler_->message(COIN_MPS_BADIMAGE, messages_) << cardReader_->cardNumber()
5932 << cardReader_->card()
5933 << CoinMessageEol;
5934 } else if (numberErrors > 100000) {
5935 handler_->message(COIN_MPS_RETURNING, messages_) << CoinMessageEol;
5936 return numberErrors;
5937 }
5938 }
5939 }
5940 if (cardReader_->whichSection() == COIN_ENDATA_SECTION) {
5941 // Error if no cones
5942 if (!numberElements) {
5943 handler_->message(COIN_MPS_EOF, messages_) << fileName_
5944 << CoinMessageEol;
5945 delete[] columnStart;
5946 delete[] column;
5947 delete[] coneType;
5948 columnStart = NULL;
5949 column = NULL;
5950 coneType = NULL;
5951 return -3;
5952 } else {
5953 columnStart[++numberCones] = numberElements;
5954 }
5955 } else {
5956 handler_->message(COIN_MPS_BADFILE1, messages_) << cardReader_->card()
5957 << cardReader_->cardNumber()
5958 << fileName_
5959 << CoinMessageEol;
5960 delete[] columnStart;
5961 delete[] column;
5962 delete[] coneType;
5963 columnStart = NULL;
5964 column = NULL;
5965 coneType = NULL;
5966 return -2;
5967 }
5968
5969 stopHash(1);
5970 return numberErrors;
5971 }
5972 // Add string to list
addString(int iRow,int iColumn,const char * value)5973 void CoinMpsIO::addString(int iRow, int iColumn, const char *value)
5974 {
5975 char id[20];
5976 sprintf(id, "%d,%d,", iRow, iColumn);
5977 int n = static_cast< int >(strlen(id) + strlen(value));
5978 if (numberStringElements_ == maximumStringElements_) {
5979 maximumStringElements_ = 2 * maximumStringElements_ + 100;
5980 char **temp = new char *[maximumStringElements_];
5981 for (int i = 0; i < numberStringElements_; i++)
5982 temp[i] = stringElements_[i];
5983 delete[] stringElements_;
5984 stringElements_ = temp;
5985 }
5986 char *line = reinterpret_cast< char * >(malloc(n + 1));
5987 stringElements_[numberStringElements_++] = line;
5988 strcpy(line, id);
5989 strcat(line, value);
5990 }
5991 // Decode string
decodeString(int iString,int & iRow,int & iColumn,const char * & value) const5992 void CoinMpsIO::decodeString(int iString, int &iRow, int &iColumn, const char *&value) const
5993 {
5994 iRow = -1;
5995 iColumn = -1;
5996 value = NULL;
5997 if (iString >= 0 && iString < numberStringElements_) {
5998 value = stringElements_[iString];
5999 sscanf(value, "%d,%d,", &iRow, &iColumn);
6000 value = strchr(value, ',');
6001 assert(value);
6002 value++;
6003 value = strchr(value, ',');
6004 assert(value);
6005 value++;
6006 }
6007 }
6008 // copies in strings from a CoinModel - returns number
copyStringElements(const CoinModel * model)6009 int CoinMpsIO::copyStringElements(const CoinModel *model)
6010 {
6011 #if COIN_BIG_INDEX == 0
6012 if (!model->stringsExist())
6013 return 0; // no strings
6014 assert(!numberStringElements_);
6015 /*
6016 First columns (including objective==numberRows)
6017 then RHS(==numberColumns (+1)) (with rowLower and rowUpper marked)
6018 then bounds LO==numberRows+1, UP==numberRows+2
6019 */
6020 int numberColumns = model->numberColumns();
6021 int numberRows = model->numberRows();
6022 int iColumn;
6023 for (iColumn = 0; iColumn < numberColumns; iColumn++) {
6024 const char *expr = model->getColumnObjectiveAsString(iColumn);
6025 if (strcmp(expr, "Numeric")) {
6026 addString(numberRows, iColumn, expr);
6027 }
6028 CoinModelLink triple = model->firstInColumn(iColumn);
6029 while (triple.row() >= 0) {
6030 int iRow = triple.row();
6031 const char *expr = model->getElementAsString(iRow, iColumn);
6032 if (strcmp(expr, "Numeric")) {
6033 addString(iRow, iColumn, expr);
6034 }
6035 triple = model->next(triple);
6036 }
6037 }
6038 int iRow;
6039 for (iRow = 0; iRow < numberRows; iRow++) {
6040 // for now no ranges
6041 const char *expr1 = model->getRowLowerAsString(iRow);
6042 const char *expr2 = model->getRowUpperAsString(iRow);
6043 if (strcmp(expr1, "Numeric")) {
6044 if (rowupper_[iRow] > 1.0e20 && !strcmp(expr2, "Numeric")) {
6045 // G row
6046 addString(iRow, numberColumns, expr1);
6047 rowlower_[iRow] = STRING_VALUE;
6048 } else if (!strcmp(expr1, expr2)) {
6049 // E row
6050 addString(iRow, numberColumns, expr1);
6051 rowlower_[iRow] = STRING_VALUE;
6052 addString(iRow, numberColumns + 1, expr1);
6053 rowupper_[iRow] = STRING_VALUE;
6054 } else if (rowlower_[iRow] < -1.0e20 && !strcmp(expr1, "Numeric")) {
6055 // L row
6056 addString(iRow, numberColumns + 1, expr2);
6057 rowupper_[iRow] = STRING_VALUE;
6058 } else {
6059 // Range
6060 printf("Unaable to handle string ranges row %d %s %s\n",
6061 iRow, expr1, expr2);
6062 abort();
6063 }
6064 }
6065 }
6066 // Bounds
6067 for (iColumn = 0; iColumn < numberColumns; iColumn++) {
6068 const char *expr = model->getColumnLowerAsString(iColumn);
6069 if (strcmp(expr, "Numeric")) {
6070 addString(numberRows + 1, iColumn, expr);
6071 collower_[iColumn] = STRING_VALUE;
6072 }
6073 expr = model->getColumnUpperAsString(iColumn);
6074 if (strcmp(expr, "Numeric")) {
6075 addString(numberRows + 2, iColumn, expr);
6076 colupper_[iColumn] = STRING_VALUE;
6077 }
6078 }
6079 return numberStringElements_;
6080 #else
6081 abort();
6082 return 0;
6083 #endif
6084 }
6085 // Constructor
CoinSet(int numberEntries,const int * which)6086 CoinSet::CoinSet(int numberEntries, const int *which)
6087 {
6088 numberEntries_ = numberEntries;
6089 which_ = new int[numberEntries_];
6090 weights_ = NULL;
6091 memcpy(which_, which, numberEntries_ * sizeof(int));
6092 setType_ = 1;
6093 }
6094 // Default constructor
CoinSet()6095 CoinSet::CoinSet()
6096 {
6097 numberEntries_ = 0;
6098 which_ = NULL;
6099 weights_ = NULL;
6100 setType_ = 1;
6101 }
6102
6103 // Copy constructor
CoinSet(const CoinSet & rhs)6104 CoinSet::CoinSet(const CoinSet &rhs)
6105 {
6106 numberEntries_ = rhs.numberEntries_;
6107 setType_ = rhs.setType_;
6108 which_ = CoinCopyOfArray(rhs.which_, numberEntries_);
6109 weights_ = CoinCopyOfArray(rhs.weights_, numberEntries_);
6110 }
6111
6112 //----------------------------------------------------------------
6113 // Assignment operator
6114 //-------------------------------------------------------------------
6115 CoinSet &
operator =(const CoinSet & rhs)6116 CoinSet::operator=(const CoinSet &rhs)
6117 {
6118 if (this != &rhs) {
6119 delete[] which_;
6120 delete[] weights_;
6121 numberEntries_ = rhs.numberEntries_;
6122 setType_ = rhs.setType_;
6123 which_ = CoinCopyOfArray(rhs.which_, numberEntries_);
6124 weights_ = CoinCopyOfArray(rhs.weights_, numberEntries_);
6125 }
6126 return *this;
6127 }
6128
6129 // Destructor
~CoinSet()6130 CoinSet::~CoinSet()
6131 {
6132 delete[] which_;
6133 delete[] weights_;
6134 }
6135 // Constructor
CoinSosSet(int numberEntries,const int * which,const double * weights,int type)6136 CoinSosSet::CoinSosSet(int numberEntries, const int *which, const double *weights, int type)
6137 : CoinSet(numberEntries, which)
6138 {
6139 weights_ = new double[numberEntries_];
6140 memcpy(weights_, weights, numberEntries_ * sizeof(double));
6141 setType_ = type;
6142 double last = weights_[0];
6143 int i;
6144 bool allSame = true;
6145 for (i = 1; i < numberEntries_; i++) {
6146 if (weights_[i] != last) {
6147 allSame = false;
6148 break;
6149 }
6150 }
6151 if (allSame) {
6152 for (i = 0; i < numberEntries_; i++)
6153 weights_[i] = i;
6154 }
6155 }
6156
6157 // Destructor
~CoinSosSet()6158 CoinSosSet::~CoinSosSet()
6159 {
6160 }
6161 #ifdef USE_SBB
6162 #include "SbbModel.hpp"
6163 #include "SbbBranchActual.hpp"
6164 // returns an object of type SbbObject
6165 SbbObject *
sbbObject(SbbModel * model) const6166 CoinSosSet::sbbObject(SbbModel *model) const
6167 {
6168 // which are matrix here - need to put as integer index
6169 abort();
6170 return new SbbSOS(model, numberEntries_, which_, weights_, 0, setType_);
6171 }
6172 #endif
6173
6174 /* vi: softtabstop=2 shiftwidth=2 expandtab tabstop=2
6175 */
6176